struct queue_limits结构体参数含义总结
参考:
1:https://developer.aliyun.com/article/784610
2:https://developer.aliyun.com/article/770780
内核版本:4.19.1
结构体定义如下:
struct queue_limits {unsigned long bounce_pfn;unsigned long seg_boundary_mask; unsigned long virt_boundary_mask;unsigned int max_hw_sectors;unsigned int max_dev_sectors;unsigned int chunk_sectors;unsigned int max_sectors;unsigned int max_write_same_sectors;unsigned int max_write_zeroes_sectors;unsigned short max_segments; unsigned int max_segment_size; unsigned int physical_block_size;unsigned short logical_block_size;unsigned int io_min;unsigned int io_opt;unsigned int alignment_offset;unsigned int max_discard_sectors;unsigned int max_hw_discard_sectors;unsigned int discard_granularity;unsigned int discard_alignment;unsigned short max_discard_segments;unsigned char discard_misaligned;unsigned short max_integrity_segments;unsigned char misaligned;unsigned char cluster;unsigned char raid_partial_stripes_expensive;enum blk_zoned_model zoned;
};
内核提供了相关的API接口去设置这些相关的参数,
在blk-settings.c文件。
seg_boundary_mask参数
该参数我的理解是 这个参数的描述的地址是一个dma地址,也就是给控制器用的,我猜测应该是通过dma_xx这系列函数将内核态的虚拟地址映射为dma地址以后,这个dma地址不能超过seg_boundary_mask 的值。
这个参数起作用的地方应该主要是在bio合并的时候调用了
这个宏,该宏会对给seg_boundary_mask 的值做一些相关的限制操作。
include/linux/bio.h
BIOVEC_SEG_BOUNDARY
/*** blk_queue_segment_boundary - set boundary rules for segment merging* @q: the request queue for the device* @mask: the memory boundary mask**/
void blk_queue_segment_boundary(struct request_queue *q, unsigned long mask)
{if (mask < PAGE_SIZE - 1) {mask = PAGE_SIZE - 1;printk(KERN_INFO "%s: set to minimum %lx\n", __func__, mask);}q->limits.seg_boundary_mask = mask;
}
EXPORT_SYMBOL(blk_queue_segment_boundary);
virt_boundary_mask参数
这个参数我的理解是最后生成的dma地址,必须要满足nvme 的prp模型。
在bio生成的时候也会做类型的限制,比如在bio_add_pc_page函数当中调用的
bvec_gap_to_prev函数,就是做类似的操作的。
block/bio.c
/*** blk_queue_virt_boundary - set boundary rules for bio merging* @q: the request queue for the device* @mask: the memory boundary mask**/
void blk_queue_virt_boundary(struct request_queue *q, unsigned long mask)
{q->limits.virt_boundary_mask = mask;
}
EXPORT_SYMBOL(blk_queue_virt_boundary);
max_segments和max_segment_size参数
这两个参数比较容易理解,但是个人感觉加上physical字段会更好,比如
段这个概念是在bio里的bvec去表示的,它可能是page的一部分,也可能等于page,但是在驱动里描述的时候,用的是内核态的虚拟地址,而且不同的bvec表示的page在虚拟地址当中可能不是连续的,但是在物理上可能是连续的,比如bvec[0]和bvec[1],是连续的,那么这个时候对于当前io请求来说,它的段的个数是1,这个1会和max_segments值进行比较。
同理,max_segment_size值就是bvec[0]和bvec[1]的地址长度大小了。
max_segments:
/*** blk_queue_max_segments - set max hw segments for a request for this queue* @q: the request queue for the device* @max_segments: max number of segments** Description:* Enables a low level driver to set an upper limit on the number of* hw data segments in a request.**/
void blk_queue_max_segments(struct request_queue *q, unsigned short max_segments)
{if (!max_segments) {max_segments = 1;printk(KERN_INFO "%s: set to minimum %d\n", __func__, max_segments);}q->limits.max_segments = max_segments;
}
EXPORT_SYMBOL(blk_queue_max_segments);
max_segment_size:
/*** blk_queue_max_segment_size - set max segment size for blk_rq_map_sg* @q: the request queue for the device* @max_size: max size of segment in bytes** Description:* Enables a low level driver to set an upper limit on the size of a* coalesced segment**/
void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size)
{if (max_size < PAGE_SIZE) {max_size = PAGE_SIZE;printk(KERN_INFO "%s: set to minimum %d\n", __func__, max_size);}q->limits.max_segment_size = max_size;
}
EXPORT_SYMBOL(blk_queue_max_segment_size);
续: