现在的位置: 首页 > 综合 > 正文

关联block_device结构

2012年08月26日 ⁄ 综合 ⁄ 共 5888字 ⁄ 字号 评论关闭

1.5.3 关联block_device结构

接下来是register_disk函数,来自fs/partitions/check.c

 

    473 /* Not exported, helper to add_disk(). */

    474 void register_disk(struct gendisk *disk)

    475 {

    476         struct block_device *bdev;

    477         char *s;

    478         int i;

    479         struct hd_struct *p;

    480         int err;

    481

    482         strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);

    483         /* ewww... some of these buggers have / in name... */

    484         s = strchr(disk->kobj.name, '/');

    485         if (s)

    486                 *s = '!';

    487         if ((err = kobject_add(&disk->kobj)))

    488                 return;

    489         err = disk_sysfs_symlinks(disk);

    490         if (err) {

    491                 kobject_del(&disk->kobj);

    492                 return;

    493         }

    494         disk_sysfs_add_subdirs(disk);

    495

    496         /* No minors to use for partitions */

    497         if (disk->minors == 1)

    498                 goto exit;

    499

    500         /* No such device (e.g., media were just removed) */

    501         if (!get_capacity(disk))

    502                 goto exit;

    503

    504         bdev = bdget_disk(disk, 0);

    505         if (!bdev)

    506                 goto exit;

    507

    508         /* scan partition table, but suppress uevents */

    509         bdev->bd_invalidated = 1;

    510         disk->part_uevent_suppress = 1;

    511         err = blkdev_get(bdev, FMODE_READ, 0);

    512         disk->part_uevent_suppress = 0;

    513         if (err < 0)

    514                 goto exit;

    515         blkdev_put(bdev);

    516

    517 exit:

    518         /* announce disk after possible partitions are already created */

    519         kobject_uevent(&disk->kobj, KOBJ_ADD);

    520

    521         /* announce possible partitions */

    522         for (i = 1; i < disk->minors; i++) {

    523                 p = disk->part[i-1];

    524                 if (!p || !p->nr_sects)

    525                         continue;

    526                 kobject_uevent(&p->kobj, KOBJ_ADD);

    527         }

    528 }

 

首先487行这个kobject_add的作用是很直观的,在Sysfs中为这块磁盘建一个子目录,例如我们为的硬盘建立一个块设备驱动,则会在/sys/block/目录中看到一个sdf,要是把这个调用kobject_add函数这行注释掉,肯定就看不到这个sdf目录。这里有两个问题

 

第一为什么kobject_add这么一调用生成的这个子目录的名字就叫做sdf”,而不叫做别的呢其实在sd_probe中做过这么一件事情,通过精心计算得到disk_name而这个disk_name正是struct gendisk的一个成员这里我们看到482行我们把disk_name给了kobj.name这就是为什么我们调用kobject_add添加一个kobject的时候它的名字就是我们当时的disk_name

 

第二为什么生成的这个子目录是在/sys/block目录下面而不是在别的位置呢还记得在alloc_disk_node中我们申请struct gendisk的情景么kobj_set_kset_s(disk,block_subsys)做的就是让disk对应的kobject从属于block_subsys对应的kobject下面这就是为什么我们现在添加这个kobject的时候它很自然的就会在/sys/block子目录下面建立文件

 

继续走disk_sysfs_symlinks来自fs/partitions/check.c这个函数虽然不短但是比较浅显易懂。

 

static int disk_sysfs_symlinks(struct gendisk *disk){

         struct device *target = get_device(disk->driverfs_dev);

         int err;

         char *disk_name = NULL;

 

         if (target) {

                 disk_name = make_block_name(disk);

                 if (!disk_name) {

                         err = -ENOMEM;

                         goto err_out;

                 }

 

                 err = sysfs_create_link(&disk->kobj, &target->kobj, "device");

                 if (err)

                         goto err_out_disk_name;

 

                 err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name);

                 if (err)

                         goto err_out_dev_link;

         }

 

         err = sysfs_create_link(&disk->kobj, &block_subsys.kobj,

                                 "subsystem");

         if (err)

                 goto err_out_disk_name_lnk;

 

         kfree(disk_name);

 

         return 0;

 

