一切皆文件之块设备驱动(二)

打开块设备

mknod

块设备同样要使用mknod创建设备节点,这与字符设备一样。会调用到init_special_inode填充inode的file_operations,只不过块设备注册的是def_blk_fops。

void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{
    inode->i_mode = mode;
    if (S_ISCHR(mode)) {
        inode->i_fop = &def_chr_fops;
        inode->i_rdev = rdev;
    } else if (S_ISBLK(mode)) {
        inode->i_fop = &def_blk_fops;
        inode->i_rdev = rdev;
    } else if (S_ISFIFO(mode))
        inode->i_fop = &pipefifo_fops;
    else if (S_ISSOCK(mode))
        ;   /* leave it no_open_fops */
    else
        printk(KERN_DEBUG "init_special_inode: bogus i_mode (
                  " inode 
                  inode->i_ino);
}

def_blk_fops如下,与字符设备一样,当打开块设备时,就会调用到blk_dev_open。

const struct file_operations def_blk_fops = {
    .open       = blkdev_open,
    .release    = blkdev_close,
    .llseek     = blkdev_llseek,
    .read_iter  = blkdev_read_iter,
    .write_iter = blkdev_write_iter,
    .iopoll     = blkdev_iopoll,
    .mmap       = generic_file_mmap,
    .fsync      = blkdev_fsync,
    .unlocked_ioctl = block_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl   = compat_blkdev_ioctl,
#endif
    .splice_read    = generic_file_splice_read,
    .splice_write   = iter_file_splice_write,
    .fallocate  = blkdev_fallocate,
}

blk_dev_open

blk_dev_open里面关键的操作时调用blkdev_get获取到块设备,并赋值file中f_mapping。

static int blkdev_open(struct inode *inode, struct file *filp)
{
    struct block_device *bdev;
    ......
    bdev = blkdev_get_by_dev(inode->i_rdev, filp->f_mode, filp);
    if (IS_ERR(bdev))
        return PTR_ERR(bdev);
    filp->f_mapping = bdev->bd_inode->i_mapping;
filp->f_wb_err = filemap_sample_wb_err(filp->f_mapping);
    return 0;
}

bdev文件系统

blk_dev_open调用blkdev_get_by_dev获取到块设备得bdev,获取块设备是通过bdev文件系统来查询获取,下面先来了解下bdev文件系统的注册过程。

bdev是系统注册是在系统启动初始化阶段调用bdev_cache_init注册的,每个块设备在bdev文件系统中都有一个inode,linux利用block_inode数据结构将inode和block_device进行关联起来,对设备block_device的查找转化为在bdev文件系统中对inode的查找。