赞
踩
参考:
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文件。
该参数我的理解是 这个参数的描述的地址是一个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);
这个参数我的理解是最后生成的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);
这两个参数比较容易理解,但是个人感觉加上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);
查看blk-setting.c里面的源码,发现并没有设置max_dev_sectors和max_sectors4参数值的api, 而只有设置max_hw_sectors和chunk_sectors的。
max_hw_sectors参数的话,在发起io请求时,req->bio->bi_iter.bi_size的值不会超过max_hw_sectors(最小值是8).
而chunk_sectors值的是在连续两次调用queue_rq回调函数时,blk_rq_pos(req)得到的扇区差值不会超过chunk_sectors。
另外两个参数没有相关api设置的话就不研究了,而且在设置max_hw_sectors值的时候,也会考虑max_dev_sectors和max_sectors4的值,,这一块我写demo,加上打印,确实是这样子。
这3个参数的值和LBA值的形成有关系,也就是和struct queue结构体里的__sector值有关系,
通过打印blk_rq_cur_sectors的值可以分析出,直接的影响就是bio里面每一个bvec的大小,比如设置为4096,
那么打印blk_rq_cur_sectors的值就为4096/512,,而physical_block_size参数和io_min的设置倒没有发现那个值会有改变或者规律,通常驱动代码里,physical_block_size和io_min是和logical_block_size一块设置的。(比如nvme驱动)。
也就是说__sector的值是和logical_block_size的值是对齐的,比如get_max_io_size函数就是做类似对齐的功能的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。