日期:2014-05-16  浏览次数:20781 次

Linux驱动开发学习归纳-4

【块设备驱动程序】

Linux系统主要有字符设备、网络设备、块设备,Linux内核中,I/O设备分为两大类:字符设备、块设备。块设备将数据存储在固定大小的块中,每个块都有自己的地址。数据块的大小通常在512字节到4K字节之间。

块设备与文件系统的关系如图所示:

块设备的结构:扇区,磁道,柱面,盘片。其中扇区是硬件设备传送数据的基本单位,其大小一般为512字节,也有更大的512*n字节的。但在Linux内核中逻辑扇区的大小历来固定大小512字节。

内存是一个线性结构,Linux系统将内存分为页,页的大小从4K到64K,当在内存和磁盘间传送数据时,先将页内的数据封装成一个段,内核以段为基本单位来读写磁盘。段用bio_vec表示,多个页被封装成多个段,多个段组成一个以bio_vec为元素的数组bi_io_vec。bi_io_vec是块I/O结构bio结构体中的一个指针,多个bio组成一个request,request将被连接到请求队列request_queue中。最后这个请求队列将被处理,将数据写到磁盘。关系如下图所示:


总结:扇区(512) <= 块 <= 段 <= 页(4096),且 块= n * 扇区, 段 = n * 块。

块设备驱动的架构:

块设备加载过程:

分配磁盘alloc_disk()  ----->  注册设备register_blkdev() ----->  不使用请求队列blk_init_queue()【使用请求队列blk_alloc_queue()】 ----->  磁盘gendisk属性的设置 ----->  激活磁盘add_disk()。

块设备卸载过程:

删除gendisk  del_gendisk() ----->  删除gendisk的引用 put_disk()  ----->  清除请求队列 blk_cleanup_queue() ----->  注销块设备 unregister_blkdev()。


通用块层是块设备驱动的核心部分,主要包括了块设备驱动程序的通用代码部分。

其中块设备加载过程用到的通用块层数据结构有: gendisk 、 request_queue 、 request 、bio 、 block_device_operations等。

在Linux内核中,gendisk表示一个磁盘,也可以表示一个分区。

113 struct gendisk {
114         int major;                      /* major number of driver */
115         int first_minor;
116         int minors;                     /* maximum number of minors, =1 for
117                                          * disks that can't be partitioned. */
118         char disk_name[32];             /* name of major driver */
119         struct hd_struct **part;        /* [indexed by minor] */
120         int part_uevent_suppress;
121         struct block_device_operations *fops;
122         struct request_queue *queue;
123         void *private_data;
124         sector_t capacity;
125 
126         int flags;
127         struct device *driverfs_dev;
128         struct kobject kobj;
129         struct kobject *holder_dir;
130         struct kobject *slave_dir;
131 
132         struct timer_rand_state *random;
133         int policy;
134 
135         atomic_t sync_io;               /* RAID */
136         unsigned long stamp;
137         int in_flight;
138 #ifdef  CONFIG_SMP
139         struct disk_stats *dkstats;
140 #else
141         struct disk_stats dkstats;
142 #endif
143         struct work_struct async_notify;
144 };

gendisk是一个动态的结构体,其成员随系统状态不断变化,所以不能静态分配该结构,内核提供专用函数alloc_disk()来分配该结构体。

697 struct gendisk *alloc_disk(int minors)
698 {
699         return alloc_disk_node(minors, -1);
700 }
701 
702 struct gendisk *alloc_disk_node(int minors, int node_id)
703 {
704         struct gendisk *disk;
705 
706         disk = kmalloc_node(sizeof(struct gendisk),
707                                 GFP_KERNEL | __GFP_ZERO, node_id);
708         if (disk