[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