1 块设备的概述
linux支持的两种重要的设备类型分别是字符设备和块设备,块设备可以随机地以固定大小的块传送数据。与字符设备相比,块设备有以下几个特殊之处:
(1)块设备可以从数据的任何位置进行访问
(2)块数据总是以固定长度进行传输,即便请求的这是一个字节
(3)对块设备的访问有大量的缓存。当进行读时,如果已经缓存了,就直接使用缓存中的数据,而不再读设备,对于写也通过缓存来进行延迟处理。
在块系统中,数据块指的是固定大小的数据,该固定大小由内核规定,通常是4096个字节。与数据块对应的是扇区,它是由设备硬件所决定的一个块,其大小取决于硬件,常见的硬件的扇区大多都是512个字节。数据块的大小都是扇区大小的整数倍。
2 对比之前的字符设备驱动程序的区别;
app:open read write
块: drv_open drv_read drv_write
硬件
如果按照操作字符设备的那套方法来操作块设备,效率低,且容易损坏仪器。
块设备的框架:
app: open,read,write "1.txt"
--------------------------------------------- 文件的读写
文件系统: vfat, ext2, ext3, yaffs2, jffs2 (把文件的读写转换为扇区的读写)
-----------------ll_rw_block----------------- 扇区的读写
1. 把"读写"放入队列
2. 调用队列的处理函数(优化/调顺序/合并)
块设备驱动程序
---------------------------------------------
硬件: 硬盘,flash
3 分析ll_rw_block函数
ll_rw_block
for (i = 0; i < nr; i++) {
struct buffer_head *bh = bhs[i];
submit_bh(rw, bh);
struct bio *bio; // 使用bh来构造bio (block input/output)
submit_bio(rw, bio);
// 通用的构造请求: 使用bio来构造请求(request)
generic_make_request(bio);
__generic_make_request(bio);
request_queue_t *q = bdev_get_queue(bio->bi_bdev); // 找到队列
// 调用队列的"构造请求函数"
ret = q->make_request_fn(q, bio);
// 默认的函数是__make_request
__make_request
// 先尝试合并
elv_merge(q, &req, bio);
// 如果合并不成,使用bio构造请求
init_request_from_bio(req, bio);
// 把请求放入队列
add_request(q, req);
// 执行队列
__generic_unplug_device(q);
// 调用队列的"处理函数"
q->request_fn(q);
4 怎么写块设备驱动程序呢?
1. 分配gendisk: alloc_disk
2. 设置
2.1 分配/设置队列: request_queue_t // 它提供读写能力
blk_init_queue
2.2 设置gendisk其他信息 // 它提供属性: 比如容量
3. 注册: add_disk
参考:driverslockxd.c和driverslockz2ram.c
--------------------------------------------------------------编辑于2017-01-13 01:03:00

1 /*参考:driverslockz2ram.c*/ 2 3 4 #include <linux/module.h> 5 #include <linux/errno.h> 6 #include <linux/interrupt.h> 7 #include <linux/mm.h> 8 #include <linux/fs.h> 9 #include <linux/kernel.h> 10 #include <linux/timer.h> 11 #include <linux/genhd.h> 12 #include <linux/hdreg.h> 13 #include <linux/ioport.h> 14 #include <linux/init.h> 15 #include <linux/wait.h> 16 #include <linux/blkdev.h> 17 #include <linux/blkpg.h> 18 #include <linux/delay.h> 19 #include <linux/io.h> 20 21 #include <asm/system.h> 22 #include <asm/uaccess.h> 23 #include <asm/dma.h> 24 25 26 #define RAMBLOCK_SIZE (1024*1024) 27 #define DEVICE_NAME "ramblock" 28 29 static DEFINE_SPINLOCK(ramblock_lock); 30 31 static struct gendisk *ramblock_gendisk; 32 static int major; 33 static struct request_queue *ramblock_queue; 34 static unsigned char *ramblock_buf; 35 36 static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo) 37 { 38 geo->heads = 2; 39 geo->cylinders = 32; 40 geo->sectors = RAMBLOCK_SIZE/2/32/512; 41 return 0; 42 } 43 44 45 static struct block_device_operations ramblock_fops = { 46 .owner = THIS_MODULE, 47 .getgeo = ramblock_getgeo, 48 }; 49 50 static void do_ramblock_request(request_queue_t *q) 51 { 52 struct request *req; 53 if((req = elv_next_request(q)) != NULL) 54 { 55 unsigned long offset = req->sector <<9; 56 unsigned long len = req->current_nr_sectors << 9; 57 58 if (rq_data_dir(req) == READ) 59 { 60 memcpy(req->buffer, ramblock_buf+offset, len); 61 } 62 else 63 { 64 memcpy(ramblock_buf+offset, req->buffer, len); 65 } 66 end_request(req, 1); 67 68 } 69 70 71 } 72 73 static int ramblock_init(void) 74 { 75 ramblock_gendisk = alloc_disk(16); 76 77 ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock); 78 ramblock_gendisk->queue = ramblock_queue; 79 80 81 major = register_blkdev(0, DEVICE_NAME); 82 ramblock_gendisk->major = major; 83 ramblock_gendisk->first_minor = 0; 84 ramblock_gendisk->fops = &ramblock_fops; 85 sprintf(ramblock_gendisk->disk_name, "ramblock"); 86 set_capacity(ramblock_gendisk, RAMBLOCK_SIZE / 512); 87 88 ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL); 89 add_disk(ramblock_gendisk); 90 91 92 return 0; 93 } 94 95 static void ramblock_exit(void) 96 { 97 unregister_blkdev(major, DEVICE_NAME); 98 del_gendisk(ramblock_gendisk); 99 put_disk(ramblock_gendisk); 100 blk_cleanup_queue(ramblock_queue); 101 102 kfree(ramblock_buf); 103 104 105 } 106 107 module_init(ramblock_init); 108 module_exit(ramblock_exit); 109 MODULE_LICENSE("GPL");
--------------------------------------------------------------编辑于2017-01-13 14:34:44