#include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/genhd.h> #include <linux/blkdev.h> #include <linux/hdreg.h> #include <linux/vmalloc.h> MODULE_LICENSE("GPL"); #define SECTOR_SIZE 512 #define N_SECTORS 1024 #define DEVICE_NAME "vdisk" static int major = 0; module_param(major,int,0); struct VDisk { const unsigned int sector_size; unsigned int n_sectors; char *data; struct request_queue *queue; struct gendisk *gd; spinlock_t lock; }; static struct VDisk *vdisk_ptr=0; //module_param(vdisk_ptr,struct VDisk *,0); struct VDisk * create_vdisk(int _sector_size, int _n_sectors) { if(vdisk_ptr) { return 0; } struct VDisk init={ sector_size: _sector_size, n_sectors: _n_sectors, }; init.data = (char *)vmalloc(_sector_size * _n_sectors); vdisk_ptr = (struct VDisk *)vmalloc(sizeof(struct VDisk)); memcpy(vdisk_ptr,&init,sizeof(init)); return vdisk_ptr; } void destroy_vdisk(void) { if(vdisk_ptr) { vfree(vdisk_ptr->data); vfree(vdisk_ptr); vdisk_ptr=0; } } static void transfer(struct VDisk *disk,unsigned long sector,unsigned long nsect,char *buf,int write) { unsigned long offset = sector * disk->sector_size; unsigned long nbytes = nsect * disk->sector_size; if(offset+nbytes > disk->sector_size * disk->n_sectors) { printk("Over the range!/n"); return; } else { if(write) { memcpy(disk->data+offset,buf,nbytes); } else { memcpy(buf,disk->data+offset,nbytes); } } } int vdisk_getgeo(struct block_device *block_device,struct hd_geometry *geo) { long size; size=vdisk_ptr->n_sectors*vdisk_ptr->sector_size; geo->cylinders = (size & ~0x3f)>>6; geo->heads =4; geo->sectors=vdisk_ptr->n_sectors; geo->start=0; return 0; } static struct block_device_operations ops = { .owner=THIS_MODULE, .getgeo=vdisk_getgeo }; static void request_proc(struct request_queue *q) { struct request *r; r = blk_fetch_request(q); while (r != NULL) { struct VDisk *dev = r->rq_disk->private_data; if (! blk_fs_request(r)) { printk ("Skip non-fs request/n"); __blk_end_request_all(r, -EIO); continue; } transfer(dev,blk_rq_pos(r),blk_rq_cur_sectors(r), r->buffer, rq_data_dir(r)); if(!__blk_end_request_cur(r,0)) { r=blk_fetch_request(q); } } } int init_vdisk() { // spin_lock_init(&vdisk_ptr->lock); vdisk_ptr=create_vdisk(SECTOR_SIZE,N_SECTORS); if(!vdisk_ptr) { printk("error:can not create vdisk!/n"); } vdisk_ptr->queue = blk_init_queue(request_proc,&vdisk_ptr->lock); blk_queue_logical_block_size(vdisk_ptr->queue,vdisk_ptr->sector_size); major=register_blkdev(major,DEVICE_NAME); vdisk_ptr->gd=alloc_disk(16); vdisk_ptr->gd->major=major; vdisk_ptr->gd->first_minor = 0; vdisk_ptr->gd->fops = &ops;/// vdisk_ptr->gd->private_data=vdisk_ptr; strcpy(vdisk_ptr->gd->disk_name,DEVICE_NAME); set_capacity(vdisk_ptr->gd,vdisk_ptr->n_sectors); vdisk_ptr->gd->queue=vdisk_ptr->queue; add_disk(vdisk_ptr->gd); return 0; } void cleanup_vdisk() { del_gendisk(vdisk_ptr->gd); put_disk(vdisk_ptr->gd); unregister_blkdev(major, DEVICE_NAME); blk_cleanup_queue(vdisk_ptr->queue); if(vdisk_ptr) { destroy_vdisk(); } } module_init(init_vdisk); module_exit(cleanup_vdisk);