err_out_disk_name_lnk:

         if (target) {

                 sysfs_remove_link(&target->kobj, disk_name);

err_out_dev_link:

                 sysfs_remove_link(&disk->kobj, "device");

err_out_disk_name:

                 kfree(disk_name);

err_out:

                 put_device(target);

         }

         return err;

}

 

我们用实际效果来解读这个函数。首先我们看正常工作的U盘会在/sys/block/sdf下面有哪些内容:

[root@localhost ~]# ls /sys/block/sdf/

capability  dev  device  holders  queue  range  removable  size  slaves  stat  subsystem  uevent

 

第一个sysfs_create_link创建的就是这里这个device这个软链接文件。我们来看它链接到哪里去了:

[root@localhost ~]# ls -l /sys/block/sdf/device

lrwxrwxrwx 1 root root 0 Dec 13 07:09

/sys/block/sdf/device

-> ../../devices/pci0000:00/0000:00:1d.7/usb4/4-4/4-4:1.0/host24/target24:0:0/24:0:0:0

 

第二个sysfs_create_link则从那边又建立一个反链接,又给链接回来了:

[root@localhost~]# ls -l ……

lrwxrwxrwx 1 root root 0 Dec 13 21:16

/sys/devices/pci0000:00/0000:00:1d.7/usb4/4-4/4-4:1.0/host24/target24:0:0/24:0:0:0/block:sdf -> ../../../../../../../../../block/sdf

 

于是这就等于你中有我我中有你,你那边有一个文件链接到了我这边,我这边有一个文件链接到了你那边。第三个sysfs_create_link,生成的是/sys/block/sdf/subsystem这个软链接文件。

[root@localhost ~]# ls -l /sys/block/sdf/subsystem

lrwxrwxrwx 1 root root 0 Dec 13 07:09 /sys/block/sdf/subsystem -> ../../block

 

三个链接文件建立好之后,disk_sysfs_symlinks也就结束了它的使命。接下来一个函数是disk_sysfs_add_subdirs。同样来自fs/partitions/check.c

 

static inline void disk_sysfs_add_subdirs(struct gendisk *disk){

         struct kobject *k;

 

         k = kobject_get(&disk->kobj);

         disk->holder_dir = kobject_add_dir(k, "holders");

         disk->slave_dir = kobject_add_dir(k, "slaves");

         kobject_put(k);

}

 

这个函数的意图太明显了,无非就是建立holdersslaves两个子目录。

 

504行接着调用一个内联函数,bdget_disk,《Thinking in C++》告诉我们内联函数最好定义在头文件中,所以这个函数来自include/linux/genhd.h

 

static inline struct block_device *bdget_disk(struct gendisk *disk, int index){

         return bdget(MKDEV(disk->major, disk->first_minor) + index);

}

 

bdget来自fs/block_dev.c

 

struct block_device *bdget(dev_t dev){

         struct block_device *bdev;

         struct inode *inode;

 

         inode = iget5_locked(bd_mnt->mnt_sb, hash(dev),

                         bdev_test, bdev_set, &dev);

 

         if (!inode)

                 return NULL;

 

         bdev = &BDEV_I(inode)->bdev;

 

         if (inode->i_state & I_NEW) {

                 bdev->bd_contains = NULL;

                 bdev->bd_inode = inode;

                 bdev->bd_block_size = (1 << inode->i_blkbits);

                 bdev->bd_part_count = 0;

                 bdev->bd_invalidated = 0;

                 inode->i_mode = S_IFBLK;

                 inode->i_rdev = dev;

                 inode->i_bdev = bdev;

                 inode->i_data.a_ops = &def_blk_aops;

                 mapping_set_gfp_mask(&inode->i_data, GFP_USER);

抱歉!评论已关闭.