Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1875839
  • 博文数量: 184
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2388
  • 用 户 组: 普通用户
  • 注册时间: 2016-12-21 22:26
个人简介

90后空巢老码农

文章分类

全部博文(184)

文章存档

2021年(26)

2020年(56)

2019年(54)

2018年(47)

2017年(1)

我的朋友

分类: LINUX

2020-10-26 19:43:08

在具体开讲今天的内容之前,由于块设备比字符设备稍显复杂,需要先把一些情况交代清楚:
1. 一个块设备使用一个struct gendisk表示(设备号与该结构存储在bdev_map当中,关于该块设备的整体操作都在这个结构里面表示),里面有对应的分区信息

点击(此处)折叠或打开

  1. struct gendisk {
  2.     /* major, first_minor and minors are input parameters only,
  3.      * don't use directly. Use disk_devt() and disk_max_parts().
  4.      */
  5.     int major;            /* major number of driver */
  6.     int first_minor;
  7.     int minors; /* maximum number of minors, =1 for
  8.                                          * disks that can't be partitioned. */

  9.     char disk_name[DISK_NAME_LEN];    /* name of major driver */

  10.     unsigned short events;        /* supported events */
  11.     unsigned short event_flags;    /* flags related to event processing */

  12.     /* Array of pointers to partitions indexed by partno.
  13.      * Protected with matching bdev lock but stat and other
  14.      * non-critical accesses use RCU. Always access through
  15.      * helpers.
  16.      */
  17.     struct disk_part_tbl __rcu *part_tbl;
  18.     struct hd_struct part0;// 整个块设备占用0号分区

  19.     const struct block_device_operations *fops;
  20.     struct request_queue *queue;
  21.     void *private_data;

  22.     int flags;
  23.     struct rw_semaphore lookup_sem;
  24.     struct kobject *slave_dir;

  25.     struct timer_rand_state *random;
  26.     atomic_t sync_io;        /* RAID */
  27.     struct disk_events *ev;
  28. #ifdef CONFIG_BLK_DEV_INTEGRITY
  29.     struct kobject integrity_kobj;
  30. #endif    /* CONFIG_BLK_DEV_INTEGRITY */
  31.     int node_id;
  32.     struct badblocks *bb;
  33.     struct lockdep_map lockdep_map;
  34. };

2. 一个块设备的每一个被打开分区,会对应一个struct block_device结构:

点击(此处)折叠或打开

  1. struct block_device {
  2.     dev_t            bd_dev; /* not a kdev_t - it's a search key */
  3.     int            bd_openers;
  4.     struct inode *        bd_inode;    /* will die */
  5.     struct super_block *    bd_super;
  6.     struct mutex        bd_mutex;    /* open/close mutex */
  7.     void *            bd_claiming;
  8.     void *            bd_holder;
  9.     int            bd_holders;
  10.     bool            bd_write_holder;
  11. #ifdef CONFIG_SYSFS
  12.     struct list_head    bd_holder_disks;
  13. #endif
  14.     struct block_device *    bd_contains;// 如果当前的block_device代表的是分区,则这个指向gendisk对应的block_device实例
  15.     unsigned        bd_block_size;
  16.     u8            bd_partno;
  17.     struct hd_struct *    bd_part;// gendisk当中对应的分区
  18.     /* number of times partitions within this device have been opened. */
  19.     unsigned        bd_part_count;
  20.     int            bd_invalidated;
  21.     struct gendisk *    bd_disk;// 整个gendisk
  22.     struct request_queue * bd_queue;
  23.     struct backing_dev_info *bd_bdi;
  24.     struct list_head    bd_list;
  25.     /*
  26.      * Private data. You must have bd_claim'ed the block_device
  27.      * to use this. NOTE: bd_claim allows an owner to claim
  28.      * the same device multiple times, the owner must take special
  29.      * care to not mess up bd_private for that case.
  30.      */
  31.     unsigned long        bd_private;

  32.     /* The counter of freeze processes */
  33.     int            bd_fsfreeze_count;
  34.     /* Mutex for freeze */
  35.     struct mutex        bd_fsfreeze_mutex;
  36. } __randomize_layout;
3. 每一个分区(包含整个块设备)都包含在一个伪文件系统bdev当中,这个文件系统对用户来说是透明的,这个伪文件系统的inode结构如下:

点击(此处)折叠或打开

  1. struct bdev_inode {
  2.     struct block_device bdev;
  3.     struct inode vfs_inode;
  4. };
关于这个伪文件系统的bdev_inode之前纠结了好久怎么解释,直到这篇文章发送出来之后,才想出个大概(如果错了,后续会填坑),由于是个文件系统,需要对应的inode的所有操作,没必要再实现一次,直接用现成的struct inode 即可,对应的块设备操作操纵struct block_device 即可,这俩是一一对应的关系,封装一起更便于管理(---->struct bdev_inode)

好了,基本交代清楚,接下来就按照打开字符设备的顺序开讲打开块设备的顺序
1. 在init_special_inode函数当中,如果是字符设备,默认i_fop设置的是def_chr_fops;如果是块设备,就是def_blk_fops了,代码如下:

