From: Lennart Poettering Date: Sun, 29 Apr 2012 12:26:07 +0000 (+0200) Subject: unit: add new dependency type RequiresMountsFor= X-Git-Tag: v183~181 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=7c8fa05c4d5d01748ff2a04edb882afb3119b7d7;ds=sidebyside unit: add new dependency type RequiresMountsFor= RequiresMountsFor= is a shortcut for adding requires and after dependencies to all mount units neeed for the specified paths. This solves a couple of issues regarding dep loop cycles for encrypted swap. --- diff --git a/Makefile.am b/Makefile.am index 41fd77379..e1501aecf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2889,6 +2889,7 @@ SED_PROCESS = \ -e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' \ + -e 's,@RANDOM_SEED\@,$(localstatedir)/lib/random-seed,g' \ -e 's,@prefix\@,$(prefix),g' \ -e 's,@exec_prefix\@,$(exec_prefix),g' \ -e 's,@libdir\@,$(libdir),g' \ diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 12416fa31..c81c7a30b 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -525,6 +525,18 @@ settings. + + RequiresMountsFor= + + Takes a space + separated list of paths. Automatically + adds dependencies of type + Requires= and + After= for all + mount units required to access the + specified path. + + OnFailureIsolate= diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 0484d7582..b8d661698 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -810,6 +810,7 @@ const BusProperty bus_unit_properties[] = { { "TriggeredBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), true }, { "PropagateReloadTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_TO]), true }, { "PropagateReloadFrom", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATE_RELOAD_FROM]), true }, + { "RequiresMountsFor", bus_property_append_strv, "as", offsetof(Unit, requires_mounts_for), true }, { "Description", bus_unit_append_description, "s", 0 }, { "LoadState", bus_unit_append_load_state, "s", offsetof(Unit, load_state) }, { "ActiveState", bus_unit_append_active_state, "s", 0 }, diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index e6d549c0f..d22802d27 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -85,6 +85,7 @@ " \n" \ " \n" \ " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index c65db30ff..d92927387 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -104,6 +104,7 @@ Unit.After, config_parse_unit_deps, UNIT_AFTER, Unit.OnFailure, config_parse_unit_deps, UNIT_ON_FAILURE, 0 Unit.PropagateReloadTo, config_parse_unit_deps, UNIT_PROPAGATE_RELOAD_TO, 0 Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_PROPAGATE_RELOAD_FROM, 0 +Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, offsetof(Unit, requires_mounts_for) Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 1665be82a..d24919f99 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2032,6 +2032,35 @@ int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const return 0; } +int config_parse_unit_requires_mounts_for( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Unit *u = userdata; + int r; + bool empty_before; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + empty_before = !u->requires_mounts_for; + + r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata); + + /* Make it easy to find units with requires_mounts set */ + if (empty_before && u->requires_mounts_for) + LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u); + + return r; +} #define FOLLOW_MAX 8 @@ -2394,6 +2423,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_socket_bindtodevice, "NETWORKINTERFACE" }, { config_parse_usec, "SECONDS" }, { config_parse_path_strv, "PATH [...]" }, + { config_parse_unit_requires_mounts_for, "PATH [...]" }, { config_parse_exec_mount_flags, "MOUNTFLAG [...]" }, { config_parse_unit_string_printf, "STRING" }, { config_parse_timer, "TIMER" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 03e13a9c8..ccc436420 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -83,6 +83,7 @@ int config_parse_unit_memory_limit(const char *filename, unsigned line, const ch int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_requires_mounts_for(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); diff --git a/src/core/manager.h b/src/core/manager.h index 154c1faeb..6d1f5d86c 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -104,6 +104,9 @@ struct Manager { * type we maintain a per type linked list */ LIST_HEAD(Unit, units_by_type[_UNIT_TYPE_MAX]); + /* To optimize iteration of units that have requires_mounts_for set */ + LIST_HEAD(Unit, has_requires_mounts_for); + /* Units that need to be loaded */ LIST_HEAD(Unit, load_queue); /* this is actually more a stack than a queue, but uh. */ diff --git a/src/core/mount.c b/src/core/mount.c index 3357b7df5..5f50d9557 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -263,6 +263,21 @@ static int mount_add_socket_links(Mount *m) { return 0; } +static int mount_add_requires_mounts_links(Mount *m) { + Unit *other; + int r; + + assert(m); + + LIST_FOREACH(has_requires_mounts_for, other, UNIT(m)->manager->has_requires_mounts_for) { + r = unit_add_one_mount_link(other, m); + if (r < 0) + return r; + } + + return 0; +} + static char* mount_test_option(const char *haystack, const char *needle) { struct mntent me; @@ -614,6 +629,10 @@ static int mount_load(Unit *u) { if ((r = mount_add_path_links(m)) < 0) return r; + r = mount_add_requires_mounts_links(m); + if (r < 0) + return r; + if ((r = mount_add_automount_links(m)) < 0) return r; diff --git a/src/core/unit.c b/src/core/unit.c index 491ba3f33..fea75e88f 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -370,6 +370,11 @@ void unit_free(Unit *u) { for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) bidi_set_free(u, u->dependencies[d]); + if (u->requires_mounts_for) { + LIST_REMOVE(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u); + strv_free(u->requires_mounts_for); + } + if (u->type != _UNIT_TYPE_INVALID) LIST_REMOVE(Unit, units_by_type, u->manager->units_by_type[u->type], u); @@ -691,6 +696,18 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->id); } + if (!strv_isempty(u->requires_mounts_for)) { + char **j; + + fprintf(f, + "%s\tRequiresMountsFor:", prefix); + + STRV_FOREACH(j, u->requires_mounts_for) + fprintf(f, " %s", *j); + + fputs("\n", f); + } + if (u->load_state == UNIT_LOADED) { CGroupBonding *b; CGroupAttribute *a; @@ -869,6 +886,12 @@ int unit_load(Unit *u) { if ((r = unit_add_default_dependencies(u)) < 0) goto fail; + if (u->load_state == UNIT_LOADED) { + r = unit_add_mount_links(u); + if (r < 0) + return r; + } + if (u->on_failure_isolate && set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) { @@ -2685,6 +2708,45 @@ void unit_ref_unset(UnitRef *ref) { ref->unit = NULL; } +int unit_add_one_mount_link(Unit *u, Mount *m) { + char **i; + + assert(u); + assert(m); + + if (u->load_state != UNIT_LOADED || + UNIT(m)->load_state != UNIT_LOADED) + return 0; + + STRV_FOREACH(i, u->requires_mounts_for) { + + if (UNIT(m) == u) + continue; + + if (!path_startswith(*i, m->where)) + continue; + + return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true); + } + + return 0; +} + +int unit_add_mount_links(Unit *u) { + Unit *other; + int r; + + assert(u); + + LIST_FOREACH(units_by_type, other, u->manager->units_by_type[UNIT_MOUNT]) { + r = unit_add_one_mount_link(u, MOUNT(other)); + if (r < 0) + return r; + } + + return 0; +} + static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { [UNIT_STUB] = "stub", [UNIT_LOADED] = "loaded", diff --git a/src/core/unit.h b/src/core/unit.h index c2bae0a45..33920892f 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -153,6 +153,8 @@ struct Unit { Set *names; Set *dependencies[_UNIT_DEPENDENCY_MAX]; + char **requires_mounts_for; + char *description; char *fragment_path; /* if loaded from a config file this is the primary path to it */ @@ -186,6 +188,9 @@ struct Unit { /* Per type list */ LIST_FIELDS(Unit, units_by_type); + /* All units which have requires_mounts_for set */ + LIST_FIELDS(Unit, has_requires_mounts_for); + /* Load queue */ LIST_FIELDS(Unit, load_queue); @@ -554,6 +559,9 @@ void unit_ref_unset(UnitRef *ref); #define UNIT_DEREF(ref) ((ref).unit) +int unit_add_one_mount_link(Unit *u, Mount *m); +int unit_add_mount_links(Unit *u); + const char *unit_load_state_to_string(UnitLoadState i); UnitLoadState unit_load_state_from_string(const char *s); diff --git a/units/systemd-random-seed-load.service.in b/units/systemd-random-seed-load.service.in index 636043602..82f49c762 100644 --- a/units/systemd-random-seed-load.service.in +++ b/units/systemd-random-seed-load.service.in @@ -8,10 +8,10 @@ [Unit] Description=Load Random Seed DefaultDependencies=no -Wants=local-fs.target Conflicts=shutdown.target -After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target +After=systemd-readahead-collect.service systemd-readahead-replay.service Before=sysinit.target shutdown.target +RequiresMountsFor=@RANDOM_SEED@ [Service] Type=oneshot diff --git a/units/systemd-random-seed-save.service.in b/units/systemd-random-seed-save.service.in index 219731bae..0ebd07d86 100644 --- a/units/systemd-random-seed-save.service.in +++ b/units/systemd-random-seed-save.service.in @@ -11,6 +11,7 @@ DefaultDependencies=no After=systemd-random-seed-load.service Before=shutdown.target Conflicts=systemd-random-seed-load.service +RequiresMountsFor=@RANDOM_SEED@ [Service] Type=oneshot