1、块设备
块设备将数据按照固定块大小的块中,每个块的大小通常在512字节到32768字节之间,磁盘、SD卡都是常见的块设备。
2、字符设备和块设备的区别:
字符设备 块设备
----------------------------------------------
按字节访问 按块进行访问
只能按照数据流访问 随机访问
直接访问设备 挂在文件系统的方式访问
3、Linux块设备处理模型
|-------------------------------------------------------------|
| VFS |
|-------------------------------------------------------------|
| | | |
|Disk Caches | |
| | | |
|-------------------------------------------------------------|
|Disk Filesystem | Disk Filesystem | Block Device File |
|----------------- -----------------------|
| Mapping Layer |
|-------------------------------------------------------------|
| Generic Block Layer |
|-------------------------------------------------------------|
| I/O Scheduler Layer |
|-------------------------------------------------------------|
| Block Device Driver | Block Device Driver |
|------------------------ | -------------------- |
| Hard Disk | Hard Disk |
|------------------------------------------------------------—|
VFS:虚拟文件系统,VFS是对各种具体文件系统的一种封装,为用户程序提供访问文件的统一接口。
Disk Cache:当用户发起文件访问请求的时候,首先会到Disk Cache中寻找文件是否被缓存,如果缓存中有则在Cache中读取,如果数据没有被缓存,那就必须到文件系统中去读取。
Mapping Layer:
1、首先确定文件系统的block size,然后计算所请求的数据包含多少个block,
2、调用具体文件系统的函数来访问文件的inode,确定所请求数据在磁盘上面的逻辑地址。
Generic block layer:
Linux内核为快设备抽象成了统一的模型,把块设备看做是若干个扇区组成的数据空间。来完成块设备的相关核心功能。
I/O scheduler layer:
I/O调度层负责将I/O操作顺序,采用电梯算法。提高 I/O 调度器的效率也是影响整个系统对块设备上数据管理效率的一个方面。
Block Device Driver:
快设备驱动程序,完成和硬件的具体交互,块设备相关数据结构
4、设备描述 gendisk结构体
内核使用 gendisk 结构来表示一个独立的磁盘设备,内核还使用 gendisk 结构来表示分区,在此结构中,很多程序必须由驱动程序来进行初始化。该结构体定义中。
4.1、gendisk结构体解析
struct gendisk {
int major; /*设备主设备号*/
int first_minor; /*起始次设备号*/
int minors; /*次设备号的数量,也称为分区数量,如果改值为1,表示无法分区*/
char disk_name[32]; /*设备名称*/
struct hd_struct **part; /*分区表的信息*/
int part_uevent_suppress;
struct block_device_operations *fops;/*块设备操作集合 */
struct request_queue *queue; /*请求队列,用于管理该设备IO请求队列的指针*/
void *private_data; /*私有数据*/
sector_t capacity; /*扇区数,512字节为1个扇区,描述设备容量*/
....
};
struct gendisk *alloc_disk(int minors)
分配一个gendisk结构,minors为此设备好的个数 = 分区数+1
void del_gendisk(struct gendisk *disk)
当不需要这个磁盘的时候,释放gendisk结构
endisk中包含一个kobject成员, 它是一个可被引用计数的结构体。通过get_disk()和put_disk()函数可用来操作引用计数。驱动通常不需要做这个。
struct kobject *get_disk(struct gendisk *disk);
void put_disk(struct gendisk *disk);
void add_disk(struct gendisk *gd);
对gendisk初始化之后还不能使用和这个设备,应该使用add_disk注册磁盘设备
static inline void set_capacity(struct gendisk *disk, sector_t size)
设置gendisk容量,块设备中最小单位是扇区,扇区的大小一般是2的整数倍,最常见的大小是512kb (xx>>9)表示/512 (xx<<9)表示*512。扇区大小是物理设备所决定的。
5、block_device_operationse结构体
类似与字符设备驱动程序中的file_operations结构,该集合用于控制设备的操作,但是在大多数情况下都是以mount的方式进行访问,用户程序一般不会直接访问块设备中的文件。需要包含头文件。
struct block_device_operations {
/*打开这个设备时候调用*/
int (*open) (struct inode *, struct file *);
/*关闭/释放 时候调用*/
int (*release) (struct inode *, struct file *);
/*ioctl()系统调用的实现,块设备包含大量的标准请求,这些标准请求由 Linux 块设备层处理,因此大部分块设备驱动的*/
int (*ioctl)