点击(此处)折叠或打开

  1. void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
  2. {
  3.     inode->i_mode = mode;
  4.     if (S_ISCHR(mode)) {
  5.         inode->i_fop = &def_chr_fops;
  6.         inode->i_rdev = rdev;
  7.     } else if (S_ISBLK(mode)) {
  8.         inode->i_fop = &def_blk_fops;
  9.         inode->i_rdev = rdev;
  10.     } else if (S_ISFIFO(mode))
  11.         inode->i_fop = &pipefifo_fops;
  12.     else if (S_ISSOCK(mode))
  13.         ;    /* leave it no_open_fops */
  14.     else
  15.         printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
  16.                  " inode %s:%lu\n", mode, inode->i_sb->s_id,
  17.                  inode->i_ino);
  18. }
这样,在open的时候,调用的就是blkdev_open了:

点击(此处)折叠或打开

  1. const struct file_operations def_blk_fops = {
  2.     .open        = blkdev_open,
  3.     .release    = blkdev_close,
  4.     .llseek        = block_llseek,
  5.     .read_iter    = blkdev_read_iter,
  6.     .write_iter    = blkdev_write_iter,
  7.     .iopoll        = blkdev_iopoll,
  8.     .mmap        = generic_file_mmap,
  9.     .fsync        = blkdev_fsync,
  10.     .unlocked_ioctl    = block_ioctl,
  11. #ifdef CONFIG_COMPAT
  12.     .compat_ioctl    = compat_blkdev_ioctl,
  13. #endif
  14.     .splice_read    = generic_file_splice_read,
  15.     .splice_write    = iter_file_splice_write,
  16.     .fallocate    = blkdev_fallocate,
  17. };

点击(此处)折叠或打开

  1. static int blkdev_open(struct inode * inode, struct file * filp)
  2. {
  3.     struct block_device *bdev;

  4.     /*
  5.      * Preserve backwards compatibility and allow large file access
  6.      * even if userspace doesn't ask for it explicitly. Some mkfs
  7.      * binary needs it. We might want to drop this workaround
  8.      * during an unstable branch.
  9.      */
  10.     filp->f_flags |= O_LARGEFILE;

  11.     filp->f_mode |= FMODE_NOWAIT;

  12.     if (filp->f_flags & O_NDELAY)
  13.         filp->f_mode |= FMODE_NDELAY;
  14.     if (filp->f_flags & O_EXCL)
  15.         filp->f_mode |= FMODE_EXCL;
  16.     if ((filp->f_flags & O_ACCMODE) == 3)
  17.         filp->f_mode |= FMODE_WRITE_IOCTL;

  18.     bdev = bd_acquire(inode);// 这里的inode是/dev/xxx的inode
  19.     if (bdev == NULL)
  20.         return -ENOMEM;

  21.     filp->f_mapping = bdev->bd_inode->i_mapping;
  22.     filp->f_wb_err = filemap_sample_wb_err(filp->f_mapping);

  23.     return blkdev_get(bdev, filp->f_mode, filp);
  24. }
在这里我们看到,blkdev_open 先是通过bd_acquire来根据当前/dev/下的相关inode,来找到对应的block_device结构,这里的具体实现就是根据设备号找到对应的bdev_inode里面的vfs_inode(这一步调用链是bd_acquire->bd_get,bd_get这会涉及到inode缓存,即在一个已装载的文件系统中,根据超级块和inode号[这里是设备号]hash存储了对应inode的相关信息),再通过container_of直接找到bdev_inode->block_device 找到block_device,找到实例之后,就是向字符设备一样的各种设置inode相关的东西了,只不过这里设置的是inode->ibdev而非inode->i_cdev而以,其余的file_operations就类似了

点击(此处)折叠或打开

  1. struct block_device *bdget(dev_t dev)// /dev/xxx 下inode对应的设备号
  2. {
  3.     struct block_device *bdev;
  4.     struct inode *inode;
  5.     // 这里找到的inode 就是bdev_inode里面的vfs_inode
  6.     inode = iget5_locked(blockdev_superblock, hash(dev),
  7.             bdev_test, bdev_set, &dev);

  8.     if (!inode)
  9.         return NULL;
  10.     // container_of(inode, struct bdev_inode, vfs_inode)
  11.     bdev = &BDEV_I(inode)->bdev;

  12.     if (inode->i_state & I_NEW) {
  13.         bdev->bd_contains = NULL;
  14.         bdev->bd_super = NULL;
  15.         bdev->bd_inode = inode;
  16.         bdev->bd_block_size = i_blocksize(inode);
  17.         bdev->bd_part_count = 0;
  18.         bdev->bd_invalidated = 0;
  19.         inode->i_mode = S_IFBLK;
  20.         inode->i_rdev = dev;
  21.         inode->i_bdev = bdev;
  22.         inode->i_data.a_ops = &def_blk_aops;
  23.         mapping_set_gfp_mask(&inode->i_data, GFP_USER);
  24.         spin_lock(&bdev_lock);
  25.         list_add(&bdev->bd_list, &all_bdevs);
  26.         spin_unlock(&bdev_lock);
  27.         unlock_new_inode(inode);
  28.     }
  29.     return bdev;
  30. }




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