| From 8f149756435998d009a8edc7206c5de038e5cbf1 Mon Sep 17 00:00:00 2001 |
| From: Karel Zak <kzak@redhat.com> |
| Date: Mon, 18 May 2015 12:30:37 +0200 |
| Subject: [PATCH] fstab-generator: add x-systemd.requires and |
| x-systemd.requires-mounts-for |
| |
| 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 |
| |
| https://bugzilla.redhat.com/show_bug.cgi?id=812826 |
| https://bugzilla.redhat.com/show_bug.cgi?id=1164334 |
| |
| Conflicts: |
| src/fstab-generator/fstab-generator.c |
| |
| Cherry-picked from: 3519d230c8bafe834b2dac26ace49fcfba139823 |
| Resolves: #1164334 |
| |
| man/systemd.mount.xml | 30 ++++++++++++++ |
| src/fstab-generator/fstab-generator.c | 76 +++++++++++++++++++++++++++++++++++ |
| src/shared/fstab-util.c | 30 ++++++++++++++ |
| src/shared/fstab-util.h | 2 + |
| 4 files changed, 138 insertions(+) |
| |
| diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml |
| index fcb9a4416..8e652e133 100644 |
| |
| |
| @@ -138,6 +138,36 @@ |
| |
| <variablelist class='fstab-options'> |
| |
| + <varlistentry> |
| + <term><option>x-systemd.requires=</option></term> |
| + |
| + <listitem><para>Configures a <varname>Requires=</varname> and |
| + an <varname>After=</varname> dependency between the created |
| + mount unit and another systemd unit, such as a device or mount |
| + unit. The argument should be a unit name, or an absolute path |
| + to a device node or mount point. This option may be specified |
| + more than once. This option is particularly useful for mount |
| + point declarations that need an additional device to be around |
| + (such as an external journal device for journal file systems) |
| + or an additional mount to be in place (such as an overlay file |
| + system that merges multiple mount points). 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 a |
| + <varname>RequiresMountsFor=</varname> dependency between the |
| + created mount unit and other mount units. The argument must be |
| + an 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> |
| |
| diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c |
| index 8e2f522bd..65ed20579 100644 |
| |
| |
| @@ -155,6 +155,64 @@ static bool mount_in_initrd(struct mntent *me) { |
| streq(me->mnt_dir, "/usr"); |
| } |
| |
| +static int write_requires_after(FILE *f, const char *opts) { |
| + _cleanup_strv_free_ char **names = NULL, **units = NULL; |
| + _cleanup_free_ char *res = NULL; |
| + char **s; |
| + int r; |
| + |
| + assert(f); |
| + assert(opts); |
| + |
| + r = fstab_extract_values(opts, "x-systemd.requires", &names); |
| + if (r < 0) |
| + return log_warning_errno(r, "Failed to parse options: %m"); |
| + if (r == 0) |
| + return 0; |
| + |
| + STRV_FOREACH(s, names) { |
| + char *x; |
| + |
| + x = unit_name_mangle_with_suffix(*s, MANGLE_NOGLOB, ".mount"); |
| + if (!x) |
| + return log_error_errno(r, "Failed to generate unit name: %m"); |
| + r = strv_consume(&units, x); |
| + if (r < 0) |
| + return log_oom(); |
| + } |
| + |
| + if (units) { |
| + res = strv_join(units, " "); |
| + if (!res) |
| + return log_oom(); |
| + fprintf(f, "After=%1$s\nRequires=%1$s\n", res); |
| + } |
| + |
| + 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, |
| @@ -225,6 +283,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) |
| @@ -289,6 +356,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 cf317e17b..e231a0ff8 100644 |
| |
| |
| @@ -125,6 +125,36 @@ 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; |
| + int r; |
| + |
| + arg = startswith(*s, name); |
| + if (!arg || *arg != '=') |
| + continue; |
| + r = strv_extend(&res, arg + 1); |
| + if (r < 0) |
| + return r; |
| + } |
| + |
| + *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 9f6b32eaf..387c562a9 100644 |
| |
| |
| @@ -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); |
| } |