学写块设备驱动(一)----了解gendisk及request处理函数

来源:互联网 发布:软件项目成本多少钱 编辑:程序博客网 时间:2024/06/05 18:34

以下是一个最简单的块设备驱动,写完可以对编写块设备驱动的框架有初步了解。

环境:

Linux 2.6.29

源码:

simp_blkdev.c:

#include<linux/init.h>#include<linux/module.h>#include<linux/genhd.h>#include<linux/fs.h>#include<linux/blkdev.h>#define SIMP_BLKDEV_DISKNAME "simp_blkdev"#define SIMP_BLKDEV_DEVICEMAJOR COMPAQ_SMART2_MAJOR#define SIMP_BLKDEV_BYTES (8*1024*1024)static DEFINE_SPINLOCK(rq_lock);unsigned char simp_blkdev_data[SIMP_BLKDEV_BYTES];static struct gendisk *simp_blkdev_disk;static struct request_queue *simp_blkdev_queue;//device's request queuestruct block_device_operations simp_blkdev_fops = {.owner = THIS_MODULE,};//handle request that pass to this devicestatic void simp_blkdev_do_request(struct request_queue *q){struct request *req;while( (req = elv_next_request(q)) != NULL){if( ( (req->sector + req->current_nr_sectors)<<9) > SIMP_BLKDEV_BYTES ){printk(KERN_ERR SIMP_BLKDEV_DISKNAME ":bad request: block=%llu, count=%u\n",(unsigned long long )req->sector,req->current_nr_sectors);end_request(req,0);continue;}switch( rq_data_dir(req)){case READ:memcpy(req->buffer,(simp_blkdev_data + (req->sector<<9)),req->current_nr_sectors << 9);end_request(req,1);break;case WRITE:memcpy((simp_blkdev_data + (req->sector<<9)),req->buffer,req->current_nr_sectors << 9);end_request(req,1);break;}}}static int simp_blkdev_init(void){int ret;//init the request queue by the handler functionsimp_blkdev_queue = blk_init_queue(simp_blkdev_do_request,&rq_lock);if(!simp_blkdev_queue){ret = -ENOMEM;goto error_init_queue;}//alloc the resource of gendisksimp_blkdev_disk = alloc_disk(1);if(!simp_blkdev_disk){ret = -ENOMEM;goto error_alloc_disk;}//populate the gendisk structurestrcpy(simp_blkdev_disk->disk_name,SIMP_BLKDEV_DISKNAME);simp_blkdev_disk->major = SIMP_BLKDEV_DEVICEMAJOR;simp_blkdev_disk->first_minor = 0;simp_blkdev_disk->fops = &simp_blkdev_fops;simp_blkdev_disk->queue = simp_blkdev_queue;set_capacity(simp_blkdev_disk,SIMP_BLKDEV_BYTES>>9);add_disk(simp_blkdev_disk);printk("module simp_blkdev added.\n");return 0;error_init_queue:blk_cleanup_queue(simp_blkdev_queue);error_alloc_disk:return ret;}static void simp_blkdev_exit(void){del_gendisk(simp_blkdev_disk);put_disk(simp_blkdev_disk);blk_cleanup_queue(simp_blkdev_queue);printk("module simp_blkdev romoved.\n");}module_init(simp_blkdev_init);module_exit(simp_blkdev_exit);

Makefile:

obj-m := simp_blkdev.oKDIR = /lib/modules/$(shell uname -r)/buildall:$(MAKE) -C $(KDIR) M=$(PWD).PHONY:cleanclean:rm -f *.mod.c *.mod.o *.ko *.o *.tmp_versions *.markers *.symvers *.order


使用块设备:

insmod simp_blkdev.kolsmod | head

可以看到simp_blkdev模块,used by 列的值为0,说明未被使用

mkfs.ext3 /dev/simp_blkdevmount /dev/simp_blkdev /mnt/simp_blkdevlsmod | head 

此时初始化文件系统并挂载,used by 列的值为1,说明被使用

cp /etc/init.d/* /mnt/simp_blkdevls /mnt/simp_blkdev

此时我们的块设备已经显得颇正常了,^ ^

rm -rf /mnt/simp_blkdevumount /mnt/simp_blkdevlsmod | head

simp_blkdev模块,used by 列的值重新为0


收获:

1. 要让一个最简单的块设备驱动可用,必须实现的关键结构为gendisk和request_queue。gendisk结构描述一个磁盘,包括主从设备号、设备操作函数、容量等信息,它通过gendisk->queue和request_queue联系起来,request_queue初始化时又向内核块设备层注册了处理request的函数(该例子中为simp_blkdev_do_request)。

2. 该版本适用于2.6.29内核,从2.6.31内核开始,一些api发生变化(见linux/include/blkdev.h)。在2.6.32内核中,

request -> sectors                               变为      blk_rq_pos(request)

request -> nr_sectors                         变为      blk_rq_nr_sectors(request)

elev_next_request(request)              变为      blk_fetch_request(request)

end_request(request, error)              变为      if (!__blk_end_request_cur(req, err)) {req = blk_fetch_request(q);}


参考:

http://bbs.chinaunix.net/thread-2017377-1-1.html

LDD3 chapter16

http://lwn.net/Articles/333620/

原创粉丝点击