塊裝置驅動1—用記憶體模擬磁碟
塊裝置驅動的引入
不能像字元裝置那樣直接進行讀寫操作,效率會很低。而是要
- 把讀寫放入佇列
- 優化後再執行
塊裝置驅動的框架
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");