Гарантируется ли, что дескриптор файла будет создан, когда процесс обращается к файлу? В частности, в /proc/pid/fd.
Я создаю программу ebpf, которая имеет точку трассировки системного вызова read() .
Цель программы — подсчитать, сколько раз был прочитан файл.
Мой текущий метод отслеживания этого заключается в следующем:
- Когда достигается точка трассировки для read(), она получает доступ к дескриптору файла (fd) и идентификатору процесса (pid). Мой код обратного вызова c выполняется с этой информацией.
- Код получает индексный дескриптор из каждого файла в /proc/{pid}/fd. Если индексный дескриптор соответствует конкретному файлу (файлам), который нужно отслеживать, я увеличиваю счетчик. Все это происходит до завершения системного вызова read().
Иногда это работает отлично и отлично... Однако я заметил кое-что странное...
- Файлы меньшего размера (например, всего 2 строки) обычно не подбираются таким образом, а файлы большего размера - да.
Например:
кот small.txt = Пропущен
кот big.txt = Виден
- Если я добавлю команду strace перед вызовом cat, она сработает
Например:
strace -q cat small.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);
}
}
Я заметил, что cat big.txt всегда имеет fd в /proc/pid/fd для big.txt, как и strace -q small.txt для small.txt.
Однако для cat small.txt, похоже , никогда не было fd .
Я предполагаю, что это как-то связано с кешированием, но я не могу понять, как осуществляется доступ к файлу в случае cat small.txt , потому что даже если он обращается к файлу через кеш, не будет ли это также создать fd и обновить /proc/pid/fd?
Если нет, то почему? И какой механизм вместо этого будет использоваться для доступа к содержимому файла?
Любая помощь приветствуется.
1 ответ
Спасибо @user1686 за ваш вопрос. Это помогло мне понять, что по сути ничто не гарантирует, что мой обратный вызов точки трассировки (который выполняется в пользовательском пространстве) завершится раньше системного вызова read(), который выполняется в пространстве ядра.
Поэтому, скорее всего, происходит то, что процесс закрывает файл до того, как мой обратный вызов сможет получить доступ к /proc/pid/fd, и поэтому нормальное поведение, при котором fd добавляется в /proc/pid/fd, происходит, как и ожидалось.