linux 内核 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\n",
                 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函数表了。

 

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`nfs3_proc_create` 函数Linux 内核中用于处理 NFSv3 协议的 `CREATE` 操作的函数。它负责在 NFS 服务器上创建一个新文件。 以下是 `nfs3_proc_create` 函数的大致流程: 1. 首先,函数会检查所传递的参数的有效性,例如文件名、父目录的文件句柄等。 2. 接下来,函数会创建一个新的 RPC 请求,并设置相关的请求参数,包括操作类型(CREATE)、文件名、父目录的文件句柄等。 3. 然后,函数会调用 `nfs3_rpc_ops` 结构中的 `create` 函数指针,将 RPC 请求发送到 NFS 服务器。 4. 在 `create` 函数中,会构建一个 RPC 消息(NFSv3 CREATE 请求),并将请求的参数填充到消息中。 5. 函数会调用 `nfs3_proc_xdr_encode` 函数来将请求消息进行编码,并将编码后的数据发送给 NFS 服务器。 6. 当服务器接收到请求后,会执行相应的操作来创建新文件,并将操作结果返回给客户端。 7. 客户端接收到服务器的响应后,会调用 `nfs3_proc_xdr_decode` 函数来解码响应消息。 8. 解码后的响应数据会被提取出来,并根据操作结果进行处理。如果创建操作成功,则会返回新文件的属性信息;否则,会返回相应的错误码。 9. 最后,函数会清理请求相关的数据结构,并返回操作结果给调用者。 需要注意的是,上述流程仅为大致过程,具体的实现细节可能因内核版本和配置而有所不同。详细的函数流程可以查看相应内核版本的源代码文件(例如 `fs/nfs/nfs3proc.c`)来进行分析和了解。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值