编写块设备驱动之内存模拟磁盘

可以参考一下内核里面的文件

在内核里面收索blk_init_queue

然后就会发现xd.c和Z2ram.c

大概看一眼,看一个去驱动程序从入口开始看,

这里有个register_blkdev注册块设备驱动,跟我们字符设备相比少了一个fops,注册块设备已经退化了,它只不过是cat /prok/device 可以看到一些信息。或者前面XT_DISK_MAJOR写为0的时候可以返回一个主设备号给你


初始化一个队列


这个函数里面第一个参数就是处理队列的函数

那队列怎么用呢,往下看


这里分配一个gendisk结构体,然后disk->queue=xd_queue


这里是注册这个disk

下面我们参考这两个文件来谢谢代码


/*1.分配一个gendisk结构体*/
 ramblock_disk=alloc_disk();

这后面的参数是次设备个数,什么意思呢??
我们在虚拟机里面使用这行命令    ls  /dev/sd* -l

然后会出现如下状况


对于一个块设备  次设备号为0的时候 就是表示整个磁盘。

次设备 1 2表示它们第几个分区 1 2表示第一 二个 分区  5表示拓展分区

所以这个参数就应该写为最多分区个数+1,因为0分区代表整个硬盘


分配/设置队列 提供读写能力 用这个函数

这个函数的参数第一个是执行队列的函数,第二个是锁 需要一个自旋锁



我们进入这个函数看一看


然后在进去看一看那


进入q = blk_init_allocated_queue_node(uninit_q, rfn, lock, node_id);这个函数里面看一看


这里有提供了默认的构造请求的函数


然后再是我们的设置属性

disk->major = XT_DISK_MAJOR;  //主设备号,主设备号怎么来的呢??? 跟我们前面写字符设备一样的
disk->first_minor = i<<6; 
disk->fops = &xd_fops;  //经过实验 尽管你这里什么都没有 你也要提供这么一个结构体

disk->private_data = p;  //这个私有数据我们不需要

disk->queue = xd_queue; 这个队列就是我们前面分配的队列

set_capacity(disk, p->heads * p->cylinders * p->sectors);  //容量 ,注意了这里要以扇区为单位,在文件系统里面他任务扇区就是512个字节


数据传输3要素,这个 struct request里面肯定有这三要素




代码

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
#include <linux/blkpg.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/gfp.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/dma.h>
#include<linux/slab.h>
static struct gendisk *ramblock_disk;
static struct request_queue *ramblock_queue;
static DEFINE_SPINLOCK(ramdisk_lock);
static int major;
static unsigned char *ramblock_buf;


static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
geo->heads = 2; //有两面
geo->sectors = 32;//一面里面有多少环
geo->cylinders = BLOCK_SIZE/2/32/512;//一环里面有多少散区


return 0;
}
static const struct block_device_operations ramblock_fops = {
.owner = THIS_MODULE,
.getgeo = ramblock_getgeo,
};
#define RAMBLOCK_SIZE (1024*1024)


static void do_block_request (struct request_queue * q)
{
struct request *req;
req = blk_fetch_request(q);
while (req) {
/*源或目的*/
unsigned long offset = blk_rq_pos(req) * 512;

// 长度
/*长度*/
unsigned long len  = blk_rq_cur_bytes(req);


if (rq_data_dir(req) == READ)
memcpy(req->buffer, ramblock_buf+offset, len);
else
memcpy(ramblock_buf+offset, req->buffer, len);
/* wrap up, 0 = success, -errno = fail */
if (!__blk_end_request_cur(req, 0))
req = blk_fetch_request(q);
}


}




static int ramblock_init(void)
{
/*1.分配一个gendisk结构体*/
ramblock_disk=alloc_disk(16);
/*2.设置*/
/*2.1分配/设置队列:提供都写能力*/
ramblock_queue = blk_init_queue(do_block_request, &ramdisk_lock);
/*2.2设置其他属性,比如容量*/
major = register_blkdev(0,"ramblock");
ramblock_disk->major = major;
ramblock_disk->first_minor = 0;
sprintf(ramblock_disk->disk_name, "ramblock");
ramblock_disk->fops = &ramblock_fops;
ramblock_disk->queue = ramblock_queue;
set_capacity(ramblock_disk, RAMBLOCK_SIZE/512);
/*3 硬件相关的操作*/
ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);
/*4.注册*/
add_disk(ramblock_disk);
return 0;
}


static void ramblock_exit(void)
{
unregister_blkdev(major,"ramblock");
del_gendisk(ramblock_disk);
put_disk(ramblock_disk);
blk_cleanup_queue(ramblock_queue);


}
module_init(ramblock_init);
module_exit(ramblock_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EIGHT");








测试

1.insmod 驱动

2.格式化 mkdosfs /dev/ramblock

3.挂接

4.读写文件 cd /tmp 在里面读写文件

5. cd /    umout /tmp

6.然后在挂接




分区测试

1.insmod ramblock.ko

2.ls /dev/ramblock

3.fdisk ramblock

输入m看下帮助信息


输入n 分区


p 主分区


第一个柱面1-32

所以分区就是1 2 3 4 5柱面合起来就是一个分区


第一个分区是从1到5柱面


是用w命令写入分区表里面去
















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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值