块设备驱动(1)-什么是块设备驱动?块设备驱动概念总结

1.块设备驱动概念

块设备驱动是针对存储设备,例如SD卡、EMMC、NAND FLASH、NOR FLSASH。
块设备驱动以块为单位进行访问、最小寻址单位是扇区、一个块中包含多个扇区、支持随机访问、带缓冲区,,当发生写入操作时,并不会立马操作硬盘,因为写之前要擦除,擦写频繁影响flash寿命。对于flash设备而言,顺序读写扇区能极大提升效率,所以对于不对存储设备,Linux里有实现不同的I/O调度算法。
image.png
而字符设备以字节为单位,不需要缓冲,只能被顺序读写

借鉴一张在网上找到的图片,框架图当然是学习中必不可备的东西,一眼便能有个清晰的认识
image.png
其中块设备驱动请求有两种形式,使用requeset_queue请求队列,以及不使用请求队列的。

2.常用结构体

2.1 block_device结构体

linux内核使用 block_device结构体表示块设备对象, 定义在include/linux/fs.h文件。

struct block_device {
	dev_t			bd_dev;  /* not a kdev_t - it's a search key */
	int			bd_openers;
	struct inode *		bd_inode;	/* will die */
	struct super_block *	bd_super;
	struct mutex		bd_mutex;	/* open/close mutex */
	struct list_head	bd_inodes;
	void *			bd_claiming;
	void *			bd_holder;
	int			bd_holders;
	bool			bd_write_holder;
#ifdef CONFIG_SYSFS
	struct list_head	bd_holder_disks;
#endif
	struct block_device *	bd_contains;
	unsigned		bd_block_size;
	struct hd_struct *	bd_part;
	/* number of times partitions within this device have been opened. */
	unsigned		bd_part_count;
	int			bd_invalidated;
	struct gendisk *	bd_disk;
	struct request_queue *  bd_queue;
	struct list_head	bd_list;
	/*
	 * Private data.  You must have bd_claim'ed the block_device
	 * to use this.  NOTE:  bd_claim allows an owner to claim
	 * the same device multiple times, the owner must take special
	 * care to not mess up bd_private for that case.
	 */
	unsigned long		bd_private;

	/* The counter of freeze processes */
	int			bd_fsfreeze_count;
	/* Mutex for freeze */
	struct mutex		bd_fsfreeze_mutex;
};

2.2 gendisk结构体

linux 内核使用 gendisk 来描述一个磁盘设备,定义include/linux/genhd.h

struct gendisk {
	/* major, first_minor and minors are input parameters only,
	 * don't use directly.  Use disk_devt() and disk_max_parts().
	 */
	int major;			/* major number of driver */
	int first_minor;
	int minors;                     /* maximum number of minors, =1 for
                                         * disks that can't be partitioned. */

	char disk_name[DISK_NAME_LEN];	/* name of major driver */
	char *(*devnode)(struct gendisk *gd, umode_t *mode);

	unsigned int events;		/* supported events */
	unsigned int async_events;	/* async events, subset of all */

	/* Array of pointers to partitions indexed by partno.
	 * Protected with matching bdev lock but stat and other
	 * non-critical accesses use RCU.  Always access through
	 * helpers.
	 */
	struct disk_part_tbl __rcu *part_tbl;
	struct hd_struct part0;

	const struct block_device_operations *fops;
	struct request_queue *queue;
	void *private_data;

	int flags;
	struct device *driverfs_dev;  // FIXME: remove
	struct kobject *slave_dir;

	struct timer_rand_state *random;
	atomic_t sync_io;		/* RAID */
	struct disk_events *ev;
#ifdef  CONFIG_BLK_DEV_INTEGRITY
	struct blk_integrity *integrity;
#endif
	int node_id;
};

major:主设备号
first_minor:第一个次设备号
minors:次设备号数量
part_tbl:磁盘对应的分区表
fops:块设备操作集
queue:磁盘对应的请求队列

2.3 block_device_operations 结构体

struct block_device_operations {
	int (*open) (struct block_device *, fmode_t);
	void (*release) (struct gendisk *, fmode_t);
	int (*rw_page)(struct block_device *, sector_t, struct page *, int rw);
	int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
	int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
	long (*direct_access)(struct block_device *, sector_t,
					void **, unsigned long *pfn, long size);
	unsigned int (*check_events) (struct gendisk *disk,
				      unsigned int clearing);
	/* ->media_changed() is DEPRECATED, use ->check_events() instead */
	int (*media_changed) (struct gendisk *);
	void (*unlock_native_capacity) (struct gendisk *);
	int (*revalidate_disk) (struct gendisk *);
	int (*getgeo)(struct block_device *, struct hd_geometry *);
	/* this callback is with swap_lock and sometimes page table lock held */
	void (*swap_slot_free_notify) (struct block_device *, unsigned long);
	struct module *owner;
};

