Chinaunix首页 | 论坛 | 博客
  • 博客访问: 232366
  • 博文数量: 27
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 213
  • 用 户 组: 普通用户
  • 注册时间: 2015-06-10 22:38
文章分类

全部博文(27)

文章存档

2016年(1)

2015年(26)

分类: LINUX

2015-06-24 23:33:38

本文所有内容基于linux v3.2.40。

  bdget_disk()是块设备操作中的常见函数,主要用于获取指定设备所对应的block_device,它的函数原型为:struct block_device *bdget_disk(struct gendisk *disk, int partno)。
  对块设备有些了解的都知道,gendisk是底层物理设备的一个抽象,比如一块硬盘在块设备驱动模型中就对应一个gendisk。gendisk又包括多个分区,每个分区有各自的分区号,分区号从数字1开始,数字0用于表示gendisk本身。
 因此,从bdget_disk()的参数列表可以看出来,该函数的实际作用为:返回第i个分区的block_device,如果i为0,返回整个设备gendisk的block_device。但其实这只是bdget_disk的一个作用,在它的内部实现中,还会有另外一个处理。
 先看一下函数实现:
    

 点击(此处)折叠或打开

  1. struct block_device *bdget_disk(struct gendisk *disk, int partno)
  2. {
  3.     struct hd_struct *part;
  4.     struct block_device *bdev = NULL;

  5.     part = disk_get_part(disk, partno); /* 找到目标分区 */
  6.     if (part) {
  7.         /* 根据分区的设备号找到对应的block_device */
  8.         bdev = bdget(part_devt(part));
  9.     }
  10.     disk_put_part(part); /* 减小引用计数 */

  11.     return bdev;
  12. }
  可以看到bdget_disk()主要靠bdget()完成,我们再追进去:
    

点击(此处)折叠或打开

  1. struct block_device *bdget(dev_t dev)
  2. {
  3.     struct block_device *bdev;
  4.     struct inode *inode;

  5.     /* 查找目标inode是否存在,如果不存在则创建并初始化
  6.      * !!!! 注意: 对于块设备而言,在创建inode的同时,会创建block_device
  7.      */
  8.     inode = iget5_locked(blockdev_superblock, hash(dev),
  9.             bdev_test, bdev_set, &dev);

  10.     if (!inode) {
  11.         return NULL;
  12.     }

  13.     /* inode与block_device被放在同一个结构体中,所以根据inode可快速找到bdev */
  14.     bdev = &BDEV_I(inode)->bdev;

  15.     /* 如果inode是新申请的,进行必要的初始化 */
  16.     if (inode->i_state & I_NEW) {
  17.         bdev->bd_contains = NULL;
  18.         bdev->bd_super = NULL;
  19.         bdev->bd_inode = inode;
  20.         bdev->bd_block_size = (1 << inode->i_blkbits);
  21.         bdev->bd_part_count = 0;
  22.         bdev->bd_invalidated = 0;
  23.         inode->i_mode = S_IFBLK;
  24.         inode->i_rdev = dev; //设置inode对应的设备号
  25.         inode->i_bdev = bdev; //关联inode与struct block_device
  26.         inode->i_data.a_ops = &def_blk_aops; /* 块设备的地址空间操作函数 */
  27.         mapping_set_gfp_mask(&inode->i_data, GFP_USER);
  28.         inode->i_data.backing_dev_info = &default_backing_dev_info;
  29.         spin_lock(&bdev_lock);
  30.         list_add(&bdev->bd_list, &all_bdevs);
  31.         spin_unlock(&bdev_lock);
  32.         unlock_new_inode(inode);
  33.     }
  34.     return bdev;
  35. }
  这里出现了一个新的结构inode,关于inode与block_device的关系,如果不是很清楚,可以参考我的另一篇博客(点这里)。
  大体浏览一下上面的代码也能看出端倪,inode并不一定是原来就存在的(也就是block_device不存在),如果不存在需要创建。
  我们知道,inode根据设备号在内核中维护了一个哈希表,在这里当我们将设备号传入iget5_locked()函数中后,会扫描该哈希表,如果没有找到inode,则会使用blockdev_superblock提供的alloc_inode函数申请一个inode节点,该节点为struct bdev_inode,是block_device和inode的结合:

点击(此处)折叠或打开

  1. struct bdev_inode {
  2.     struct block_device bdev;
  3.     struct inode vfs_inode;
  4. };
    也就是说,对于块设备而言,在创建inode的时候,就同时创建了block_device。inode创建完成后,会将新的inode添加到哈希表中。
    bdget()函数的第20行,会对返回的inode进行判断,如果是新创建的inode,进行一些必要的初始化。

    看到这里应该明白了,bdget_disk()函数实现两个功能:
    1) 创建block_device。
    2) 获取block_device。

    其实内核中有两处调用点分别对应以上两个功能:
    1) 块设备注册调用add_disk()时,会调用该函数为新的块设备创建对应的block_device。
    2) 打开块设备文件(open操作)时,会根据设备号查找目标设备对应的block_device。当然,这个时候可能需要直接调用bdget()。

    以上就是关于函数bdget_disk的解析,如有错误欢迎批评指正。

    




阅读(9394) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

夕阳下的孤影2015-09-10 20:53:00

maybe524:写得真好。希望能加你好友

可以一块学习linux内核,互相进步

回复 | 举报

maybe5242015-09-08 18:01:40

写得真好。希望能加你好友