Package: systemd Version: 215-5+b1 Severity: important Tags: patch upstream fixed-upstream
systemd ignores the discard option from /etc/fstab for swap entries, interpreting only the priority options. This option is important for virtualization with thin-provisioning, and also for SSD even if some people are discussing its usefulness. Anyway this is supported by the kernel and other init systems (both in Wheezy and Jessie). The problem has been fixed upstream in version 217. I have attached the corresponding patches, they apply fine on the debian package (with only one fuzzy hunk). I have tested them and the resulting packages works correctly. I know Jessie is now frozen, but given it is a regression from Wheezy for people switching to systemd, it would be nice if they can be included in Jessie anyway. -- Package-specific info: -- System Information: Debian Release: jessie/sid APT prefers unstable APT policy: (500, 'unstable') Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 3.16.0-4-amd64 (SMP w/8 CPU cores) Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages systemd depends on: ii acl 2.2.52-2 ii adduser 3.113+nmu3 ii initscripts 2.88dsf-58 ii libacl1 2.2.52-2 ii libaudit1 1:2.4-1 ii libblkid1 2.25.2-2 ii libc6 2.19-13 ii libcap2 1:2.24-6 ii libcap2-bin 1:2.24-6 ii libcryptsetup4 2:1.6.6-3 ii libgcrypt20 1.6.2-4 ii libkmod2 18-3 ii liblzma5 5.1.1alpha+20120614-2+b1 ii libpam0g 1.1.8-3.1 ii libselinux1 2.3-2 ii libsystemd0 215-5+b1 ii sysv-rc 2.88dsf-58 ii udev 215-5+b1 ii util-linux 2.25.2-2 Versions of packages systemd recommends: ii dbus 1.8.10-1 ii libpam-systemd 215-5+b1 Versions of packages systemd suggests: pn systemd-ui <none> -- Configuration Files: /etc/systemd/timesyncd.conf changed [not included] -- no debconf information
>From 86b23b07c96b185126bfbf217227dad362a20c25 Mon Sep 17 00:00:00 2001 From: Jan Synacek <jsyna...@redhat.com> Date: Wed, 24 Sep 2014 14:29:05 +0200 Subject: [PATCH] swap: introduce Discard property Process possible "discard" values from /etc/fstab. --- man/systemd.swap.xml | 14 ++++++++++ src/core/execute.c | 25 ++++++++++++++++++ src/core/execute.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/swap.c | 49 +++++++++++++++++++++++------------ src/core/swap.h | 1 + src/fstab-generator/fstab-generator.c | 10 +++++++ 7 files changed, 84 insertions(+), 17 deletions(-) diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml index 62a4d08..481dc52 100644 --- a/man/systemd.swap.xml +++ b/man/systemd.swap.xml @@ -171,6 +171,20 @@ </varlistentry> <varlistentry> + <term><varname>Discard=</varname></term> + + <listitem><para>Enable discards, if the swap + backing device supports the discard or trim + operation. Can be one of <literal>none</literal>, + <literal>once</literal>, <literal>pages</literal> + or <literal>all</literal>. Defaults to + <literal>none</literal>. (See + <citerefentry><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry> + for more information.) + </para></listitem> + </varlistentry> + + <varlistentry> <term><varname>TimeoutSec=</varname></term> <listitem><para>Configures the time to wait for the swapon command to diff --git a/src/core/execute.c b/src/core/execute.c index 8c9dfde..07ec7a2 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2566,6 +2566,31 @@ int exec_command_set(ExecCommand *c, const char *path, ...) { return 0; } +int exec_command_append(ExecCommand *c, const char *path, ...) { + va_list ap; + char **l; + int r; + + assert(c); + assert(path); + + va_start(ap, path); + l = strv_new_ap(path, ap); + va_end(ap); + + if (!l) + return -ENOMEM; + + r = strv_extend_strv(&c->argv, l); + if (r < 0) { + strv_free(l); + return r; + } + + return 0; +} + + static int exec_runtime_allocate(ExecRuntime **rt) { if (*rt) diff --git a/src/core/execute.h b/src/core/execute.h index 6f35736..2694315 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -233,6 +233,7 @@ void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix); void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix); void exec_command_append_list(ExecCommand **l, ExecCommand *e); int exec_command_set(ExecCommand *c, const char *path, ...); +int exec_command_append(ExecCommand *c, const char *path, ...); void exec_context_init(ExecContext *c); void exec_context_done(ExecContext *c); diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 050c5d8..8805411 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -297,6 +297,7 @@ Automount.DirectoryMode, config_parse_mode, 0, m4_dnl Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what) Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority) +Swap.Discard, config_parse_string, 0, offsetof(Swap, parameters_fragment.discard) Swap.TimeoutSec, config_parse_sec, 0, offsetof(Swap, timeout_usec) EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl CGROUP_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl diff --git a/src/core/swap.c b/src/core/swap.c index b88a914..2e12824 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -152,6 +152,9 @@ static void swap_done(Unit *u) { free(s->parameters_fragment.what); s->parameters_fragment.what = NULL; + free(s->parameters_fragment.discard); + s->parameters_fragment.discard = NULL; + s->exec_runtime = exec_runtime_unref(s->exec_runtime); exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX); s->control_command = NULL; @@ -602,10 +605,12 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sPriority: %i\n" "%sNoAuto: %s\n" - "%sNoFail: %s\n", + "%sNoFail: %s\n" + "%sDiscard: %s\n", prefix, p->priority, prefix, yes_no(p->noauto), - prefix, yes_no(p->nofail)); + prefix, yes_no(p->nofail), + prefix, p->discard); if (s->control_pid > 0) fprintf(f, @@ -734,36 +739,46 @@ fail: static void swap_enter_activating(Swap *s) { int r, priority; + char *discard; assert(s); s->control_command_id = SWAP_EXEC_ACTIVATE; s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE; - if (s->from_fragment) + if (s->from_fragment) { priority = s->parameters_fragment.priority; - else + discard = s->parameters_fragment.discard; + } else { priority = -1; + discard = NULL; + } + + r = exec_command_set(s->control_command, "/sbin/swapon", NULL); + if (r < 0) + goto fail; if (priority >= 0) { char p[DECIMAL_STR_MAX(int)]; sprintf(p, "%i", priority); + r = exec_command_append(s->control_command, "-p", p, NULL); + if (r < 0) + goto fail; + } - r = exec_command_set( - s->control_command, - "/sbin/swapon", - "-p", - p, - s->what, - NULL); - } else - r = exec_command_set( - s->control_command, - "/sbin/swapon", - s->what, - NULL); + if (discard && !streq(discard, "none")) { + const char *discard_arg = "--discard"; + + if (!streq(discard, "all")) + discard_arg = strappenda("--discard=", discard); + + r = exec_command_append(s->control_command, discard_arg, NULL); + if (r < 0) + goto fail; + } + r = exec_command_append(s->control_command, s->what, NULL); if (r < 0) goto fail; diff --git a/src/core/swap.h b/src/core/swap.h index f2ae49b..3482d65 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -63,6 +63,7 @@ typedef enum SwapResult { typedef struct SwapParameters { char *what; + char *discard; int priority; bool noauto:1; bool nofail:1; diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 2c38ab9..5569325 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -73,6 +73,8 @@ static int mount_find_pri(struct mntent *me, int *ret) { static int add_swap(const char *what, struct mntent *me) { _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL; _cleanup_fclose_ FILE *f = NULL; + char *discard = NULL; + bool noauto; int r, pri = -1; @@ -118,6 +120,14 @@ static int add_swap(const char *what, struct mntent *me) { "What=%s\n", what); + discard = mount_test_option(me->mnt_opts, "discard"); + if (discard) { + discard = strpbrk(discard, "="); + fprintf(f, + "Discard=%s\n", + discard ? discard+1 : "all"); + } + if (pri >= 0) fprintf(f, "Priority=%i\n", -- 2.1.3
>From 4f52d3fe2da7c3449b7fbfaa7c64a83354d3b56c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbys...@in.waw.pl> Date: Sat, 27 Sep 2014 22:02:04 -0400 Subject: [PATCH] fstab-generator: properly deal with discard as non-last option Previous code would only return correct results when discard was the last option. While at it, avoid incorrect behaviour for (invalid) 'pri' option not followed by '=...', and also do not return -1 as the error code. --- src/core/swap.c | 2 +- src/fstab-generator/fstab-generator.c | 73 ++++++++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/src/core/swap.c b/src/core/swap.c index 2e12824..36c9e02 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -610,7 +610,7 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) { prefix, p->priority, prefix, yes_no(p->noauto), prefix, yes_no(p->nofail), - prefix, p->discard); + prefix, p->discard ?: "none"); if (s->control_pid > 0) fprintf(f, diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 5569325..5dafcba 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -46,34 +46,70 @@ static int arg_root_rw = -1; static int mount_find_pri(struct mntent *me, int *ret) { - char *end, *pri; + char *end, *opt; unsigned long r; assert(me); assert(ret); - pri = hasmntopt(me, "pri"); - if (!pri) + opt = hasmntopt(me, "pri"); + if (!opt) return 0; - pri += 4; + opt += strlen("pri"); + + if (*opt != '=') + return -EINVAL; errno = 0; - r = strtoul(pri, &end, 10); + r = strtoul(opt + 1, &end, 10); if (errno > 0) return -errno; - if (end == pri || (*end != ',' && *end != 0)) + if (end == opt + 1 || (*end != ',' && *end != 0)) return -EINVAL; *ret = (int) r; return 1; } +static int mount_find_discard(struct mntent *me, char **ret) { + char *opt, *ans; + size_t len; + + assert(me); + assert(ret); + + opt = hasmntopt(me, "discard"); + if (!opt) + return 0; + + opt += strlen("discard"); + + if (*opt == ',' || *opt == '\0') + ans = strdup("all"); + else { + if (*opt != '=') + return -EINVAL; + + len = strcspn(opt + 1, ","); + if (len == 0) + return -EINVAL; + + ans = strndup(opt + 1, len); + } + + if (!ans) + return -ENOMEM; + + *ret = ans; + return 1; +} + static int add_swap(const char *what, struct mntent *me) { _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL; _cleanup_fclose_ FILE *f = NULL; - char *discard = NULL; + _cleanup_free_ char *discard = NULL; bool noauto; int r, pri = -1; @@ -89,7 +125,13 @@ static int add_swap(const char *what, struct mntent *me) { r = mount_find_pri(me, &pri); if (r < 0) { log_error("Failed to parse priority"); - return pri; + return r; + } + + r = mount_find_discard(me, &discard); + if (r < 0) { + log_error("Failed to parse discard"); + return r; } noauto = !!hasmntopt(me, "noauto"); @@ -120,18 +162,11 @@ static int add_swap(const char *what, struct mntent *me) { "What=%s\n", what); - discard = mount_test_option(me->mnt_opts, "discard"); - if (discard) { - discard = strpbrk(discard, "="); - fprintf(f, - "Discard=%s\n", - discard ? discard+1 : "all"); - } - if (pri >= 0) - fprintf(f, - "Priority=%i\n", - pri); + fprintf(f, "Priority=%i\n", pri); + + if (discard) + fprintf(f, "Discard=%s\n", discard); fflush(f); if (ferror(f)) { -- 2.1.3
>From cdc8982030271785d650af410230397bbb5a4be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbys...@in.waw.pl> Date: Sun, 28 Sep 2014 10:37:52 -0400 Subject: [PATCH] core/swap: follow the configured unit by default Phenomenon: parameters configured in /etc/fstab for swap units are ignored. E.g. pri= settings have no effect when systemd starts swap units. What is even more confusing, .swap units for the name used in /etc/fstab initially show proper values for Priority=, but after starting them, they are re-initalized from /proc/swaps and show the -1 value from /proc/swaps. Change swap units to follow the original configured unit. This way proper settings are used when starting the swap. --- src/core/swap.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/core/swap.c b/src/core/swap.c index 36c9e02..ef90d0e 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1208,11 +1208,25 @@ static Unit *swap_following(Unit *u) { assert(s); - if (streq_ptr(s->what, s->devnode)) + /* If the user configured the swap through /etc/fstab or + * a device unit, follow that. */ + + if (s->from_fragment) return NULL; - /* Make everybody follow the unit that's named after the swap - * device in the kernel */ + LIST_FOREACH_AFTER(same_devnode, other, s) + if (other->from_fragment) + return UNIT(other); + + LIST_FOREACH_BEFORE(same_devnode, other, s) + if (other->from_fragment) + return UNIT(other); + + /* Otherwise make everybody follow the unit that's named after + * the swap device in the kernel */ + + if (streq_ptr(s->what, s->devnode)) + return NULL; LIST_FOREACH_AFTER(same_devnode, other, s) if (streq_ptr(other->what, other->devnode)) @@ -1225,6 +1239,7 @@ static Unit *swap_following(Unit *u) { first = other; } + /* Fall back to the first on the list */ return UNIT(first); } -- 2.1.3
>From 4afbccded23f5144e39a7f7b243393799186ba39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbys...@in.waw.pl> Date: Sun, 28 Sep 2014 22:13:07 -0400 Subject: [PATCH] core/swap: advertise Discard over dbus --- src/core/dbus-swap.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c index 93eae53..c854716 100644 --- a/src/core/dbus-swap.c +++ b/src/core/dbus-swap.c @@ -55,12 +55,36 @@ static int property_get_priority( return sd_bus_message_append(reply, "i", p); } +static int property_get_discard( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Swap *s = SWAP(userdata); + const char *p; + + assert(bus); + assert(reply); + assert(s); + + if (s->from_fragment) + p = s->parameters_fragment.discard ?: "none"; + else + p = "none"; + return sd_bus_message_append(reply, "s", p); +} + static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, swap_result, SwapResult); const sd_bus_vtable bus_swap_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("What", "s", NULL, offsetof(Swap, what), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Priority", "i", property_get_priority, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Discard", "s", property_get_discard, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Swap, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Swap, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Swap, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), -- 2.1.3
>From 3018d31238caabc2e204aa161e647dc1c1b5d1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbys...@in.waw.pl> Date: Thu, 2 Oct 2014 00:11:36 -0400 Subject: [PATCH] core/swap: only make configured units part of swap.target We used to make all .swap units either RequiredBy=swap.target or WantedBy=swap.target. But swap.target should be the "configured swap units", either through /etc/fstab or non-generated .swap units. It is surprising when systemd starts treating a swap device that was possibly temporarily enabled as a hard dependency for other units. So do not add dependencies with swap.target for units gleaned from /proc/swaps. Similarly, we added dependencies for all aliases of the device name, which clutters up the dependency graph but does not seem to bring any value, since the status of those following units is consistent with the main one anyway. This should be a fix for [1], and it seems the right thing to do anyway. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1114786 --- src/core/swap.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/core/swap.c b/src/core/swap.c index ef90d0e..b2ca048 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -213,7 +213,7 @@ static int swap_add_device_links(Swap *s) { } static int swap_add_default_dependencies(Swap *s) { - bool nofail = false, noauto = false; + bool nofail, noauto; int r; assert(s); @@ -228,23 +228,25 @@ static int swap_add_default_dependencies(Swap *s) { if (r < 0) return r; - if (s->from_fragment) { - SwapParameters *p = &s->parameters_fragment; + if (!s->from_fragment) + /* The swap unit can either be for an alternative device name, in which + * case we don't need to add the dependency on swap.target because this unit + * is following a different unit which will have this dependency added, + * or it can be derived from /proc/swaps, in which case it was started + * manually, and should not become a dependency of swap.target. */ + return 0; - nofail = p->nofail; - noauto = p->noauto; - } + nofail = s->parameters_fragment.nofail; + noauto = s->parameters_fragment.noauto; if (!noauto) { if (nofail) r = unit_add_dependency_by_name_inverse(UNIT(s), UNIT_WANTS, SPECIAL_SWAP_TARGET, NULL, true); else r = unit_add_two_dependencies_by_name_inverse(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SWAP_TARGET, NULL, true); - if (r < 0) - return r; } - return 0; + return r < 0 ? r : 0; } static int swap_verify(Swap *s) { -- 2.1.3
>From 47cb901e38cd7092576fc8e76cc4a14f39bf719d Mon Sep 17 00:00:00 2001 From: Lennart Poettering <lenn...@poettering.net> Date: Tue, 28 Oct 2014 14:24:46 +0100 Subject: [PATCH] swap: replace Discard= setting by a more generic Options= setting For now, it's systemd itself that parses the options string, but as soon as util-linux' swapon can take the option string directly with -o we should pass it on unmodified. --- man/systemd.swap.xml | 16 +++--- src/core/dbus-swap.c | 13 +++-- src/core/load-fragment-gperf.gperf.m4 | 2 +- src/core/swap.c | 91 ++++++++++++++++++++++++++++++----- src/core/swap.h | 2 +- src/fstab-generator/fstab-generator.c | 56 +++------------------ 6 files changed, 103 insertions(+), 77 deletions(-) diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml index 00fafdc..44c16e7 100644 --- a/man/systemd.swap.xml +++ b/man/systemd.swap.xml @@ -171,14 +171,14 @@ </varlistentry> <varlistentry> - <term><varname>Discard=</varname></term> - - <listitem><para>Enable discards, if the swap - backing device supports the discard or trim - operation. Can be one of <literal>none</literal>, - <literal>once</literal>, <literal>pages</literal> - or <literal>all</literal>. Defaults to - <literal>none</literal>. (See + <term><varname>Options=</varname></term> + + <listitem><para>May contain an option + string for the swap device. This may + be used for controlling discard + options among other functionality, if + the swap backing device supports the + discard or trim operation. (See <citerefentry><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry> for more information.) </para></listitem> diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c index c854716..1e7f66d 100644 --- a/src/core/dbus-swap.c +++ b/src/core/dbus-swap.c @@ -55,7 +55,7 @@ static int property_get_priority( return sd_bus_message_append(reply, "i", p); } -static int property_get_discard( +static int property_get_options( sd_bus *bus, const char *path, const char *interface, @@ -65,17 +65,16 @@ static int property_get_discard( sd_bus_error *error) { Swap *s = SWAP(userdata); - const char *p; + const char *options = NULL; assert(bus); assert(reply); assert(s); if (s->from_fragment) - p = s->parameters_fragment.discard ?: "none"; - else - p = "none"; - return sd_bus_message_append(reply, "s", p); + options = s->parameters_fragment.options; + + return sd_bus_message_append(reply, "s", options); } static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, swap_result, SwapResult); @@ -84,7 +83,7 @@ const sd_bus_vtable bus_swap_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("What", "s", NULL, offsetof(Swap, what), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Priority", "i", property_get_priority, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), - SD_BUS_PROPERTY("Discard", "s", property_get_discard, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("Options", "s", property_get_options, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Swap, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Swap, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Swap, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 26d40fb..ca01394 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -299,7 +299,7 @@ Automount.DirectoryMode, config_parse_mode, 0, m4_dnl Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what) Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority) -Swap.Discard, config_parse_string, 0, offsetof(Swap, parameters_fragment.discard) +Swap.Options, config_parse_string, 0, offsetof(Swap, parameters_fragment.options) Swap.TimeoutSec, config_parse_sec, 0, offsetof(Swap, timeout_usec) EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl CGROUP_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl diff --git a/src/core/swap.c b/src/core/swap.c index b2ca048..1204386 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -152,8 +152,8 @@ static void swap_done(Unit *u) { free(s->parameters_fragment.what); s->parameters_fragment.what = NULL; - free(s->parameters_fragment.discard); - s->parameters_fragment.discard = NULL; + free(s->parameters_fragment.options); + s->parameters_fragment.options = NULL; s->exec_runtime = exec_runtime_unref(s->exec_runtime); exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX); @@ -608,11 +608,11 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) { "%sPriority: %i\n" "%sNoAuto: %s\n" "%sNoFail: %s\n" - "%sDiscard: %s\n", + "%sOptions: %s\n", prefix, p->priority, prefix, yes_no(p->noauto), prefix, yes_no(p->nofail), - prefix, p->discard ?: "none"); + prefix, strempty(p->options)); if (s->control_pid > 0) fprintf(f, @@ -739,9 +739,74 @@ fail: swap_enter_dead(s, SWAP_FAILURE_RESOURCES); } +static int mount_find_pri(const char *options, int *ret) { + const char *opt; + char *end; + unsigned long r; + + assert(ret); + + if (!options) + return 0; + + opt = mount_test_option(options, "pri"); + if (!opt) + return 0; + + opt += strlen("pri"); + if (*opt != '=') + return -EINVAL; + + errno = 0; + r = strtoul(opt + 1, &end, 10); + if (errno > 0) + return -errno; + + if (end == opt + 1 || (*end != ',' && *end != 0)) + return -EINVAL; + + *ret = (int) r; + return 1; +} + +static int mount_find_discard(const char *options, char **ret) { + const char *opt; + char *ans; + size_t len; + + assert(ret); + + if (!options) + return 0; + + opt = mount_test_option(options, "discard"); + if (!opt) + return 0; + + opt += strlen("discard"); + if (*opt == ',' || *opt == '\0') + ans = strdup("all"); + else { + if (*opt != '=') + return -EINVAL; + + len = strcspn(opt + 1, ","); + if (len == 0) + return -EINVAL; + + ans = strndup(opt + 1, len); + } + + if (!ans) + return -ENOMEM; + + *ret = ans; + return 1; +} + static void swap_enter_activating(Swap *s) { - int r, priority; - char *discard; + _cleanup_free_ char *discard = NULL; + int r, priority = -1; assert(s); @@ -749,11 +814,11 @@ static void swap_enter_activating(Swap *s) { s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE; if (s->from_fragment) { + mount_find_discard(s->parameters_fragment.options, &discard); + priority = s->parameters_fragment.priority; - discard = s->parameters_fragment.discard; - } else { - priority = -1; - discard = NULL; + if (priority < 0) + mount_find_pri(s->parameters_fragment.options, &priority); } r = exec_command_set(s->control_command, "/sbin/swapon", NULL); @@ -770,9 +835,11 @@ static void swap_enter_activating(Swap *s) { } if (discard && !streq(discard, "none")) { - const char *discard_arg = "--discard"; + const char *discard_arg; - if (!streq(discard, "all")) + if (streq(discard, "all")) + discard_arg = "--discard"; + else discard_arg = strappenda("--discard=", discard); r = exec_command_append(s->control_command, discard_arg, NULL); diff --git a/src/core/swap.h b/src/core/swap.h index 3482d65..053c849 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -63,7 +63,7 @@ typedef enum SwapResult { typedef struct SwapParameters { char *what; - char *discard; + char *options; int priority; bool noauto:1; bool nofail:1; diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 32a8f9b..e257c12 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -47,7 +47,6 @@ static char *arg_usr_what = NULL; static char *arg_usr_fstype = NULL; static char *arg_usr_options = NULL; - static int mount_find_pri(struct mntent *me, int *ret) { char *end, *opt; unsigned long r; @@ -60,7 +59,6 @@ static int mount_find_pri(struct mntent *me, int *ret) { return 0; opt += strlen("pri"); - if (*opt != '=') return -EINVAL; @@ -76,43 +74,9 @@ static int mount_find_pri(struct mntent *me, int *ret) { return 1; } -static int mount_find_discard(struct mntent *me, char **ret) { - char *opt, *ans; - size_t len; - - assert(me); - assert(ret); - - opt = hasmntopt(me, "discard"); - if (!opt) - return 0; - - opt += strlen("discard"); - - if (*opt == ',' || *opt == '\0') - ans = strdup("all"); - else { - if (*opt != '=') - return -EINVAL; - - len = strcspn(opt + 1, ","); - if (len == 0) - return -EINVAL; - - ans = strndup(opt + 1, len); - } - - if (!ans) - return -ENOMEM; - - *ret = ans; - return 1; -} - static int add_swap(const char *what, struct mntent *me) { _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL; _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *discard = NULL; bool noauto; int r, pri = -1; @@ -131,12 +95,6 @@ static int add_swap(const char *what, struct mntent *me) { return r; } - r = mount_find_discard(me, &discard); - if (r < 0) { - log_error("Failed to parse discard"); - return r; - } - noauto = !!hasmntopt(me, "noauto"); name = unit_name_from_path(what, ".swap"); @@ -165,16 +123,18 @@ static int add_swap(const char *what, struct mntent *me) { "What=%s\n", what); + /* Note that we currently pass the priority field twice, once + * in Priority=, and once in Options= */ if (pri >= 0) fprintf(f, "Priority=%i\n", pri); - if (discard) - fprintf(f, "Discard=%s\n", discard); + if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults")) + fprintf(f, "Options=%s\n", me->mnt_opts); - fflush(f); - if (ferror(f)) { - log_error("Failed to write unit file %s: %m", unit); - return -errno; + r = fflush_and_check(f); + if (r < 0) { + log_error("Failed to write unit file %s: %s", unit, strerror(-r)); + return r; } /* use what as where, to have a nicer error message */ -- 2.1.3