代码语言: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");