当进程访问文件时,是否保证会创建文件描述符?具体来说,在 /proc/pid/fd 中

当进程访问文件时,是否保证会创建文件描述符?具体来说,在 /proc/pid/fd 中

我正在创建一个具有以下特征的 ebpf 程序系统调用上的跟踪点读()

该程序的目的是计算文件被读取的次数。

我目前追踪此问题的方法如下:

  1. 当 read() 的跟踪点命中时,它可以访问文件描述符 (fd) 和进程 ID (pid)。我的 c 回调代码会使用此信息执行。
  2. 代码从 /proc/{pid}/fd 中的每个文件获取 inode。如果 inode 与要监视的特定文件匹配,则我增加计数。这一切都发生在 read() 系统调用完成之前。

有时这很有效...但是我注意到一些奇怪的事情......

  1. 较小的文件(例如总共 2 行)通常不会以这种方式被拾取,但较大的文件则会。

例如:

猫小.txt=错过

猫大.txt=已看过

  1. 如果我在 cat 调用之前添加 strace 命令,它就会起作用

例如:

strace -q 猫小.txt=已看过

处理此问题的 ebpf 代码可以在这里看到:

void handle_event(void *ctx, void *data, unsigned int data_sz)
{
    //struct that holds data like pid, and fd
    struct data_t *m = data;

    //get /proc/pid/fd as string
    char path_str[100];
    sprintf(path_str, "/proc/%d/fd", m->pid);
    

    //for traversing the proc dir
    DIR *mydir;
    struct dirent *myfile;
    struct stat mystat;

    //traverse /proc/pid/fd
    char buf[512];
    mydir = opendir(path_str);
    if(mydir != NULL){

        while((myfile = readdir(mydir)) != NULL)
        {
            //stat each file
            sprintf(buf, "%s/%s", path_str, myfile->d_name);
            stat(buf, &mystat);
            
            //check if inode matches from list
            if(mystat.st_ino == 1396301 || mystat.st_ino == 1319264 || mystat.st_ino == 5768513 || mystat.st_ino == 1318781){
                //alert message to signify file was read
                printf("Read file!\n");
                printf("inode = %d \n", mystat.st_ino);
            }


        }
    }
    //close the dir
    if(mydir != NULL){
        closedir(mydir);
    }

    
}

我注意到的是猫大.txt/proc/pid/fd 中始终有一个 big.txt 的 fd,strace -q 小.txt对于 small.txt。

然而对于猫小.txt似乎从来没有 fd

我假设这与缓存有关,但我似乎无法弄清楚在以下情况下文件是如何被访问的猫小.txt,因为即使它通过缓存访问文件,它也不会产生 fd,并更新 /proc/pid/fd?

如果不是,为什么?应该使用什么机制来访问文件内容?

任何帮助将非常感激。

答案1

感谢 @user1686 提出您的问题。这让我明白,本质上没有什么可以确保我的跟踪点回调(在用户空间中执行)在内核空间中执行的 read() 系统调用之前完成。

因此,可能发生的情况是,在我的回调可以访问 /proc/pid/fd 之前,进程关闭了文件,因此将 fd 添加到 /proc/pid/fd 的正常行为如预期发生。

相关内容