Linux 块设备驱动

Linux 三大驱动分别是:字符设备驱动、块设备驱动、网络设备驱动。

块设备是针对存储设备的,比如 SD 卡、EMMC、NAND Flash、Nor Flash、SPI Flash、机械硬盘、固态硬盘等。因此块设备驱动其实就是这些存储设备驱动,块设备驱动相比字符设备驱动的主要区别如下:

①、块设备只能以块为单位进行读写访问,块是 linux 虚拟文件系统(VFS)基本的数据传输
单位。字符设备是以字节为单位进行数据传输的,不需要缓冲。

②、块设备在结构上是可以进行随机访问的,对于这些设备的读写都是按块进行的,块设备使用缓冲区来暂时存放数据,等到条件成熟以后再一次性将缓冲区中的数据写入块设备中。
这么做的目的为了提高块设备寿命,大家如果仔细观察的话就会发现有些硬盘或者 NAND
Flash 就会标明擦除次数(flash 的特性,写之前要先擦除),比如擦除 100000 次等。因此,为了提高块设备寿命而引入了缓冲区,数据先写入到缓冲区中,等满足一定条件后再一次性写入到真正的物理存储设备中,这样就减少了对块设备的擦除次数,提高了块设备寿命。

字符设备是顺序的数据流设备,字符设备是按照字节进行读写访问的。字符设备不需要缓
冲区,对于字符设备的访问都是实时的,而且也不需要按照固定的块大小进行访问。

块设备结构的不同其 I/O 算法也会不同,比如对于 EMMC、SD 卡、NAND Flash 这类没
有任何机械设备的存储设备就可以任意读写任何的扇区(块设备物理存储单元)。但是对于机械硬盘这样带有磁头的设备,读取不同的盘面或者磁道里面的数据,磁头都需要进行移动,因此对于机械硬盘而言,将那些杂乱的访问按照一定的顺序进行排列可以有效提高磁盘性能,linux 里面针对不同的存储设备实现了不同的 I/O 调度算法。

块设备驱动框架

Linux 内核使用 block_device 结构体表示块设备

24  struct block_device {
25  	sector_t		bd_start_sect;
26  	struct disk_stats __percpu *bd_stats;
27  	unsigned long		bd_stamp;
28  	bool			bd_read_only;	/* read-only policy */
29  	dev_t			bd_dev;
30  	int			bd_openers;
31  	struct inode *		bd_inode;	/* will die */
32  	struct super_block *	bd_super;
33  	void *			bd_claiming;
34  	struct device		bd_device;
35  	void *			bd_holder;
36  	int			bd_holders;
37  	bool			bd_write_holder;
38  	struct kobject		*bd_holder_dir;
39  	u8			bd_partno;
40  	spinlock_t		bd_size_lock; /* for bd_inode->i_size updates */
41  	struct gendisk *	bd_disk;
42  
43  	/* The counter of freeze processes */
44  	int			bd_fsfreeze_count;
45  	/* Mutex for freeze */
46  	struct mutex		bd_fsfreeze_mutex;
47  	struct super_block	*bd_fsfreeze_sb;
48  
49  	struct partition_meta_info *bd_meta_info;
50  #ifdef CONFIG_FAIL_MAKE_REQUEST
51  	bool			bd_make_it_fail;
52  #endif
53  
54  	ANDROID_KABI_RESERVE(1);
55  	ANDROID_KABI_RESERVE(2);
56  	ANDROID_KABI_RESERVE(3);
57  	ANDROID_KABI_RESERVE(4);
58  } __randomize_layout;

对于 block_device 结构体,我们重点关注一下第 41 行的 bd_disk 成员变量,此成员变量为 gendisk 结构体指针类型,内核使用 block_device 来表示一个具体的块设备对象,比如一个硬盘或者分区,如果是硬盘的话,bd_disk 就指向通用磁盘结构 gendisk。

注册块设备:和字符设备驱动一样,我们需要向内核注册新的块设备、申请设备号,块设备注册函数为 register_blkdev

注销块设备:和字符设备驱动一样,如果不使用某个块设备了,那么就需要注销掉,函数为
unregister_blkdev

Linux 内核使用 gendisk 结构体来描述一个磁盘设备

