linux block设备,Linux I/O Block–块设备的表示

块设备的分区信息由struct hd_struct结构描述,其中最重要的信息就是分区的起始扇区号和分区的大小。所有分区信息都一起保存在gendisk的part_tbl结构中,同时每个分区的block_device也可以通过bd_part来查询对应的分区信息。

下图描述了block_device,gendisk以及分区描述符之间的关系(块设备有两个分区)

8096a944bc1cb29166ce96c659985ea6.png

下面通过打开一个块设备的过程,来理解这些结构之间的联系。

对于块设备文件的操作,通过block_dev伪文件系统来完成,open操作定义的函数为blkdev_open()

blkdev_open的主要任务有两个

1.获取设备的block_device信息

2.从gendisk中读取相关信息保存到block_device,同时建立数据结构之间的联系

static int blkdev_open(struct inode * inode, struct file * filp)

{

struct block_device *bdev;

int res;

/*

* Preserve backwards compatibility and allow large file access

* even if userspace doesn't ask for it explicitly. Some mkfs

* binary needs it. We might want to drop this workaround

* during an unstable branch.

*/

filp->f_flags |= O_LARGEFILE;

if (filp->f_flags & O_NDELAY)

filp->f_mode |= FMODE_NDELAY;

if (filp->f_flags & O_EXCL)

filp->f_mode |= FMODE_EXCL;

if ((filp->f_flags & O_ACCMODE) == 3)

filp->f_mode |= FMODE_WRITE_IOCTL;

bdev = bd_acquire(inode);//获取block device实例

if (bdev == NULL)

return -ENOMEM;

filp->f_mapping = bdev->bd_inode->i_mapping;

res = blkdev_get(bdev, filp->f_mode);//通过gendisk获取信息并建立联系

if (res)

return res;

if (filp->f_mode & FMODE_EXCL) {

res = bd_claim(bdev, filp);

if (res)

goto out_blkdev_put;

}

return 0;

out_blkdev_put:

blkdev_put(bdev, filp->f_mode);

return res;

}

bd_acquire()负责获取block_device的实例

static struct block_device *bd_acquire(struct inode *inode)

{

struct block_device *bdev;

spin_lock(&bdev_lock);

bdev = inode->i_bdev;//如果这个设备之前被打开过则可以直接通过i_bdev获取

if (bdev) {

atomic_inc(&bdev->bd_inode->i_count);

spin_unlock(&bdev_lock);

return bdev;

}

spin_unlock(&bdev_lock);

bdev = bdget(inode->i_rdev);//通过设备号的信息来获取block device实例

if (bdev) {

spin_lock(&bdev_lock);

if (!inode->i_bdev) {

/*

* We take an additional bd_inode->i_count for inode,

* and it's released in clear_inode() of inode.

* So, we can access it via ->i_mapping always

* without igrab().

*/

atomic_inc(&bdev->bd_inode->i_count);

inode->i_bdev = bdev;

inode->i_mapping = bdev->bd_inode->i_mapping;

list_add(&inode->i_devices, &bdev->bd_inodes);

}

spin_unlock(&bdev_lock);

}

return bdev;

}

——————————-分割线——————————-

struct block_device *bdget(dev_t dev)

{

struct block_device *bdev;

struct inode *inode;

/*这里先在inode的哈希表中进行查找与dev设备号对应的inode,如果没找到的话,

则通过bdev伪文件系统创建bdev_inode(包含inode和block device的结构体)*/

inode = iget5_locked(blockdev_superblock, hash(dev),

bdev_test, bdev_set, &dev);

if (!inode)

return NULL;

//通过inode获取bdev_inode,再通过bdev_inode获取block device实例

bdev = &BDEV_I(inode)->bdev;

if (inode->i_state & I_NEW) {

/*分别设置block device和inode的相关域*/

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);

inode->i_data.backing_dev_info = &default_backing_dev_info;

spin_lock(&bdev_lock);

list_add(&bdev->bd_list, &all_bdevs);

spin_unlock(&bdev_lock);

unlock_new_inode(inode);

}

return bdev;

}0b1331709591d260c1c78e86d0c51c18.png

Published by

风君子

独自遨游何稽首 揭天掀地慰生平