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。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CentOS 7 编译安装 Git

CentOS 7 编译安装 Git 背景来源删除旧版本 Git安装依赖包下载 Git 源代码检验相关依赖,设置安装路径编译安装添加 Git 环境变量重新加载配置文件查看版本号参考文献 背景来源 为什么要安装新版本呢? 因为无聊,哈哈哈,其实也不是…

Linux下进程的调度与切换

🌎进程的调度与切换 文章目录: 进程的调度与切换 进程切换 进程调度       活动状态进程队列       位图判断       过期队列 总结 前言: 在Linux操作系统中,进程的调度与切换是操作系统核心功能之一&#xff…

【JACS】:用于稳定单原子分散的催化剂架构可对吸附到 Pt 原子、氧化 Pt 簇和 TiO2上金属 Pt 簇的 CO 进行特定位点光谱和反应性测量

摘要:氧化物负载的贵金属纳米粒子是广泛使用的工业催化剂。由于费用和稀有性,开发降低贵金属纳米颗粒尺寸并稳定分散物质的合成方案至关重要。负载型原子分散的单贵金属原子代表了最有效的金属利用几何结构,尽管由于合成均匀且稳定的单原子分…

《论文阅读》E-CORE:情感相关性增强的移情对话生成 EMNLP 2023

《论文阅读》E-CORE:情感相关性增强的移情对话生成 EMNLP 2023 前言摘要模型架构图构建边的构建和初始化节点的初始化图更新情感相关性加强解码损失函数总结前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来…

2.3 性能度量

目录 2.3.1 错误路和精度 2.3.2 查准率,查全率与F1 2.3.4 代价敏感错误率与代价曲线 对学习器的泛化性能进行评估,不仅需要有效可行的实验估计方法,还需要有衡量模型泛化能力的评价标准,这就是性能度量(performance measure).性能度量反映了任务需求,…

uwsgi+nginx+django 部署学习

收集静态文件及部署配置 DEBUG False STATICFILES_DIRS [os.path.join(BASE_DIR, "static"), ] STATIC_ROOT /data/static python3 manage.py collectstatic 收集静态文件,成功后可在STATIC_ROOT目录查看 安装依赖 pip3 install uwsgi django项目结…

粤嵌6818开发板通过MobaXterm使用SSH连接开发板

链接:https://pan.baidu.com/s/18ISP4Ub1HtQx6jCvTQTUHw?pwdfjmu 提取码:fjmu 1.把SSH_config.tar.bz 下载到开发板中 2.解压 SSH_config.tar.bz 解压命令:tar -xzvf SSH_config.tar.bz 3.配置SSH 进入SSH/openssh目录&am…

Python二级备考(1)考纲+基础操作

