Что делает epoll с файловым дескриптором, который ссылается на каталог?


Как и сказано в заголовке, я регистрирую файловый дескриптор, который является каталогом с epoll, что он делает?

1 10

1 ответ:

Ничего -- вызов для регистрации fd (по крайней мере, для обычных файловых систем Linux) завершится неудачей с EPERM.

Я протестировал это с помощью следующей демонстрационной программы:

#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main(void) {
    int ep = epoll_create1(0);
    int fd = open("/tmp", O_RDONLY|O_DIRECTORY);
    struct epoll_event evt = {
        .events = EPOLLIN
    };

    if (ep < 0 || fd < 0) {
        printf("Error opening fds.\n");
        return -1;
    }

    if (epoll_ctl(ep, EPOLL_CTL_ADD, fd, &evt) < 0) {
        perror("epoll_ctl");
        return -1;
    }
    return 0;
}

Со следующим результатом:

[nelhage@hectique:/tmp]$ make epoll
cc     epoll.c   -o epoll
[nelhage@hectique:/tmp]$ ./epoll
epoll_ctl: Operation not permitted
Чтобы выяснить, что здесь происходит, я пошел к источнику. Я случайно знаю , что большая часть поведения epoll определяется функцией ->poll на struct file_operations, соответствующей целевому файлу, который зависит от файловой системы в вопрос. Я выбрал ext4 в качестве типичного примера и посмотрел на fs/ext4/dir.c, который определяет ext4_dir_operations следующим образом:
const struct file_operations ext4_dir_operations = {
    .llseek     = ext4_dir_llseek,
    .read       = generic_read_dir,
    .readdir    = ext4_readdir,
    .unlocked_ioctl = ext4_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl   = ext4_compat_ioctl,
#endif
    .fsync      = ext4_sync_file,
    .release    = ext4_release_dir,
};
Обратите внимание на отсутствие определения .poll, то есть оно будет инициализировано в NULL. Итак, возвращаясь к epoll, который определен в fs/eventpoll.c, мы ищем проверки на poll, которые являются нулевыми, и мы находим один на ранней стадии в определении epoll_ctl syscall:
/* The target file descriptor must support poll */
error = -EPERM;
if (!tfile->f_op || !tfile->f_op->poll)
    goto error_tgt_fput;

Как показал наш тест, если целевой файл не поддерживает poll, попытка вставки будет просто провалиться с EPERM.

Возможно, что другие файловые системы определяют методы .poll для своих объектов файлов каталогов, но я сомневаюсь, что многие из них это делают.