open :打开指定的块设备
release:释放指定块设备
rw_page :数用于读写指定的页
ioctl:块设备IO控制
compat_ioctl:32位设备调用的ioctl函数
getgeo:获取磁盘信息,包括磁头、柱面和扇区
owner:标明属于哪个模块

3.块设备操作常用API

3.1块设备操作

1)注册块设备
int register_blkdev(unsigned int major, const char *name)
2)注销块设备
void unregister_blkdev(unsigned int major, const char *name)

major:主设备号
name:块设备名字

3.2gendisk相关操作

1)申请gendisk
struct gendisk *alloc_disk(int minors)
minors:次设备号数量、即gendisk对应的分区数量

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

3)将 gendisk 添加到内核
void add_disk(struct gendisk *disk)
disk:要添加的gendisk结构体

4)设置 gendisk 容量
void set_capacity(struct gendisk *disk, sector_t size)
size:扇区数量大小,块设备驱动之间的扇区固定512字节,无论物理扇区是多大

5)增加gendisk 引用计数
struct kobject *get_disk(struct gendisk *disk)

5)减小gendisk 引用计数
void put_disk(struct gendisk *disk)

4.块设备IO请求过程

4.1 请求队列 request_queue

内核将块设备的读写,都放入到请求队列request_queue中,通过request请求,其中包含块设备从哪个地址读取,读取的数据长度,读取到哪里等。每个gendisk结构体中都有一个requeset_queue,即每个磁盘gendisk都会分配一个request_queue。
初始化请求队列之后,赋值给gendisk的queue成员变量
1)初始化请求队列(使用默认IO调度器)
当访问外部硬件、光盘、磁盘等,需要控制访问顺序来提升访问效率,则需要使用默认IO调度器,即需要使用这个API
request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
rfn:请求处理函数指针
lcok:自旋锁指针

2)删除请求队列
void blk_cleanup_queue(struct request_queue *q)
q:删除的请求队列

3)分配请求队列(不使用默认IO调度器),并绑定制造请求函数
当访问简单的SD卡等,可以进行随机访问,不需要控制访问顺序来提升访问效率,则不需要设置IO调度器,即可直接使用这个API
struct request_queue *blk_alloc_queue(gfp_t gfp_mask)
gfp_mask : 内存分配的方式。 GFP_KERNEL和GFP_ATOMIC,
GFP_ATOMIC: 用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠
GFP_KERNEL: 内核内存的正常分配. 可能睡眠

void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
mfs:make_request_fn函数指针
blk_alloc_queue不使用默认IO调度器,需要自己实现mfs函数。上层代码向请求队列发生请求,调用make_request_fn函数。

4.2 请求request

请求队列(request_queue)里面包含的就是一系列的请求(request),其中的bio成员变量保存真正的数据。

1)获取请求
从request_queue中依次获取每个request
request *blk_peek_request(struct request_queue *q)
q:指定request_queue
返回值:request_queue 中下一个要处理的请求(request)

2)开启请求
从request_queue中获取到request后,调用该函数开始处理这个request
void blk_start_request(struct request *req)
**req:**要开始处理的请求

3)获取并处理请求
一次性完成请求的获取和开启
struct request *blk_fetch_request(struct request_queue *q)

4)其他API

blk_end_request()   //请求中指定字节数据被处理完成。 
blk_end_request_all()  //请求中所有数据全部处理完成。 
blk_end_request_cur()  //当前请求中的 chunk。 
blk_end_request_err()  //处理完请求,直到下一个错误产生。 
__blk_end_request()  //和 blk_end_request 函数一样,但是需要持有队列锁。 
__blk_end_request_all()  //和 blk_end_request_all 函数一样,但是需要持有队列锁。 
__blk_end_request_cur() //和 blk_end_request_cur 函数一样,但是需要持有队列锁。 
__blk_end_request_err() //和 blk_end_request_err 函数一样,但是需要持有队列锁

4.3 bio结构

每个 request 里面会有多个 bio,bio 保存着最终要读写的数据、地址等信息。
从 request_queue 中取出一个一个的 request,然后再从每个 request 里面取出 bio, 最后根据 bio 的描述讲数据写入到块设备,或者从块设备中读取数据
image.png

源码如下:

struct bio {
	struct bio		*bi_next;	/* request queue link */
	struct block_device	*bi_bdev;
	unsigned long		bi_flags;	/* status, command, etc */
	unsigned long		bi_rw;		/* bottom bits READ/WRITE,
						 * top bits priority
						 */
	struct bvec_iter	bi_iter;
	/* Number of segments in this BIO after
	 * physical address coalescing is performed.
	 */
	unsigned int		bi_phys_segments;
	/*
	 * To keep track of the max segment size, we account for the
	 * sizes of the first and last mergeable segments in this bio.
	 */
	unsigned int		bi_seg_front_size;
	unsigned int		bi_seg_back_size;

	atomic_t		bi_remaining;

	bio_end_io_t		*bi_end_io;

	void			*bi_private;
#ifdef CONFIG_BLK_CGROUP
	/*
	 * Optional ioc and css associated with this bio.  Put on bio
	 * release.  Read comment on top of bio_associate_current().
	 */
	struct io_context	*bi_ioc;
	struct cgroup_subsys_state *bi_css;
#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;

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


struct bvec_iter {
    sector_t bi_sector; /* I/O 请求的设备起始扇区(512 字节) */
    unsigned int bi_size; /* 剩余的 I/O 数量 */
    unsigned int bi_idx; /* blv_vec 中当前索引 */
    unsigned int bi_bvec_done; /* 当前 bvec 中已经处理完成的字节数 */
};

struct bio_vec {
    struct page *bv_page; /* 页 */
    unsigned int bv_len; /* 长度 */	
    unsigned int bv_offset; /* 偏移 */
};

其中的bio与bio_iter 与 bio_vec之间的关系如下图所示,他们协同完成描述了数据源、数据长度以及数据目的地。
image.png

4.3.1 bio操作API

/// 遍历bio请求
#define __rq_for_each_bio(_bio, rq) \
     if ((rq->bio)) \
         for (_bio = (rq)->bio; _bio; _bio = _bio->bi_next)

/// 遍历bio中的段
#define bio_for_each_segment(bvl, bio, iter) \
     __bio_for_each_segment(bvl, bio, iter, (bio)->bi_iter)

/// 通知bio处理函数
/// 当不使用默认IO调度器,而使用blk_alloc_queue 自己实现制造请求
/// 则在bio处理完成后要通知内核bio处理完成
bvoid bio_endio(struct bio *bio, int error);

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

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

相关文章

GPU,一统天下

三十年前,CPU 和其他专用处理器几乎处理所有计算任务。那个时代的显卡有助于加快 Windows 和应用程序中 2D 形状的绘制速度,但没有其他用途。 快进到今天,GPU 已经成为业界最具主导地位的芯片之一。 但具有讽刺意味的是,图形芯片…

checking file system on C

1、win7系统 开机检查C盘,虽然可以ESC取消检查,每次操作很麻烦,且没有意思 2、注册表清空BootExecute数值数据 1)打开注册表 WinR (快捷键)输入“regedit”,回车 2)位置HKEY_LOCAL…

HTML5+CSS3+移动web——CSS基础

系列文章目录 HTML5CSS3移动web——HTML 基础-CSDN博客https://blog.csdn.net/ymxk2876721452/article/details/136070953?spm1001.2014.3001.5501HTML5CSS3移动web——列表、表格、表单-CSDN博客https://blog.csdn.net/ymxk2876721452/article/details/136221443?spm1001.2…

基于stm32的流水灯设计

1基于stm32的流水灯设计[proteus仿真] 速度检测系统这个题目算是课程设计和毕业设计中常见的题目了,本期是一个基于51单片机的自行车测速系统设计 需要的源文件和程序的小伙伴可以关注公众号【阿目分享嵌入式】,赞赏任意文章 2¥&#xff0c…

考研经验|如何从考研失败中走出来?

对我来说,太丢人了 其实我在本科的时候在同学眼中,一直很优秀,每年奖学金必有我的,国家励志奖学金,国家奖学金,这种非常难拿的奖学金,我也拿过,本科期间学校有一个公费去新西兰留学的…

Haproxy集群

一、HAProxy介绍 HAProxy是法国开发者威利塔罗(Willy Tarreau)在2000年使用C语言开发的一个开源软件,是一款具备高并发(一万以上)、高性能的TCP和HTTP负载均衡器,支持基于cookie的持久性,自动故障切换,支持正则表达式及web状态统…

数据库--SQL语言-1

