zoukankan      html  css  js  c++  java
  • 字符设备文件的打开

    打开字符设备文件,还是通过 sys_open() 系统调用。在经过一连串的调用后,nameidata_to_filp, 内核会走到 __dentry_open() 函数。在这个函数中,执行了以下代码片段:

        f->f_mapping = inode->i_mapping;
        f->f_path.dentry = dentry;
        f->f_path.mnt = mnt;
        f->f_pos = 0;
        f->f_op = fops_get(inode->i_fop);
        file_move(f, &inode->i_sb->s_files);
    
        error = security_dentry_open(f, cred);
        if (error)
            goto cleanup_all;
    
        if (!open && f->f_op)
            open = f->f_op->open;
        if (open) {
            error = open(inode, f);
            if (error)
                goto cleanup_all;
        }
        ima_counts_get(f);

    其中重要的三行:

    f->f_op = fops_get(inode->i_fop);
    open = f->f_op->open;
    error = open(inode, f); 

    其中,f 是 struct file 型的指针,open 是一个函数指针。所以这三行代码主要做了两件事:
    1. 给 struct file 型变量的 f_op 字段赋值;
    2. 调用 f_op->open() 函数。这里需要说明的是,f_op 字段的值是从 inode->i_fop 中得来的,那 inode->i_fop 的值又是怎么来的呢?对于一个设备文件来说,它的 inode->i_fop 的值是在 mknod() 时由内核根据设备文件的类型默认指定的。对应字符设备文件,i_fop 就指向 def_chr_fops 这个 struct file_operations 型变量。
    def_chr_fops 定义在 fs/char_dev.c 文件中:

    const struct file_operations def_chr_fops = {
        .open = chrdev_open,
    }; 

    哈,这个 file_operations 真偷懒,就定义了一个 open 方法。

    下面看一下 chrdev_open() 函数的实现,它是所有字符设备文件的最初通用的 open 方法。

    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 节点中取出 cdev 结构的指针(如果 inode 是第一次打开的话,则通过 kobj_lookup() 根据设备号从 cdev_map 中找出 cdev,并保存在 inode->i_cdev 中)。然后用  cdev->ops 替换 file->f_op 从而使用字符设备驱动自己提供的 file_operations。最后,调用字符设备驱动提供的 open 方法。

  • 相关阅读:
    /etc/vim/vimrc的一个的配置
    vim上下左右键输出A B
    数据结构-栈的实现之行编译器核心实现
    数据结构-栈的实现之括号匹配检测
    数据结构-栈的实现之数制转换
    数据结构-线性表的链式结构
    数据结构-栈的顺序结构两种方式
    简介
    数据结构-线性表的顺序结构
    NHibernate系列文章十六:使用程序集管理NHibernate项目(附程序下载)
  • 原文地址:https://www.cnblogs.com/codestub/p/filesystem.html
Copyright © 2011-2022 走看看