内存模拟块设备驱动程序设计

2022-05-08 16:13:21 浏览数 (1)

代码语言:javascript复制
/*既然上面分析了,块设备的工作原理。 那如何写一个块设备呢?*/

/*怎么写一个块设备驱动程序?
* 1. 分配一个gendisk结构,用alloc_disk函数
* 2. 分配一个request队列,用blk_init_queue函数
* 3. 设置gendisk结构
* 3.1 设置主设备号,次设备号
* 3.2 设置block_device_operations结构
* 3.3 设置queueu结构
* 4. 注册gendisk:     用add_disk函数     
*/

/***既然知道如何写一个块设备驱动程序,我们就动手用内存模拟一个块设备驱动***/

#define BLOCK_SIZE (1024*1024)
static struct gendisk *block_disk;
struct request_queue *block_queue;
static DEFINE_SPINLOCK(block_lock);
static int major;
static unsigned char *block_buf;

//硬盘容量 = 柱面数(表示每面盘面上有几条磁道,一般总数是1024) × 磁头数(表示盘面数) × 扇区数(表示每条磁道有几个扇区,一般总数是64)× 扇区(存储基本单元,大小一般为512B/4KB)
static int ramblock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
	/* 容量=heads*cylinders*sectors*512 */
	geo->heads     = 2;													//磁头
	geo->cylinders = 32;                        //柱面
	geo->sectors   = RAMBLOCK_SIZE/2/32/512;		//扇区
	return 0;
}

static const struct block_device_operations z2_fops =
{
	.owner	= THIS_MODULE,
	.getgeo	= block_getgeo,
};

static void block_request_func(request_queue_t * q)
{
		struct request *req;
	  while ((req = elv_next_request(q)) != NULL) {
		/* 数据传输三要素: 源,目的,长度 */
		
		unsigned long offset = req->sector * 512;

		unsigned long len = req->current_nr_sectors * 512; // 长度

		if (rq_data_dir(req) == READ)//读设备
		{
			memcpy(req->buffer, ramblock_buf offset, len);
		}
		else  //写设备
		{
			memcpy(ramblock_buf offset, req->buffer, len);
		}		
		
		end_request(req, 1);
}

static int block_init(void)
{
	//1. 	分配一个gendisk结构,用alloc_disk函数
	block_disk = alloc_disk(10); //10个分区
		
	//2.  分配一个request队列,用blk_init_queue函数
	block_queue = blk_init_queue(block_request_func, &block_lock);
	
	//设置queueu结构
	block_disk->queue = block_disk;
	
	//3.  设置gendisk结构
	major = register_blkdev(0, "block");
	block_disk->major = major;
	block_disk->first_minor = 0;
	block_disk->fops = &block_fops;
	sprintf(block_disk->disk_name, "myblock");
	set_capacity(ramblock_disk, BLOCK_SIZE / 512); //设置容量
	
	//既然我们用内存模拟块设备,需要分配一块内存
	block_disk = kzalloc(BLOCK_SIZE, GFP_KERNEL);
	
	//4.  注册gendisk:     用add_disk函数
	add_disk(block_disk);
}

//释放申请的内存
static void block_exit(void)
{
	unregister_blkdev(major, "myblock");
	del_gendisk(block_disk);
	put_disk(block_disk);
	blk_cleanup_queue(block_disk);
	kfree(block_disk);
}

module_init(block_init);
module_exit(block_exit);

MODULE_LICENSE("GPL");

0 人点赞