《Linux内核设计与实现》学习【9】—— 块I/O

本文介绍了块设备的特点,如扇区和块的概念,并详细解释了缓冲区头、bio结构的作用。此外,还探讨了几种I/O调度算法,包括linus电梯、最终期限I/O、预测I/O和完全公正排队等算法的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 块设备

特点:
  1)能够随机访问数据
  2)最小的可寻址单元是扇区,扇区的大小是2的整数倍,一般是 512字节。
扇区和块:
  扇区——物理设备的最小可寻址单元
  块——逻辑上的最小寻址单元

2 缓冲区头

调入块到缓冲区中,每个缓存区对应一个buffer_head描述符,称作缓冲区头。
弊端:
  1)对内核来说,操作页面更为简单
  2)每个缓冲区头只能表示一个块,所以内核在处理大数据时,会分解为对一个个小的块的操作,造成不必要的负担和空间浪费。

3 bio

  块I/O的基本容器——bio。

struct bio {
	sector_t		bi_sector;	/* device address in 512 byte
						   sectors */
	struct bio		*bi_next;	/* request queue link */
	struct block_device	*bi_bdev;
	unsigned long		bi_flags;	/* status, command, etc */
	unsigned long		bi_rw;		/* bottom bits READ/WRITE,
						 * top bits priority
						 */

	unsigned short		bi_vcnt;	/* how many bio_vec's */
	unsigned short		bi_idx;		/* current index into bvl_vec */

	/* Number of segments in this BIO after
	 * physical address coalescing is performed.
	 */
	unsigned int		bi_phys_segments;

	unsigned int		bi_size;	/* residual I/O count */

	/*
	 * To keep track of the max segment size, we account for the
	 * sizes of the first and last mergeable segments in this bio.
	 */
	unsigned int		bi_seg_front_size;
	unsigned int		bi_seg_back_size;

	unsigned int		bi_max_vecs;	/* max bvl_vecs we can hold */

	unsigned int		bi_comp_cpu;	/* completion CPU */

	atomic_t		bi_cnt;		/* pin count */

	struct bio_vec		*bi_io_vec;	/* the actual vec list */

	bio_end_io_t		*bi_end_io;

	void			*bi_private;
#if defined(CONFIG_BLK_DEV_INTEGRITY)
	struct bio_integrity_payload *bi_integrity;  /* data integrity */
#endif

	bio_destructor_t	*bi_destructor;	/* destructor */

	/*
	 * We can inline a number of vecs at the end of the bio, to avoid
	 * double allocations for a small number of bio_vecs. This member
	 * MUST obviously be kept at the very end of the bio.
	 */
	struct bio_vec		bi_inline_vecs[0];
};

最重要的是bi_vec、bi_vcnt和bi_idx,关系
在这里插入图片描述
每个IO请求通过一个bio结构体描述,每个请求包括一个或多个块。
bi_io_vect指向bio_vec结构体数组,该结构体数组包含了一个特定I/O操作所需使用到的所有片段,bio_vec描述了每个片段在物理页中的实际位置。共有bi_cnt个片段,bi_idx指向当前片段。

4 I/O调度

  为减少磁盘寻址时间,需要对块IO请求做优化。通过两种方法:合并与排序。

4.1 linus 电梯

  按扇区增长方向有序排列,类似电梯的工作方式,先沿一个方向移动,再向另一方向移动。当一个新请求加入I/O请求队列时,可能会发生以下4种操作:
  1)如果队列中已存在一个对相邻磁盘扇区操作的请求,那么新请求将和这个已存在的请求合并成一个请求
  2)如果队列中存在一个驻留时间过长的请求,那么新请求之间查到队列尾部,防止旧的请求发生饥饿
  3)如果队列中已扇区方向为序存在合适的插入位置,那么新请求将被插入该位置,保证队列中的请求是以被访问磁盘物理位置为序进行排列的
  4)如果队列中不存在合适的请求插入位置,请求将被插入到队列尾部

4.2 最终期限I/O调度

  linus电梯问题:请求饥饿,发现有驻留时间过长的请求,新请求被插入到队列尾。还有可能造成写—饥饿—读这种特殊问题。
  最终期限I/O调度算法给每个请求设置了超时时间,默认情况下,读请求的超时时间500ms,写请求的超时时间是5s
  具体过程:
  1)新请求交给排序队列
  2)将读请求加入到读请求FIFO队列,写请求加入到写请求FIFO队列
  3)普通操作,将排序队列的头部推入到派发队列
  4)若读/写请求队列有超时,处理超时请求
在这里插入图片描述

4.3 预测I/O调度

  最终期限I/O调度问题:写操作繁重的状态时,会大大降低系统的吞吐量。
  预测I/O调度基于最终期限I/O调度,多了以下操作:
  1)新的读请求提交后,并不立即进行请求处理,而是有意等待片刻(默认是6ms)
  2)等待期间如果有其他对磁盘相邻位置进行读操作的读请求加入,会立刻处理这些读请求
  3)等待期间如果没有其他读请求加入,那么等待时间相当于浪费掉
  4)等待时间结束后,继续执行以前剩下的请求

4.4 完全公正的排队I/O调度

  每个进程有自己的队列,CFQI/O调度程序把进入的I/O请求放入特定的队列中。调度程序以时间片轮转调度对哦,从每个队列中选取请求数,然后进行下一轮调度。

4.5 空操作的I/O调度

  空操作I/O调度只做一件事情,当有新的请求到来时,把它与任一相邻的请求合并。
  在启动时通过命令行选项 elevator=xxx 来启用任何一种

参数I/O调度程序
as预测
cfq完全公正排队
deadline最终期限
noop空操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值