[systemd-devel] [PATCH v2 5/5] mount: auto-detect iSCSI and FCoE as requiring network
Karel Zak
kzak at redhat.com
Thu Dec 18 04:03:17 PST 2014
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 <kzak at redhat.com>
http://karelzak.blogspot.com
More information about the systemd-devel
mailing list