练习网站:自学SQL网 Select 查询语法复习 SELECT column, another_column, …FROM mytableWHERE condition AND/OR another_condition AND/OR …; 操作符号: 如果属性是字符串, 我们会用到字符串相关的一些操作符号,其中 LIKE&#xff08…

【数理统计实验(四)】方差分析

🍉CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一|统计学|干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项,参与研究经费10w、40w级横向 文…

FIT介绍-0

1、背景 FIT是flattened image tree的简称,它采用了device tree source file(DTS)的语法,生成的image文件也和dtb文件类似(称做itb)。 结构如下图: 其中image source file(.its)和device tree …

Midjourney绘图欣赏系列(八)

Midjourney介绍 Midjourney 是生成式人工智能的一个很好的例子,它根据文本提示创建图像。它与 Dall-E 和 Stable Diffusion 一起成为最流行的 AI 艺术创作工具之一。与竞争对手不同,Midjourney 是自筹资金且闭源的,因此确切了解其幕后内容尚不…

【alibaba funAsr-0.1.9实时语音转文字部署(内外网】

alibaba funAsr-0.1.9实时语音转文字部署(内外网) 官方参考文档: https://github.com/alibaba-damo-academy/FunASR/blob/main/runtime/docs/SDK_advanced_guide_online_zh.md 前提: 我的内网服务器是华为欧拉,arm…

【Linux】shell理解及linux权限解读(“花花公子Root”的自由人生)

目录 1.shell外壳理解 1.1 什么是shell外壳: 1.2 为什么存在shell外壳程序: 1.3外壳程序的具体工作阶段是怎么样的?(招实习生,工作失败也不影响公司) 2.linux下的权限的概念 2.1linux的用户 2.2.文件类型和…

基于c#语言的股票模拟交易软件的开发与实现

基于C#语言的股票模拟交易软件(资管软件/分仓软件)的开发与实现是一个涉及多个技术领域的项目。以下是一个大致的开发流程和实现要点: 一、项目概述 股票模拟交易软件旨在提供一个虚拟的股票交易环境,让用户可以在没有真实资金投…

MySQL常见的存储引擎介绍

我将为您详细讲解 MySQL 常见的存储引擎,以及它们的使用场景、特点、区别和优势。MySQL 支持多种存储引擎,每种存储引擎都有其特定的优势和局限性。了解这些存储引擎的特点和适用场景对于选择合适的存储引擎以及优化数据库性能至关重要。 1. InnoDB 存储…

25改考408最新资讯!拷贝

东北大学 东北大学计算机考研全面改考408 东北大学计算机学院官网:http://www.cse.neu.edu.cn/6274/list.htm 东北大学计算机考研全面改考408 公告原文 东北大学计算机科学与工程学院关于调整2025年硕士研究生招生计算机科学与技术、计算机技术、人工智能专业初试…

AHU 算法分析 实验四 动态规划

实验四:动态规划 实验目的 • 理解动态规划的基本思想,理解动态规划算法的两个基本要素最 优子结构性质和子问题的重叠性质。 • 熟练掌握典型的动态规划问题。 • 掌握动态规划思想分析问题的一般方法,对较简单的问题能正确 分析&#x…

智慧公厕方案_智慧公厕解决方案_智慧公厕整体解决方案

一、什么是智慧公厕? 在现代城市化进程中,公共厕所是不可或缺的基础设施之一。然而,传统的公厕管理模式已经无法满足市民对高效、便捷厕所服务的需求。为了实现公共厕所的信息化管理,智慧公厕整体解决方案应运而生。智慧公厕具体…

查看pip当前关联python版本及位置

好久没用python了,把各种pip指向的环境忘光光啦,这里记录一下查看pip当前关联的python版本及位置的方法: pip -V结果: 我一般不用这个版本的python,去环境变量看了一下,原来是anaconda的Scripts自带pip&a…

Cisco Packet Tracer 模拟器实现一些交换机的基本配置

1. 内容 应用Cisco Packet Tracer 5.3搭建网络 应用Cisco Packet Tracer 5.3配置网络 通过不同的命令实现交换机的基本配置,包括交换机的各种配置模式、交换机的基本配置、交换机的端口配置。 2. 过程 2.1 打开软件 安装模拟器后打开如下: 图1 安装并…

揭秘数据中心幕后:从电力消耗到温度调控的策略

建设并运营数据中心并非简单的连接硬盘、通电和联网就可以,而是涉及复杂的硬件集成、能源管理、散热设计以及适应不断增长的数据处理和存储需求等诸多挑战。随着全球互联网的普及和AI技术的快速发展,数据中心的规模和能耗需求都在急剧增加。尤其是在电力…