Linux 块设备驱动分析(一)

Linux 块设备驱动分析(一)
Linux 块设备驱动分析(二)
Linux 块设备驱动分析(三)

Linux块设备IO子系统框架

块设备与字符设备的不同

块设备是与字符设备并列的概念,这两类设备在Linux中驱动的结构有较大差异,总体而言,块设备驱动比字符设备驱动要复杂得多,在I/O操作上表现出极大的不同,缓冲、I/O调度、请求队列等都是与块设备驱动相关的概念。

系统中能够随机(不需要按顺序)访问固定大小数据片的硬件设备称作块设备,这些固定大小的数据片就称作块。最常见的块设备是硬盘,除此以外,还有软盘驱动器、蓝光光驱和闪存等许多其他块设备。块设备的一般访问方式是通过文件系统。

另一种基本的设备类型是字符设备。字符设备按照字符流的方式被有序访问,像串口和键盘就属于字符设备。

块设备中最小的可寻址单元是扇区,扇区大小最常见的是512字节。虽然物理磁盘寻址是按照扇区级进行的,但是内核执行的所有磁盘操作都是按照块进行的。由于扇区是设备的最小可寻址单元,所以块不能比扇区还小,只能数倍于扇区大小。另外,内核(对有扇区的硬件设备)还要求块大小是2的整数倍,而且不能超过一个页的长度,通常块大小是512字节、1KB或4KB。

块设备的I/O操作特点
(1)块设备只能以块为单位接受输入和返回输出,而字符设备则以字节为单位。
(2)块设备对于 I/O 请求有对应的缓冲区,因此它们可以选择以什么顺序进行响应,字符设备无须缓冲且被直接读写。对于存储设备而言调整读写的顺序作用巨大,因为在读写连续的扇区比分离的扇区更快。
(3)字符设备只能被顺序读写,而块设备可以随机访问。虽然块设备可随机访问,但是对于磁盘这类机械设备而言,顺序地组织块设备的访问可以提高性能。

Linux块设备IO子系统框架
在这里插入图片描述

VFS

内核都是通过文件系统访问块设备的,而不同的硬件平台采用的文件系统不一样,如Ext2、FAT、NFS等,不同的文件系统,访问的接口肯定是不太一样的,但是不管采用何种文件系统,应用层都可以通过open打开一个文件,然后read读取文件中的数据,也可以write往文件中写数据,这得归功于VFS,虚拟文件系统。VFS是对各种具体文件系统的一种封装,用户程序访问文件提供统一的接口。

Generic Block Layer

该层隐藏了底层硬件块设备的特性,将对不同块设备的操作转换成对逻辑数据块的操作,为文件系统层提供通用的块设备读写接口。

I/O Scheduler Layer

接收通用块层发出的I/O请求,为了优化寻址操作,内核既不会简单地按请求接收次序,也不会立即将其提交给磁盘,而是试图合并与排序请求,这可以极大地提高系统的整体性能。

主要的数据结构

gendisk结构体,描述一个通用的磁盘设备,对应一个具体的磁盘,结构体定义如下:

struct gendisk {
	
	//磁盘的主设备号
	int major;	

	//磁盘的第一个次设备号	,如果有分区,每个分区都需要一个次设备号	 
	int first_minor;

	//次设备号个数,1表示不分区
	int minors;                     

	//磁盘的name
	char disk_name[DISK_NAME_LEN];	

	......

	//描述磁盘分区表信息
	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;

	......

};

字符设备有一个file_operations,对应的块设备有一个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 *, bool);
	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 **, pfn_t *,
			long);
	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;
	const struct pr_ops *pr_ops;
};

一块磁盘是可以分成多个分区的,每个分区可以安装不同类型的文件系统,比如ext2、ext4等文件系统。
在这里插入图片描述

hd_struct结构体,描述一个具体的磁盘分区,定义如下:

struct hd_struct {
	
	//分区在磁盘内的起始扇区编号
	sector_t start_sect;

	//分区的大小(扇区数)
	sector_t nr_sects;
	
	......
	struct device __dev;
	struct kobject *holder_dir;
	
  	//如果分区只读则policy为1,否则为0;partno为该分区的区号
	int policy, partno; 
	
	......
};

gendisk里有一成员part_tbl,描述磁盘的分区表信息,定义如下:

struct disk_part_tbl {
	struct rcu_head rcu_head;

	//struct hd_struct数组的大小
	int len;

	struct hd_struct __rcu *last_lookup;
	
	//struct hd_struct数组
	struct hd_struct __rcu *part[];
};

Linux内核也把分区也当作一个块设备。

block_device结构体,描述一个逻辑上的块设备,对应一个磁盘或分区,定义如下:

struct block_device {
	dev_t			bd_dev;     //设备号 
	int			bd_openers;   //这个块设备被打开的次数

	......

	//如果块设备代表一个分区,那么该项指向整个磁盘的block_device 
	struct block_device *	bd_contains;

	//块设备的块长度(以字节为单位)
	unsigned		bd_block_size;

	//指向块设备的分区对象
	struct hd_struct *	bd_part;

	//如果块设备代表一个磁盘,该域表示其分区被打开的次数;如果代表分区的话,该域为0
	unsigned		bd_part_count;
	int			bd_invalidated;

	//指向所在磁盘的gendisk 
	struct gendisk *	bd_disk;

	
	struct request_queue *  bd_queue;

	//用于链接到全局链表all_bdevs
	struct list_head	bd_list;

	......

};


block_device、hd_struct和gendisk之间的关系如下图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值