zoukankan      html  css  js  c++  java
  • proc_create函数内幕初探

    一直以为PROC文件系统很是晦涩难懂,平时仅仅是使用它,不愿意去触碰内核中的具体实现。今天突发奇想,想看看里面究竟是怎么实现的,结果……真是大跌眼镜,没想到里面并不复杂

    关于PROC文件系统的功能以及在Linux中的地位就不多说了,在用户空间和内核空间交互的界面也扮演者举足轻重的地位。我们今天就从proc_create函数开始,看看其中的实现。该函数会创建一个PROC entry,用户可以通过对文件系统中的该文件,和内核进行数据的交互。

    static inline struct proc_dir_entry *proc_create(
        const char *name, umode_t mode, struct proc_dir_entry *parent,
        const struct file_operations *proc_fops)
    {
        return proc_create_data(name, mode, parent, proc_fops, NULL);
    }

    简要介绍下参数:

    name:名字

    mod:模式

    parent:父entry,为NULL的话,默认父entry是/proc

    struct proc_dir_entry proc_root = {
    .low_ino = PROC_ROOT_INO,
    .namelen = 5,
    .mode = S_IFDIR | S_IRUGO | S_IXUGO,
    .nlink = 2,
    .count = ATOMIC_INIT(1),
    .proc_iops = &proc_root_inode_operations,
    .proc_fops = &proc_root_operations,
    .parent = &proc_root,
    .name = "/proc",
    };

    proc_fops:操作函数表

    函数返回一个proc_dir_entry。可以看到proc_create中直接调用了proc_create_data,而该函数主要完成2个功能1、调用__proc_create完成具体proc_dir_entry的创建。2、调用proc_register把entry注册进系统。

    struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
                        struct proc_dir_entry *parent,
                        const struct file_operations *proc_fops,
                        void *data)
    {
        struct proc_dir_entry *pde;
        if ((mode & S_IFMT) == 0)
            mode |= S_IFREG;
    
        if (!S_ISREG(mode)) {
            WARN_ON(1);    /* use proc_mkdir() */
            return NULL;
        }
    
        if ((mode & S_IALLUGO) == 0)
            mode |= S_IRUGO;
        pde = __proc_create(&parent, name, mode, 1);
        if (!pde)
            goto out;
        pde->proc_fops = proc_fops;
        pde->data = data;
        if (proc_register(parent, pde) < 0)
            goto out_free;
        return pde;
    out_free:
        kfree(pde);
    out:
        return NULL;
    }

    先看proc_dir_entry的创建,这里通过__proc_create函数,其实该函数内部也很简单,就是为entry分配了空间,并对相关字段进行设置,主要包含name,namelen,mod,nlink等。创建好后,就设置操作函数proc_fops和data。然后就调用proc_register进行注册,

    static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
    {
        struct proc_dir_entry *tmp;
        int ret;
        
        ret = proc_alloc_inum(&dp->low_ino);
        if (ret)
            return ret;
         /*如果是 目录*/
        if (S_ISDIR(dp->mode)) {
            dp->proc_fops = &proc_dir_operations;
            dp->proc_iops = &proc_dir_inode_operations;
            dir->nlink++;
            /*如果是链接*/
        } else if (S_ISLNK(dp->mode)) {
            dp->proc_iops = &proc_link_inode_operations;
            /*如果是文件*/
        } else if (S_ISREG(dp->mode)) {
            BUG_ON(dp->proc_fops == NULL);
            dp->proc_iops = &proc_file_inode_operations;
        } else {
            WARN_ON(1);
            return -EINVAL;
        }
    
        spin_lock(&proc_subdir_lock);
    
        for (tmp = dir->subdir; tmp; tmp = tmp->next)
            if (strcmp(tmp->name, dp->name) == 0) {
                WARN(1, "proc_dir_entry '%s/%s' already registered
    ",
                    dir->name, dp->name);
                break;
            }
        /*子dir链接成链表,且子dir中含有父dir的指针*/
        dp->next = dir->subdir;
        dp->parent = dir;
        dir->subdir = dp;
        spin_unlock(&proc_subdir_lock);
    
        return 0;
    }

    函数首先分配一个inode number,然后根据entry的类型对其进行操作函数赋值,主要分为目录、链接、文件。这里我们只关注文件,文件的操作函数一般由用户自己定义,即上面我们设置的ops,这里仅仅是设置inode操作函数表,设置成了全局的proc_file_inode_operations,然后插入到父目录的子文件链表中,注意是头插法。基本结构如下,其中每个子节点都有指向父节点的指针。 

     其实创建entry的过程就这么简单,由于PROC也是一种文件系统,所以可以和ext2/ext3等文件系统一样,作为一个实体文件系统,通过VFS给用户提供统一的接口。相对于实体的文件系统而言,PROC文件系统要简单的多。因为其不需要管理具体磁盘上的文件,不需要和硬件打交道。正常情况下用户发起文件操作流程为:用户层序->系统调用->VFS层->具体文件系统->磁盘驱动程序。而针对PROC文件系统而言,其不需要和磁盘驱动打交道,最低层的部分就是操作系统各个子模块提供的操作函数表。这个就需要根据不同的模块进行不同的操作了,所以都是某个模块自己通过PROC的接口,向PROC注册内容,针对我们普通用户添加的entry,最低层的操作自然是我们注册的ops函数表了。

    以马内利

    参考资料:

    LInux内核3.10.1源码

  • 相关阅读:
    06 is和==的区别 encode()编码 decode()解码
    05 dic的增删改查 字典的嵌套 考试题dic.get()的相关使用
    03 编码 int ,bool,str的常用操作 主要讲str
    01 基本数据类型 变量 if语句
    04 列表的增删改查 常用方法 元祖 range
    02 while循环 格式化输出 运算符
    多校2 Harmonious Army hdu6598 网络流
    P3159 [CQOI2012]交换棋子 网络流
    P2172 [国家集训队]部落战争 最大流
    P2402 奶牛隐藏 网络流
  • 原文地址:https://www.cnblogs.com/ck1020/p/7475729.html
Copyright © 2011-2022 走看看