summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2012-04-29 14:26:07 +0200
committerLennart Poettering <lennart@poettering.net>2012-04-30 10:52:07 +0200
commit7c8fa05c4d5d01748ff2a04edb882afb3119b7d7 (patch)
treea3dc4d052ac25915fa0b23bf695891d5989aff7e
parenta8ad0f89286b878cbe1f330f72abd2d22813f8ea (diff)
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.
-rw-r--r--Makefile.am1
-rw-r--r--man/systemd.unit.xml12
-rw-r--r--src/core/dbus-unit.c1
-rw-r--r--src/core/dbus-unit.h1
-rw-r--r--src/core/load-fragment-gperf.gperf.m41
-rw-r--r--src/core/load-fragment.c30
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/core/manager.h3
-rw-r--r--src/core/mount.c19
-rw-r--r--src/core/unit.c62
-rw-r--r--src/core/unit.h8
-rw-r--r--units/systemd-random-seed-load.service.in4
-rw-r--r--units/systemd-random-seed-save.service.in1
13 files changed, 142 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am
index 41fd773795..e1501aecf0 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 12416fa317..c81c7a30b0 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -526,6 +526,18 @@
</varlistentry>
<varlistentry>
+ <term><varname>RequiresMountsFor=</varname></term>
+
+ <listitem><para>Takes a space
+ separated list of paths. Automatically
+ adds dependencies of type
+ <varname>Requires=</varname> and
+ <varname>After=</varname> for all
+ mount units required to access the
+ specified path.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>OnFailureIsolate=</varname></term>
<listitem><para>Takes a boolean
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 0484d75829..b8d661698b 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 e6d549c0fb..d22802d274 100644
--- a/src/core/dbus-unit.h
+++ b/src/core/dbus-unit.h
@@ -85,6 +85,7 @@
" <property name=\"TriggeredBy\" type=\"as\" access=\"read\"/>\n" \
" <property name=\"PropagateReloadTo\" type=\"as\" access=\"read\"/>\n" \
" <property name=\"PropagateReloadFrom\" type=\"as\" access=\"read\"/>\n" \
+ " <property name=\"RequiresMountsFor\" type=\"as\" access=\"read\"/>\n" \
" <property name=\"Description\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"LoadState\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"ActiveState\" type=\"s\" access=\"read\"/>\n" \
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index c65db30fff..d929273877 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 1665be82a0..d24919f998 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 03e13a9c8c..ccc436420e 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 154c1faeb7..6d1f5d86c2 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 3357b7df5b..5f50d9557a 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 491ba3f33f..fea75e88fe 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 c2bae0a45c..33920892fd 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 6360436021..82f49c762b 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 219731bae5..0ebd07d868 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