Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does epoll do with a file descriptor that refers to a directory?

Just like the title says, it I register a file descriptor that is a directory with epoll, what does it do?

like image 429
Alex Gaynor Avatar asked Aug 06 '12 17:08

Alex Gaynor


People also ask

What is epoll file descriptor?

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.

How does epoll Wait work?

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().

What is a file descriptor in Linux?

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.

What is an epoll event?

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.


1 Answers

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.

like image 56
nelhage Avatar answered Sep 20 '22 12:09

nelhage