知识储备:
块设备驱动是基于扇区(sector)来访问底层物理磁盘,基于块(block)来访问上层文件系统。扇区一般是2的n次方大小,典型为512B,内核也要求块是2的n次方大小,且块大小通常为扇区大小的整数倍,并且块大小要小于页面大小,典型大小为512B、1K或4K。
内存和NOR型闪存的基本存储单元是bit,用户可以随机访问任何一个bit的信息。NAND型闪存的基本存储单元是页(Page)(可以看到, NAND型闪存的页就类似硬盘的扇区,硬盘的一个扇区也为512字节)。每一页的有效容量是512字节的倍数。所谓的有效容量是指用于数据存储的部分,实际上还要加上16字节的校验信息,因此我们可以在闪存厂商的技术资料当中看到“(512+16)Byte”的表示方式。目前2Gb以下容量的NAND型闪存绝大多数是(512+16)字节的页面容量,2Gb以上容量的NAND型闪存则将页容量扩大到(2048+64)字节。
NAND型闪存以块为单位进行擦除操作。闪存的写入操作必须在空白区域进行,如果目标区域已经有数据,必须先擦除后写入,因此擦除操作是闪存的基本操作。一般每个块包含32个512字节的页,容量16KB;而大容量闪存采用2KB页时,则每个块包含64个页,容量128KB。每颗NAND型闪存的I/O接口一般是8条,每条数据线每次传输(512+16)bit信息,8条就是(512+16)×8bit,也就是前面说的512字节。
源代码:
#include<linux/init.h>
#include<linux/module.h>
#include<linux/genhd.h>
#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 <linux/gfp.h>
#include <linux/slab.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/dma.h>
//#define DEV_MAJOR 251
#define RAMDISK_SIZE (1024)
static struct gendisk * mydisk;
static struct request_queue *blkdev_queue;
static DEFINE_SPINLOCK(ramdisk_lock);
static unsigned char *ram_buff;
static int DEV_MAJOR;
static const struct block_device_operations rmbk_fops = {
.owner = THIS_MODULE,
};
static void ramblock_do_request(struct request_queue * q)
{
struct request *req;
printk("do:ramblock_do_request\n");
req = blk_fetch_request(q);
while (req){
//源或目的
unsigned long offset = blk_rq_pos(req)*512;
//目的或源
//req->buffer
// 长度
unsigned long len = blk_rq_cur_bytes(req);
if(rq_data_dir(req) == READ)
memcpy(req->buffer, ram_buff+offset, len);
else
memcpy(ram_buff+offset,req->buffer,len);
// wrap up ,0 = success, -errno =fail
if(!__blk_end_request_cur(req,0))
req = blk_fetch_request(q);
}
}
static int blkdev_init(void)
{
printk("begin\n");
// int ret;
DEV_MAJOR = register_blkdev(DEV_MAJOR, "vmdisk");/* 注册块设备 */
/* 分配gendisk结构体*/
mydisk = alloc_disk(1);
blkdev_queue = blk_init_queue(ramblock_do_request,&ramdisk_lock);/* 为块设备准备一个请求队列 */
mydisk->queue = blkdev_queue;
mydisk->major = DEV_MAJOR;
mydisk->first_minor = 0;
mydisk->fops = &rmbk_fops;
sprintf(mydisk->disk_name, "vmdisk");
set_capacity(mydisk, RAMDISK_SIZE);
ram_buff = kzalloc(RAMDISK_SIZE, GFP_KERNEL);
add_disk(mydisk);
return 0;
}
static void blkdev_exit(void)
{ printk("quit\n");
unregister_blkdev(DEV_MAJOR, "vmdisk");
del_gendisk(mydisk);
put_disk(mydisk);
blk_cleanup_queue(blkdev_queue);
kfree(ram_buff);
}
module_init(blkdev_init);
module_exit(blkdev_exit);
MODULE_LICENSE("GPL");
终端输入
FDISK的/ dev / ramdisk的进入块设备的设置
然后执行
mkfs.vfat的/ dev / ramdisk的对分区进行格式化
接下来将其挂载到文件系统
执行命令
mount /dev/块设备名 /ming
成功挂载
测试读写操作
LS> ming/123
cat 123