非常简单的一个块设备驱动,simp_blkdev,2.6.31之后的变化

以下代码亲测在2.6.38上测试通过,在3的内核上不行,因为3的内核有许多API已经变了(见上篇),而且3的struct request没有buffer这个成员

simp_blkdev.c:


#include<linux/init.h>
#include<linux/module.h>
#include<linux/string.h>
#include<linux/blkdev.h>
#include<linux/hdreg.h>

#define SIMP_BLKDEV_MAJOR 180 
#define SIMP_BLKDEV_DISKNAME "simp_blkdev"
#define SIMP_BLKDEV_BYTES (2*1024*1024) //块设备的大小 2M

static struct request_queue *simp_blkdev_queue = NULL;   //良好的习惯
static struct gendisk *simp_blkdev_disk = NULL;
static unsigned char simp_blkdev_data[SIMP_BLKDEV_BYTES];

//负责处理块设备请求的函数
static void simp_blkdev_do_request(struct request_queue *q)
{
    struct request *req;

    req = blk_fetch_request(q);
    //从请求队列中不断的提取下一条请求,然后对请求进行处理
    while(req){
        //如果传送的扇区超出块设备大小。
        //扇区->字节,blk_rq_pos当前要传送的扇区,blk_rq_cur_sectors当前要传送的扇区数量
        if((blk_rq_pos(req) + blk_rq_cur_sectors(req)) << 9 > SIMP_BLKDEV_BYTES){
            printk(KERN_ERR "bad request:block=%llu,count=%u\n",(unsigned long long)blk_rq_pos(req),blk_rq_cur_sectors(req));
            if(!__blk_end_request_cur(req,0))//结束这个请求,0表示成功
                    req = blk_fetch_request(q);
        continue;
        }

        switch (rq_data_dir(req)){
            case READ:
                memcpy(req->buffer,simp_blkdev_data+(blk_rq_pos(req) << 9),blk_rq_cur_sectors(req) << 9); //从第二个参数的地址拷贝第三个参数的字节数到第一个参数的地址
        if(!__blk_end_request_cur(req,0))//结束这个请求,0表示成功
                    req = blk_fetch_request(q);
                break;
            case WRITE:
                memcpy(simp_blkdev_data+(blk_rq_pos(req) << 9),req->buffer,blk_rq_cur_sectors(req) << 9);
        if(!__blk_end_request_cur(req,0))//结束这个请求,0表示成功
                    req = blk_fetch_request(q);
                break;
            default:
                break;
        }
    }
}

struct block_device_operations simp_blkdev_fops = {
    .owner = THIS_MODULE,
};

static int __init simp_blkdev_init(void)
{
    int ret;
    //请求队列初始化,绑定函数
    simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request,NULL);
    if(!simp_blkdev_queue){ //初始化失败
        ret = - ENOMEM;
        goto err_init_queue;
    }
    register_blkdev(SIMP_BLKDEV_MAJOR,SIMP_BLKDEV_DISKNAME);//注册主设备
    simp_blkdev_disk = alloc_disk(1); //申请gendisk
    if(!simp_blkdev_disk){
        ret = - ENOMEM;
        goto err_alloc_disk;
    }
    //gendisk初始化
    strcpy(simp_blkdev_disk->disk_name,SIMP_BLKDEV_DISKNAME);
    simp_blkdev_disk->major = SIMP_BLKDEV_MAJOR;
    simp_blkdev_disk->first_minor = 0;  //第一次设备号
    simp_blkdev_disk->fops = &simp_blkdev_fops;
    simp_blkdev_disk->queue = simp_blkdev_queue;
    //设置块设备的大小,块设备使用扇区作为单位设置,而扇区的大小默认是512字节。
    //在把字节为单位的大小转换为以扇区为单位时,我们需要除以512,或者右移9位可能更快一些。
    set_capacity(simp_blkdev_disk,SIMP_BLKDEV_BYTES>>9);
    add_disk(simp_blkdev_disk); //向系统添加这个块设备

    return 0;

    err_alloc_disk:
        blk_cleanup_queue(simp_blkdev_queue);
    err_init_queue:
        return ret;
}

static void __exit simp_blkdev_exit(void)
{
    unregister_blkdev(SIMP_BLKDEV_MAJOR,SIMP_BLKDEV_DISKNAME);//注销设备驱动
    del_gendisk(simp_blkdev_disk); //从系统中删除这个块设备
    put_disk(simp_blkdev_disk); //释放申请的空间
    blk_cleanup_queue(simp_blkdev_queue);
}

module_init(simp_blkdev_init);
module_exit(simp_blkdev_exit);

MODULE_AUTHOR("ZHYANG");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("simp_blkdev");




Makefile:

obj-m := simp_blkdev.o
KDIR := /opt/FriendlyARM/mini6410/linux/linux-2.6.38/
PWD := $(shell pwd)
default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
    rm -rf *.ko *.o *.mod.* *.symvers *.order


测试(我是在tiny6410(2.6.38)上测试的,因为我的电脑是3.16的,虽然我又编译了2.6.38的内核但就是跑不起来,无奈就用板子试了)没有板子也没关系,只要电脑内核是2的也能成功:

1.insmod simp_blkdev.ko

2.mkfs.ext2 /dev/simp_blkdev    

        板子上只有ext2和vfat两种文件系统,没有ext3更没有ext4,所以我这边用ext2,查看支持的文件系统用ls /sbin/mkfs.*

3.mkdir -p /mnt/blk

4.mount /dev/simp_blkdev /mnt/blk

未mount前lsmod和mount后是这样的


可以看到模块引用计数从0变为1了,等会umount掉又会变成0

5.ls /mnt/blk


6.umount /mnt/blk

7.rmmod simp_blkdev

我的这份代码跟网上其他类似的代码不同的地方有这些:

1.最坑爹的一点!!!!blk_end_request_cur(req,0)    0是表示成功的!不是网上代码看到的0是失败,害我整整搞了一天啊!!!!!!!一直在mkfs.ext2那句整个板子卡死

2.网上其他代码的主设备号是抢其他的设备的,我这边是单独自己选个没用到的设备自己进行注册,所以才有init中才有register_blkdev这句,insmod成功之后你能在cat /proc/device中看到它

3.其他的一些变化详见上篇

4.__blk_end_request_cur或者__blk_end_request_all都可以用,效果是一样的,我还不知道具体区别是什么。


ps:

blk_alloc_queue分配的请求队列中make_request_fn是没有被赋值的,所以要实现无请求队列的simp_blkdev要自己写个simp_blkdev_make_request并绑定到request_quque的make_request_fn,而blk_init_quque则把make_request_fn与simp_blkdev_do_request绑定在一起。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值