[systemd-devel] [PATCH] fstab-generator: add x-systemd.requires and x-systemd.requires-mounts-for

Karel Zak kzak at redhat.com
Fri May 15 03:41:12 PDT 2015


Currently we have no way how to specify dependencies between fstab
entries (or another units) in the /etc/fstab. It means that users are
forced to bypass fstab and write .mount units manually.

The patch introduces new systemd fstab options:

x-systemd.requires=<PATH>

 - to specify dependence an another mount (PATH is translated to unit name)

x-systemd.requires=<UNIT>

 - to specify dependence on arbitrary UNIT

x-systemd.requires-mounts-for=<PATH ...>

 - to specify dependence on another paths, implemented by
   RequiresMountsFor=. The option may be specified more than once.

For example two bind mounts where B depends on A:

 /mnt/test/A    /mnt/test/A     none    bind,defaults
 /mnt/test/A    /mnt/test/B     none    bind,x-systemd.requires=/mnt/test/A

More complex example with overlay FS where one mount point depends on
"low" and "upper" directories:

 /dev/sdc1   /mnt/low    ext4     defaults
 /dev/sdc2   /mnt/high   ext4     defaults
 overlay     /mnt/merged overlay  lowerdir=/mnt/low,upperdir=/mnt/high/data,workdir=/mnt/high/work,x-systemd.requires-mounts-for=/mnt/low,x-systemd.requires-mounts-for=mnt/high

References: https://bugzilla.redhat.com/show_bug.cgi?id=812826
---
v3:
 - add generic fstab_extract_values() to fstab-util.c
 - completely rely on unit_name_mangle_with_suffix()
v2:
 - rename x-systemd.after to x-systemd.requires
 - allow to specify x-systemd.requires-mounts-for= more than once
 - propagate errors
 - fix some typos

 man/systemd.mount.xml                 | 20 +++++++++++
 src/fstab-generator/fstab-generator.c | 63 +++++++++++++++++++++++++++++++++++
 src/shared/fstab-util.c               | 35 +++++++++++++++++++
 src/shared/fstab-util.h               |  2 ++
 4 files changed, 120 insertions(+)

diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
index 862f42e..58ad6a6 100644
--- a/man/systemd.mount.xml
+++ b/man/systemd.mount.xml
@@ -139,6 +139,26 @@
     <variablelist class='fstab-options'>
 
       <varlistentry>
+        <term><option>x-systemd.requires=</option></term>
+
+        <listitem><para>Configures <varname>After=</varname> and <varname>Requires=</varname> dependency
+        between the mount and another mount or systemd unit. The argument is absolute path to
+        another mount point or unit name. See <varname>After=</varname> and <varname>Requires=</varname> in
+        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        for details.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>x-systemd.requires-mounts-for=</option></term>
+
+        <listitem><para>Configures <varname>RequiresMountsFor=</varname> dependency between the mount and
+        another mount. The argument must be absolute path. This option may be specified more than once.
+        See <varname>RequiresMountsFor=</varname> in
+        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        for details.</para></listitem>
+       </varlistentry>
+
+      <varlistentry>
         <term><option>x-systemd.automount</option></term>
 
         <listitem><para>An automount unit will be created for the file
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 167ec60..a162489 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -177,6 +177,51 @@ static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
         return 0;
 }
 
+static int write_requires_after(FILE *f, const char *opts) {
+        _cleanup_free_ char *arg = NULL, *unit = NULL;
+        int r;
+
+        assert(f);
+        assert(opts);
+
+        r = fstab_filter_options(opts, "x-systemd.requires\0", NULL, &arg, NULL);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to parse options: %m");
+        if (r == 0)
+                return 0;
+
+        r = unit_name_mangle_with_suffix(arg, UNIT_NAME_NOGLOB, ".mount", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
+
+        fprintf(f, "After=%1$s\nRequires=%1$s\n", unit);
+
+        return 0;
+}
+
+static int write_requires_mounts_for(FILE *f, const char *opts) {
+        _cleanup_strv_free_ char **paths = NULL;
+        _cleanup_free_ char *res = NULL;
+        int r;
+
+        assert(f);
+        assert(opts);
+
+        r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to parse options: %m");
+        if (r == 0)
+                return 0;
+
+        res = strv_join(paths, " ");
+        if (!res)
+                return log_oom();
+
+        fprintf(f, "RequiresMountsFor=%s\n", res);
+
+        return 0;
+}
+
 static int add_mount(
                 const char *what,
                 const char *where,
@@ -251,6 +296,15 @@ static int add_mount(
         if (post && !noauto && !nofail && !automount)
                 fprintf(f, "Before=%s\n", post);
 
+        if (!automount && opts) {
+                 r = write_requires_after(f, opts);
+                 if (r < 0)
+                         return r;
+                 r = write_requires_mounts_for(f, opts);
+                 if (r < 0)
+                         return r;
+        }
+
         if (passno != 0) {
                 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
                 if (r < 0)
@@ -315,6 +369,15 @@ static int add_mount(
                                 "Before=%s\n",
                                 post);
 
+                if (opts) {
+                        r = write_requires_after(f, opts);
+                        if (r < 0)
+                                return r;
+                        r = write_requires_mounts_for(f, opts);
+                        if (r < 0)
+                                return r;
+                }
+
                 fprintf(f,
                         "[Automount]\n"
                         "Where=%s\n",
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
index cf317e1..e376b54 100644
--- a/src/shared/fstab-util.c
+++ b/src/shared/fstab-util.c
@@ -125,6 +125,41 @@ answer:
         return !!n;
 }
 
+int fstab_extract_values(const char *opts, const char *name, char ***values)
+{
+        _cleanup_strv_free_ char **optsv = NULL, **res = NULL;
+        char **s;
+
+        assert(opts);
+        assert(name);
+        assert(values);
+
+        optsv = strv_split(opts, ",");
+        if (!optsv)
+                return -ENOMEM;
+
+        STRV_FOREACH(s, optsv) {
+                char *arg;
+
+                arg = startswith(*s, name);
+                if (!arg || *arg != '=')
+                        continue;
+
+                arg = strdup(arg + 1);
+                if (!arg)
+                        return -ENOMEM;
+                if (!res)
+                        res = strv_new(arg, NULL);
+                else
+                        strv_push(&res, arg);
+        }
+
+        *values = res;
+        res = NULL;
+
+        return !!*values;
+}
+
 int fstab_find_pri(const char *options, int *ret) {
         _cleanup_free_ char *opt = NULL;
         int r;
diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
index 9f6b32e..387c562 100644
--- a/src/shared/fstab-util.h
+++ b/src/shared/fstab-util.h
@@ -28,6 +28,8 @@
 int fstab_filter_options(const char *opts, const char *names,
                          const char **namefound, char **value, char **filtered);
 
+int fstab_extract_values(const char *opts, const char *name, char ***values);
+
 static inline bool fstab_test_option(const char *opts, const char *names) {
         return !!fstab_filter_options(opts, names, NULL, NULL, NULL);
 }
-- 
2.1.0



More information about the systemd-devel mailing list