From ef734fd6c2ec4e5602bbfe2a0d26dcf39c14d2bf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Jan 2010 06:04:08 +0100 Subject: [PATCH] watch mount status file --- manager.c | 11 ++-- manager.h | 14 +++++- mount.c | 148 ++++++++++++++++++++++++++++++++++++------------------ mount.h | 7 +++ unit.c | 6 +++ unit.h | 9 ++-- 6 files changed, 138 insertions(+), 57 deletions(-) diff --git a/manager.c b/manager.c index 06a171ff2..ac1c79c5f 100644 --- a/manager.c +++ b/manager.c @@ -36,7 +36,7 @@ static int manager_setup_signals(Manager *m) { assert_se(sigaddset(&mask, SIGPIPE) == 0); assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - m->signal_watch.type = WATCH_SIGNAL_FD; + m->signal_watch.type = WATCH_SIGNAL; if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) return -errno; @@ -56,7 +56,7 @@ Manager* manager_new(void) { if (!(m = new0(Manager, 1))) return NULL; - m->signal_watch.fd = m->epoll_fd = -1; + m->signal_watch.fd = m->mount_watch.fd = m->epoll_fd = -1; if (!(m->units = hashmap_new(string_hash_func, string_compare_func))) goto fail; @@ -1123,7 +1123,7 @@ static int process_event(Manager *m, struct epoll_event *ev, bool *quit) { switch (w->type) { - case WATCH_SIGNAL_FD: + case WATCH_SIGNAL: /* An incoming signal? */ if (ev->events != POLLIN) @@ -1157,6 +1157,11 @@ static int process_event(Manager *m, struct epoll_event *ev, bool *quit) { break; } + case WATCH_MOUNT: + /* Some mount table change, intended for the mount subsystem */ + mount_fd_event(m, ev->events); + break; + default: assert_not_reached("Unknown epoll event type."); } diff --git a/manager.h b/manager.h index 793a55fb4..88b8509cf 100644 --- a/manager.h +++ b/manager.h @@ -13,9 +13,10 @@ typedef struct Watch Watch; enum WatchType { WATCH_INVALID, - WATCH_SIGNAL_FD, + WATCH_SIGNAL, WATCH_FD, - WATCH_TIMER + WATCH_TIMER, + WATCH_MOUNT }; struct Watch { @@ -48,6 +49,10 @@ struct Manager { Hashmap *units; /* name string => Unit object n:1 */ Hashmap *jobs; /* job id => Job object 1:1 */ + /* To make it easy to iterate through the units of a specific + * type we maintain a per type linked list */ + LIST_HEAD(Meta, units_per_type[_UNIT_TYPE_MAX]); + /* Units that need to be loaded */ LIST_HEAD(Meta, load_queue); /* this is actually more a stack than a queue, but uh. */ @@ -67,7 +72,12 @@ struct Manager { Watch signal_watch; + /* Data specific to the device subsystem */ struct udev* udev; + + /* Data specific to the mount subsystem */ + FILE *proc_self_mountinfo; + Watch mount_watch; }; Manager* manager_new(void); diff --git a/mount.c b/mount.c index d9d461a59..a1c33442c 100644 --- a/mount.c +++ b/mount.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "unit.h" #include "mount.h" @@ -27,17 +29,20 @@ static const char* const state_string_table[_MOUNT_STATE_MAX] = { }; static void mount_done(Unit *u) { - Mount *d = MOUNT(u); + Mount *m = MOUNT(u); - assert(d); - free(d->what); - free(d->where); + assert(m); + free(m->what); + free(m->where); } static void mount_set_state(Mount *m, MountState state) { MountState old_state; assert(m); + if (state == m->state) + return; + old_state = m->state; m->state = state; @@ -83,6 +88,10 @@ static UnitActiveState mount_active_state(Unit *u) { } static void mount_shutdown(Manager *m) { + assert(m); + + if (m->proc_self_mountinfo) + fclose(m->proc_self_mountinfo); } static int mount_add_node_links(Mount *m) { @@ -119,35 +128,34 @@ static int mount_add_node_links(Mount *m) { } static int mount_add_path_links(Mount *m) { - Iterator i; - Unit *other; + Meta *other; int r; /* Adds in link to other mount points, that might lie below or * above us in the hierarchy */ - HASHMAP_FOREACH(other, UNIT(m)->meta.manager->units, i) { + LIST_FOREACH(units_per_type, other, UNIT(m)->meta.manager->units_per_type[UNIT_MOUNT]) { Mount *n; - if (other->meta.type != UNIT_MOUNT) - continue; + n = (Mount*) other; - n = MOUNT(other); + if (n == m) + return 0; if (path_startswith(m->where, n->where)) { - if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, other)) < 0) + if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, (Unit*) other)) < 0) return r; - if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, other)) < 0) + if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, (Unit*) other)) < 0) return r; } else if (startswith(n->where, m->where)) { - if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, other)) < 0) + if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, (Unit*) other)) < 0) return r; - if ((r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m))) < 0) + if ((r = unit_add_dependency((Unit*) other, UNIT_REQUIRES, UNIT(m))) < 0) return r; } } @@ -155,7 +163,7 @@ static int mount_add_path_links(Mount *m) { return 0; } -static int mount_add_one(Manager *m, const char *what, const char *where, bool live) { +static int mount_add_one(Manager *m, const char *what, const char *where, bool live, bool set_flags) { char *e; int r; Unit *u; @@ -199,15 +207,24 @@ static int mount_add_one(Manager *m, const char *what, const char *where, bool l if ((r = unit_set_description(u, where)) < 0) goto fail; + } else { delete = false; free(e); } - if (live) + if (set_flags) + MOUNT(u)->still_exists = true; + + if (live) { + if (set_flags) + MOUNT(u)->just_created = !MOUNT(u)->from_proc_self_mountinfo; MOUNT(u)->from_proc_self_mountinfo = true; - else + } else { + if (set_flags) + MOUNT(u)->just_created = !MOUNT(u)->from_etc_fstab; MOUNT(u)->from_etc_fstab = true; + } if ((r = mount_add_node_links(MOUNT(u))) < 0) goto fail; @@ -264,7 +281,7 @@ static char *fstab_node_to_udev_node(char *p) { return strdup(p); } -static int mount_load_etc_fstab(Manager *m) { +static int mount_load_etc_fstab(Manager *m, bool set_flags) { FILE *f; int r; struct mntent* me; @@ -295,7 +312,7 @@ static int mount_load_etc_fstab(Manager *m) { if (where[0] == '/') path_kill_slashes(where); - r = mount_add_one(m, what, where, false); + r = mount_add_one(m, what, where, false, set_flags); free(what); free(where); @@ -310,20 +327,18 @@ finish: return r; } -static int mount_load_proc_self_mountinfo(Manager *m) { - FILE *f; +static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { int r; assert(m); - if (!(f = fopen("/proc/self/mountinfo", "r"))) - return -errno; + rewind(m->proc_self_mountinfo); for (;;) { int k; char *device, *path, *d, *p; - if ((k = fscanf(f, + if ((k = fscanf(m->proc_self_mountinfo, "%*s " /* (1) mount id */ "%*s " /* (2) parent id */ "%*s " /* (3) major:minor */ @@ -333,63 +348,64 @@ static int mount_load_proc_self_mountinfo(Manager *m) { "%*[^-]" /* (7) optional fields */ "- " /* (8) seperator */ "%*s " /* (9) file system type */ - "%ms" /* (10) mount source */ - "%*[^\n]", /* some rubbish at the end */ + "%ms" /* (10) mount source */ + "%*[^\n]", /* some rubbish at the end */ &path, &device)) != 2) { - if (k == EOF) { - if (feof(f)) - break; + if (k == EOF) + break; - r = -errno; - goto finish; - } - - r = -EBADMSG; - goto finish; + return -EBADMSG; } if (!(d = cunescape(device))) { free(device); free(path); - r = -ENOMEM; - goto finish; + return -ENOMEM; } free(device); if (!(p = cunescape(path))) { free(d); free(path); - r = -ENOMEM; - goto finish; + return -ENOMEM; } free(path); - r = mount_add_one(m, d, p, true); + r = mount_add_one(m, d, p, true, set_flags); free(d); free(p); if (r < 0) - goto finish; + return r; } - r = 0; - -finish: - fclose(f); - - return r; + return 0; } static int mount_enumerate(Manager *m) { int r; + struct epoll_event ev; assert(m); - if ((r = mount_load_etc_fstab(m)) < 0) + if (!(m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "r"))) + return -errno; + + m->mount_watch.type = WATCH_MOUNT; + m->mount_watch.fd = fileno(m->proc_self_mountinfo); + + zero(ev); + ev.events = EPOLLERR; + ev.data.ptr = &m->mount_watch; + + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch.fd, &ev) < 0) + return -errno; + + if ((r = mount_load_etc_fstab(m, false)) < 0) goto fail; - if ((r = mount_load_proc_self_mountinfo(m)) < 0) + if ((r = mount_load_proc_self_mountinfo(m, false)) < 0) goto fail; return 0; @@ -399,6 +415,40 @@ fail: return r; } +void mount_fd_event(Manager *m, int events) { + Meta *meta; + int r; + + assert(m); + assert(events == POLLERR); + + /* The manager calls this for every fd event happening on the + * /proc/self/mountinfo file, which informs us about mounting + * table changes */ + + if ((r = mount_load_proc_self_mountinfo(m, true)) < 0) { + log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-errno)); + return; + } + + manager_dispatch_load_queue(m); + + LIST_FOREACH(units_per_type, meta, m->units_per_type[UNIT_MOUNT]) { + Mount *mount = (Mount*) meta; + + if (mount->just_created && mount->state == MOUNT_DEAD) + mount_set_state(mount, MOUNT_MOUNTED); + else if (!mount->still_exists && mount->state == MOUNT_MOUNTED) { + mount_set_state(mount, MOUNT_DEAD); + mount->from_proc_self_mountinfo = false; + } + + /* Clear the flags for later calls */ + mount->just_created = false; + mount->still_exists = false; + } +} + const UnitVTable mount_vtable = { .suffix = ".mount", diff --git a/mount.h b/mount.h index 9a8079f48..2f9022605 100644 --- a/mount.h +++ b/mount.h @@ -25,8 +25,15 @@ struct Mount { bool from_etc_fstab:1; bool from_proc_self_mountinfo:1; + + /* Used while looking for mount points that vanished or got + * added from/to /proc/self/mountinfo */ + bool still_exists:1; + bool just_created:1; }; extern const UnitVTable mount_vtable; +void mount_fd_event(Manager *m, int events); + #endif diff --git a/unit.c b/unit.c index 7954c0418..624ea0cb5 100644 --- a/unit.c +++ b/unit.c @@ -147,6 +147,9 @@ int unit_add_name(Unit *u, const char *text) { return r; } + if (u->meta.type == _UNIT_TYPE_INVALID) + LIST_PREPEND(Meta, units_per_type, u->meta.manager->units_per_type[t], &u->meta); + u->meta.type = t; if (!u->meta.id) @@ -224,6 +227,9 @@ void unit_free(Unit *u) { SET_FOREACH(t, u->meta.names, i) hashmap_remove_value(u->meta.manager->units, t, u); + if (u->meta.type != _UNIT_TYPE_INVALID) + LIST_REMOVE(Meta, units_per_type, u->meta.manager->units_per_type[u->meta.type], &u->meta); + if (u->meta.in_load_queue) LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta); diff --git a/unit.h b/unit.h index 3e42ebe90..2433cc7d7 100644 --- a/unit.h +++ b/unit.h @@ -14,14 +14,11 @@ typedef enum UnitLoadState UnitLoadState; typedef enum UnitActiveState UnitActiveState; typedef enum UnitDependency UnitDependency; -#include "job.h" -#include "manager.h" #include "set.h" #include "util.h" #include "list.h" #include "socket-util.h" #include "execute.h" -#include "util.h" #define UNIT_NAME_MAX 128 #define DEFAULT_TIMEOUT_USEC (20*USEC_PER_SEC) @@ -92,6 +89,9 @@ enum UnitDependency { _UNIT_DEPENDENCY_INVALID = -1 }; +#include "manager.h" +#include "job.h" + struct Meta { Manager *manager; UnitType type; @@ -116,6 +116,9 @@ struct Meta { /* Load queue */ LIST_FIELDS(Meta, load_queue); + + /* Per type list */ + LIST_FIELDS(Meta, units_per_type); }; #include "service.h" -- 2.30.2