总览
本文使用 linux-2.6.22.6 内核, 使用jz2440开发板.
块设备的驱动框架 驱动框架
ll_rw_block
: Low Level Read/Write block device
submit_bh
: submit Buffer Head
submit_bio
: submit Block IO (Input/Output)
elv_merge
: elevator merge. 用电梯算法合并数据
硬盘基础概念 块设备为了兼容机械结构的硬盘, 使用了一些硬盘特有的概念.
存储容量 = 磁头数 x 柱面数 x 扇区数 x 512(扇区字节数)
存储容量 = 柱面大小 x 柱面数
柱面大小 = 磁头数 x 扇区数 x 512(扇区字节数)
英语
中文
说明
Disk
磁盘
就是硬盘
Platter
圆盘
硬盘的盘片
Head
磁头
盘片有2面: 2磁头/圆盘
Track
磁道
圆盘被分割为多个同心圆, 即磁道
Sector
扇区
磁道被分割后的扇形区域
Cylinder
柱面
由多个圆盘的同一磁道构成
Partition
分区
软件概念, 以柱面为单位
参考资料
块设备驱动范例 块设备驱动的实现更为简单. Linux内核做掉了大部分工作, 驱动层只需要专注于硬件的块读写功能. 而且其框架相对固定, 不像字符设备有多种不同的框架组合.
可以参考内核里的两个文件
drivers\block\xd.c
用于 XT hard disk.
drivers\block\z2ram.c
ram disk.
给出的源码没有做返回值判断, 实际使用时务必参考上面的范例实现错误处理 .
基本步骤如下:
分配gendisk: alloc_disk
设置 2.1 分配/设置缓冲队列. blk_init_queue
2.2 设置gendisk其他信息, 用于提供硬件属性, 如容量
硬件初始化操作
注册: add_disk
ramblock.c #include <linux/major.h> #include <linux/vmalloc.h> #include <linux/init.h> #include <linux/module.h> #include <linux/blkdev.h> #include <linux/hdreg.h> MODULE_LICENSE("GPL" ); MODULE_AUTHOR("DRAAPHO" ); #define DEVICE_NAME "RAMDISK" #define RAMBLOCK_SIZE (1024*1024) static int major;static struct gendisk *ramblock_disk ;static request_queue_t *ramblock_queue;static DEFINE_SPINLOCK (ramblock_lock) ;static unsigned char *ramblock_buf;static int ramblock_getgeo (struct block_device *bdev, struct hd_geometry *geo) { geo->heads = 2 ; geo->cylinders = 32 ; geo->sectors = RAMBLOCK_SIZE/2 /32 /512 ; return 0 ; } static struct block_device_operations ramblock_fops = { .owner = THIS_MODULE, .getgeo = ramblock_getgeo, }; static void do_ramblock_request (request_queue_t * q) { static int r_cnt = 0 ; static int w_cnt = 0 ; struct request *req ; while ((req = elv_next_request(q)) != NULL ) { unsigned long offset = req->sector*512 ; unsigned long len = req->current_nr_sectors*512 ; if (rq_data_dir(req) == READ) { printk("do_ramblock_request read %d\n" , ++r_cnt); memcpy (req->buffer, ramblock_buf+offset, len); } else { printk("do_ramblock_request write %d\n" , ++w_cnt); memcpy (ramblock_buf+offset, req->buffer, len); } end_request(req, 1 ); } } static int ramblock_init (void ) { ramblock_disk = alloc_disk(16 ); ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock); ramblock_disk->queue = ramblock_queue; major = register_blkdev(0 , DEVICE_NAME); ramblock_disk->major = major; ramblock_disk->first_minor = 0 ; sprintf (ramblock_disk->disk_name, "ramblock" ); ramblock_disk->fops = &ramblock_fops; set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512 ); ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL); add_disk(ramblock_disk); return 0 ; } static void ramblock_exit (void ) { del_gendisk(ramblock_disk); put_disk(ramblock_disk); blk_cleanup_queue(ramblock_queue); unregister_blkdev(major, DEVICE_NAME); kfree(ramblock_buf); } module_init(ramblock_init); module_exit(ramblock_exit);
Makefile obj-m := ramblock.o KERN_SRC := /home/draapho/share/jz2440/kernel/linux-2.6.22.6/ PWD := $(shell pwd) modules: make -C $(KERN_SRC) M=$(PWD) modules clean: make -C $(KERN_SRC) M=$(PWD) clean
测试 $ make modules $ insmod ramblock.ko ramblock:do_ramblock_request read 1 unknown partition table $ ls /dev/ramblock* $ cat /proc/devices 254 RAMDISK $ mkdosfs /dev/ramblock $ mount /dev/ramblock /tmp $ vi /tmp/test do_ramblock_request read 43 $ sync do_ramblock_request write 6 do_ramblock_request write 7 ...... $ cp ramblock.c /tmp/ $ sync do_ramblock_request write 11 do_ramblock_request write 12 ...... $ ls /tmp ramblock.c test $ umount /tmp do_ramblock_request write 16 ...... $ ls /tmp $cat /dev/ramblock > ./ramblock.bin do_ramblock_request read ...... $ sudo mount -o loop ramblock.bin /mnt $ ls /mnt ramblock.c test $ sudo umount /mnt $ mkdir /ramdisk $ mount /dev/ramblock /ramdisk $ ls /ramdisk ramblock.c test $ df Filesystem 1k-blocks Used Available Use% Mounted on /dev/ramblock 1004 6 998 1% /ramdisk $ umount /ramdisk $ rmdir /ramdisk $ rmmod ramblock $ insmod ramblock.ko $ ls /dev/ramblock* /dev/ramblock $ fdisk /dev/ramblock m n p Partition number: 1 cylinder value: 1-8 n p Partition number: 2 cylinder value: 9-32 p w $ ls /dev/ramblock* -l brw-rw---- 1 0 0 254, 0 Jan 1 00:01 /dev/ramblock brw-rw---- 1 0 0 254, 1 Jan 1 00:01 /dev/ramblock1 brw-rw---- 1 0 0 254, 2 Jan 1 00:01 /dev/ramblock2 $ mkdosfs /dev/ramblock1 $ mkdosfs /dev/ramblock2 $ mkdir /mnt/ramdisk1 $ mkdir /mnt/ramdisk2 $ mount /dev/ramblock1 /mnt/ramdisk1 $ mount /dev/ramblock2 /mnt/ramdisk2 $ mkdosfs /dev/ramblock $ umount /mnt/ramdisk1 $ umount /mnt/ramdisk2 $ rmdir /mnt/ramdisk1 $ rmdir /mnt/ramdisk2
原创于 DRA&PHO