ubuntu linux块设备驱动 ramdisk 实验,RAMDISK块设备驱动程序

from: http://blog.163.com/hjw_vc/blog/static/1148310352009104952466/

ram、loop、网络设备等驱动通常使用自己编写的make_request函数来处理bio结构,免去内核使用I/O调度器处理的麻烦。

而像硬盘等这些有磁道、扇区的设备驱动则使用request函数,内核会提供 __make_request()函数并调用I/O调度器来处理bio结构,以提高磁盘的读写效率

下面是一个使用内存来虚拟的磁盘的驱动程序,适用于PC机上内核版本号大于2.6.24的Linux系统

ramdisk_driver.c 驱动程序代码如下:

#include

#include

#include

#include

#include

#define DEVICE_MAJOR 240

#define DEVICE_NAME "ramdisk"

#define SECTOR_SIZE 512

//扇区大小

#define DISK_SIZE (3*1024*1024)

//虚拟磁盘大小

#define SECTOR_ALL (DISK_SIZE/SECTOR_SIZE)

//虚拟磁盘的扇区数

static struct gendisk *p_disk; //用来指向申请的gendisk结构体

static struct request_queue *p_queue; //用来指向请求队列

static unsigned char mem_start[DISK_SIZE]; //分配一块3M 的内存作为虚拟磁盘

/***********************************************************************

对于ram、loop、网络设备等使用自己编写的make_request函数来处理bio

省去使用内核I/O调度器的过程,make_request返回值是0

**********************************************************************/

static void ramdisk_make_request(struct request_queue *q,struct bio *bio)

{

struct bio_vec *bvec; //bio结构中包含多个bio_vec结构

int i; //用于循环的变量,不需要赋值

void *disk_mem; //指向虚拟磁盘正在读写的位置

if((bio->bi_sector*SECTOR_SIZE)+bio->bi_size>DISK_SIZE)

{ //检查超出容量的情况

printk("ramdisk over flowed!\n");

bio_endio(bio,1); //第二个参数为1通知内核bio处理出错

return ;

}

disk_mem=mem_start+bio->bi_sector*SECTOR_SIZE; //mem_start是虚拟磁盘的起始地址

//bio_for_each_segment是一个for循环的宏,每次循环处理一个bio_vec

bio_for_each_segment(bvec,bio,i){

void *iovec; //指向内核存放数据的地址

iovec=kmap(bvec->bv_page)+bvec->bv_offset; //将bv_page映射到高端内存

switch(bio_data_dir(bio)){ //bio_data_dir(bio)返回要处理数据的方向

case READA: //READA是预读,RAED是读,采用同一处理

case READ:memcpy(iovec,disk_mem,bvec->bv_len);break;

case WRITE:memcpy(disk_mem,iovec,bvec->bv_len);break;

default:bio_endio(bio,1);kunmap(bvec->bv_page);return ; //处理失败的情况

}

kunmap(bvec->bv_page); //释放bv_page的映射

disk_mem+=bvec->bv_len; //移动虚拟磁盘的指向位置,准备下一个循环bvec的读写做准备

}

bio_endio(bio,0); //第二个参数为0通知内核处理成功

return ;

}

static struct block_device_operations ramdisk_fops={

.owner=THIS_MODULE,

};

static int ramdisk_init(void)

{

p_queue=blk_alloc_queue(GFP_KERNEL); //申请请求队列,不附加make_request函数

if(!p_queue)return -1;

blk_queue_make_request(p_queue,ramdisk_make_request); //将自己编写的make_request函数添加到申请的队列

p_disk=alloc_disk(1); //申请一个分区的gendisk结构体

if(!p_disk)

{

blk_cleanup_queue(p_queue); //gendisk申请失败,清除已申请的请求队列

return -1;

}

strcpy(p_disk->disk_name,DEVICE_NAME); //块设备名

p_disk->major=DEVICE_MAJOR; //主设备号

p_disk->first_minor=0; //次设备号

p_disk->fops=&ramdisk_fops; //fops地址

p_disk->queue=p_queue; //请求队列地址

set_capacity(p_disk,SECTOR_ALL); //设置磁盘扇区数

add_disk(p_disk); //设置好后添加这个磁盘

return 0;

}

static void ramdisk_exit(void)

{

del_gendisk(p_disk); //删除gendisk注册信息

put_disk(p_disk); //释放disk空间

blk_cleanup_queue(p_queue); //清除请求队列

}

module_init(ramdisk_init);

module_exit(ramdisk_exit);

MODULE_LICENSE("GPL");

编译成模块按下列步骤实验一下: insmod ramdisk_driver.ko //动态挂载驱动模块 lsmod  //查看是否多了个ramdisk_driver模块 ls /dev  //查看一下/dev目录下是否多了个ramdisk节点 mkfs.ext3 /dev/ramdisk  //在虚拟磁盘上建立ext3文件系统 mount /dev/ramdisk /mnt/test   //挂载到/mnt/test目录下,然后去看看mnt下面是不是多了lost+found文件夹 终端敲入mount,看一下mount的记录,是不是ext3格式 玩够了之后就清除掉 umount /mnt/test rmmod ramdisk_driver

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值