summaryrefslogtreecommitdiffstats
path: root/libmount/src/monitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmount/src/monitor.c')
-rw-r--r--libmount/src/monitor.c79
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 }
};