linux一切设备皆文件的实现(一)

fs/inode.c
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 = &def_fifo_fops;
    else if (S_ISSOCK(mode))
        inode->i_fop = &bad_sock_fops;
    else
        printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
                  " inode %s:%lu\n", mode, inode->i_sb->s_id,
                  inode->i_ino);
}

通过inode中mode获取文件的类型
对于字符设备 ,对应结构struct cdev , const struct file_operations *ops 对应操作方法,   fs/char_dev.c
static int chrdev_open(struct inode *inode, struct file *filp)
{
    struct cdev *p;
    struct cdev *new = NULL;
    int ret = 0;

    spin_lock(&cdev_lock);
    p = inode-> i_cdev;
    if (!p) {
        struct kobject *kobj;
        int idx;
        spin_unlock(&cdev_lock);
        kobj = kobj_lookup(cdev_map, inode-> i_rdev, &idx);
        if (!kobj)
            return -ENXIO;
         new = container_of(kobj, struct cdev, kobj);
        spin_lock(&cdev_lock);
        /* Check i_cdev again in case somebody beat us to it while
           we dropped the lock. */
        p = inode->i_cdev;
        if (!p) {
            inode->i_cdev = p = new;
            list_add(&inode->i_devices, &p->list);
            new = NULL;
        } else if (!cdev_get(p))
            ret = -ENXIO;
    } else if (!cdev_get(p))
        ret = -ENXIO;
    spin_unlock(&cdev_lock);
    cdev_put(new);
    if (ret)
        return ret;

    ret = -ENXIO;
    filp-> f_op = fops_get(p->ops);
    if (!filp->f_op)
        goto out_cdev_put;

    if (filp->f_op->open) {
        ret = filp->f_op->open(inode, filp);
        if (ret)
            goto out_cdev_put;
    }

    return 0;

out_cdev_put:
    cdev_put(p);
    return ret;
}

inode中的 i_rdev记录了设备号,通过 i_rdev找到kobj,然后得到 struct cdev,而这个过程是在cdev_add中完成struct cdev和设备号之间的映射的。

对于块设备, 对应结构struct block_device,    const struct block_device_operations *fops对应操作方法, fs/block_dev.c:
static int blkdev_open(struct inode * inode, struct file * filp)
{
    struct block_device *bdev;

    /*
     * 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);
    if (bdev == NULL)
        return -ENOMEM;

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

    return blkdev_get(bdev, filp->f_mode, filp);
}

static struct block_device *bd_acquire(struct inode *inode)
{
    struct block_device *bdev;

    spin_lock(&bdev_lock);
    bdev = inode-> i_bdev;
    if (bdev) {
        ihold(bdev->bd_inode);
        spin_unlock(&bdev_lock);
        return bdev;
    }
    spin_unlock(&bdev_lock);

    bdev = bdget(inode-> i_rdev);  //通过设备号找到struct block_device
    if (bdev) {
        spin_lock(&bdev_lock);
        if (!inode->i_bdev) {
            /*
             * We take an additional reference to bd_inode,
             * and it's released in clear_inode() of inode.
             * So, we can access it via ->i_mapping always
             * without igrab().
             */
            ihold(bdev->bd_inode);
            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代表一个块设备
struct block_device *bdget(dev_t dev)
{
    struct block_device *bdev;
    struct inode *inode;

    inode = iget5_locked(blockdev_superblock, hash(dev),
            bdev_test, bdev_set, &dev);

    if (!inode)
        return NULL;

    bdev = &BDEV_I(inode)->bdev;

    ...
}
int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
{
    ...
    res = __blkdev_get(bdev, mode, 0);
    ...
}
static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
{
    ...
    disk = get_gendisk(bdev->bd_dev, &partno);
    ...
    ret = disk->fops->open(bdev, mode);
    ...
}

struct gendisk *get_gendisk(dev_t devt, int *partno)
{
    struct gendisk *disk = NULL;

    if (MAJOR(devt) != BLOCK_EXT_MAJOR) {
        struct kobject *kobj;

        kobj = kobj_lookup(bdev_map, devt, partno);
        if (kobj)
            disk = dev_to_disk(kobj_to_dev(kobj));
    } else {
        struct hd_struct *part;

        mutex_lock(&ext_devt_mutex);
        part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
        if (part && get_disk(part_to_disk(part))) {
            *partno = part->partno;
            disk = part_to_disk(part);
        }
        mutex_unlock(&ext_devt_mutex);
    }

    return disk;
}



  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值