Just like the title says, it I register a file descriptor that is a directory with epoll, what does it do?
Nothing -- the call to register the fd will (at least for common Linux filesystems) fail with EPERM
.
I tested this using the following demo program:
#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;
}
With the following result:
[nelhage@hectique:/tmp]$ make epoll
cc epoll.c -o epoll
[nelhage@hectique:/tmp]$ ./epoll
epoll_ctl: Operation not permitted
To figure out what was going on here, I went to the source. I happen to know that most of the behavior of epoll
is determined by the ->poll
function on the struct file_operations
corresponding to the target file, which depends on the file system in question. I picked ext4
as a typical example, and looked at fs/ext4/dir.c
, which defines ext4_dir_operations
as follows:
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,
};
Note the lack of a .poll
definition, meaning it will be initialized to NULL
. So, swinging back to epoll, which is defined in fs/eventpoll.c
, we look for checks for poll
being NULL, and we find one early on in the epoll_ctl
syscall definition:
/* The target file descriptor must support poll */
error = -EPERM;
if (!tfile->f_op || !tfile->f_op->poll)
goto error_tgt_fput;
As our test indicated, if the target file doesn't support poll
, the insert attempt will just fail out with EPERM
.
It's possible that other filesystems define .poll
methods on their directory file objects, but I doubt that many do.
dirfd(opendir("/tmp"))
preferred over open(path, O_RDONLY|O_DIRECTORY);
? Just a style question. Using opendir
doesn't magically make the fs support poll. –
Teyde dirfd(opendir("..."))
is more portable, so is probably preferred in general. I'm a Linux kernel hacker, so I personally tend to default to using the system-call interface even when it's not the most appropriate, because I know it better. Obviously here it doesn't really matter, since epoll
is also Linux specific. –
Oscoumbrian © 2022 - 2024 — McMap. All rights reserved.
inotify
. – Riga