0
点赞
收藏
分享

微信扫一扫

linux内核IO子系统之BIO

1.什么是bio

block io,内核IO子系统中最重要的一个结构体struct bio,内核需要读写文件时,会构造一个bio结构体,将此bio结构体放到io队列中。结构体定义如下

/*
 * main unit of I/O for the block layer and lower layers (ie drivers and
 * stacking drivers)
 */
struct bio {
	struct bio		*bi_next;	/* request queue link */
	struct gendisk		*bi_disk;
	unsigned int		bi_opf;		/* bottom bits req flags,
						 * top bits REQ_OP. Use
						 * accessors.
						 */
	unsigned short		bi_flags;	/* status, etc and bvec pool number */
	unsigned short		bi_ioprio;
	unsigned short		bi_write_hint;
	blk_status_t		bi_status;
	u8			bi_partno;
	atomic_t		__bi_remaining;

	struct bvec_iter	bi_iter;

	bio_end_io_t		*bi_end_io;

	void			*bi_private;
#ifdef CONFIG_BLK_CGROUP
	/*
	 * Represents the association of the css and request_queue for the bio.
	 * If a bio goes direct to device, it will not have a blkg as it will
	 * not have a request_queue associated with it.  The reference is put
	 * on release of the bio.
	 */
	struct blkcg_gq		*bi_blkg;
	struct bio_issue	bi_issue;
#ifdef CONFIG_BLK_CGROUP_IOCOST
	u64			bi_iocost_cost;
#endif
#endif

#ifdef CONFIG_BLK_INLINE_ENCRYPTION
	struct bio_crypt_ctx	*bi_crypt_context;
#endif

	union {
#if defined(CONFIG_BLK_DEV_INTEGRITY)
		struct bio_integrity_payload *bi_integrity; /* data integrity */
#endif
	};

	unsigned short		bi_vcnt;	/* how many bio_vec's */

	/*
	 * Everything starting with bi_max_vecs will be preserved by bio_reset()
	 */

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

	atomic_t		__bi_cnt;	/* pin count */

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

	struct bio_set		*bi_pool;

	KABI_RESERVE(1)
	KABI_RESERVE(2)
	KABI_RESERVE(3)
	KABI_RESERVE(4)

	/*
	 * 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[];
};

2.struct bio结构体

网上讲bio结构体的很多,讲的也不是很明白,我写一下我自己学习的理解。 其实就是看内核读写磁盘时,需要提供哪些信息可以支撑本次请求。其实也简单,无论读写,都需要提供两个信息: 内存信息:本次请求,内存数据来源(写)/目的(读)。相关的信息包括 struct bio_vec *bi_io_vec; //描述内存信息,包含struct page、len、offset。这里可以是一个数组,数组中一个元素描述一个内存片段 unsigned short bi_vcnt; //指示bi_io_vec由多少个数据(即多少个内存片段)

磁盘信息:本次请求,磁盘操作哪个位置。由两个字段来描述 struct gendisk *bi_disk; //用来说明操作哪个磁盘设备 struct bvec_iter; //用来描述操作的扇区位置、大小等

历史沿革:这部分信息在低版本linux(如linux-0.11)中由struct buffer_head结构体来描述,最新版本内核调整到bio描述,buffer_head还在,但是变成了其他用途了

3.一个struct bio结构体能描述几个io请求

一个bio只能描述一个io请求,如果由多个io请求,可以通过struct bio *bi_next;串联起来 一个io请求是指操作一个连续磁盘位置一次。例如:一个8k的文件,文件系统block块是4k,磁盘sector是512字节,这个文件在文件系统层面分成不连续的两个block存储,每个block占用8个连续的sector,那么这一次8k的读请求需要构造两个bio请求。

4.关于分散读(scatter read)和聚集写(gather write)

一个bio请求在磁盘侧对应一个连续位置,但是对于内存侧可以有多个位置,由struct bio_vec *bi_io_vec数组来描述,数组中一个元素表示一个内存片段。读写是对称的,即可以将多个内存片段逐个写入连续磁盘位置;或者从磁盘连续位置读到内存的多个内存片段中。这样做的好处是灵活,同时减小了拷贝次数。想象一下,如果内存侧也需要是连续的空间,那么对于分散的读写,或者readv/writev这样的操作就需要先在内存中进行拷贝操作。 注意,无论读写,都需要填写struct bio_vec,指示内存数据来源(写)/目的(读)。

5.关于内存描述部分的几个成员

(1)性能优化 struct bio_vec *bi_io_vec; //内存侧片段 struct bio_vec bi_inline_vecs[]; //柔性数组 在内存片段比较少的时候(低于BIO_INLINE_VECS(4)个片段,实际的绝大多数场景),可以直接在柔性数组中分配struct bio_vec bi_inline_vecs[],然后将bi_io_vec指向bi_inline_vecs柔性数组,这样在分配bio时,就直接分配好了bio_vec结构体,减少一次内存分配;同时也减少了一点内存碎片。 (2)pagecache struct bio_vec的定义如下

struct bio_vec {
	struct page *bv_page;	//注意这里是物理页框
	unsigned int bv_len;
	unsigned int bv_offset;
}

此处的bv_page对应的页面,就是我们平时说的pagecache,也就是页缓存。例外情况:

  • direct io:open时指定O_DIRECT标志
  • 裸设备io:例如直接读取/dev/sda
举报

相关推荐

0 条评论