内核模块从3.1迁移至3.18:proc_dir_entry使用问题咨询
正确使用
struct proc_dir_entry 在内核3.18版本的方式 首先得明确:fs/proc/internal.h 是内核内部的头文件,绝对不应该在外部模块中引用——它只供proc文件系统自身的代码使用,对外没有稳定性承诺,所以你引用它会提示文件不存在是完全正常的(内核编译环境不会把内部头文件暴露给模块开发者)。
从3.10版本开始,struct proc_dir_entry 被改为不透明类型(opaque type),目的是隐藏内部实现细节,强制开发者使用内核提供的标准API来操作proc目录项,避免模块依赖于内核内部结构体的具体布局(这会导致模块在内核版本升级时极易崩溃)。
下面是3.18版本下操作proc_dir_entry的正确姿势:
1. 创建proc目录/文件的标准API
原来你可能会手动初始化proc_dir_entry结构体,现在必须用这些内核提供的创建函数:
- 创建proc目录:
struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent) - 创建普通proc文件:
struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops) - 创建带私有数据的proc文件:
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) - 创建自动清理的临时proc文件:
struct proc_dir_entry *proc_create_temp(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops, void (*release)(struct proc_dir_entry *), void *data)
2. 设置/获取proc项属性的辅助函数
原来直接访问proc_dir_entry成员(比如->owner、->data)的操作,现在要用对应的内核辅助函数:
- 设置owner:推荐在创建时通过
file_operations的owner字段指定当前模块(THIS_MODULE),也可以用proc_set_user(struct proc_dir_entry *pde, const struct cred *cred)调整权限 - 获取私有数据:
void *proc_get_data(struct proc_dir_entry *pde) - 设置私有数据:
void proc_set_data(struct proc_dir_entry *pde, void *data, void (*release)(void *)) - 调整权限:创建时通过
proc_create的mode参数指定即可,后续修改尽量避免,若确有需求可使用内核标准的权限修改函数
3. 删除proc目录/文件的正确方式
不再手动释放结构体,而是调用专用删除函数:
- 删除proc项(文件或目录):
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
注意:如果是用
proc_create_data创建并设置了release函数,删除时会自动调用该函数释放私有数据。
示例代码片段
比如创建一个支持读写的proc文件:
#include <linux/module.h> #include <linux/proc_fs.h> #include <linux/uaccess.h> static char proc_buf[256]; static ssize_t proc_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { return simple_read_from_buffer(buf, count, pos, proc_buf, strlen(proc_buf)); } static ssize_t proc_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { if (count >= sizeof(proc_buf)) return -EINVAL; if (copy_from_user(proc_buf, buf, count)) return -EFAULT; proc_buf[count] = '\0'; return count; } static const struct file_operations proc_fops = { .owner = THIS_MODULE, .read = proc_read, .write = proc_write, }; static struct proc_dir_entry *my_proc_entry; static int __init my_module_init(void) { // 在/proc根目录下创建名为"my_proc"的文件 my_proc_entry = proc_create("my_proc", 0644, NULL, &proc_fops); if (!my_proc_entry) return -ENOMEM; return 0; } static void __exit my_module_exit(void) { remove_proc_entry("my_proc", NULL); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL");
关键注意事项
- 绝对不要尝试直接包含
internal.h或者手动解析proc_dir_entry的内部结构——这不仅违反内核开发规范,还会导致你的模块在不同内核版本(甚至同版本的不同配置)下崩溃。 - 所有操作都要依赖内核公开的
proc_fs.h中的API,这些API在稳定版本分支中是向后兼容的。 - 如果需要实现动态生成内容的proc文件(比如遍历系统状态),可以结合
seq_file接口使用,它同样通过proc_create挂载到proc文件系统中。
内容的提问来源于stack exchange,提问作者FirmwareRootkits
相关产品推荐
相关产品推荐

