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

Reply via email to