segment
segment 的概念实际来自 DMA controller,DMA controller 可以实现一段内存物理地址区间与一段设备物理地址区间之间的数据拷贝,segment 就描述 DMA 数据传输过程中的一段连续的内存空间,也就是说 DMA controller 可以将内存中一个 segment 中的数据拷贝到设备,或将设备中的数据拷贝到 segment 中。
segment 可以是一个 page,也可以是一个 page 的其中一部分,通常存储一个或多个相邻的 sector 的数据。
内核使用 struct bio_vec 来描述 segment 描述符,其中使用 (page, offset_in_page, len) 三元组来描述这一段内存区间。
struct bio_vec {
struct page *bv_page;
unsigned int bv_len;
unsigned int bv_offset;
};
一个 bio 可以包含多个 segment,每个 bio 都维护有一个 segment array 即 bio_vec 数组,其中组织了该 bio 包含的所有 segment;
struct bio {
struct bio_vec *bi_io_vec; /* the actual vec list */
...
};
bio_segments(bio) 用于返回 bio 中剩余待处理的 struct bio_vec 的数量,例如 bio 创建的时候 @bi_io_vec[] 数组一共存储了 X 个 struct bio_vec,在处理了 Y 个 struct bio_vec 之后,bio_segments(bio) 返回值为 (X-Y)。
physical segment
introduction to physical segment
在介绍 physical segment 的概念之前,有必要介绍一下 DMA controller 中 scatter-gather 的概念;
支持 scatter-gather 特性的 DMA controller 可以在一次 DMA transfer 中,实现多个非连续的物理内存区间到一个连续的设备地址区间之间的数据传输,这里的每个连续的物理内存区间就称为一个 physical segment。
那么这里的 physical segment 与之前介绍的 segment 有什么区别呢?
以 bio 为例,实际上 bio 中的一个 bio_vec 就相当于是一个 segment,但是多个 bio_vec 描述的内存区间在物理地址上可能是相邻的,也就是说在执行 DMA transfer 操作的时候,这两个 bio_vec 描述的内存区间实际上可以合并为一个更大的内存区间;
例如下图中 bio_vec[1] 和 bio_vec[2] 描述的内存区间虽然在虚拟地址上并不连续,但是在物理地址上是连续的,因而这两个 "segment" 可以合并为一个 physical segment。
bio 的 @bi_phys_segments 字段就描述该 bio 包含的 physical segment 的数量;
struct bio {
/* Number of segments in this BIO after
* physical address coalescing is performed.
*/
unsigned int