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
This commit is contained in:
Karel Zak
2015-05-18 16:07:52 +02:00
committed by Lennart Poettering
parent 06ee4910e4
commit 3519d230c8
4 changed files with 139 additions and 0 deletions
+77
View File
@@ -177,6 +177,65 @@ 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_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;
r = unit_name_mangle_with_suffix(*s, UNIT_NAME_NOGLOB, ".mount", &x);
if (r < 0)
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,
@@ -251,6 +310,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 +383,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",
+30
View File
@@ -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;
+2
View File
@@ -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);
}