1、块设备驱动往往为磁盘设备的驱动,但是由于磁盘设备的IO性能与CPU相比很差,因此,块设备的数据流往往会引入文件系统的Cache机制。
2、实现角度:Linux为块设备和字符设备提供了两套机制。字符设备的实现:内核例程和用户态API一一对应,用户层的Read函数直接对应内核中的read例程,这种映射关系由file_operation维护。
块设备:read、write API没有直接到块设备层,而是直接到文件系统层,再由文件系统层发起读写请求。
3、blok_device_operations结构体
与字符驱动设备程序一样,块设备驱动程序也包含在<linux/fs.h>中定义的blok_device_operations结构体
struct block_device_operations { int (*open) (struct block_device *, fmode_t); int (*release) (struct gendisk *, fmode_t); int (*locked_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); int (*direct_access) (struct block_device *, sector_t, void , unsigned long *); int (*media_changed) (struct gendisk *); int (*revalidate_disk) (struct gendisk *); int (*getgeo)(struct block_device *, struct hd_geometry *); struct module *owner; };
讯享网
对块设备的读写请求都是以异步方式发送到设备相关request队列之中
4.1、gendisk的操作函数:
/* 分配gendisk */
struct gendisk *alloc_disk(int minors);
/* 删除gendisk */
void del_gendisk(struct gendisk *gd);
/* 增加gendisk */
void add_disk(struct gendisk *gd);
4.2、gendisk
一个块设备物理实体由一个gendisk结构体来表示(<linux/genhd.h>定义),每个gendisk可以支持多个分区。
每个gendisk包含了本物理实体的全部信息以及操作函数接口。整个块设备的注册是围绕gendisk来展开的。在驱动程序中初始化gendisk成员如下。
讯享网struct gendisk { 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[32]; /* name of major driver */ struct hd_struct part; /* 磁盘上的分区信息 */ int part_uevent_suppress; struct block_device_operations *fops;/*块设备操作结构体blok_device_operations*/ struct request_queue *queue; void *private_data; sector_t capacity; int flags; struct device *driverfs_dev; struct kobject kobj; struct kobject *holder_dir; struct kobject *slave_dir; struct timer_rand_state *random; int policy; atomic_t sync_io; /* RAID */ unsigned long stamp; int in_flight; #ifdef CONFIG_SMP struct disk_stats *dkstats; #else struct disk_stats dkstats; #endif struct work_struct async_notify; };
2、register_blkdev()函数用来注册块设备驱动,并申请主设备号
/* 注册块设备驱动 */
int register_blkdev(unsigned int major, const char *name);
/* 注销块设备驱动 */
int unregister_blkdev(unsigned int major, const char *name);
4、int minors; //次设备的最大数目,未分区则 = 1
5、char disk_name[32]; //磁盘名字
6、struct block_device_operations *fops; //块设备操作函数集合
7、struct request_queue *queue; //请求队列
用来管理该设备的I/O请求,请求队列的相关函数:
/* 报告完成 */
void blk_end_request_all(struct request *rq, int error);
void __blk_end_request_all(struct request *rq, int error); //在持有队列锁的场景下调用
对请求的处理有两种模式,可以使用请求队列,也可以不使用,在使用请求队列时,使用blk_init_queue()函数,不用请求队列时,将blk_alloc_queue()和blk_queue_make_request()结合使用,一般模式为;
8、int flags; //描述驱动器状态的标志
如果为可移动介质:GENHD_FL_REMOVABLE
如果为CD_ROM:GENHD_FL_CD
如果不需要分区信息出现在 /proc/partitions, 设置为
GENHD_FL_SUPPRESS_PARTITIONS_INFO
void set_capacity(struct gendisk *disk, sector_t size);
块设备中最小的可寻址单元是扇区,扇区大小一般是2 的整数倍,最常见的大小是512 字节。扇区的
大小是设备的物理属性,扇区是所有块设备的基本单元,块设备无法对比它还小的单元进行寻址和操作,
不过许多块设备能够一次就传输多个扇区。虽然大多数块设备的扇区大小都是512 字节,不过其他大小的
扇区也很常见,比如,很多CD-ROM 盘的扇区都是2KB。
不管物理设备的真实扇区大小是多少,内核与块设备驱动交互的扇区都以512 字节为单位。因此,
set_capacity()函数也以512 字节为单位。
10、void *private_data; //指向私有数据的指针
可用于指向磁盘的任何私有数据。,用法与file结构体的private_data类似

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/129687.html