From f43fb23a2f80077248753d598be5af2dae8a5a40 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 6 Jan 2015 16:18:52 +0100 Subject: libmount: (monitor) make mnt_monitor_next_changed() usable for epoll version too Signed-off-by: Karel Zak --- libmount/src/monitor.c | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) (limited to 'libmount/src/monitor.c') diff --git a/libmount/src/monitor.c b/libmount/src/monitor.c index 2ec2510ed..f0d91d931 100644 --- a/libmount/src/monitor.c +++ b/libmount/src/monitor.c @@ -336,7 +336,8 @@ int mnt_monitor_enable_userspace(struct libmnt_monitor *mn, int enable, const ch if (mnt_has_regular_mtab(NULL, NULL)) return -ENOSYS; - filename = mnt_get_utab_path(); /* /run/mount/utab */ + if (!filename) + filename = mnt_get_utab_path(); /* /run/mount/utab */ if (!filename) { DBG(MONITOR, ul_debugobj(mn, "failed to get userspace mount table path")); return -EINVAL; @@ -451,9 +452,22 @@ int mnt_monitor_enable_kernel(struct libmnt_monitor *mn, int enable) if (!me) goto err; + /* If you want to use epoll FD in another epoll then top level + * epoll_wait() will drain all events from low-level FD if the + * low-level FD is not added with EPOLLIN. It means without EPOLLIN it + * it's impossible to detect which low-level FD has been active. + * + * Unfortunately, use EPOLLIN for mountinfo is tricky because in this + * case kernel returns events all time (we don't read from the FD). + * The solution is to use also edge-triggered (EPOLLET) flag, then + * kernel generate events on moutinfo changes only. The disadvantage is + * that we have to drain initial event generated by EPOLLIN after + * epoll_ctl(ADD). See monitor_modify_epoll(). + */ + me->events = EPOLLPRI | EPOLLIN | EPOLLET; + me->type = MNT_MONITOR_TYPE_KERNEL; me->opers = &kernel_opers; - me->events = EPOLLPRI; me->path = strdup(_PATH_PROC_MOUNTINFO); if (!me->path) goto err; @@ -493,7 +507,11 @@ static int monitor_modify_epoll(struct libmnt_monitor *mn, if (errno != EEXIST) goto err; } - + if (me->events & (EPOLLIN | EPOLLET)) { + /* Drain initial events generated for /proc/self/mountinfo */ + struct epoll_event events[1]; + while (epoll_wait(mn->fd, events, 1, 0) > 0); + } } else if (me->fd) { DBG(MONITOR, ul_debugobj(mn, " remove fd=%d (for %s)", me->fd, me->path)); if (epoll_ctl(mn->fd, EPOLL_CTL_DEL, me->fd, NULL) < 0) { @@ -554,14 +572,10 @@ int mnt_monitor_close_fd(struct libmnt_monitor *mn) * @mn: monitor * * The file descriptor is associated with all monitored files and it's usable - * for example for epoll. - * - * Note that if you want to use the @fd in your epoll then you will get only - * notification, but mnt_monitor_next_changed() does not work in this case. You - * have to call mnt_monitor_event_cleanup() after each event if you do not use - * mnt_monitor_next_changed(). + * for example for epoll. You have to call mnt_monitor_event_cleanup() or + * mnt_monitor_next_changed() after each event. * - * Returns: >=0 on success, <0 on error + * Returns: >=0 (fd) on success, <0 on error */ int mnt_monitor_get_fd(struct libmnt_monitor *mn) { @@ -664,7 +678,7 @@ static struct monitor_entry *get_changed(struct libmnt_monitor *mn) * @filename: returns changed file (optional argument) * @type: returns MNT_MONITOR_TYPE_* (optional argument) * - * The function does not wait and it's designed to provide details about chnages. + * The function does not wait and it's designed to provide details about changes. * * Returns: 0 on success, 1 no change, <0 on error */ @@ -819,6 +833,7 @@ int test_epoll(struct libmnt_test *ts, int argc, char *argv[]) printf("waiting for changes...\n"); do { + const char *filename = NULL; struct epoll_event events[1]; int n = epoll_wait(efd, events, 1, -1); @@ -830,9 +845,9 @@ int test_epoll(struct libmnt_test *ts, int argc, char *argv[]) if (n == 0 || events[0].data.fd != fd) continue; - printf(" change detected\n"); - mnt_monitor_event_cleanup(mn); - + printf(" top-level FD active\n"); + while (mnt_monitor_next_changed(mn, &filename, NULL) == 0) + printf(" %s: change detected\n", filename); } while (1); rc = 0; -- cgit v1.2.3-55-g7522