You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux4.19内核集成proc_entry后filp_open报错无法启动问题求解

问题根因

你的实现从方案设计到上下文使用都存在明显错误,直接导致内核启动失败:

  1. 上下文非法:update_curr是调度器核心路径函数,运行时持有运行队列自旋锁,处于原子上下文,不能调用任何可能阻塞的函数。filp_open内部涉及VFS路径遍历、内存分配、锁抢占,属于典型的可能阻塞函数,在原子上下文调用必然触发死锁,前几次报错是因为proc文件系统尚未挂载、你的自定义节点还未创建,后续直接卡死就是触发了原子上下文睡眠的异常。
  2. 方案逻辑错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 14:54:04