【Tiny6410 And Linux】—(5.2)—RamDisk 驱动实现(自己绑定 make_request_fn() )——代码

本文介绍了一个简单的Linux块设备驱动程序实现过程,包括源代码和Makefile配置。该驱动程序能够处理基本的读写请求,并通过bio结构进行数据操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

直接来吧!

 

1、驱动程序

 

①、blk.c

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>	/* printk() */
#include <linux/slab.h>		/* kmalloc() */
#include <linux/fs.h>		/* everything... */
#include <linux/errno.h>	/* error codes */
#include <linux/timer.h>
#include <linux/types.h>	/* size_t */
#include <linux/fcntl.h>	/* O_ACCMODE */
#include <linux/hdreg.h>	/* HDIO_GETGEO */
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h>	/* invalidate_bdev */
#include <linux/bio.h>
#include <linux/major.h>
#include <linux/version.h>


#define SIMP_BLKDEV_DEVICEMAJOR		COMPAQ_SMART2_MAJOR
#define SIMP_BLKDEV_DISKNAME        	"_Justin"
#define SIMP_BLKDEV_BYTES        	(16 * 1024 * 1024)

static struct request_queue *simp_blkdev_queue;
static struct gendisk *simp_blkdev_disk;
unsigned char simp_blkdev_data[SIMP_BLKDEV_BYTES];
/*
 * simp_blkdev_make_request
 */
static int simp_blkdev_make_request(struct request_queue *q, struct bio *bio)
{
        struct bio_vec *bvec;
        int i;
        void *dsk_mem;
	
	/* 判断 IO 请求是否超出实际 RanDisk 大小 */
        if((bio->bi_sector << 9) + bio->bi_size > SIMP_BLKDEV_BYTES) 
	{
                printk(KERN_ERR SIMP_BLKDEV_DISKNAME
                        ": bad request: block=%llu, count=%u\n",
                        (unsigned long long)bio->bi_sector, bio->bi_size);

/* 条件编译,对于 2.4 内核之后的变量多了一个,伤不起阿! */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
                /* 返回这个对 bio 请求的处理结果,-EIO 表示出错 */
                bio_endio(bio, 0, -EIO);
#else
                bio_endio(bio, -EIO);
#endif

                return 0;
        }

        dsk_mem = simp_blkdev_data + (bio->bi_sector << 9);
        /* 遍历 bio 中所有的 bvec */
        bio_for_each_segment(bvec, bio, i)
        {
                void *iovec_mem;

                switch(bio_rw(bio))
                {
                        case READ:
                        case READA:             /* 读和预读都进行同样的处理 */
                                /* 用 kmalloc 将请求页映射到非线性映射区域进行
                                 * 访问,这种方法主要是为了兼容高端内存,
                                 * (bvec->bv_page 可能源于高端内存) */
                                iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset;
                                memcpy(iovec_mem, dsk_mem, bvec->bv_len);
                                kunmap(bvec->bv_page);
                                break;
                        case WRITE:
                                iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset;
                                memcpy(dsk_mem, iovec_mem, bvec->bv_len);
                                kunmap(bvec->bv_page);
                                break;

                        default:
                                printk(KERN_ERR SIMP_BLKDEV_DISKNAME
                                        ":Unknown value of bio_rw: %lu\n",
                                        bio_rw(bio));
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
                                bio_endio(bio, 0, -EIO);
#else
                                bio_endio(bio, -EIO);
#endif
                                return 0;
                }
                dsk_mem += bvec->bv_len;
        }

/* 返回这个对 bio 请求的处理结果,0 表示正常 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
        bio_endio(bio, 0, 0);
#else
        bio_endio(bio, 0);
#endif
        return 0;
}

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

/* 
 * simp_blkdev_init
 */
static int __init simp_blkdev_init(void)
{
        int ret;

	/* 分配一个请求队列 */
        simp_blkdev_queue = blk_alloc_queue(GFP_KERNEL);
        if(!simp_blkdev_queue) 
	{
                ret = -ENOMEM;
                goto err_alloc_queue;
        }
	
	/* 为请求队列绑定 make_request_fn 方法 */
        blk_queue_make_request(simp_blkdev_queue, simp_blkdev_make_request);

	/* 分配一个 gendisk 结构 */
        simp_blkdev_disk = alloc_disk(1);
        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_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);

        return 0;

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

/* 
 * simp_blkdev_exit
 */
static void __exit simp_blkdev_exit(void)
{
        del_gendisk(simp_blkdev_disk);		/* 删除 gendisk 结构 */
        put_disk(simp_blkdev_disk);		/* 释放一个该对象的引用 */
        blk_cleanup_queue(simp_blkdev_queue);	/* 清理请求队列 */
}

module_init(simp_blkdev_init);
module_exit(simp_blkdev_exit);


 

②、Makefile

ifneq ($(KERNELRELEASE),)
obj-m := blk.o
else
KDIR := /lib/modules/2.6.27.62/build
all:
	make -C $(KDIR) M=$(PWD) modules 
clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers  modul*
endif


 

2、实验结果

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值