blkdev_get()函数负责从gendisk中获取信息,并建立相关数据结构之间的联系
int blkdev_get(struct block_device *bdev, fmode_t mode)
{
return __blkdev_get(bdev, mode, 0);
}
注意_blkdev_get()传递的最后一个参数为0,也就是说默认打开的是主设备
获取到gendisk之后会分四种情况进行处理,也就是针对设备是不是第一次打开以及打开的设备是主设备还是分区来进行不同的处理,具体见代码注释
static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
{
struct gendisk *disk;
int ret;
int partno;
int perm = 0;
if (mode & FMODE_READ)
perm |= MAY_READ;
if (mode & FMODE_WRITE)
perm |= MAY_WRITE;
/*
* hooks: /n/, see "layering violations".
*/
if (!for_part) {
ret = devcgroup_inode_permission(bdev->bd_inode, perm);
if (ret != 0) {
bdput(bdev);
return ret;
}
}
lock_kernel();
restart:
ret = -ENXIO;
//获取该设备的gendisk实例,如果bd_dev对应的是一个分区设备的话,partno将会被修改
disk = get_gendisk(bdev->bd_dev, &partno);
if (!disk)
goto out_unlock_kernel;
mutex_lock_nested(&bdev->bd_mutex, for_part);
if (!bdev->bd_openers) {//如果是第一次打开设备
bdev->bd_disk = disk;//建立block device和gendisk之间的联系
bdev->bd_contains = bdev;
if (!partno) {//partno为0,也就是说打开的是主设备而不是分区
struct backing_dev_info *bdi;
ret = -ENXIO;
bdev->bd_part = disk_get_part(disk, partno);//获取gendisk中的分区数组
if (!bdev->bd_part)
goto out_clear;
if (disk->fops->open) {//gendisk中定义了open方式
ret = disk->fops->open(bdev, mode);//调用open针对具体的设备进行打开操作
if (ret == -ERESTARTSYS) {
/* Lost a race with 'disk' being
* deleted, try again.
* See md.c
*/
disk_put_part(bdev->bd_part);
bdev->bd_part = NULL;
module_put(disk->fops->owner);
put_disk(disk);
bdev->bd_disk = NULL;
mutex_unlock(&bdev->bd_mutex);
goto restart;
}
if (ret)
goto out_clear;
}
if (!bdev->bd_openers) {
bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);//从gendisk中提取容量信息设置到block device
bdi = blk_get_backing_dev_info(bdev);
if (bdi == NULL)
bdi = &default_backing_dev_info;
bdev->bd_inode->i_data.backing_dev_info = bdi;
}
//块设备上的分区改变导致分区在内核中的信息无效,则要重新扫描分区
if (bdev->bd_invalidated)
rescan_partitions(disk, bdev);
} else {//如果打开的是分区
struct block_device *whole;
whole = bdget_disk(disk, 0);//获取主设备的block device实例
ret = -ENOMEM;
if (!whole)
goto out_clear;
BUG_ON(for_part);
ret = __blkdev_get(whole, mode, 1);
if (ret)
goto out_clear;
bdev->bd_contains = whole;//设置分区的block device实例的bd_contains域到主设备
bdev->bd_inode->i_data.backing_dev_info =
whole->bd_inode->i_data.backing_dev_info;
bdev->bd_part = disk_get_part(disk, partno);
if (!(disk->flags & GENHD_FL_UP) ||
!bdev->bd_part || !bdev->bd_part->nr_sects) {
ret = -ENXIO;
goto out_clear;
}
bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9);
}
} else {//如果不是第一次打开
module_put(disk->fops->owner);
put_disk(disk);
disk = NULL;
if (bdev->bd_contains == bdev) {//打开的是主设备
if (bdev->bd_disk->fops->open) {
ret = bdev->bd_disk->fops->open(bdev, mode);//调用定义的open
if (ret)
goto out_unlock_bdev;
}
if (bdev->bd_invalidated)
rescan_partitions(bdev->bd_disk, bdev);
}
}
bdev->bd_openers++;//计数值加1
if (for_part)//如果是分区则分区计数值也加1
bdev->bd_part_count++;
mutex_unlock(&bdev->bd_mutex);
unlock_kernel();
return 0;
out_clear:
disk_put_part(bdev->bd_part);
bdev->bd_disk = NULL;
bdev->bd_part = NULL;
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
if (bdev != bdev->bd_contains)
__blkdev_put(bdev->bd_contains, mode, 1);
bdev->bd_contains = NULL;
out_unlock_bdev:
mutex_unlock(&bdev->bd_mutex);
out_unlock_kernel:
unlock_kernel();
if (disk)
module_put(disk->fops->owner);
put_disk(disk);
bdput(bdev);
return ret;
}