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

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

环境:

Linux 2.6.29

源码:

simp_blkdev.c:

[cpp]
view plaincopyprint?
#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 queue

struct block_device_operations simp_blkdev_fops = {
.owner = THIS_MODULE,
};
//handle request that pass to this device
static 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 function
simp_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 gendisk
simp_blkdev_disk = alloc_disk(1);
if(!simp_blkdev_disk){
ret = -ENOMEM;
goto error_alloc_disk;
}


//populate the gendisk structure
strcpy(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:

[cpp]
view plaincopyprint?
obj-m := simp_blkdev.o
KDIR = /lib/modules/$(shell uname -r)/build

all:
$(MAKE) -C $(KDIR) M=$(PWD)

.PHONY:clean
clean:
rm -f *.mod.c *.mod.o *.ko *.o *.tmp_versions *.markers *.symvers *.order



使用块设备:

[plain]
view plaincopyprint?
insmod simp_blkdev.ko
lsmod | head



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

[plain]
view plaincopyprint?
mkfs.ext3 /dev/simp_blkdev
mount /dev/simp_blkdev /mnt/simp_blkdev
lsmod | head


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

[plain]
view plaincopyprint?
cp /etc/init.d/* /mnt/simp_blkdev
ls /mnt/simp_blkdev


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

[plain]
view plaincopyprint?
rm -rf /mnt/simp_blkdev
umount /mnt/simp_blkdev
lsmod | 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) 变为 blk_end_request_all(request, error)

我在2.6.32内核下对照上述源码修改api时遇到一些问题。假如使用blk_end_request_all(request, error),insmod直接死机;假如使用__blk_end_request_all(request, error),可以insmod,但是不能够mkfs和mount,查看dmesg为 “EXT3-no journal”错误。查看源码blk-core.c,只知道blk_end_request_all比__blk_end_request_all多了加锁和解锁的操作,但是由于队列锁方面的知识不足,现在无法解决该错误,故暂时使用2.6.29内核实践学习。如果读者你恰巧遇到同样的问题并恰巧成功了,请您一定告诉我答案。

参考:

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

LDD3 chapter16

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

你可能感兴趣的:(学写块设备驱动(一)----了解gendisk及request处理函数)