当前位置:   article > 正文

struct queue_limits结构体参数学习

struct queue_limits结构体参数学习

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;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

内核提供了相关的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
  • 1
/**
 * 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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

关于max_hw_sectors,max_dev_sectors,chunk_sectors,max_sectors4个有关扇区参数的理解。

查看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,加上打印,确实是这样子。

physical_block_size和logical_block_size和io_min参数的理解。

这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函数就是做类似对齐的功能的。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/217489
推荐阅读
  

闽ICP备14008679号