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. Ideas? Karel 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) continue; fprintf(stderr, "*** has high event (fd=%d)\n", events[0].data.fd); 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) clean_inotify_buf(fd); } else break; /* no event */ } while (1); clean_inotify_buf(a); clean_inotify_buf(b); } while (1); } -- Karel Zak <k...@redhat.com> http://karelzak.blogspot.com _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel