proc源码解析(五)--proc的管理函数(转自若木)

proc目录是系统模拟出来的一个文件系统,本身并不存在于磁盘上,其中的文件都表示内核参数的信息,这些信息分两类,一类是可都可写的,这 类参数都在“/proc/sys”目录下,另一类是只读的,就是“/proc/sys”目录之外的其他目录和文件,当然这只是一种惯例,实际在其他目录下建立可读写的/proc文件也是可以的。
    Linux内核在2.4以后/proc目录文件的建立已经变得很容易,以前版本都还需要构造文件操作结构来实现,现在只需要调用简单函数就可以了。Linux提供了一系列的创建函数

创建一个 proc 文件 
根据对 proc 文件的不同使用,内核提供了多种包装函数来创建一个 proc 文件。

方法一: 
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent)
这是最直接,包装最少的创建方法。
参数 name 是要创建的 proc 文件名。mode 是该文件权限值,例如 S_IRUGO,可传入0表示采用系统默认值。parent 指定该文件的上层 proc 目录项,如果为 NULL,表示创建在 /proc 根目录下。
create_proc_entry() 完成的任务主要包括:检测 mode 值,分配 proc_dir_entry 结构,注册 proc_dir_entry。其定义如下:


struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
                     struct proc_dir_entry *parent)
{
    struct proc_dir_entry *ent;
    nlink_t nlink;
    /* 要创建的项是目录,设置其mode */
    if (S_ISDIR(mode)) {
        if ((mode & S_IALLUGO) == 0)
            mode |= S_IRUGO | S_IXUGO;
        nlink = 2;
    } else { //非目录
        if ((mode & S_IFMT) == 0)
            mode |= S_IFREG;
        if ((mode & S_IALLUGO) == 0)
            mode |= S_IRUGO;
        nlink = 1;
    }
    /* 注意此处:这是create_proc_entry的主要实现函数,该函数也可以用来单独创
     * 建一个目录项,二者区别就在于create_proc_entry函数调用下边的
     * proc_register函数注册了proc_dir_entry,也就是使用默认的    
    * proc_file_operations。  */
    ent = proc_create(&parent,name,mode,nlink);
    if (ent) {
        if (proc_register(parent, ent) < 0) {
            kfree(ent);
            ent = NULL;
        }
    }
    return ent;
}


方法二:


static inline struct proc_dir_entry *create_proc_read_entry(const char *name,
    mode_t mode, struct proc_dir_entry *base, 
    read_proc_t *read_proc, void * data)
{
    struct proc_dir_entry *res=create_proc_entry(name,mode,base);
    if (res) {
        res->read_proc=read_proc;
        res->data=data;
    }
    return res;

}


    如果要创建一个只读的 proc 文件,可以采用 create_proc_read_entry() 这个接口。这个接口其实就是给 proc_dir_entry 多赋了两个值,其中 read_proc 是一个函数指针, data 是 read_proc 调用时传给它一个参数。关于 read_proc 函数,接下来会另行分析。
方法三: 
static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent  const char *name, mode_t mode, nlink_t nlink)
    如果要创建一个 proc 文件,并且不用 proc_fs 默认提供的 file_operations 的话,可以使用 proc_create() 这个函数。
    每个 proc 文件也都会用到 file_operations,在调用 create_proc_entry() 创建 proc 文件时,其中一步是调用 proc_register(),proc_register() 会为 proc_dir_entry 提供一个默认的 file_operations,而 proc_create() 与 create_proc_entry() 唯一差别就是不用调用proc_register(),这样在 proc_register() 时就不会设置使用 proc_fs 默认的 file_operations 了。
proc_fs 默认的 file_operations 定义如下:


static const struct file_operations proc_file_operations = {
    .llseek = proc_file_lseek,
    .read     = proc_file_read,
    .write     = proc_file_write,
};


关于这个 proc_file_operations,后面会继续讲到。
proc_create() 一般在创建使用 seq_file 接口的 proc 文件时会使用。

创建一个 proc 目录 
    创建一个 proc 目录就调用 struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent) 这个函数。参数name 是目录名,parent 是该目录的上层 proc 目录项,如果为 NULL,表示创建在 /proc 根目录下。

删除一个 proc 项
 
    要删除一个 proc 文件或目录就调用
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)

注意事项 
    proc 项创建时要避免已经存在同名的 proc 项,否则注册时内核会报错(但还是会成功返回那个 proc 项),在删除时有时会删不掉(尤其是 proc 目录)。删除一个 proc 目录会把这个目录所有的 proc 文件都删除。

读 proc 文件 
    proc 文件的读需要自己提供一个 read_proc_t 类型的函数放在 proc_dir_entry 结构中供 proc_file_read() 函数调用。下面是 read_proc_t 类型函数的定义:
typedef int (read_proc_t)(char *page, char **start, off_t off, int count,
                               int *eof, void *data);
 这个函数的定义很复杂,不过当 proc 文件返回的数据量总是小于一个 PAGE_SIZE 时可以简化使用。关于这个函数以及它的那一大串参数我觉得再怎么解释都解释不全,所以还是留给自己去看 proc_file_read() 的代码就明白了。

写 proc 文件 
 proc 文件的写很简单。write_proc_t 类型函数的定义如下:
typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data);

注册目录项 
    前边说过要使用默认的proc_file_operations,就要注册目录项,也就是create_proc_entry函数中调用的proc_register()函数,该函数的实现主要有三部分:
1.调用get_inode_number函数生成一个唯一的inode号
2.根据不同的目录项类型,初始化不同的文件操作函数集。
3.设置next与parent,使目录项并入目录树中
其定义如下:


static int proc_register(struct proc_dir_entry* dir, struct proc_dir_entry * dp)
{
    unsigned int i;
    //生成唯一的inode号
    i = get_inode_number();
    if (i == 0)
        return -EAGAIN;
    dp->low_ino = i;
    //设置合适的文件操作函数
    if (S_ISDIR(dp->mode)) {
        if (dp->proc_iops == NULL) {
            dp->proc_fops = &proc_dir_operations;
            dp->proc_iops = &proc_dir_inode_operations;
        }
        dir->nlink++;
    } else if (S_ISLNK(dp->mode)) {
        if (dp->proc_iops == NULL)
            dp->proc_iops = &proc_link_inode_operations;
    } else if (S_ISREG(dp->mode)) {
        if (dp->proc_fops == NULL)
            dp->proc_fops = &proc_file_operations;
        if (dp->proc_iops == NULL)
            dp->proc_iops = &proc_file_inode_operations;
    }
    //将目录项合并到proc目录树中
    spin_lock(&proc_subdir_lock);
    dp->next = dir->subdir;
    dp->parent = dir;
    dir->subdir = dp;
    spin_unlock(&proc_subdir_lock);

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值