summaryrefslogtreecommitdiffstats
path: root/libmount/src/monitor.c
diff options
context:
space:
mode:
authorKarel Zak2015-01-06 16:18:52 +0100
committerKarel Zak2015-01-06 16:19:02 +0100
commitf43fb23a2f80077248753d598be5af2dae8a5a40 (patch)
treec9281695065acc125363e3c4d636c7f3e1bf48cf /libmount/src/monitor.c
parentlinmount: (monitor) refresh docs, headers and symbols table (diff)
downloadkernel-qcow2-util-linux-f43fb23a2f80077248753d598be5af2dae8a5a40.tar.gz
kernel-qcow2-util-linux-f43fb23a2f80077248753d598be5af2dae8a5a40.tar.xz
kernel-qcow2-util-linux-f43fb23a2f80077248753d598be5af2dae8a5a40.zip
libmount: (monitor) make mnt_monitor_next_changed() usable for epoll version too
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libmount/src/monitor.c')
-rw-r--r--libmount/src/monitor.c43
1 files changed, 29 insertions, 14 deletions
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;