就像标题所说的那样,我注册了一个文件描述符,这个文件描述符是一个带有epoll的目录,它有什么作用?
什么都没有 – 调用注册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
大部分行为是由目标文件对应的struct file_operations
上的->poll
函数确定的,这取决于所讨论的文件系统。 我选择了ext4
作为一个典型的例子,并且查看了定义 ext4_dir_operations
fs/ext4/dir.c
,如下所示:
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
。 所以,回到fs/eventpoll.c
定义的epoll,我们查找poll
为NULL的检查,我们在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
方法,但我怀疑很多。