块设备驱动程序分析之内存模拟磁盘
2012-09-25 09:59
411 查看
#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/blkpg.h> #include <linux/delay.h> #include <linux/io.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/dma.h> static struct gendisk *ramblock_disk; static request_queue_t *ramblock_queue; static int major; static DEFINE_SPINLOCK(ramblock_lock); static struct block_device_operations ramblock_fops = { .owner = THIS_MODULE, }; #define RAMBLOCK_SIZE (1024*1024) static unsigned char *ramblock_buf; static void do_ramblock_request(request_queue_t * q) { static int cnt = 0; struct request *req; / *这个循环里面从队列里一个一个地取出请求,并处理* / while ((req = elv_next_request(q)) != NULL) { /* 数据传输三要素: 源,目的,长度 */ /* 源/目的: */ unsigned long offset = req->sector * 512; /* 目的/源: */ // req->buffer /* 长度: */ unsigned long len = req->current_nr_sectors * 512; if (rq_data_dir(req) == READ) { memcpy(req->buffer, ramblock_buf+offset, len);//读的时候从内存读取数据放入req->buffer } else { memcpy(ramblock_buf+offset, req->buffer, len);//写的时候从req->buffer读取数据到内存 } end_request(req, 1);//一个请求处理完毕后要结束请求,才能处理下一个请求 } } static int ramblock_init(void) { ramblock_disk = alloc_disk(16); ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock); ramblock_disk->queue = ramblock_queue; major = register_blkdev(0, "ramblock"); /* cat /proc/devices */ ramblock_disk->major = major; ramblock_disk->first_minor = 0; sprintf(ramblock_disk->disk_name, "ramblock"); ramblock_disk->fops = &ramblock_fops; set_capacity(ramblock_disk, RAMBLOCK_SIZE / 512); ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL); 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); kfree(ramblock_buf); } module_init(ramblock_init); module_exit(ramblock_exit); MODULE_LICENSE("GPL");
总结:
在这个程序里面,我们开辟了一块内存区模拟这个磁盘。也就是说,我们对块设备的操作实际上是对这块内存的操作。对于这块内存的操作我们有必要来唠叨一下:首先数据传送肯定需要三个要素,一是源,二是目的,三是长度。我们需要对这些参数进行设置,所有的这些参数信息都在req这个结构体里面,其中req->sector表示下一个要提交的扇区,那么ramblock_buf+req->sector*512就表示要下一次要处理的内存的首地址。req->current_nr_sectors表示当前要处理的扇区的个数,那么req->current_nr_sectors就表示要处理的内存的长度。而读数据时,读出的数据放在req->buffer中,写数据时,要写入的数据也在req->buffer中,所以req->buffer既是源也是目的。
其实说道这里,我已经乱了。我已经完全不知道程序是如何执行的,所以我们还是从应用空间出来,在来啰嗦一遍:
我们以读取为例,当应用空间读块设备的时候,会调用ll_rw_block函数,然后会将请求放入到我们在驱动程序里面申请的队列里面,但是此时不会处理该请求,当请求结束后,才开始处理所有的请求。这时就会调用我们注册的队列处理函数来处理队列里面的请求,处理请求的时候我们会根据电梯调度算法一个一个取出请求来处理,当然取出请求的时候,需要获得请求结构体,里面记载了该请求的相关信息,我们处理该请求需要依赖于这些信息。而且每处理完一个请求需要结束该请求,否则无法处理下一个请求。但是我们需要知道,我们构造请求时候有合并请求,这就告诉我们,处理每个请求并不是处理一个512字节的块,而是处理多个块的组合。
测试:
(1)insmod block.ko
(2)格式化: mkdosfs /dev/ramblock
(3)挂接: mount /dev/ramblock /tmp/
(4)读写文件: cd /tmp, 在里面vi文件,如vi text.c,在里面写入hello,ls命令可以看到text.c文件,但是看不见tmp目录下原来的文件了
(5)卸载:cd /; umount /tmp/ 我们发现tmp目录下面已经没有text.c这文件了,有的只是tmp目录下原来的文件。
以上我们将块设备挂接到tmp目录下之后,tmp目录就相当于块设备了。
相关文章推荐
- 块设备驱动程序分析之内存模拟磁盘
- Tiny6410开发板下块设备驱动程序的编写驱动之用内存模拟磁盘(二)
- arm 驱动进阶:块设备驱动程序程序设计之用内存模拟磁盘
- linux块设备驱动程序分析之 nor flash驱动分析 以及使用内存模拟 nor flash
- Tiny6410开发板下块设备驱动程序的编写驱动之用内存模拟磁盘(一)
- 内存模拟块设备驱动程序设计
- 块设备驱动1—用内存模拟磁盘
- 编写块设备驱动之内存模拟磁盘
- 通过上节的块设备驱动分析,本节便通过内存来模拟块设备驱动
- 嵌入式驱动开发之--- 虚拟磁盘SBULL块设备驱动程序分析
- 2014-04-19 块设备驱动程序(模拟内存)__
- 块设备驱动之内存模拟硬盘
- 块设备框架实例(基于内存模拟)
- Linux设备驱动学习(1) 全局内存空间“设备”驱动程序globalmem
- Linux设备驱动程序——内存和I/O基础知识学习:(1)内核中相关基础知识学习
- 内存模拟磁盘,让你体验下急速
- Linux下常用系统分析工具总结(CPU,网络,磁盘,内存)
- 使用 ksar 工具分析10个方面系统性能 ——磁盘 I/O、网络、CPU 、内存、NFS 、系统中断、内存分页
- linux性能分析工具介绍(CPU,内存,磁盘I/O,网络)
- 深入浅出分析Linux设备驱动程序中断