全部博文(22)
分类: LINUX
2010-04-07 15:38:26
每个块设备都拥有一个操作接口:struct block_device_operations,该接口定义了open、close、ioctl等函数接口,但没有,也没有必要定义read、write函数接口。
初始化一个块设备的过程如下:
int setup_device(block_dev_t *dev, int minor)
{
int hardsect_size = HARDSECT_SIZE;
int chunk_size;
sector_t dev_size;
/* 分配一个请求队列 */
dev->queue = blk_alloc_queue(GFP_KERNEL);
if (dev->queue == NULL) {
printk(ERROR, "blk_alloc_queue failure!\n");
return -ENOMEM;
}
chunk_size = dev->chunk_size >> 9; //sectors
/* 将block_make_request注册到q->make_request上 */
blk_queue_make_request(dev->queue, block_make_request);
blk_queue_max_sectors(dev->queue, chunk_size);
blk_queue_hardsect_size(dev->queue, hardsect_size);
blk_queue_merge_bvec(dev->queue, block_mergeable_bvec);
dev->queue->queuedata = dev;
/* 将block_unplug注册到q->unplug_fn上 */
dev->queue->unplug_fn = block_unplug;
/* 分配一个gendisk */
dev->gd = alloc_disk(1);
if (!dev->gd) {
prink(ERROR, "alloc_disk failure!\n");
blk_cleanup_queue(dev->queue);
return -ENOMEM;
}
dev->gd->major = block_major; /* 设备的major号 */
dev->gd->first_minor = minor; /* 设备的minor号 */
dev->gd->fops = &block_ops; /* 块设备的操作接口,open、close、ioctl */
dev->gd->queue = dev->queue; /* 块设备的请求队列 */
dev->gd->private_data = dev;
snprintf(dev->gd->disk_name, 32, dev->block_name);
dev_size = (sector_t) dev->dev_size >> 9;
set_capacity(dev->gd, dev_size); /* 设置块设备的容量 */
add_disk(dev->gd); /* 添加块设备 */
return 0;
}
通过register_blkdev函数将块设备注册到Linux系统。示例代码如下:
static int blockdev_init(void)
{
…
block_major = register_blkdev(block_major, "blockd");
if (block_major <= 0) {
printk(ERROR, "blockd: cannot get major %d\n", block_major);
return -EFAULT;
}
…
}
通过unregister_blkdev函数清除一个块设备。示例代码如下:
static int blockdev_cleanup(void)
{
…
unregister_blkdev(block_major, "blockd");
…
}
make_request函数是块设备中最重要的接口函数,每个块设备都需要提供make_request函数。如果块设备为有请求队列的实际设备,那么make_request函数被注册为__make_request,该函数由Linux系统提供;反之,需要用户提供私有函数。__make_request函数功能在前文已述。
在用户提供的私有make_request函数中往往对bio进行过滤处理,这样的驱动在Linux中有md(raid0、raid1、raid5),过滤处理完毕之后,私有make_request函数返回1,告诉generic_make_request函数进行bio转