考试大纲如下: 基本要求 考试内容 考试方式 比较希望能直接刷题,因为不懂的比较多可能会看视频。 基础操作刷题: 知乎大头计算机1-13题 import jieba txtinput() lsjieba.lcut(txt) print("{:.1f}".format(len(txt)/len(ls)…

鸿蒙Next 支持数据双向绑定的组件:Checkbox--Search--TextInput

Checkbox $$语法,$$绑定的变量发生变化时,会触发UI的刷新 Entry Component struct MvvmCase { State isMarry:boolean falseStatesearchText:string build() {Grid(){GridItem(){Column(){Text("checkbox 的双向绑定")Checkbox().select($$…

【GPT-SOVITS-04】SOVITS 模块-鉴别模型解析

说明:该系列文章从本人知乎账号迁入,主要原因是知乎图片附件过于模糊。 知乎专栏地址: 语音生成专栏 系列文章地址: 【GPT-SOVITS-01】源码梳理 【GPT-SOVITS-02】GPT模块解析 【GPT-SOVITS-03】SOVITS 模块-生成模型解析 【G…

机器学习_线性回归

文章目录 线性回归的定义损失函数(误差大小)梯度下降算法梯度下降的API(LinearRegression)均方误差(Mean Squared Error)MSE) 评价机制最小二乘法之正规方程正规方程vs梯度下降 欠拟合与过拟合回归算法之岭回归L2正则化 线性回归的定义 线性回归的定义是:目标值预期…

html5cssjs代码 022 表单输入类型示例

html5&css&js代码 022 表单输入类型示例 一、代码二、解释 这段HTML代码定义了一个网页&#xff0c;展示了表单输入类型示例。 一、代码 <!DOCTYPE html> <html lang"zh-cn"> <head><title>编程笔记 html5&css&js 表单输入…

短剧小程序软件开发首页接口转发到Selectpage

工具&#xff1a;用的是uniapp开发 技术栈&#xff1a;vue、nide..js、云开发 用时&#xff1a;20工作天 软件&#xff1a;Hb、微信开发者工具 <?php namespace app\api\controller; use app\common\controller\Api; /** * 首页接口 */ class Index extends Api { …

pytorch卸载cuda+cudnn并重新配置GPU环境,亲测有效

pytorch卸载cudacudnn 一、卸载cuda 进入【控制面板】&#xff0c;点击【卸载程序】 将红色框中带版本号的都卸载 二、删除cudnn配置 1、进入安装路径 将以下版本号文件直接删除 pytorch配置GPU环境 一、查看支持的cuda最高版本 1、winr&#xff0c;输入cmd&#xf…

【开源】SpringBoot框架开发二手车交易系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手车档案管理模块2.3 车辆预约管理模块2.4 车辆预定管理模块2.5 车辆留言板管理模块2.6 车辆资讯管理模块 三、系统设计3.1 E-R图设计3.2 可行性分析3.2.1 技术可行性分析3.2.2 操作可行性3.2.3 经济…

单片机原理

AT89S51单片机片内硬件结构 &#xff08; 本节以AT89S51为例介绍51单片机的基本结构&#xff0c;如下图所示&#xff09; AT89S51单片机的片内结构&#xff0c;从图中可见 AT89S51单片机的基本组成&#xff1a; 1. CPU&#xff1a;8位的CPU 由控制器和运算器构成 2. 数据存…

【Frida】04_Frida中使用TypeScript脚本(采坑)

▒ 目录 ▒ &#x1f6eb; 导读需求开发环境演示目标 1️⃣ 操作步骤安装node 20.10.0在 VSCode 中打开项目目录初始化一个 NodeJS 项目安装 TypeScript初始化 TypeScript 项目安装依赖配置 TypeScript编写代码编译设置编译脚本运行&#xff0c;查看结果 2️⃣ 采坑frida-compi…

WEB前端项目开发——(一)(2024)

目录 1 通过Git Bash安装 vue-cli 2 创建项目 3 解决Git Bash方向键失效 4 重新进行项目创建 5 浏览器输入地址查看 6 案例——简单修改v3-calendar中的内容 7 测试页面效果 本篇文章介绍通过了Git Bash创建v3-calendar项目&#xff0c;之后对v3-calendar进行简单…

使用gitee自动备份文件

需求 舍友磁盘前两天gg了&#xff0c;里面的论文没有本地备份&#xff0c;最后费劲巴拉的在坚果云上找到了很早前的版本。我说可以上传到github&#xff0c;建一个私人仓库就行了&#xff0c;安全性应该有保证&#xff0c;毕竟不是啥学术大亨&#xff0c;不会有人偷你论文。但是…

R语言:microeco:一个用于微生物群落生态学数据挖掘的R包,第四:trans_beta class

trans_beta class&#xff1a;利用trans_beta类可以变换和绘制beta分集的距离矩阵。该类中涉及到beta多样性的分析主要包括排序、群距、聚类和方差分析。我们首先使用PCoA显示排序。 > dataset$cal_betadiv() The result is stored in object$beta_diversity ... > t1 &…