前一章我们介绍了通用磁盘结构体struct gendisk
的申请操作,本章我们将要介绍申请完通用块结构体之后怎么把通用块结构体增加到内核空间去,并且使内核认识到:哦…这就是我们的磁盘啊! 使用此操作之后我们便可以随心所欲的操作我们的磁盘了。
主要函数
把通用磁盘结构体struct gendisk
增加到内核的操作十分简单就是一个函数:add_disk。先说明一下这个函数的大体功能:
add_disk函数说明:
传入参数:
@struct gendisk* disk : 向内核添加入通用磁盘的结构体
返回值:
void
函数功能:
向内核中完成通用磁盘的注册。
主要完成一下操作:
1. 获取MKDEV(disk->major, disk->part0.partno + disk->first_minor)头一个设备号的地址
2. 向bdev_map散列表中注册进入块设备号的主设备号和次设备号。
3. 使用BLKDEV文件系统第一次获取bdev结构,也就是把block_device注册进入bdev文件系统
4. 把通用磁盘的工作队列的backing_dev_info注册进入系统
具体实现
add_disk代码全部实现如下:
void add_disk(struct gendisk *disk)
{
struct backing_dev_info *bdi;
dev_t devt;
int retval;
/* minors == 0 indicates to use ext devt from part0 and should
* be accompanied with EXT_DEVT flag. Make sure all
* parameters make sense.
*/
WARN_ON(disk->minors && !(disk->major || disk->first_minor));
WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT));
disk->flags |= GENHD_FL_UP;
retval = blk_alloc_devt(&disk->part0, &devt);
if (retval) {
WARN_ON(1);
return;
}
disk_to_dev(disk)->devt = devt;
/* ->major and ->first_minor aren't supposed to be
* dereferenced from here on, but set them just in case.
*/
disk->major = MAJOR(devt);
disk->first_minor = MINOR(devt);
blk_register_region(disk_devt(disk), disk->minors, NULL,
exact_match, exact_lock, disk);
register_disk(disk);
blk_register_queue(disk);
bdi = &disk->queue->backing_dev_info;
bdi_register_dev(bdi, disk_devt(disk));
retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
"bdi");
WARN_ON(retval);
}
代码解读:
- 获取MKDEV(disk->major, disk->part0.partno + disk->first_minor)头一个设备号的地址,以下代码就是实现此操作的目的,
disk->flags |= GENHD_FL_UP;
retval = blk_alloc_devt(&disk->part0, &devt);
if (retval) {
WARN_ON(1);
return;
}
disk_to_dev(disk)->devt = devt;
其中blk_alloc_devt
函数原型如下:
int blk_alloc_devt(struct hd_struct *part, dev_t *devt)
{
struct gendisk *disk = part_to_disk(part);
int idx, rc;
/* in consecutive minor range? */
//此函的的主要部分,如果part->partno< disk->minors时候我们知道传入的part为part0,所以partno = 0, disk->minors则为大于零的数值。
if (part->partno < disk->minors) {
*devt = MKDEV(disk->major, disk->first_minor + part->partno);
return 0;
}
/* allocate ext devt */
do {
if (!idr_pre_get(&ext_devt_idr, GFP_KERNEL))
return -ENOMEM;
rc = idr_get_new(&ext_devt_idr, part, &idx);
} while (rc == -EAGAIN);
if (rc)
return rc;
if (idx > MAX_EXT_DEVT) {
idr_remove(&ext_devt_idr, idx);
return -EBUSY;
}
*devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx));
return 0;
}
上面函数最主要部分为: *devt = MKDEV(disk->major, disk->first_minor + part->partno);
获取第一个设备号的值。
2. 向bdev_map散列表中注册进入块设备号的主设备号和次设备号。主要执行如下函数:
blk_register_region(disk_devt(disk), disk->minors, NULL,
exact_match, exact_lock, disk);
以上函数原型如下:
blk_register_region(disk_devt(disk), disk->minors, NULL,
exact_match, exact_lock, disk);
其中bdev_map为kobj_map类型,其下的主要作用如下:
3. 使用BLKDEV文件系统第一次获取bdev结构,也就是把block_device注册进入bdev文件系统
主要执行如下函数:
register_disk(disk);
此函数的主要作用如下:
1. 在/sys/目录下建立相应的目录,
2.向内核中增加part0.__dev设备。
3. 在/sys/block/xxx目录下建立holder slaves目录。
4. 在bdev目录下生成block_device结构并且测试、把bdev->invalite结构使能。
- 把通用磁盘的工作队列的backing_dev_info注册进入系统并且在/sys/block/xxxx目录下生成bdi目录。