前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊块设备核心数据结构

聊聊块设备核心数据结构

作者头像
用户4700054
发布2022-08-17 12:52:12
7110
发布2022-08-17 12:52:12
举报
文章被收录于专栏:存储内核技术交流
块设备架构
  • 通用块设备层: 负责从文件系统层传递下来的磁盘O请求,用户态发起的读写操作,经过vfs到实际文件系统ext4,最终需要经过通用块设备层,实际文件系统传递过来的IO操作是通过submit_biobio结构传递给通用块设备层。submit_bio将bio请求到磁盘request请求的转换(请求的合并和IO优化),并将request请求挂入到磁盘请求的队列中,然后进行处理。
  • IO 调度层:负责磁盘IO调度的优化,目前内核支持noop(先来先处理)cfq(按照每个进程的IO请求的公平原则,基于数据量原则)deadline(基于最小寻道时间来处理请求,基于时延的方式),每一种的IO调度针对不同的应用场景的workload会有不同的效果
  • 块设备驱动层:负责将磁盘IO请求转换成磁盘控制器的寄存器读写操作,从而启动硬件读写动作以及相应的中断处理
代码语言:javascript
复制
/** 
* submit_bio - 为 I/O 向块设备层提交 bio 
* @bio: &struct bio 描述 I/O 
* 
* submit_bio() 的目的与 generic_make_request() 非常相似,并且
* 使用它功能来完成大部分工作。两者都是相当粗糙的
* 接口;@bio 必须预先设置并准备好进行 I/O。
* 
*/ 
blk_qc_t  submit_bio ( struct  bio  * bio) 
{ 
	/* 
	 * 如果是常规读/写或附加数据的屏障,
	 * 在提交之前先进行正常的会计处理。
	 */ 
	if ( bio_has_data (bio)) {
		无符号 整数计数;

		if (不太可能( bio_op (bio) == REQ_OP_WRITE_SAME))
			计数=  queue_logical_block_size (bio -> bi_disk -> queue) >>  9 ; 
		否则
			计数=  bio_sectors (bio); 

		if ( op_is_write ( bio_op (bio))) { 
			count_vm_events (PGPGOUT, count); 
		} else { 
			task_io_account_read (bio -> bi_iter.bi_size); 
			count_vm_events(PGPGIN,计数);
		} 

		if (不太可能(block_dump)) { 
			char b[BDEVNAME_SIZE]; 
			printk (KERN_DEBUG "%s(%d): %s block %Lu on %s (%u 个扇区)\n" , 
			current -> comm, task_pid_nr (current), 
				op_is_write ( bio_op (bio)) ?  "WRITE"  :  "READ" , 
				( unsigned  long  long )bio -> bi_iter.bi_sector, 
				bio_devname (bio, b), count); 
		} 
	}

	返回 generic_make_request (bio); 
}

块设备内核磁盘、分区、块设备关系

  • struct block_device:块设备对于整个内核有三个作用,第一,对物理硬盘进行分割;第二,向上与文件系统进行交互;第三,向下与物理磁盘的枢纽。块设备通过struct block_device->bd_inode指向类似于/dev/sda1这样的关联索引节点。在设备驱动层看来,每个struct block_device代表一个块设备,事实上磁盘才是块设备核心.当struct block_device是一个分区上的块设备时候,bd_contains指向包含整个磁盘设备的对应的那个struct block_device.
  • struct gendisk:每一个物理磁盘只有唯一个struct gendisk结构,磁盘上的每一个分区struct hd_struct对应一个块设备struct block_device数据结构。
  • struct hd_struct:用于联系逻辑分区和物理磁盘建立的映射关系,最核心记录是记录该分区中第一个扇区在物理磁盘中的位置和该分区占用的连续的扇区数
代码语言:javascript
复制
// 块设备的结构表示
struct  block_device { 
	dev_t 			bd_dev;  /* 不是 kdev_t - 它是搜索键 */ 
	// 打开的次数
	int 			bd_openers; 
	// 设备的inode,比如/dev/sda1 
	struct  inode  * 		bd_inode;	
	// 设备所在文件系统的超级块
	结构 super_block  * 	bd_super; 
	// 互斥锁
	struct  mutex 		bd_mutex;	/* 打开/关闭互斥锁 */ 
	// 申请该设备者
	void  * 			bd_claiming; 
	// 该持有设备者
	void  * 			bd_holder; 
	// 设备持持者; 
	int 			bd_holders 
	// 是否是写持有
	布尔 bd_write_holder;
# ifdef CONFIG_SYSFS 
	struct  list_head 	bd_holder_disks; 
# endif 
	// 如果是空,则指向整个物理磁盘设备的块设备;否则为
	struct  block_device  * 	bd_contains; 
	// 块大小,以字节为单位
	unsigned 		bd_block_size; 
	u8 bd_partno; 
	//如果是分区则指向的分区
	struct  hd_struct  * 	bd_part; 
	// 磁盘引用次数
	unsigned 		bd_part_count; 
	int 			bd_invalidated;
	// 指向整个磁盘设备
	struct  gendisk  * 	bd_disk; 
	// 本设备的UIO请求
	struct  request_queue  *  bd_queue; 
	结构 backing_dev_info  * bd_bdi; 
	结构 list_head 	bd_list; 
	/* 
	 * 私有数据。您必须 bd_claim'ed block_device 
	 * 才能使用它。注意:bd_claim 允许所有者
	 多次声明同一设备,所有者必须特别
	 注意不要在这种情况下弄乱 bd_private。
	 */
	无符号 长		bd_private; 

	/* 冻结进程的计数器 */ 
	int 			bd_fsfreeze_count; 
	/* 用于冻结的互斥体 */ 
	struct  mutex 		bd_fsfreeze_mutex; 
} __randomize_layout; 


// 磁盘物理的标识
struct  gendisk{ 
	//主设备号
	int major;			
	// 与磁盘关联的第一个次设备号
	int first_minor; 
	
	//磁盘标准名称
	char disk_name[DISK_NAME_LEN];	
	// 获取磁盘的devnode函数
	char  * ( * devnode)( struct  gendisk  * gd, umode_t  * mode); 

	//磁盘的分区表,可以包含多个struct hd_struct分区
	struct  disk_part_tbl __rcu * part_tbl; 
	// 分区表中第0个分区
	struct  hd_struct part0; 

	// 块设备的操作指针表
	const  struct  block_device_operations  * fops; 
	// 请求机会
	结构 request_queue  *队列;
	无效 *私有数据;

	//磁盘状态
	int flags; 
	结构 rw_semaphore lookup_sem; 
	结构 kobject  * slave_dir; 

	结构 timer_rand_state  *随机;
	atomic_t sync_io;		/* RAID */ 
	struct  disk_events  * ev; 
# ifdef   CONFIG_BLK_DEV_INTEGRITY 
	struct  kobject integrity_kobj; 
# endif 	/* CONFIG_BLK_DEV_INTEGRITY */ 
	int node_id; 
	结构 坏块 * bb; 
	结构 lockdep_map lockdep_map; 
}; 


// 一个磁盘分区的磁盘
结构 号{ 
	// 该磁盘分区的结构_ 结构号的
	标识 
	//这个地方有哪些的
	第一个sector_sector_t 
	seqcount_t nr_sects_seq; 
	扇区_t对齐_偏移;
	无符号 整数丢弃对齐;
	结构 设备__dev;
	结构 kobject  * holder_dir; 
	诠释政策,partno;
	结构 partition_meta_info  *信息;
# ifdef CONFIG_FAIL_MAKE_REQUEST 
	intmake_it_fail; 
# endif
	无符号 长标记;
	atomic_t in_flight[ 2 ];
# ifdef 	CONFIG_SMP 
	struct  disk_stats __percpu * dkstats; 
# else 
	struct  disk_stats dkstats; 
# endif 
	struct  percpu_ref ref; 
	结构 rcu_work rcu_work; 
};

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-02-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 存储内核技术交流 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 块设备架构
  • 块设备内核磁盘、分区、块设备关系
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档