环境:
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/
作者:qq418674358 发表于2013-7-22 1:00:09
阅读:47 评论:0