121  struct gendisk {
122  	/* major, first_minor and minors are input parameters only,
123  	 * don't use directly.  Use disk_devt() and disk_max_parts().
124  	 */
125  	int major;			/* major number of driver */
126  	int first_minor;
127  	int minors;                     /* maximum number of minors, =1 for
128                                           * disks that can't be partitioned. */
129  
130  	char disk_name[DISK_NAME_LEN];	/* name of major driver */
131  
132  	unsigned short events;		/* supported events */
133  	unsigned short event_flags;	/* flags related to event processing */
134  
135  	struct xarray part_tbl;
136  	struct block_device *part0;
137  
138  	const struct block_device_operations *fops;
139  	struct request_queue *queue;
140  	void *private_data;
141  
142  	int flags;
143  	unsigned long state;
144  #define GD_NEED_PART_SCAN		0
145  #define GD_READ_ONLY			1
146  #define GD_DEAD				2
147  
148  	struct mutex open_mutex;	/* open/close mutex */
149  	unsigned open_partitions;	/* number of open partitions */
150  
151  	struct backing_dev_info	*bdi;
152  	struct kobject *slave_dir;
153  #ifdef CONFIG_BLOCK_HOLDER_DEPRECATED
154  	struct list_head slave_bdevs;
155  #endif
156  	struct timer_rand_state *random;
157  	atomic_t sync_io;		/* RAID */
158  	struct disk_events *ev;
159  #ifdef  CONFIG_BLK_DEV_INTEGRITY
160  	struct kobject integrity_kobj;
161  #endif	/* CONFIG_BLK_DEV_INTEGRITY */
162  #if IS_ENABLED(CONFIG_CDROM)
163  	struct cdrom_device_info *cdi;
164  #endif
165  	int node_id;
166  	struct badblocks *bb;
167  	struct lockdep_map lockdep_map;
168  	u64 diskseq;
169  
170  	ANDROID_KABI_RESERVE(1);
171  	ANDROID_KABI_RESERVE(2);
172  	ANDROID_KABI_RESERVE(3);
173  	ANDROID_KABI_RESERVE(4);
174  };

major 为磁盘设备的主设备号。first_minor 为磁盘的第一个次设备号。minors 为磁盘的此设备号数量,也就是磁盘的分区数量,这些分区的主设备号一样,此设备号不同。fops 为块设备操作集,为 block_device_operations 结构体类型。和字符设备操作集 file_operations 一样,是块设备驱动中的重点!queue 为磁盘对应的请求队列,所以针对该磁盘设备的请求都放到此队列中,驱动程序需要处理此队列中的所有请求。

编写块的设备驱动的时候需要分配并初始化一个 gendisk,linux 内核提供了一组 gendisk 操作函数:

申请 gendisk:
struct gendisk *alloc_disk(int minors)

删除 gendisk:
void del_gendisk(struct gendisk *gp)

将 gendisk 添加到内核:
void add_disk(struct gendisk *disk)

设置 gendisk 容量:
void set_capacity(struct gendisk *disk, sector_t size)

调整 gendisk 引用计数:
truct kobject * get_disk_and_module (struct gendisk *disk)
void put_disk(struct gendisk *disk)

和字符设备的 file_operations 一样,块设备也有操作集,为结构体 block_device_operations

1935  struct block_device_operations {
1936  	blk_qc_t (*submit_bio) (struct bio *bio);
1937  	int (*open) (struct block_device *, fmode_t);
1938  	void (*release) (struct gendisk *, fmode_t);
1939  	int (*rw_page)(struct block_device *, sector_t, struct page *, unsigned int);
1940  	int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
1941  	int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
1942  	unsigned int (*check_events) (struct gendisk *disk,
1943  				      unsigned int clearing);
1944  	void (*unlock_native_capacity) (struct gendisk *);
1945  	int (*getgeo)(struct block_device *, struct hd_geometry *);
1946  	int (*set_read_only)(struct block_device *bdev, bool ro);
1947  	/* this callback is with swap_lock and sometimes page table lock held */
1948  	void (*swap_slot_free_notify) (struct block_device *, unsigned long);
1949  	int (*report_zones)(struct gendisk *, sector_t sector,
1950  			unsigned int nr_zones, report_zones_cb cb, void *data);
1951  	char *(*devnode)(struct gendisk *disk, umode_t *mode);
1952  	struct module *owner;
1953  	const struct pr_ops *pr_ops;
1954  
1955  	/*
1956  	 * Special callback for probing GPT entry at a given sector.
1957  	 * Needed by Android devices, used by GPT scanner and MMC blk
1958  	 * driver.
1959  	 */
1960  	int (*alternative_gpt_sector)(struct gendisk *disk, sector_t *sector);
1961  
1962  	ANDROID_KABI_RESERVE(1);
1963  	ANDROID_KABI_RESERVE(2);
1964  	ANDROID_OEM_DATA(1);
1965  };

