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
相关产品推荐
相关产品推荐

