On Wed, Dec 17, 2014 at 08:04:38PM +0100, Lennart Poettering wrote:
> > This is important details, because if you use epoll file descriptor 
> > in another epoll then you're correctly notified on the top-level epoll, 
> > but you lost information about which underneath file descriptor is active 
> > -- then it was impossible to verify the inotify IN_MOVED_TO utab
> > event.
> Hmm? Not following. The top-level epoll will get an event telling you
> that which low-level epoll is triggered. Then, you read an event from
> that which tells you precisely which actual file has been triggered...

Yes, was my original idea, then followed by frustration ;-) 

It seems it the hierarchy of epolls works only if all the file
descriptors are with EPOLLIN. I had /proc/self/mountinfo with EPOLLPRI
only (because with EPOLLIN it generates events all time as I don't
read the file content).

Today I played with it a little bit more and I found that possible
solution is to use EPOLLPRI | EPOLLIN | EPOLLET for the /proc/self/mountinfo.



PS. if anyone wants to play with it then below is test program, just
copy and past to test.c

 $ make test
 $ touch AAA BBB
 $ ./test AAA BBB

 and "cat AAA" or "mount <something>" on another terminal

#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <fcntl.h>

static int get_inotify(const char *filename)
        int fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);

        if (inotify_add_watch(fd, filename, IN_CLOSE_NOWRITE) < 0)
                err(EXIT_FAILURE, "%s: add watch failed", filename);
        return fd;

static void clean_inotify_buf(int fd)
        char buf[BUFSIZ];
        while (read(fd, buf, sizeof(buf)) > 0);         /* non-blocking */

int main(int argc, char **argv)
        int a, b, c;
        int low_efd, high_efd;
        struct epoll_event ev;

        /* low epoll */
        low_efd = epoll_create1(EPOLL_CLOEXEC);
        if (low_efd < 0)
                err(EXIT_FAILURE, "failed to create epoll");

        ev.events = EPOLLPRI | EPOLLIN;
        a = ev.data.fd = get_inotify(argv[1]);
        if (epoll_ctl(low_efd, EPOLL_CTL_ADD, a, &ev) < 0)
                err(EXIT_FAILURE, "failed to add %s to low-epoll", argv[1]);

        ev.events = EPOLLPRI | EPOLLIN;
        b = ev.data.fd = get_inotify(argv[2]);
        if (epoll_ctl(low_efd, EPOLL_CTL_ADD, b, &ev) < 0)
                err(EXIT_FAILURE, "failed to add %s to low-epoll", argv[2]);

        ev.events = EPOLLPRI | EPOLLIN | EPOLLET;
        c = ev.data.fd = open("/proc/self/mountinfo", O_RDONLY | O_CLOEXEC);
        if (epoll_ctl(low_efd, EPOLL_CTL_ADD, c, &ev) < 0)
                err(EXIT_FAILURE, "failed to add mountinfo to low-epoll");

        /* high epoll */
        high_efd = epoll_create1(EPOLL_CLOEXEC);
        if (high_efd < 0)
                err(EXIT_FAILURE, "failed to create high-epoll");

        ev.events = EPOLLPRI | EPOLLIN;
        ev.data.fd = low_efd;
        if (epoll_ctl(high_efd, EPOLL_CTL_ADD, low_efd, &ev) < 0)
                err(EXIT_FAILURE, "failed to add to high-epoll");

        fprintf(stderr, "      top=%d\n", high_efd);
        fprintf(stderr, "        |\n");
        fprintf(stderr, "      low=%d\n", low_efd);
        fprintf(stderr, "    /   |   \\\n");
        fprintf(stderr, "  A=%d  B=%d   C=%d\n\n", a, b, c);

        do {
                struct epoll_event events[1];
                int n;

                fprintf(stderr, "Wainting for event...\n");
                n = epoll_wait(high_efd, events, 1, -1);
                if (n < 0)
                        err(EXIT_FAILURE, "high-epoll wait failed");
                if (!n)

                fprintf(stderr, "*** has high event (fd=%d)\n", 
                do {
                        n = epoll_wait(low_efd, events, 1, 0);
                        if (n < 0)
                                err(EXIT_FAILURE, "low-epoll wait failed");
                        else if (n) {
                                int fd = events[0].data.fd;
                                fprintf(stderr, "   *** has low event 
(fd=%d)\n", fd);
                                if (fd == a || fd == b)
                        } else
                                break;          /* no event */
                } while (1);
        } while (1);


 Karel Zak  <k...@redhat.com>
systemd-devel mailing list

Reply via email to