open 函数用于打开指定的设备。release 函数用于关闭(释放)指定的块设备。rw_page 函数用于读写指定的页。ioctl 函数用于块设备 I/O 控制。compat_ioctl 函数与 ioctl 函数一样,都是用于块设备的 I/O 控制。区别在于在 64位系统上,32 位应用程序的 ioctl 会调用 compat_iotl 函数。在 32 位系统上运行的 32 位应用程序调用的就是 ioctl 函数。getgeo 函数用于获取磁盘信息,包括磁头、柱面和扇区等信息。owner 表示此结构体属于哪个模块,一般直接设置为 THIS_MODULE。

块设备 I/O 请求过程

大家如果仔细观察的话会在 block_device_operations 结构体中并没有找到 read 和 write 这样的读写函数,那么块设备是怎么从物理块设备中读写数据?这里就引处理块设备驱动中非常重要的 request_queue、request 和 bio。

内核将对块设备的读写都发送到请求队列 request_queue 中,request_queue 中是大量的 request(请求结构体),而 request 又包含了 bio,bio 保存了读写相关数据,比如从块设备的哪个地址开始读取、读取的数据长度,读取到哪里,如果是写的话还包括要写入的数据等。

gendisk 结构体里面有一个 request_queue 结构体指针类型成员变量 queue,在编写块设备驱动的时候,每个磁盘(gendisk)都要分配一个 request_queue。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/464543.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【洞察】区块链、web3、元宇宙等技术共同催生出了什么样的商业未来?

下文为中国信息通信研究院云计算与大数据研究所所长何宝宏为思二勋所著的《分布式商业生态战略:数字商业新逻辑与企业数字化转型新策略》一书所作的推荐序。 近两年来,区块链已从鲜为人知发展到尽人皆知且众说纷纭,从产业初期的静默发展到产…

若你有才能,最好能遇上识才之人,高俅发迹的故事很好诠释了千里马与伯乐的关系

若你有才能,最好能遇上识才之人,高俅发迹的故事很好诠释了千里马与伯乐的关系 其实,“千里马”和“伯乐”都是中国古代传说里的角色。伯乐是古代一个善于相马(识别马的好坏)的人,而“千里马”则是指一匹能跑…

2、FreeRTOS之队列管理

xQueueReceive() 用于从队列中接收 ( 读取)数据单元。接收到的单元同时会从队列 中删除。 xQueuePeek() 也是从从队列中接收数据单元,不同的是并不从队列中删出接收到 的单元。 uxQueueMessagesWaiting()用于查询队列中当前有效数据单元个数。 写队列任…

简介:项目管理九大知识五大过程

前言 项目管理(Project Management,PM/Management by Projects,MBP) 在有限的资源约束下,运用系统的观点、方法和理论,对项目涉及的全部工作进行有效地管理。即从项目的投资决策开始到项目结束的全过程进行计划、组织、指挥、协调…

【首次抽奖】16G、32G免费送!云服务器选购推荐 京东云 阿里云 腾讯云对比 幻兽帕鲁 雾锁王国 省钱学生党

好消息:抽奖活动开启!时间:3月17日——3月24日 最高奖品:16G 6个月;32G 3个月 抽奖规则:B站点赞评论关注即可参与抽奖,3.24日公布获奖名单。 抽奖地址: 【首次抽奖】16G、32G免费…

TTS 擂台: 文本转语音模型的自由搏击场

对文本转语音 (text-to-speech, TTS) 模型的质量进行自动度量非常困难。虽然评估声音的自然度和语调变化对人类来说是一项微不足道的任务,但对人工智能来说要困难得多。为了推进这一领域的发展,我们很高兴推出 TTS 擂台。其灵感来自于LMSys为 LLM 提供的…

检索增强生成(RAG)应用的构建:LangChain与LlamaIndex的比较与选择

对于我要做RAG应用,我应该使用两者中的哪一个。或者说还是都使用? 在人工智能领域,检索增强生成(RAG)应用正变得越来越受欢迎,因为它们能够结合大型语言模型(LLMs)的自然语言处理能力…

不允许你不知道的Python私有属性和私有方法

