diff options
Diffstat (limited to 'libmount/src/monitor.c')
-rw-r--r-- | libmount/src/monitor.c | 79 |
1 files changed, 62 insertions, 17 deletions
diff --git a/libmount/src/monitor.c b/libmount/src/monitor.c index f99751e..941f5d5 100644 --- a/libmount/src/monitor.c +++ b/libmount/src/monitor.c @@ -64,6 +64,8 @@ struct libmnt_monitor { int fd; /* public monitor file descriptor */ struct list_head ents; + + unsigned int kernel_veiled: 1; }; struct monitor_opers { @@ -226,18 +228,16 @@ static int userspace_add_watch(struct monitor_entry *me, int *final, int *fd) assert(me->path); /* - * libmount uses rename(2) to atomically update utab, monitor - * rename changes is too tricky. It seems better to monitor utab - * lockfile close. + * libmount uses utab.event file to monitor and control utab updates */ - if (asprintf(&filename, "%s.lock", me->path) <= 0) { - rc = -errno; + if (asprintf(&filename, "%s.event", me->path) <= 0) { + rc = -ENOMEM; goto done; } - /* try lock file if already exists */ + /* try event file if already exists */ errno = 0; - wd = inotify_add_watch(me->fd, filename, IN_CLOSE_NOWRITE); + wd = inotify_add_watch(me->fd, filename, IN_CLOSE_WRITE); if (wd >= 0) { DBG(MONITOR, ul_debug(" added inotify watch for %s [fd=%d]", filename, wd)); rc = 0; @@ -256,7 +256,7 @@ static int userspace_add_watch(struct monitor_entry *me, int *final, int *fd) if (!*filename) break; - /* try directory where is the lock file */ + /* try directory where is the event file */ errno = 0; wd = inotify_add_watch(me->fd, filename, IN_CREATE|IN_ISDIR); if (wd >= 0) { @@ -339,10 +339,10 @@ static int userspace_event_verify(struct libmnt_monitor *mn, e = (const struct inotify_event *) p; DBG(MONITOR, ul_debugobj(mn, " inotify event 0x%x [%s]\n", e->mask, e->len ? e->name : "")); - if (e->mask & IN_CLOSE_NOWRITE) + if (e->mask & IN_CLOSE_WRITE) status = 1; else { - /* event on lock file */ + /* add watch for the event file */ userspace_add_watch(me, &status, &fd); if (fd != e->wd) { @@ -473,12 +473,28 @@ err: return rc; } +static int kernel_event_verify(struct libmnt_monitor *mn, + struct monitor_entry *me) +{ + int status = 1; + + if (!mn || !me || me->fd < 0) + return 0; + + if (mn->kernel_veiled && access(MNT_PATH_UTAB ".act", F_OK) == 0) { + status = 0; + DBG(MONITOR, ul_debugobj(mn, "kernel event veiled")); + } + return status; +} + /* * kernel monitor operations */ static const struct monitor_opers kernel_opers = { .op_get_fd = kernel_monitor_get_fd, .op_close_fd = kernel_monitor_close_fd, + .op_event_verify = kernel_event_verify }; /** @@ -547,6 +563,28 @@ err: return rc; } +/** + * mnt_monitor_veil_kernel: + * @mn: monitor instance + * @enable: 1 or 0 + * + * Force monitor to ignore kernel events if the same mount/umount operation + * will generate an userspace event later. The kernel-only mount operation will + * be not affected. + * + * Return: 0 on success and <0 on error. + * + * Since: 2.40 + */ +int mnt_monitor_veil_kernel(struct libmnt_monitor *mn, int enable) +{ + if (!mn) + return -EINVAL; + + mn->kernel_veiled = enable ? 1 : 0; + return 0; +} + /* * Add/Remove monitor entry to/from monitor epoll. */ @@ -854,6 +892,8 @@ static struct libmnt_monitor *create_test_monitor(int argc, char *argv[]) warn("failed to initialize kernel monitor"); goto err; } + } else if (strcmp(argv[i], "veil") == 0) { + mnt_monitor_veil_kernel(mn, 1); } } if (i == 1) { @@ -870,7 +910,8 @@ err: /* * create a monitor and add the monitor fd to epoll */ -static int __test_epoll(struct libmnt_test *ts, int argc, char *argv[], int cleanup) +static int __test_epoll(struct libmnt_test *ts __attribute__((unused)), + int argc, char *argv[], int cleanup) { int fd, efd = -1, rc = -1; struct epoll_event ev; @@ -900,12 +941,14 @@ static int __test_epoll(struct libmnt_test *ts, int argc, char *argv[], int clea goto done; } - printf("waiting for changes...\n"); do { const char *filename = NULL; struct epoll_event events[1]; - int n = epoll_wait(efd, events, 1, -1); + int n; + + printf("waiting for changes...\n"); + n = epoll_wait(efd, events, 1, -1); if (n < 0) { rc = -errno; warn("polling error"); @@ -947,7 +990,8 @@ static int test_epoll_cleanup(struct libmnt_test *ts, int argc, char *argv[]) /* * create a monitor and wait for a change */ -static int test_wait(struct libmnt_test *ts, int argc, char *argv[]) +static int test_wait(struct libmnt_test *ts __attribute__((unused)), + int argc, char *argv[]) { const char *filename; struct libmnt_monitor *mn = create_test_monitor(argc, argv); @@ -962,6 +1006,7 @@ static int test_wait(struct libmnt_test *ts, int argc, char *argv[]) while (mnt_monitor_next_change(mn, &filename, NULL) == 0) printf(" %s: change detected\n", filename); + printf("waiting for changes...\n"); } mnt_unref_monitor(mn); return 0; @@ -970,9 +1015,9 @@ static int test_wait(struct libmnt_test *ts, int argc, char *argv[]) int main(int argc, char *argv[]) { struct libmnt_test tss[] = { - { "--epoll", test_epoll, "<userspace kernel ...> monitor in epoll" }, - { "--epoll-clean", test_epoll_cleanup, "<userspace kernel ...> monitor in epoll and clean events" }, - { "--wait", test_wait, "<userspace kernel ...> monitor wait function" }, + { "--epoll", test_epoll, "<userspace kernel veil ...> monitor in epoll" }, + { "--epoll-clean", test_epoll_cleanup, "<userspace kernel veil ...> monitor in epoll and clean events" }, + { "--wait", test_wait, "<userspace kernel veil ...> monitor wait function" }, { NULL } }; |