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

Linux内核模块实现长中断处理 关闭进程txt文件时系统冻结如何解决

问题排查与解决方案

核心错误原因

  • 参数传错,close_fd调用完全不符合预期:close_fd接收的入参是当前进程的文件描述符编号(即你代码里的int类型变量i),你直接传入struct file*类型的fdt->fd[i],属于完全的参数类型错误,直接触发内核空指针或非法地址访问,导致系统冻结。
  • 没有加必要的锁,存在严重竞争条件:
    • 遍历进程列表for_each_process时必须持有tasklist_lock读锁,否则进程可能在遍历中途退出,触发内存访问错误
    • 访问进程的files_struct、fdtable结构时必须持有对应结构的自旋锁,否则多核心场景下并发修改文件表会直接破坏内核数据结构
  • 上下文使用错误:你提到逻辑在中断处理函数中执行,而中断上下文不允许执行任何可能阻塞的操作,d_path、close_fd/filp_close这类函数都有可能阻塞,中断上下文无法调度,一旦阻塞就会导致整个系统彻底冻结。
  • 跨进程操作文件描述符逻辑错误:close_fd只能操作当前进程的文件描述符,你直接在其他上下文操作目标进程10367的文件表,会破坏进程内部的文件描述符状态,直接触发崩溃。
  • 遍历逻辑边界错误:你直接用fdt->fd[i] != NULL作为循环终止条件,没有用fdtable的max_fds作为边界,会导致越界访问内存。

修复方案

1. 中断上下文仅做事件触发,业务逻辑移到进程上下文

中断处理函数里只记录触发信息,用工作队列(workqueue)把关闭文件的逻辑推后到内核线程的进程上下文执行,避免中断上下文阻塞。

2. 修正锁逻辑与关闭逻辑

参考实现代码:

read_lock(&tasklist_lock);
for_each_process(task_list) {
    if (task_list->pid != 10367) continue;
    get_task_struct(task_list); // 持有进程引用,防止中途退出
    read_unlock(&tasklist_lock); // 遍历完就释放进程列表锁,减少锁持有时间

    if (!task_list->files) {
        put_task_struct(task_list);
        return;
    }
    // 操作文件表前加锁
    spin_lock(&task_list->files->file_lock);
    struct fdtable *fdt = files_fdtable(task_list->files);
    // 遍历fd要用max_fds做边界,避免越界访问
    for (int i = 0; i < fdt->max_fds; i++) {
        if (!fdt->fd[i]) continue;
        // 你的文件路径判断逻辑
        char buf[PATH_MAX];
        const char *path = d_path(&fdt->fd[i]->f_path, buf, sizeof(buf));
        if (!strstr(path, ".txt")) continue;

        // 持有文件引用,防止提前释放
        struct file *filp = fdt->fd[i];
        get_file(filp);
        // 清空对应fd表项
        fd_install(i, NULL);
        put_unused_fd(i);
        spin_unlock(&task_list->files->file_lock);

        // 关闭文件
        filp_close(filp, task_list->files);
        fput(filp);

        spin_lock(&task_list->files->file_lock);
    }
    spin_unlock(&task_list->files->file_lock);
    put_task_struct(task_list);
    return;
}
read_unlock(&tasklist_lock);

3. 更安全的替代方案

如果业务允许,不要直接在内核强行关闭进程的文件描述符,而是找到目标进程后发送SIGTERM信号让进程自行退出清理,完全避免破坏进程内部状态的风险,实现起来也更简单:

read_lock(&tasklist_lock);
struct task_struct *target = find_task_by_vpid(10367);
if (target) {
    send_sig(SIGTERM, target, 0);
}
read_unlock(&tasklist_lock);

内容的提问来源于stack exchange,提问作者Anh Hoang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:24:02