📄 vdisk.c
字号:
/* * vdisk.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 <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)static unsigned char vdisk_mem[VDISK_SIZE];/* Various static variables go here. Most are used only in the vdisk code. */static struct gendisk *vdisks;static struct block_device *vdisk_bdev;/* Protected device data */static struct request_queue *vdisk_queue;static int vdisk_blkdev_IO(int rw, struct bio_vec *vec, sector_t sector){ 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 = 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; 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); 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; vdisk_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; struct gendisk *disk; vdisks = alloc_disk(1); if (!vdisks) goto out; vdisk_queue = blk_alloc_queue(GFP_KERNEL); if (!vdisk_queue) { put_disk(vdisks); goto out; } vdisk_major = register_blkdev(VDISK_MAJOR, "vdisk"); if ( vdisk_major<0 ) { put_disk(vdisks); blk_cleanup_queue(vdisk_queue); err = -EIO; goto out; } blk_queue_make_request(vdisk_queue, &vdisk_make_request); blk_queue_hardsect_size(vdisk_queue, 512); disk = vdisks; disk->major = VDISK_MAJOR; disk->first_minor = 0; disk->fops = &vdisk_bd_op; disk->queue = vdisk_queue; disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO; sprintf(disk->disk_name, "vdisk"); set_capacity(disk, VDISK_SIZE/SECTOR_SIZE); add_disk(vdisks); memset(vdisk_mem, 0, VDISK_SIZE); printk("VDISK driver initialized, vdisk_major= %d\n", vdisk_major); return 0;out: put_disk(vdisks); blk_cleanup_queue(vdisk_queue); return err;}static void __exit vdisk_cleanup(void){ struct block_device *bdev = vdisk_bdev; vdisk_bdev = NULL; if (bdev) { invalidate_bdev(bdev); blkdev_put(bdev); } del_gendisk(vdisks); put_disk(vdisks); blk_cleanup_queue(vdisk_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 + -