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 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel