Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >聊聊块设备核心数据结构

聊聊块设备核心数据结构

作者头像
用户4700054
发布于 2022-08-17 04:52:12
发布于 2022-08-17 04:52:12
90100
代码可运行
举报
运行总次数:0
代码可运行
块设备架构
  • 通用块设备层: 负责从文件系统层传递下来的磁盘O请求,用户态发起的读写操作,经过vfs到实际文件系统ext4,最终需要经过通用块设备层,实际文件系统传递过来的IO操作是通过submit_biobio结构传递给通用块设备层。submit_bio将bio请求到磁盘request请求的转换(请求的合并和IO优化),并将request请求挂入到磁盘请求的队列中,然后进行处理。
  • IO 调度层:负责磁盘IO调度的优化,目前内核支持noop(先来先处理)cfq(按照每个进程的IO请求的公平原则,基于数据量原则)deadline(基于最小寻道时间来处理请求,基于时延的方式),每一种的IO调度针对不同的应用场景的workload会有不同的效果
  • 块设备驱动层:负责将磁盘IO请求转换成磁盘控制器的寄存器读写操作,从而启动硬件读写动作以及相应的中断处理
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** 
* 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
代码运行次数:0
运行
AI代码解释
复制
// 块设备的结构表示
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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
聊聊块设备那点事
IO体系结构是什么样的? 系统如何判断设备数据是否就绪方式? 目前系统判断设备上的数据是否就绪采用了轮询和中断两种方式。轮询方式是不断的重复询问设备上的数据是否可用,如果可用,CPU就读取数据;中断方式中系统为每个CPU提供了中断线,可由各个系统设备共享。每个中断通过一个唯一的标识,内核对使用的每个中断提供一个中断服务。中断将暂停正常系统工作,在外设的数据已经就绪,需要由内核或者应用处理,外设会引发一个中断,系统就不需要频繁检查是否有新的数据可用,外设有新数据的情况会自动通知系统。 内核如何管理磁盘设备
用户4700054
2022/08/17
1.3K0
聊聊块设备那点事
Linux | 块设备了解之三层结构
块设备是文件系统的底层支撑,完成数据的存储和访问。块设备也能脱离文件系统以螺设备的形式工作。
heidsoft
2023/03/18
1.7K0
Linux | 块设备了解之三层结构
14.块设备驱动
1、字符设备驱动:   当我们的应用层读写(read()/write())字符设备驱动时,是按字节/字符来读写数据的,期间没有任何缓存区,因为数据量小,不能随机读取数据,例如:按键、LED、鼠标、键盘等 2、块设备:   块设备是i/o设备中的一类, 当我们的应用层对该设备读写时,是按扇区大小来读写数据的,若读写的数据小于扇区的大小,就会需要缓存区, 可以随机读写设备的任意位置处的数据,例如 普通文件(.txt,.c等),硬盘,U盘,SD卡。 3、块设备结构: 段(Segments):由若干个块组成。是Linux内存管理机制中一个内存页或者内存页的一部分。 块 (Blocks): 由Linux制定对内核或文件系统等数据处理的基本单位。通常由1个或多个扇区组成。(对Linux操作系统而言) 扇区(Sectors):块设备的基本单位。通常在512字节到32768字节之间,默认512字节 应用程序进行文件的读写,通过文件系统将文件的读写转换为块设备驱动操作硬件。
嵌入式与Linux那些事
2021/05/20
1.2K0
22.Linux-块设备驱动之框架详细分析(详解)
本节目的:     通过分析块设备驱动的框架,知道如何来写驱动 1.之前我们学的都是字符设备驱动,先来回忆一下 字符设备驱动: 当我们的应用层读写(read()/write())字符设备驱动时,是按字
诺谦
2018/01/03
2.5K0
22.Linux-块设备驱动之框架详细分析(详解)
Linux块设备驱动详解
  传统的机械硬盘一般为3.5英寸硬盘,并由多个圆形蝶片组成,每个蝶片拥有独立的机械臂和磁头,每个堞片的圆形平面被划分了不同的同心圆,每一个同心圆称为一个磁道,位于最外面的道的周长最长称为外道,最里面的道称为内道,通常硬盘厂商会将圆形蝶片最靠里面的一些内道(速度较慢,影响性能)封装起来不用;道又被划分成不同的块单元称为扇区,每个道的周长不同,现代硬盘不同长度的道划分出来的扇区数也是不相同的,而磁头不工作的时候一般位于内道,如果追求响应时间,则数据可存储在硬盘的内道,如果追求大的吞吐量,则数据应存储在硬盘的外道;
