日期:2014-05-16 浏览次数:20848 次
【块设备驱动程序】
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