​ 1.为什么要使用私有属性和私有方法 嘿,各位Python爱好者们,你们有没有遇到过这样的情况:你正在编写一个类,里面有一些属性或方法,你并不想让它们被外部直接访问或修改,但又需要某种方式来控制它们的访问…

【C/C++】C语言开发者必读:迈向C++的高效编程之旅

🧑 作者简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方…

VUE3项目学习系列--Axios二次封装(五)

Axios中文文档 | Axios中文网 (axios-http.cn) Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequ…

【回归预测】基于SSA-BP(麻雀搜索算法优化BP神经网络)的回归预测 多输入单输出【Matlab代码#69】

文章目录 【可更换其他算法,获取资源请见文章第6节:资源获取】1. BP神经网络2. 麻雀搜索算法3. SSA-BP神经网络模型的构建4. 部分代码展示5. 仿真结果展示 【可更换其他算法,获取资源请见文章第6节:资源获取】 1. BP神经网络 BP&…

新手向-从VNCTF2024的一道题学习QEMU Escape

[F] 说在前面 本文的草稿是边打边学边写出来的,文章思路会与一个“刚打完用户态 pwn 题就去打 QEMU Escape ”的人的思路相似,在分析结束以后我又在部分比较模糊的地方加入了一些补充,因此阅读起来可能会相对轻松(当然也不排除这是…

python之前端css样式(一)

css ID选择器 #c1{color:red;#边框为红色border:1px solid red; } <div id"c2">中国移动</div> 类选择器 .xx{color:blue; } <div class"xx">中国联通</div> 标签选择器 li{color: pink; } <ul><li>北京</li…

STM32输入捕获模式测频率

STM32频率的测量&#xff1a;高频适合使用的方法是测频法&#xff0c;低频适合使用的是测周法&#xff0c;&#xff08;其中使用测频法测量频率比较稳定&#xff0c;使用测周法测量频率的方式没有这么稳定&#xff0c;因为测周法只会通过一次的测量就能得出结果所以测试出来的频…

任务管理器进程结束错了,电脑显示白屏该怎么办

电脑就是一个全白&#xff0c;吓人的一批&#xff0c;毕竟以前出过cmd运行出错&#xff0c;然后黑屏&#xff0c;最后只能重装系统。这里出现白屏是还好的&#xff0c;切换了另外的用户&#xff0c;发现电脑上原来的文件还在&#xff0c;所有按下面的方法就解决了。 1.打开任务…

网络编程—DAY3

模拟面试 1.什么是IP地址 是给互联网上的每台主机分配的唯一标识 2.IP地址和mac地址的区别 mac地址是设备的硬件地址&#xff0c;ip地址是给主机分配的网络地址 3.当电脑从一个网络切换到另一个网络哪个会变 ip地址会变&#xff0c;mac地址不会变 4.什么是端口号 用于区…

leetcode 热题 100_环形链表 II

题解一&#xff1a; 哈希表&#xff1a;遍历链表&#xff0c;用哈希表存储遍历过的链表节点&#xff0c;判断链表节点是否在哈希表中存在&#xff0c;如果存在说明链表出现过&#xff0c;第一个重复出现的节点即为开始入环的第一个节点。 import java.util.HashSet;public cla…

【计算机网络】什么是http?

​ 目录 前言 1. 什么是HTTP协议&#xff1f; 2. 为什么使用HTTP协议&#xff1f; 3. HTTP协议通信过程 4. 什么是url&#xff1f; 5. HTTP报文 5.1 请求报文 5.2 响应报文 6. HTTP请求方式 7. HTTP头部字段 8. HTTP状态码 9. 连接管理 长连接与短连接 管线化连接…

无线局域网——wlan

目录 一.wlan的含义和发展 二.wlan技术带来的挑战 1.企业办公场景多样 2.位置速度的要求 3.安全的要求 4.规范的挑战 三.家庭和企业不同的部署需求 1.胖AP模式组网 2.AC瘦AP模式组网 3.组网模式的不同 四.三层隧道转发实验 1.拓扑 2.AP上线 核心交换机vlan ​编辑…

IIS上部署.netcore WebApi项目及swagger

.netcore项目一般是直接双击exe文件&#xff0c;运行服务&#xff0c;今天有个需求&#xff0c;需要把.netcore项目运行在IIS上&#xff0c;遇到了一个小坑&#xff0c;在这里记录一下。 安装IIS&#xff0c;怎么部署站点&#xff0c;这些过于简单就不细说了&#xff0c;不知道…