block驱动

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/blkpg.h>
#include <linux/bio.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>


#define BLK_SIZE (10*1024*512)
#define SECTOR_SIZE (512)


MODULE_AUTHOR("Pingbo An");
MODULE_LICENSE("GPL v2");


struct vmem_device {
	struct gendisk *disk;
	struct request_queue *que;
	void *buf;
	spinlock_t lock;
	ssize_t size;
};

struct vmem_device *vdev=NULL;
static int vmem_major;


static int vmem_open(struct block_device *bdev, fmode_t mode)
{
	return 0;
}

static void vmem_release(struct gendisk *disk, fmode_t mode)
{
}

static int vmem_ioctl(struct block_device *bdev, fmode_t mode,
			unsigned command, unsigned long argument)
{
	return 0;
}


static int vmem_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
	geo->cylinders=1;
	geo->heads=1;
	geo->sectors=BLK_SIZE/SECTOR_SIZE;
	return 0;
}



static struct block_device_operations vmem_fops={
	.owner=THIS_MODULE,
	.getgeo=vmem_getgeo,
	.ioctl=vmem_ioctl,
	.open=vmem_open,
	.release=vmem_release,
};



static int vmem_transfer(struct vmem_device *vdev, uint64_t pos, ssize_t size, void *buffer, int write)
{

	if(write)
		memcpy(vdev->buf+pos, buffer, size);
	else
		memcpy(buffer, vdev->buf+pos, size);

	return 0;
}

static void vmem_request(struct request_queue *q){

	struct request *req;
	uint64_t pos=0;
	ssize_t size=0;
	struct bio_vec bvec;
	int rv=0;
	struct req_iterator iter;
	void *kaddr=NULL;

	while((req=blk_fetch_request(q)) != NULL){
		
		spin_unlock_irq(q->queue_lock);

		pos=blk_rq_pos(req)*SECTOR_SIZE;
		size=blk_rq_bytes(req);
		if(pos+size>vdev->size){
			printk(KERN_WARNING "beyond addr\n");
			rv=-EIO;
			goto skip;
		}

		rq_for_each_segment(bvec, req, iter){
			kaddr=kmap(bvec.bv_page);
			rv=vmem_transfer(vdev, pos, bvec.bv_len, kaddr+bvec.bv_offset, rq_data_dir(req));
			if(rv<0)
				goto skip;
		pos+=bvec.bv_len;
		kunmap(bvec.bv_page);
		}
	skip:
		blk_end_request_all(req, rv);
		spin_lock_irq(q->queue_lock);
	}

}


static int __init vmem_init(void)
{
	struct gendisk *disk;
	vmem_major=register_blkdev(0, "VMEM");
	vdev=kzalloc(sizeof(struct vmem_device), GFP_KERNEL);
	if(!vdev){
		printk(KERN_WARNING "vmem_device: unable to allocate mem\n");
		goto out;
	}

	vdev->size=BLK_SIZE;
	vdev->buf=vmalloc(vdev->size);
	if(vdev->buf==NULL){
		printk(KERN_WARNING "failed to vmalloc vdev->buf\n");
		goto out_dev;
	}
	
	spin_lock_init(&vdev->lock);
	vdev->que=blk_init_queue(vmem_request, &vdev->lock);
	if(vdev->que==NULL){
		printk(KERN_WARNING "failed to init queue\n");
		goto out_buf;
	}
	disk=alloc_disk(1);
	if(disk==NULL){
		printk(KERN_WARNING "failed to alloc disk\n");
		goto out_que;
	}
	vdev->disk=disk;
	disk->major=vmem_major;
	disk->first_minor=1;
	disk->fops=&vmem_fops;
	disk->queue=vdev->que;
	disk->private_data=vdev;
	sprintf(disk->disk_name, "VMEM");
	set_capacity(disk, BLK_SIZE/SECTOR_SIZE);
	add_disk(disk);
	printk(KERN_INFO "succeed to init\n");
	return 0;

	
out_que:
	blk_cleanup_queue(vdev->que);
out_buf:
	vfree(vdev->buf);
out_dev:
	kfree(vdev);

out:
	unregister_blkdev(vmem_major, "VMEM");
	
	return -1;
		
}


static void __exit vmem_exit(void)
{
	
	del_gendisk(vdev->disk);
	blk_cleanup_queue(vdev->que);
	put_disk(vdev->disk);

	vfree(vdev->buf);	
	kfree(vdev);
	unregister_blkdev(vmem_major, "VMEM");
	printk(KERN_INFO "module exit\n");
}


module_init(vmem_init);
module_exit(vmem_exit);



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值