Just like the title says, it I register a file descriptor that is a directory with epoll, what does it do?
epoll is a Linux kernel system call for a scalable I/O event notification mechanism, first introduced in version 2.5. 44 of the Linux kernel. Its function is to monitor multiple file descriptors to see whether I/O is possible on any of them.
The epoll_wait() system call waits for events on the epoll(7) instance referred to by the file descriptor epfd. The buffer pointed to by events is used to return information from the ready list about file descriptors in the interest list that have some events available. Up to maxevents are returned by epoll_wait().
A file descriptor is an unsigned integer used by a process to identify an open file. The number of file descriptors available to a process is limited by the /OPEN_MAX control in the sys/limits. h file. The number of file descriptors is also controlled by the ulimit -n flag.
epoll stands for event poll and is a Linux specific construct. It allows for a process to monitor multiple file descriptors and get notifications when I/O is possible on them. It allows for both edge-triggered as well as level-triggered notifications.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With