Linux4.19内核集成proc_entry后filp_open报错无法启动问题求解
问题根因
你的实现从方案设计到上下文使用都存在明显错误,直接导致内核启动失败:
- 上下文非法:
update_curr是调度器核心路径函数,运行时持有运行队列自旋锁,处于原子上下文,不能调用任何可能阻塞的函数。filp_open内部涉及VFS路径遍历、内存分配、锁抢占,属于典型的可能阻塞函数,在原子上下文调用必然触发死锁,前几次报错是因为proc文件系统尚未挂载、你的自定义节点还未创建,后续直接卡死就是触发了原子上下文睡眠的异常。 - 方案逻辑错误:proc本身是内核向用户空间暴露的接口,内核侧完全不需要通过文件API读取自己创建的proc节点数据,绕一大圈调用VFS接口属于完全冗余的错误设计。
正确实现方案
你只需要维护一个内核全局变量存储阈值,proc节点仅作为用户空间读写这个变量的接口,内核侧直接访问变量即可,完全避免文件操作:
步骤1:定义阈值变量与访问接口
在调度器相关代码(比如kernel/sched/fair.c)中添加阈值变量和保护锁:
// 默认阈值设为100 static unsigned int open_file_threshold = 100; // 用自旋锁保护多线程读写 static DEFINE_SPINLOCK(threshold_lock); // 内核侧读阈值的接口,直接在update_curr里调用即可 unsigned int get_threshold(void) { unsigned int val; spin_lock(&threshold_lock); val = open_file_threshold; spin_unlock(&threshold_lock); return val; }
步骤2:实现proc节点的读写回调
proc的读写逻辑直接操作上述全局变量,不需要额外存储字符串:
static ssize_t threshold_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { char tmp_buf[32]; int len = scnprintf(tmp_buf, sizeof(tmp_buf), "%u\n", get_threshold()); return simple_read_from_buffer(buf, count, ppos, tmp_buf, len); } static ssize_t threshold_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char tmp_buf[32]; unsigned int new_val; int ret; if (count >= sizeof(tmp_buf)) return -EINVAL; ret = simple_write_to_buffer(tmp_buf, sizeof(tmp_buf)-1, ppos, buf, count); if (ret < 0) return ret; tmp_buf[ret] = '\0'; if (kstrtouint(tmp_buf, 10, &new_val)) return -EINVAL; // 写入新阈值 spin_lock(&threshold_lock); open_file_threshold = new_val; spin_unlock(&threshold_lock); return count; } static const struct file_operations threshold_proc_fops = { .read = threshold_read, .write = threshold_write, .llseek = default_llseek, };
步骤3:创建proc节点
将节点创建逻辑放到非原子上下文的初始化路径,确保在proc文件系统挂载后执行:
static int __init threshold_proc_init(void) { // 创建/proc/open_file_threshold节点,权限644,root可写其他用户可读 proc_create("open_file_threshold", 0644, NULL, &threshold_proc_fops); return 0; } // late_initcall确保proc初始化完成后再执行节点创建 late_initcall(threshold_proc_init);
使用说明
- 内核侧在
update_curr里直接调用get_threshold()获取当前阈值即可,开销极低、上下文安全。 - 用户侧可通过
echo 200 > /proc/open_file_threshold修改阈值,cat /proc/open_file_threshold读取当前阈值,满足动态调整需求。
内容的提问来源于stack exchange,提问作者Kshitij Deogade
相关产品推荐
相关产品推荐

