📄 vdisk-multdev.c
字号:
/* * vdisk-multdev.c - virtual disk driver * * Copyright 2008 (C) weiqin (qinwei1998@hotmail.com) * * This code is based in part on ramdisk driver , only for teching * * This software is distributed under the terms of the GNU General * Public License ("GPL") as published by the Free Software Foundation, * either version 2 of that License or (at your option) any later version. * */#include <linux/string.h>#include <linux/slab.h>#include <asm/atomic.h>#include <linux/bio.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/pagemap.h>#include <linux/blkdev.h>#include <linux/genhd.h>#include <linux/buffer_head.h> #include <linux/backing-dev.h>#include <linux/blkpg.h>#include <linux/writeback.h>#include <linux/vmalloc.h>#include <asm/uaccess.h>#ifdef VDISK_DEBUG#define dprintk(fmt, args...) printk(fmt, ## args)#else#define dprintk(fmt, args...) /* not debugging: nothing */#endif#define VDISK_MAJOR 254#define VDISK_SIZE (2*1024*1024)#define SECTOR_SIZE (512)struct vdisk_struct{ struct gendisk *rd_disk; struct block_device *rd_bdev; struct request_queue *rd_queue; unsigned char * vdisk_mem;};/* Various static variables go here. Most are used only in the vdisk code. */#define CONFIG_BLK_DEV_VDISK_COUNT 3static struct vdisk_struct virtual_disks[CONFIG_BLK_DEV_VDISK_COUNT];static int vdisk_blkdev_IO(int rw, struct bio_vec *vec, sector_t sector, int devno){ pgoff_t index = sector >> (PAGE_CACHE_SHIFT - 9); unsigned int vec_offset = vec->bv_offset; int offset = (sector << 9) & ~PAGE_CACHE_MASK; int size = vec->bv_len; char * accessoffset; dprintk("start: sectors=%d, vec_offset=%d, offset=%d, size=%d\n", (int)sector, vec_offset, offset, size); do{ int count; char *src; char *dst; count = PAGE_CACHE_SIZE - offset; if (count > size) count = size; size -= count; accessoffset = virtual_disks[devno].vdisk_mem + ( index * PAGE_SIZE ); index++; if (rw == READ) { src = accessoffset + offset; dst = kmap_atomic(vec->bv_page, KM_USER1) + vec_offset; } else { src = kmap_atomic(vec->bv_page, KM_USER0) + vec_offset; dst = accessoffset + offset; } offset = 0; vec_offset += count; dprintk("rw=%d, sectors=%d, vec_offset=%d, offset=%d, size=%d\n", rw, (int)sector, vec_offset, offset, size); memcpy(dst, src, count); if( rw == READ ){ flush_dcache_page(vec->bv_page); kunmap_atomic(dst, KM_USER1); }else{ kunmap_atomic(src, KM_USER0); } }while( size ); return 0;}static int vdisk_make_request(struct request_queue *q, struct bio *bio){ struct block_device *bdev = bio->bi_bdev; unsigned int unit = iminor(bdev->bd_inode); sector_t sector = bio->bi_sector; unsigned long len = bio->bi_size >> 9; int rw = bio_data_dir(bio); struct bio_vec *bvec; int ret = 0, i; if (sector + len > get_capacity(bdev->bd_disk)) goto fail; if (rw==READA) rw=READ; bio_for_each_segment(bvec, bio, i) { ret |= vdisk_blkdev_IO(rw, bvec, sector, unit); sector += bvec->bv_len >> 9; } if (ret) goto fail; bio_endio(bio, bio->bi_size, 0); return 0;fail: bio_io_error(bio, bio->bi_size); return 0;} static int vdisk_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return 0;}static int vdisk_open(struct inode *inode, struct file *filp){ struct block_device *bdev = inode->i_bdev; unsigned bsize; unsigned unit = iminor(inode); if (virtual_disks[unit].rd_bdev == NULL) { virtual_disks[unit].rd_bdev = bdev; bsize = bdev_hardsect_size(bdev); bdev->bd_block_size = bsize; } return 0;}static struct block_device_operations vdisk_bd_op = { .owner = THIS_MODULE, .open = vdisk_open, .ioctl = vdisk_ioctl,};/* * This is the registration and initialization section of the vdisk driver */static int vdisk_major = 0;static int __init vdisk_init(void){ int err = -ENOMEM; int i; for (i = 0; i < CONFIG_BLK_DEV_VDISK_COUNT; i++) { virtual_disks[i].rd_disk = alloc_disk(1); if (!virtual_disks[i].rd_disk) goto out; virtual_disks[i].rd_queue = blk_alloc_queue(GFP_KERNEL); if (!virtual_disks[i].rd_queue) { put_disk(virtual_disks[i].rd_disk); goto out; } virtual_disks[i].vdisk_mem = vmalloc(VDISK_SIZE); if (!virtual_disks[i].vdisk_mem) { put_disk(virtual_disks[i].rd_disk); blk_cleanup_queue(virtual_disks[i].rd_queue); goto out; } } vdisk_major = register_blkdev(VDISK_MAJOR, "vdisk"); if ( vdisk_major<0 ) { err = -EIO; goto out; } for (i = 0; i < CONFIG_BLK_DEV_VDISK_COUNT; i++) { struct gendisk *disk; blk_queue_make_request(virtual_disks[i].rd_queue, &vdisk_make_request); blk_queue_hardsect_size(virtual_disks[i].rd_queue, 512); disk = virtual_disks[i].rd_disk; disk->major = VDISK_MAJOR; disk->first_minor = i; disk->fops = &vdisk_bd_op; disk->queue = virtual_disks[i].rd_queue; disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO; sprintf(disk->disk_name, "vdisk%d", i); set_capacity(disk, VDISK_SIZE/SECTOR_SIZE); add_disk(disk); } printk("VDISK driver initialized, vdisk_major= %d\n", vdisk_major); return 0;out: while (i--) { put_disk(virtual_disks[i].rd_disk); blk_cleanup_queue(virtual_disks[i].rd_queue); } return err;}static void __exit vdisk_cleanup(void){ int i; for (i = 0; i < CONFIG_BLK_DEV_VDISK_COUNT; i++) { struct block_device *bdev = virtual_disks[i].rd_bdev; virtual_disks[i].rd_bdev = NULL; if (bdev) { invalidate_bdev(bdev); blkdev_put(bdev); } del_gendisk(virtual_disks[i].rd_disk); put_disk(virtual_disks[i].rd_disk); blk_cleanup_queue(virtual_disks[i].rd_queue); } unregister_blkdev(VDISK_MAJOR, "vdisk");}module_init(vdisk_init);module_exit(vdisk_cleanup);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -