• 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源码

  • 相关阅读:
    elemenui数据表格加入计数器和输入框
    递归求阶乘
    递归累和
    递归
    file类
    Object类
    首页背景图
    异常的处理
    数据结构有什么用?常见的数据结构有什么?
    线程、并发、并行、进程是什么,以及如何开启新的线程?
  • 原文地址:https://www.cnblogs.com/ck1020/p/7475729.html
Copyright © 2020-2023  润新知