块设备驱动的引入
不能像字符设备那样直接进行读写操作,效率会很低。而是要
- 把读写放入队列
- 优化后再执行
块设备驱动的框架
app: open read write "test.text"
---------------------------------------------------------------- 文件的读写
文件系统: vfat, ext2, yaffs
---------------------------------------------------------------- 扇区的读写
块设备驱动程序
----------------------------------------------------------------
硬件: 硬盘, flash
思路:
- (把文件的读写转化成扇区的读写)(电梯调度算法)
- 把读写放入队列
- 调用队列的处理函数(优化/调顺序/合并/)
块设备驱动程序编写:
1. 分配gendisk:alloc_disk
2. 设置
2.1 分配/设置队列: blk_int_queue request_queuet //提供读写能力
2.2 设置gendisk其它信息 //提供属性
3. 注册:add_disk
举例:使用内存模拟硬盘块设备操作 (参考xd.c z2ran.c)
1. 修改/drivers/block/Kconfig,增加以下内容
config RAM_BLOCK_YE
tristate"YE Test Ram Block"
2. 修改/drivers/block/Makefile,增加以下内容
obj-$(CONFIG_RAM_BLOCK_YE) += ramblock.o
3. 配置make menuconfig,选择为M
4. 生成驱动模块, makeM=drivers/block
注:以下是测试步骤,但目前驱动有问题,不能全部实现以下功能。
测试1
1. 安装驱动: insmod ramblock.ko
2. 格式化: mk -> mkdosfs /dev/ramblock
3. 挂接: cd/tmp -> mount/dev/ramblock /tmp/
4. 读写文件: cd /tmp -> vi test.txt
5. 退出后,再挂接,查看是否有上次建立的文件:
umount /tmp/
mount /dev/ramblock /tmp/
6. 挂接到PC上:cat /dev/ramblock > /mnt/ramblock.bin
sudo mount -o loop ramblock.bin /mnt
7. 分区: fd-> fdisk /dev/ramblock
附代码:
static struct gendisk *ramblock_disk;
static struct request_queue *ramblock_queue;
static int major;
static DEFINE_SPINLOCK(ramblock_lock);
#define RAMBLOCK_SIZE (1024*1024)
static unsigned char *ramblock_buf;
static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
/* 容量=heads*cylinders*sectors*512 */
geo->heads = 2;
geo->cylinders = 32;
geo->sectors = RAMBLOCK_SIZE/2/32/512;
return 0;
}
static struct block_device_operations ramblock_fops = {
.owner = THIS_MODULE,
.getgeo = ramblock_getgeo,
};
static void do_ramblock_request(struct request_queue * q)
{
struct request *req;
req = blk_fetch_request(q);
while (req) {
unsigned long offset = blk_rq_pos(req) << 9;
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);
}
__blk_end_request_cur(req, 1);
}
}
static int ramblock_init(void)
{
/* 1. 申请设备号 */
major = register_blkdev(0, "ramblock");
/* 2. 分配gendisk结构体 */
ramblock_disk = alloc_disk(16);
/* 3. 分配请求队列,绑定请求队列和请求函数 */
ramblock_queue = blk_init_queue(do_ramblock_request, &ramblock_lock);
/* 4. 给gendisk成员赋值 */
ramblock_disk->major = major;
ramblock_disk->first_minor = 0;
ramblock_disk->fops = &ramblock_fops;
sprintf(ramblock_disk->disk_name, "ramblock");
ramblock_disk->queue = ramblock_queue;
/* 5. 注册 */
add_disk(ramblock_disk);
//blk_register_region(MKDEV(major, 0), 8, THIS_MODULE,z2_find, NULL, NULL);
return 0;
}
static void ramblock_exit(void)
{
//blk_unregister_region(MKDEV(major, 0), 8);
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");