epoll对引用目录的文件描述符做了什么?

Ale*_*nor 10 linux epoll file-descriptor

就像标题所说,我注册了一个文件描述符,这是一个epoll目录,它有什么作用?

nel*_*age 14

没什么 - 注册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;
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

[nelhage@hectique:/tmp]$ make epoll
cc     epoll.c   -o epoll
[nelhage@hectique:/tmp]$ ./epoll
epoll_ctl: Operation not permitted
Run Code Online (Sandbox Code Playgroud)

为了弄清楚这里发生了什么,我去了源头.我碰巧知道大多数行为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,
};
Run Code Online (Sandbox Code Playgroud)

注意缺少.poll定义,这意味着它将被初始化为NULL.因此,回到定义的epoll,fs/eventpoll.c我们寻找检查为pollNULL,我们在syscall定义的早期找到一个epoll_ctl:

/* The target file descriptor must support poll */
error = -EPERM;
if (!tfile->f_op || !tfile->f_op->poll)
    goto error_tgt_fput;
Run Code Online (Sandbox Code Playgroud)

正如我们的测试所示,如果目标文件不支持poll,插入尝试将失败EPERM.

其他文件系统可能.poll在其目录文件对象上定义方法,但我怀疑很多人都这样做.