块设备驱动程序3

Virtual_blkdev.c

//============================================================================   
// Name        : Virtual_blkdev   
// Author      : Haier   
// Version     : 0.3   
// Copyright   : Your copyright notice   
// Description : blkdev driver in c, Ansi-style , compile by GCC, Linux 2.6.32  
//============================================================================ 

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/hdreg.h>
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/bio.h>

#define VIRTUAL_BLKDEV_DEVICEMAJOR COMPAQ_SMART2_MAJOR
#define VIRTUAL_BLKDEV_DISKNAME "Virtual_blkdev"
#define VIRTUAL_BLKDEV_BYTES (8*1024*1024)
#define VIRTUAL_BLKDEV_MAXPARTITIONS (5)

static struct request_queue *Virtual_blkdev_queue;
static struct gendisk *Virtual_blkdev_disk;
unsigned char Virtual_blkdev_data[VIRTUAL_BLKDEV_BYTES];

static int Virtual_blkdev_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
	if(VIRTUAL_BLKDEV_BYTES < 16 * 1024 * 1024)
	{
		geo->heads = 1;
		geo->sectors = 1;
	}
	else if(VIRTUAL_BLKDEV_BYTES < 512 * 1024 * 1024)
	{
		geo->heads = 1;
		geo->sectors = 32;
	}
	else if(VIRTUAL_BLKDEV_BYTES < 16ULL * 1024 * 1024 * 1024)
	{
		geo->heads = 32;
		geo->sectors = 32;
	}
	else 
	{
		geo->heads = 255;
		geo->sectors = 63;
	}
	
	geo->cylinders = (VIRTUAL_BLKDEV_BYTES >> 9) / (geo->heads/geo->sectors);
	
	return 0;
}

static int Virtual_blkdev_make_request(struct request_queue *q, struct bio *bio)
{
	struct bio_vec *bvec;
	int i;
	void *dsk_mem;
	
	if((bio->bi_sector << 9) + bio->bi_size > VIRTUAL_BLKDEV_BYTES)
	{
		printk(KERN_ERR VIRTUAL_BLKDEV_DISKNAME
		": bad request: block=%llu, count=%u\n",
		(unsigned long long)bio->bi_sector, bio->bi_size);
		
		#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
			bio_endio(bio, 0, -FIO);
		#else
			bio_endio(bio, -EIO);
		#endif
		
		return 0;
	}
	
	dsk_mem = Virtual_blkdev_data + (bio->bi_sector << 9);
	bio_for_each_segment(bvec, bio, i)
	{
		void *iovec_mem;
		
		switch(bio_rw(bio))
		{
			case READ:
			case READA:
			{
				iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset;
				memcpy(iovec_mem, dsk_mem, bvec->bv_len);
				kunmap(bvec->bv_page);
				
				break;
			}
			case WRITE:
			{
				iovec_mem = kmap(bvec->bv_page) + bvec->bv_offset;
				memcpy(dsk_mem, iovec_mem, bvec->bv_len);
				kunmap(bvec->bv_page);
				
				break;
			}
			
			default:
			{
				printk(KERN_ERR VIRTUAL_BLKDEV_DISKNAME
				": unknown value of bio_rw: %lu\n",
				bio_rw(bio));
				
				#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
					bio_endio(bio, 0, -EIO);
				#else
					bio_endio(bio, -EIO);
				#endif
				
				return 0;
			}
						
		}
		
		dsk_mem += bvec->bv_len;
		
	}
	#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
		bio_endio(bio, bio->bi_size, 0);
	#else 
		bio_endio(bio, 0);
	#endif
	
	return 0;
}

struct block_device_operations Virtual_blkdev_fops =
{
	.owner = THIS_MODULE,
	.getgeo = Virtual_blkdev_getgeo,
};

static int __init Virtual_blkdev_init(void)
{
	int ret;
	
	Virtual_blkdev_disk = alloc_disk(VIRTUAL_BLKDEV_MAXPARTITIONS);
	if(!Virtual_blkdev_disk)
	{
		ret = -ENOMEM;
		goto err_alloc_disk;
	}
	
	Virtual_blkdev_queue = blk_alloc_queue(GFP_KERNEL);
	if(!Virtual_blkdev_queue)
	{
		ret = -ENOMEM;
		goto err_init_queue;
	}
	
	blk_queue_make_request(Virtual_blkdev_queue, Virtual_blkdev_make_request);
	
	strcpy(Virtual_blkdev_disk->disk_name, VIRTUAL_BLKDEV_DISKNAME);
	Virtual_blkdev_disk->major = VIRTUAL_BLKDEV_DEVICEMAJOR;
	Virtual_blkdev_disk->first_minor = 0;
	Virtual_blkdev_disk->fops = &Virtual_blkdev_fops;
	Virtual_blkdev_disk->queue = Virtual_blkdev_queue;
	set_capacity(Virtual_blkdev_disk, VIRTUAL_BLKDEV_BYTES>>9);
	add_disk(Virtual_blkdev_disk);
	
	return 0;
	
	err_init_queue:
		put_disk(Virtual_blkdev_disk);
	err_alloc_disk:
		return ret;
}

static void __exit Virtual_blkdev_exit(void)
{
	del_gendisk(Virtual_blkdev_disk);
	put_disk(Virtual_blkdev_disk);
	blk_cleanup_queue(Virtual_blkdev_queue);
}

module_init(Virtual_blkdev_init);
module_exit(Virtual_blkdev_exit);


Makefile

 

target = Virtual_blkdev

ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/`uname -r`/build

modules:
	$(MAKE) -C $(KERNELDIR) M=`pwd` modules

modules_install:
	insmod $(target).ko

uninstall:
	rmmod $(target).ko
	
clean:
	rm -rf *.o *.mod.c *.ko *.symvers *.order *.unsigned

else
	obj-m := $(target).o
endif


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值