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

Linux内核:给定struct file指针如何查找其所属task_struct

核心前提

struct file 不存在唯一绑定的“所属task_struct”。
这个结构体代表内核层面的一个打开文件实例,本身维护引用计数f_count记录当前被引用的次数,引用它的可以是任意数量进程的文件描述符,也可以是内核态的临时引用(比如驱动、文件系统内部持有)。最常见的多进程持有同一个struct file的场景包括:fork后父子进程共享打开的文件、通过UNIX域套接字传递文件描述符给其他进程、多线程共享线程组的文件描述符表。你能实现的是查找所有当前持有该struct file引用的用户态进程,不存在反向找唯一所属进程的可能。

具体实现方法

内核没有提供直接的反向查询API,只能通过全量遍历匹配的方式实现,步骤如下:

  • 遍历系统全局进程链表:内核以init_task为表头维护了所有进程/线程的双向循环链表,通过task_struct的tasks成员挂载,遍历前需要持有tasklist_lock读锁,保证遍历过程中链表结构不会被修改。
  • 跳过无文件描述符表的任务:内核线程的task_struct->files指针为空,没有用户态打开的文件,直接跳过即可。
  • 遍历单个任务的文件描述符表:对每个有效任务,持有其files_struct->file_lock自旋锁,通过files_fdtable()获取当前的fd表结构struct fdtable,该结构的fd成员是struct file*数组,存储了该任务所有fd对应的file指针,max_fds是当前fd表支持的最大fd值。
  • 指针匹配:从0到max_fds遍历fd数组,比对每个条目和你持有的目标struct file指针是否相等,相等则说明当前任务持有该文件的引用。
避坑提醒
  • 不要用struct file->f_owner反向找进程:这个成员的作用是记录文件IO事件产生信号时的接收进程,和文件的实际持有者没有必然关联,绝大多数场景下不会被主动设置,查询结果完全不可靠。
  • 注意性能开销:全量遍历进程+遍历每个进程的fd表的时间复杂度和系统总打开文件数正相关,在打开文件多的服务器上开销极高,只适合调试、问题排查这类低频场景,绝对不能放到内核核心执行路径中。
  • 注意对象生命周期:如果遍历过程中拿到task_struct或者struct file指针需要在锁外使用,必须先拿对应的引用计数:持有task_struct用get_task_struct(),持有file用get_file(),用完后分别调用put_task_struct()和fput()释放,避免对象被提前释放触发野指针问题。
  • 注意去重:同一线程组的多个线程默认共享同一个files_struct,遍历到同组的每个线程时都会匹配到同一个file指针,如果只需要找不同的文件表持有者,需要对files_struct指针做去重处理。
参考实现代码(内核态)
#include <linux/sched.h>
#include <linux/fdtable.h>
#include <linux/file.h>

void list_tasks_holding_target_file(struct file *target)
{
    struct task_struct *pos;

    if (!target)
        return;

    read_lock(&tasklist_lock);
    for_each_process(pos) {
        struct files_struct *files = pos->files;
        struct fdtable *fdt;
        int fd;

        if (!files)
            continue;

        spin_lock(&files->file_lock);
        fdt = files_fdtable(files);
        for (fd = 0; fd < fdt->max_fds; fd++) {
            if (rcu_dereference_check(fdt->fd[fd],
                    lockdep_is_held(&files->file_lock)) == target) {
                pr_info("pid:%d comm:%s holds target file at fd:%d\n",
                    pos->pid, pos->comm, fd);
                break; // 找到一个fd就跳出当前进程的遍历,找全量引用就删掉这行
            }
        }
        spin_unlock(&files->file_lock);
    }
    read_unlock(&tasklist_lock);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 03:21:40