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