嵌入式与Linux那些事
2021/05/20
6.4K0
聊聊内核中IO子系统-上篇
I/O子系统概貌 VFS:内核提供不同实现文件系统的抽象,应用端一般请求到vfs,vfs在调用实际文件系统的posix语义函数,可以理解为vfs作为用户态和实际文件系统的之间的转换桥梁,为用户态提供对于底层磁盘文件系统无感知的文件系统服务层。 Page Cache: 缓存文件系统的数据,这里包括文件系统元数据和文件系统数据,在块缓存之上构建页缓存(常说的Buffer/Cache). Mapping Layer:如果内核需要从块设备上读取数据,就必须知道数据在物理设备上的位置,这个是由映射层Mappin
用户4700054
2022/08/17
7060
聊聊内核中IO子系统-上篇
23.Linux-块设备驱动(详解)
诺谦
2018/01/03
3.9K0
23.Linux-块设备驱动(详解)
Linux驱动开发: 块设备驱动开发
块是一种具有一定结构的随机存取设备,对这种设备的读写是按块进行的,他使用缓冲区来存放暂时的数据,待条件成熟后,从缓存一次性写入设备或者从设备一次性读到缓冲区。 块设备是与字符设备并列的概念, 这两类设备在 Linux 中驱动的结构有较大差异,总体而言, 块设备驱动比字符设备驱动要复杂得多,在 I/O 操作上表现出极大的不同,缓冲、 I/O 调度、请求队列等都是与块设备驱动相关的概念。
DS小龙哥
2022/01/17
36K0
Linux驱动开发: 块设备驱动开发
详解 | Linux系统是如何实现存储并读写文件的?
Linux系统文件操作主要是通过块设备驱动来实现的。 块设备主要指的是用来存储数据的设备,类似于SD卡、U盘、Nor Flash、Nand Flash、机械硬盘和固态硬盘等。块设备驱动就是用来访问这些存储设备的,其与字符设备驱动不同的是:
开源519
2020/09/29
2.1K0
详解 | Linux系统是如何实现存储并读写文件的?
[046]块设备驱动初探
研究IO也很久了,一直无法串联bio和块设备驱动,只知道bio经过IO调度算法传递到块设备驱动,怎么过去的,IO调度算法在哪里发挥作用,一直没有完全搞明白,查看了很多资料,终于对块设备驱动有所理解,也打通了bio到块设备。
王小二
2020/06/08
2.4K0
[046]块设备驱动初探
技术干货 | 漫游Linux块IO
在计算机的世界里,我们可以将业务进行抽象简化为两种场景——计算密集型和IO密集型。这两种场景下的表现,决定这一个计算机系统的能力。数据库作为一个典型的基础软件,它的所有业务逻辑同样可以抽象为这两种场景的混合。因此,一个数据库系统性能的强悍与否,往往跟操作系统和硬件提供的计算能力、IO能力紧密相关。
沃趣科技
2022/12/31
1.9K0
技术干货 | 漫游Linux块IO
Linux下驱动开发_块设备驱动开发(内存模拟存储)
块设备驱动块是Linux下3大设备驱动框架之一,块设备主要是针对存储类型的设备设计的驱动,配合文件系统完成数据存储。在应用层的cp、cd、touch、vim、mount等等可以操作文件,可以操作目录的命令都会通过文件系统,通过块设备驱动完成对底层存储设备的访问,实现数据读取或者写入。
DS小龙哥
2022/10/31
5.4K0
Linux下驱动开发_块设备驱动开发(内存模拟存储)
内存模拟块设备驱动程序设计
/*既然上面分析了,块设备的工作原理。 那如何写一个块设备呢?*/ /*怎么写一个块设备驱动程序? * 1. 分配一个gendisk结构,用alloc_disk函数 * 2. 分配一个request队列,用blk_init_queue函数 * 3. 设置gendisk结构 * 3.1 设置主设备号,次设备号 * 3.2 设置block_device_operations结构 * 3.3 设置queueu结构 * 4. 注册gendisk: 用add_disk函数 */ /***既然知道
DragonKingZhu
2022/05/08
1.5K0
Linux MTD子系统(二)——mtdblock驱动分析
在之前的文章Linux MTD子系统(一)中有提到过mtd块设备,mtd块设备是在MTD设备之上模拟的块设备。 它的作用实际上只有一个——便于我们使用mount(umount)挂载(卸载)MTD设备中的文件系统,例如yaffs2,JFFS2等等。
知否知否应是绿肥红瘦
2025/02/19
6440
Linux MTD子系统(二)——mtdblock驱动分析
Linux文件系统【真的很详细】
哈喽,大家好。今天我们学习文件系统,我们之前在Linux基础IO中研究的是进程和被打开文件之间的关系,以及如何管理被打开的文件。那么,在磁盘中没有被打开的文件应该怎样管理呢?今天,我们一块研究一下。我们开始啦!
破晓的历程
2024/06/24
1.8K0
Linux文件系统【真的很详细】
通俗易懂!快速了解虚拟文件系统(VFS)
为什么 Linux 内核的文件系统类型那么多,都能挂载上呢?为什么系统里可以直接 mount 其他文件系统呢?甚至能把 windows 下的文件夹挂载到 windows 上,为什么 Linux 的虚拟文件系统这么强大?这得益于它的数据结构设计得十分精妙。好像听过,Linux 有什么解决不了的?加一层。
哆哆jarvis
2022/08/23
3.2K0
通俗易懂!快速了解虚拟文件系统(VFS)
Linux内核(5.10)-IO全路径-文件系统到磁盘-或远端iscsi/nvmeof协议盘
DAX: 磁盘(disk)的访问模式有三种 BUFFERED、DIRECT、DAX。前面提到的由于page cache存在可以避免耗时的磁盘通信就是BUFFERED访问模式的集中体现;但是如果我要求用户的write请求要实时存储到磁盘里,不能只在内存中更新,那么此时我便需要DIRECT模式;大家可能听说过flash分为两种nand flash和nor flash,nor flash可以像ram一样直接通过地址线和数据线访问,不需要整块整块的刷,对于这种场景我们采用DAX模式。所以file_operations的read_iter和write_iter回调函数首先就需要根据不同的标志判断采用哪种访问模式, kernel在2020年12月的patch中提出了folio的概念,我们可以把folio简单理解为一段连续内存,一个或多个page的集合
晓兵
2023/12/07
2.3K0
Linux内核(5.10)-IO全路径-文件系统到磁盘-或远端iscsi/nvmeof协议盘
文件系统专栏 | 之文件系统架构
文件系统层次分析 由上而下主要分为用户层、VFS层、文件系统层、缓存层、块设备层、磁盘驱动层、磁盘物理层 用户层:最上面用户层就是我们日常使用的各种程序,需要的接口主要是文件的创建、删除、打开、关闭、写、读等。 VFS层:我们知道Linux分为用户态和内核态,用户态请求硬件资源需要调用System Call通过内核态去实现。用户的这些文件相关操作都有对应的System Call函数接口,接口调用 VFS对应的函数。 文件系统层:不同的文件系统实现了VFS的这些函数,通过指针注册到VFS里面。所以,用户的操作
刘盼
2022/08/26
3.2K0
文件系统专栏 | 之文件系统架构
VFS四大对象之二 struct inode
继上一篇文章:https://cloud.tencent.com/developer/article/1053842 二、inode结构体:(转自http://blog.csdn.net/shanshanpt/article/details/38943731) inode结构体在(include/linux/fs.h中): 保存的其实是实际的数据的一些信息,这些信息称为“元数据”(也就是对文件属性的描述)。例如:文件大小,设备标识符,用户标识符,用户组标识符,文件模式,扩展属性,文件读取或修改的时间戳,链接
233333
2018/03/07
3.1K0
Linux虚拟文件系统初探
什么是VFS? Linux内核使用工厂的设计模式抽象出实际文件系统统一接口,这个就是虚拟文件系统(VFS),根据应用程序调用虚拟文件系统接口,根据不同的文件系统类型(xfs/zfs/ext4)来调用实
用户4700054
2022/08/17
9780
相关推荐
聊聊块设备那点事
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档