C/C++教程

BLOCK层代码分析(6)之SGL聚散列表

本文主要是介绍BLOCK层代码分析(6)之SGL聚散列表,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

        原本计划本节介绍request的分配,发现会涉及到数据组织从bio到sgl的映射,因此本节介绍数据的SGL组织方式。

        在BLOCK层数据的组织形式为bio和request,通过这两个结构体就可以找到数据的位置。但若传输到SCSI层,硬盘位置用scsi command表示,内存中位置用scatterlist表示。本小节讲述scatterlist是如何将数据组织起来的。

1. scatterlist结构体

        结构体scatterlis包含从CPU视角和设备视角看到的数据的地址和长度(包括页内偏移)。但其中page_link有两个特殊作用:(1)当第0 bit为1时即设置SG_CHAIN,表明当前sgl是链接sgl,只起链接到下一个sgl的作用,这个sgl不会指向数据;(2)当第1bit为1时即设置SG_END,表明当前sgl是最后一个sgl,这个sgl仍指向数据。当其他情况时指向数据对应的第一个页信息。

        成员offset表示数据在页中的偏移。成员length表示数据的长度。

        成员dma_address表示数据的DMA地址即设备看到的地址,成员dma_length表示数据的DMA长度。

2. SGL类型

        SGL分为non-chained SGL和chained SGL。

        Non-chained SGL表示多个sgl是连续的,内核这里对最大的non-chained SGL数目做限制,最大不超过SG_MAX_SINGLE_ALLOC,当申请的SGL个数超过此限制时会自动生成chained SGL。

        Chained SGL存在多个的SGL链,每个SGL链中的SGL是连续的,其中每个SGL链(除了最后一个SGL链)最后一个SGL起链接作用。每个SGL链最大的SGL数目为SG_CHUNK_SIZE(128)。

3. SGL API介绍

        函数sg_alloc_table()用来分配non-chained SGL(当申请的数目nents超过限制时,也会生成chained SGL)。

int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)

        函数sg_alloc_table_chained()来分配chained SGL。其中nents为需要分配的SGL数目,first_chunk为sg_table中已经存在的SGL链,SGL链数目为first_chunk_nents。后面申请的SGL链与first_chunk相链。

​
int sg_alloc_table_chained(struct sg_table *table, int nents, struct scatterlist *first_chunk, unsigned nents_first_chunk)

        两者最终会调用__sg_alloc_table()。这里处理四种情况:

(1)first_chunk = NULL, nents <= max_ents时

        这种情况为sg_table,并没有提前分配SGL链,且需要分配SGL数目小于最大一次性能够分配的数目,此时通过alloc_fn()直接分配即可,生成non-chained SGL链。

(2)first_chunk = NULL, nents > max_ents时

        这种情况为sg_table,并没有提前分配SGL链,且需要分配SGL数目大于最大一次性能够分配的数目,此时通过alloc_fn()会分配一个包含max_ents数目的SGL的SGL链,剩下的部分分配另一个SGL链,并将它们链起来,生成chained SGL链。

(3)first_chunk != NULL, nents <= max_ents时

        这种情况为sg_table,提前分配SGL链, 且提前分配的SGL链上SGL数目满足需要的SGL链,此时会直接返回当前的sg_table。

(4)first_chunk != NULL, nents > max_ents时

         这种情况为sg_table,提前分配SGL链, 但提前分配的SGL链上SGL数目不能够满足nents数目,此时需要通过alloc_fn()分配剩余的数目的SGL组成SGL链,并与提供分配的SGL链连接起来,生成chained SGL链。

4. SCSI命令的SGL

        在SCSI层在分配request时默认内置了2个SGL(实际真正使用的仅1个,另一个做链接SGL使用),在申请时使用sg_alloc_table_chained(&cmd->sdb.table, nr_segs, cmd->sdb.table.sgl, SCSI_INLINE_SG_CNT)申请链式SGL。

        下图为申请150个SGL的情况,其中内置2个SGL为第一个SGL链,这个是随request提前分配的(静态分配),后面两个SGL链是从sgpool中申请分配的(动态分配)。

这篇关于BLOCK层代码分析(6)之SGL聚散列表的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!