A System and Service Manager
CentOS Sources
2018-10-30 aed85756ad77ebf2bc728449578b90c56d588c09
import systemd-219-62.el7
47 files added
4 files renamed
1 files modified
4023 ■■■■■ changed files
SOURCES/0614-tmpfiles-don-t-skip-cleanup-of-read-only-root-owned-.patch 41 ●●●●● patch | view | raw | blame | history
SOURCES/0615-timer-we-already-got-the-trigger-before-no-need-to-c.patch 28 ●●●●● patch | view | raw | blame | history
SOURCES/0616-doc-fix-links-to-binfmt_misc-kernel-documentation.patch 79 ●●●●● patch | view | raw | blame | history
SOURCES/0617-man-udevadm-remove-superfluous-version-from-subcomma.patch 27 ●●●●● patch | view | raw | blame | history
SOURCES/0618-man-udevadm-correctly-show-the-short-version-of-exit.patch 23 ●●●●● patch | view | raw | blame | history
SOURCES/0619-core-timer-downgrade-message-about-random-time-addit.patch 30 ●●●●● patch | view | raw | blame | history
SOURCES/0620-fd-util-add-new-acquire_data_fd-API-helper.patch 277 ●●●●● patch | view | raw | blame | history
SOURCES/0621-systemd-analyze-make-dump-work-for-large-of-units.patch 189 ●●●●● patch | view | raw | blame | history
SOURCES/0622-use-max.-message-size-allowed-by-DBus-spec-8936.patch 27 ●●●●● patch | view | raw | blame | history
SOURCES/0623-cryptsetup-support-LUKS2-on-disk-format.patch 77 ●●●●● patch | view | raw | blame | history
SOURCES/0624-core-scope-fix-missing-fragment_path.patch 56 ●●●●● patch | view | raw | blame | history
SOURCES/0625-units-don-t-put-udev-to-its-own-mount-namespace-with.patch 27 ●●●●● patch | view | raw | blame | history
SOURCES/0626-rules-disable-support-for-Lenovo-IR-cameras.patch 37 ●●●●● patch | view | raw | blame | history
SOURCES/0627-core-make-sure-systemctl-reload-or-try-restart-is-ac.patch 92 ●●●●● patch | view | raw | blame | history
SOURCES/0628-core-fix-confusing-logging-of-instantaneous-jobs.patch 247 ●●●●● patch | view | raw | blame | history
SOURCES/0629-core-correct-return-value-from-reload-methods.patch 43 ●●●●● patch | view | raw | blame | history
SOURCES/0630-core-always-try-harder-to-get-unit-status-message-fo.patch 91 ●●●●● patch | view | raw | blame | history
SOURCES/0631-core-unit_get_status_message_format-never-returns-NU.patch 63 ●●●●● patch | view | raw | blame | history
SOURCES/0632-core-try-harder-to-get-job-completion-messages-too.patch 254 ●●●●● patch | view | raw | blame | history
SOURCES/0633-core-remove-generic-job-completion-messages-from-uni.patch 132 ●●●●● patch | view | raw | blame | history
SOURCES/0634-core-do-not-log-done-failed-condition-jobs-as-if-uni.patch 67 ●●●●● patch | view | raw | blame | history
SOURCES/0635-core-log-completion-of-remaining-job-types.patch 42 ●●●●● patch | view | raw | blame | history
SOURCES/0636-core-adjust-job-completion-message-log-levels.patch 75 ●●●●● patch | view | raw | blame | history
SOURCES/0637-mount-add-new-LazyUnmount-setting-for-mount-units-ma.patch 111 ●●●●● patch | view | raw | blame | history
SOURCES/0638-rules-Add-MODEL_ID-for-NVMe-device-7037.patch 42 ●●●●● patch | view | raw | blame | history
SOURCES/0639-umount-always-use-MNT_FORCE-in-umount_all-7213.patch 2 ●●● patch | view | raw | blame | history
SOURCES/0640-core-Implement-timeout-based-umount-remount-limit.patch 21 ●●●● patch | view | raw | blame | history
SOURCES/0641-core-Implement-sync_with_progress.patch 2 ●●● patch | view | raw | blame | history
SOURCES/0642-journal-fix-HMAC-calculation-when-appending-a-data-o.patch 48 ●●●●● patch | view | raw | blame | history
SOURCES/0643-journal-forward-messages-from-dev-log-unmodified-to-.patch 135 ●●●●● patch | view | raw | blame | history
SOURCES/0644-tmpfiles-use-safe_glob.patch 158 ●●●●● patch | view | raw | blame | history
SOURCES/0645-Fix-SELinux-labels-in-cgroup-filesystem-root-directo.patch 52 ●●●●● patch | view | raw | blame | history
SOURCES/0646-core-dont-t-remount-sys-fs-cgroup-for-relabel-if-not.patch 91 ●●●●● patch | view | raw | blame | history
SOURCES/0647-fix-race-between-daemon-reload-and-other-commands.patch 188 ●●●●● patch | view | raw | blame | history
SOURCES/0648-core-delay-adding-target-dependencies-until-all-unit.patch 223 ●●●●● patch | view | raw | blame | history
SOURCES/0649-man-correct-the-meaning-of-TimeoutStopSec.patch 35 ●●●●● patch | view | raw | blame | history
SOURCES/0650-rules-mark-hotplugged-memory-as-movable.patch 32 ●●●●● patch | view | raw | blame | history
SOURCES/0651-udev-add-ID_INPUT_SWITCH-for-devices-with-switch-cap.patch 27 ●●●●● patch | view | raw | blame | history
SOURCES/0652-rules-disable-support-for-Dell-IR-cameras.patch 32 ●●●●● patch | view | raw | blame | history
SOURCES/0653-rpm-fix-systemd_user_post-macro.patch 36 ●●●●● patch | view | raw | blame | history
SOURCES/0654-rpm-remove-confusing-user-before-global.patch 35 ●●●●● patch | view | raw | blame | history
SOURCES/0655-automount-handle-state-changes-of-the-corresponding-.patch 4 ●●●● patch | view | raw | blame | history
SOURCES/0656-man-document-that-SIGCONT-always-follows-SIGTERM.patch 32 ●●●●● patch | view | raw | blame | history
SOURCES/0657-rules-add-udev-rule-that-automatically-offline-HW-at.patch 46 ●●●●● patch | view | raw | blame | history
SOURCES/0658-Revert-rules-mark-hotplugged-memory-as-movable.patch 25 ●●●●● patch | view | raw | blame | history
SOURCES/0659-rules-implement-new-memory-hotplug-policy.patch 49 ●●●●● patch | view | raw | blame | history
SOURCES/0660-Revert-rules-add-udev-rule-that-automatically-offlin.patch 48 ●●●●● patch | view | raw | blame | history
SOURCES/0661-cryptsetup-generator-introduce-basic-keydev-support.patch 258 ●●●●● patch | view | raw | blame | history
SOURCES/0662-cryptsetup-generator-don-t-return-error-if-target-di.patch 38 ●●●●● patch | view | raw | blame | history
SOURCES/0663-cryptsetup-generator-allow-whitespace-characters-in-.patch 62 ●●●●● patch | view | raw | blame | history
SOURCES/0664-Make-sure-the-mount-units-pulled-by-RequiresMountsFo.patch 50 ●●●●● patch | view | raw | blame | history
SPECS/systemd.spec 117 ●●●● patch | view | raw | blame | history
SOURCES/0614-tmpfiles-don-t-skip-cleanup-of-read-only-root-owned-.patch
New file
@@ -0,0 +1,41 @@
From 38c68c3b13e278a77a4bd02d97f6b3f81db46288 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Tue, 27 Mar 2018 10:34:06 +0200
Subject: [PATCH] tmpfiles: don't skip cleanup of read-only root owned files if
 TMPFILES_AGE_ALL is set
Resolves: #1533638
---
 src/tmpfiles/tmpfiles.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index ddb274fce..5212d72f5 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -367,6 +367,7 @@ static int dir_cleanup(
                 struct stat s;
                 usec_t age;
                 _cleanup_free_ char *sub_path = NULL;
+                const char *e;
                 if (STR_IN_SET(dent->d_name, ".", ".."))
                         continue;
@@ -399,10 +400,13 @@ static int dir_cleanup(
                         continue;
                 }
-                /* Do not delete read-only files owned by root */
-                if (s.st_uid == 0 && !(s.st_mode & S_IWUSR)) {
-                        log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p, dent->d_name);
-                        continue;
+                e = getenv("TMPFILES_AGE_ALL");
+                if (!e) {
+                        /* Do not delete read-only files owned by root */
+                        if (s.st_uid == 0 && !(s.st_mode & S_IWUSR)) {
+                                log_debug("Ignoring \"%s/%s\": read-only and owner by root.", p, dent->d_name);
+                                continue;
+                        }
                 }
                 sub_path = strjoin(p, "/", dent->d_name, NULL);
SOURCES/0615-timer-we-already-got-the-trigger-before-no-need-to-c.patch
New file
@@ -0,0 +1,28 @@
From cfa30c21a4e5324a43695fcf43fe984aed2a8a8e Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
Date: Mon, 26 Feb 2018 13:56:52 +0100
Subject: [PATCH] timer: we already got the trigger before, no need to call
 UNIT_TRIGGER again
In d7b2f6ef we forgot to replace this occurence.
rhel-only
Resolves: #1549119
---
 src/core/timer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/timer.c b/src/core/timer.c
index 91d8db67e..0a264f60d 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -421,7 +421,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
                         case TIMER_UNIT_INACTIVE:
-                                base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
+                                base = trigger->inactive_enter_timestamp.monotonic;
                                 if (base <= 0)
                                         base = t->last_trigger.monotonic;
SOURCES/0616-doc-fix-links-to-binfmt_misc-kernel-documentation.patch
New file
@@ -0,0 +1,79 @@
From fdc7b6b2af0b80e13bebae8d2f461f54cb71c9d2 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Fri, 27 Apr 2018 08:57:08 +0200
Subject: [PATCH] doc: fix links to binfmt_misc kernel documentation
Resolves: #1572244
---
 man/binfmt.d.xml                        | 2 +-
 src/test/test-util.c                    | 2 +-
 units/proc-sys-fs-binfmt_misc.automount | 2 +-
 units/proc-sys-fs-binfmt_misc.mount     | 2 +-
 units/systemd-binfmt.service.in         | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/man/binfmt.d.xml b/man/binfmt.d.xml
index 5b63cfb4c..1a57517d0 100644
--- a/man/binfmt.d.xml
+++ b/man/binfmt.d.xml
@@ -67,7 +67,7 @@
     <para>Each file contains a list of binfmt_misc kernel binary
     format rules. Consult <ulink
-    url="https://www.kernel.org/doc/Documentation/binfmt_misc.txt">binfmt_misc.txt</ulink>
+    url="https://www.kernel.org/doc/Documentation/admin-guide/binfmt-misc.rst">binfmt_misc.rst</ulink>
     for more information on registration of additional binary formats
     and how to write rules.</para>
diff --git a/src/test/test-util.c b/src/test/test-util.c
index fcf5416c0..f2c52edce 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -1213,7 +1213,7 @@ static void test_files_same(void) {
 static void test_is_valid_documentation_url(void) {
         assert_se(documentation_url_is_valid("http://www.freedesktop.org/wiki/Software/systemd"));
-        assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/binfmt_misc.txt"));
+        assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/admin-guide/binfmt-misc.rst"));
         assert_se(documentation_url_is_valid("file:/foo/foo"));
         assert_se(documentation_url_is_valid("man:systemd.special(7)"));
         assert_se(documentation_url_is_valid("info:bar"));
diff --git a/units/proc-sys-fs-binfmt_misc.automount b/units/proc-sys-fs-binfmt_misc.automount
index 6be38937b..b28bf9bb8 100644
--- a/units/proc-sys-fs-binfmt_misc.automount
+++ b/units/proc-sys-fs-binfmt_misc.automount
@@ -7,7 +7,7 @@
 [Unit]
 Description=Arbitrary Executable File Formats File System Automount Point
-Documentation=https://www.kernel.org/doc/Documentation/binfmt_misc.txt
+Documentation=https://www.kernel.org/doc/Documentation/admin-guide/binfmt-misc.rst
 Documentation=http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems
 DefaultDependencies=no
 Before=sysinit.target
diff --git a/units/proc-sys-fs-binfmt_misc.mount b/units/proc-sys-fs-binfmt_misc.mount
index 8c7c38631..8d22dc908 100644
--- a/units/proc-sys-fs-binfmt_misc.mount
+++ b/units/proc-sys-fs-binfmt_misc.mount
@@ -7,7 +7,7 @@
 [Unit]
 Description=Arbitrary Executable File Formats File System
-Documentation=https://www.kernel.org/doc/Documentation/binfmt_misc.txt
+Documentation=https://www.kernel.org/doc/Documentation/admin-guide/binfmt-misc.rst
 Documentation=http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems
 DefaultDependencies=no
diff --git a/units/systemd-binfmt.service.in b/units/systemd-binfmt.service.in
index 02dfe774d..e066f7fec 100644
--- a/units/systemd-binfmt.service.in
+++ b/units/systemd-binfmt.service.in
@@ -8,7 +8,7 @@
 [Unit]
 Description=Set Up Additional Binary Formats
 Documentation=man:systemd-binfmt.service(8) man:binfmt.d(5)
-Documentation=https://www.kernel.org/doc/Documentation/binfmt_misc.txt
+Documentation=https://www.kernel.org/doc/Documentation/admin-guide/binfmt-misc.rst
 DefaultDependencies=no
 Conflicts=shutdown.target
 After=systemd-readahead-collect.service systemd-readahead-replay.service proc-sys-fs-binfmt_misc.automount
SOURCES/0617-man-udevadm-remove-superfluous-version-from-subcomma.patch
New file
@@ -0,0 +1,27 @@
From 5fa3a659c5d106734b3fa76270f048b8b2ea0194 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Fri, 23 Mar 2018 11:20:31 +0100
Subject: [PATCH] man/udevadm: remove superfluous --version from subcommand
Resolves: #1553076
---
 man/udevadm.xml | 6 ------
 1 file changed, 6 deletions(-)
diff --git a/man/udevadm.xml b/man/udevadm.xml
index 8ef9e23aa..99eae387f 100644
--- a/man/udevadm.xml
+++ b/man/udevadm.xml
@@ -187,12 +187,6 @@
             <para>Cleanup the udev database.</para>
           </listitem>
         </varlistentry>
-        <varlistentry>
-          <term><option>--version</option></term>
-          <listitem>
-            <para>Print version.</para>
-          </listitem>
-        </varlistentry>
         <varlistentry>
           <term><option>-h</option></term>
           <term><option>--help</option></term>
SOURCES/0618-man-udevadm-correctly-show-the-short-version-of-exit.patch
New file
@@ -0,0 +1,23 @@
From 81725f613bebedc27f7ff763097bcb393f9c4bd9 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Wed, 7 Mar 2018 18:45:29 +0100
Subject: [PATCH] man/udevadm: correctly show the short version of --exit
Resolves: #1552712
---
 man/udevadm.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/man/udevadm.xml b/man/udevadm.xml
index 99eae387f..e11c2cb2e 100644
--- a/man/udevadm.xml
+++ b/man/udevadm.xml
@@ -374,7 +374,7 @@
       <para>Modify the internal state of the running udev daemon.</para>
       <variablelist>
         <varlistentry>
-          <term><option>-x</option></term>
+          <term><option>-e</option></term>
           <term><option>--exit</option></term>
           <listitem>
             <para>Signal and wait for systemd-udevd to exit.</para>
SOURCES/0619-core-timer-downgrade-message-about-random-time-addit.patch
New file
@@ -0,0 +1,30 @@
From 7adabea503fb86b3b33da17fe65a2b5a246fcac7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 5 Feb 2017 03:37:46 -0500
Subject: [PATCH] core/timer: downgrade message about random time addition
 (#5229)
This seems like something that shouldn't be higher then debug level, even
if it does not get emitted too often.
Fixes #5228.
(cherry picked from commit 382852fd581efe3cc0ae11154102ab9f435adea1)
Resolves: #1587906
---
 src/core/timer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/timer.c b/src/core/timer.c
index 0a264f60d..d32b007c7 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -335,7 +335,7 @@ static void add_random(Timer *t, usec_t *v) {
         else
                 *v += add;
-        log_unit_info(UNIT(t)->id, "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
+        log_unit_debug(UNIT(t)->id, "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
 }
 static void timer_enter_waiting(Timer *t, bool initial) {
SOURCES/0620-fd-util-add-new-acquire_data_fd-API-helper.patch
New file
@@ -0,0 +1,277 @@
From 581edd240f8dd68b1dbb4070353ddb2059eb8a67 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 27 Oct 2017 10:56:42 +0200
Subject: [PATCH] fd-util: add new acquire_data_fd() API helper
All this function does is place some data in an in-memory read-only fd,
that may be read back to get the original data back.
Doing this in a way that works everywhere, given the different kernels
we support as well as different privilege levels is surprisingly
complex.
(cherry picked from commit a548e14d690133dd8cca2d5ab8082bb23259fd5f)
Related: #1446095
---
 src/shared/util.c    | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/util.h    |  10 ++++
 src/test/test-util.c |  49 ++++++++++++++++
 3 files changed, 215 insertions(+)
diff --git a/src/shared/util.c b/src/shared/util.c
index af0953273..982f5e044 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -95,6 +95,7 @@
 #include "sparse-endian.h"
 #include "conf-parser.h"
 #include "cgroup-util.h"
+#include "memfd-util.h"
 int saved_argc = 0;
 char **saved_argv = NULL;
@@ -8893,3 +8894,158 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
         return m / max;
 }
+
+int acquire_data_fd(const void *data, size_t size, unsigned flags) {
+
+        char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+        _cleanup_close_pair_ int pipefds[2] = { -1, -1 };
+        char pattern[] = "/dev/shm/data-fd-XXXXXX";
+        _cleanup_close_ int fd = -1;
+        int isz = 0, r;
+        ssize_t n;
+        off_t f;
+
+        assert(data || size == 0);
+
+        /* Acquire a read-only file descriptor that when read from returns the specified data. This is much more
+         * complex than I wish it was. But here's why:
+         *
+         * a) First we try to use memfds. They are the best option, as we can seal them nicely to make them
+         *    read-only. Unfortunately they require kernel 3.17, and – at the time of writing – we still support 3.14.
+         *
+         * b) Then, we try classic pipes. They are the second best options, as we can close the writing side, retaining
+         *    a nicely read-only fd in the reading side. However, they are by default quite small, and unprivileged
+         *    clients can only bump their size to a system-wide limit, which might be quite low.
+         *
+         * c) Then, we try an O_TMPFILE file in /dev/shm (that dir is the only suitable one known to exist from
+         *    earliest boot on). To make it read-only we open the fd a second time with O_RDONLY via
+         *    /proc/self/<fd>. Unfortunately O_TMPFILE is not available on older kernels on tmpfs.
+         *
+         * d) Finally, we try creating a regular file in /dev/shm, which we then delete.
+         *
+         * It sucks a bit that depending on the situation we return very different objects here, but that's Linux I
+         * figure. */
+
+        if (size == 0 && ((flags & ACQUIRE_NO_DEV_NULL) == 0)) {
+                /* As a special case, return /dev/null if we have been called for an empty data block */
+                r = open("/dev/null", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (r < 0)
+                        return -errno;
+
+                return r;
+        }
+
+        if ((flags & ACQUIRE_NO_MEMFD) == 0) {
+                fd = memfd_new("data-fd");
+                if (fd < 0)
+                        goto try_pipe;
+
+                n = write(fd, data, size);
+                if (n < 0)
+                        return -errno;
+                if ((size_t) n != size)
+                        return -EIO;
+
+                f = lseek(fd, 0, SEEK_SET);
+                if (f != 0)
+                        return -errno;
+
+                r = memfd_set_sealed(fd);
+                if (r < 0)
+                        return r;
+
+                r = fd;
+                fd = -1;
+
+                return r;
+        }
+
+try_pipe:
+        if ((flags & ACQUIRE_NO_PIPE) == 0) {
+                if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0)
+                        return -errno;
+
+                isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
+                if (isz < 0)
+                        return -errno;
+
+                if ((size_t) isz < size) {
+                        isz = (int) size;
+                        if (isz < 0 || (size_t) isz != size)
+                                return -E2BIG;
+
+                        /* Try to bump the pipe size */
+                        (void) fcntl(pipefds[1], F_SETPIPE_SZ, isz);
+
+                        /* See if that worked */
+                        isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
+                        if (isz < 0)
+                                return -errno;
+
+                        if ((size_t) isz < size)
+                                goto try_dev_shm;
+                }
+
+                n = write(pipefds[1], data, size);
+                if (n < 0)
+                        return -errno;
+                if ((size_t) n != size)
+                        return -EIO;
+
+                (void) fd_nonblock(pipefds[0], false);
+
+                r = pipefds[0];
+                pipefds[0] = -1;
+
+                return r;
+        }
+
+try_dev_shm:
+        if ((flags & ACQUIRE_NO_TMPFILE) == 0) {
+                fd = open("/dev/shm", O_RDWR|O_TMPFILE|O_CLOEXEC, 0500);
+                if (fd < 0)
+                        goto try_dev_shm_without_o_tmpfile;
+
+                n = write(fd, data, size);
+                if (n < 0)
+                        return -errno;
+                if ((size_t) n != size)
+                        return -EIO;
+
+                /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
+                xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+                r = open(procfs_path, O_RDONLY|O_CLOEXEC);
+                if (r < 0)
+                        return -errno;
+
+                return r;
+        }
+
+try_dev_shm_without_o_tmpfile:
+        if ((flags & ACQUIRE_NO_REGULAR) == 0) {
+                fd = mkostemp_safe(pattern, O_CLOEXEC);
+                if (fd < 0)
+                        return fd;
+
+                n = write(fd, data, size);
+                if (n < 0) {
+                        r = -errno;
+                        goto unlink_and_return;
+                }
+                if ((size_t) n != size) {
+                        r = -EIO;
+                        goto unlink_and_return;
+                }
+
+                /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
+                r = open(pattern, O_RDONLY|O_CLOEXEC);
+                if (r < 0)
+                        r = -errno;
+
+        unlink_and_return:
+                (void) unlink(pattern);
+                return r;
+        }
+
+        return -EOPNOTSUPP;
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index 526a6fe84..9c4be0256 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -1112,3 +1112,13 @@ int parse_percent(const char *p);
 uint64_t system_tasks_max(void);
 uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
+
+enum {
+        ACQUIRE_NO_DEV_NULL = 1 << 0,
+        ACQUIRE_NO_MEMFD    = 1 << 1,
+        ACQUIRE_NO_PIPE     = 1 << 2,
+        ACQUIRE_NO_TMPFILE  = 1 << 3,
+        ACQUIRE_NO_REGULAR  = 1 << 4,
+};
+
+int acquire_data_fd(const void *data, size_t size, unsigned flags);
diff --git a/src/test/test-util.c b/src/test/test-util.c
index f2c52edce..efb02ff53 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -1861,6 +1861,54 @@ static void test_system_tasks_max_scale(void) {
         assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX);
 }
+static void test_acquire_data_fd_one(unsigned flags) {
+        char wbuffer[196*1024 - 7];
+        char rbuffer[sizeof(wbuffer)];
+        int fd;
+
+        fd = acquire_data_fd("foo", 3, flags);
+        assert_se(fd >= 0);
+
+        zero(rbuffer);
+        assert_se(read(fd, rbuffer, sizeof(rbuffer)) == 3);
+        assert_se(streq(rbuffer, "foo"));
+
+        fd = safe_close(fd);
+
+        fd = acquire_data_fd("", 0, flags);
+        assert_se(fd >= 0);
+
+        zero(rbuffer);
+        assert_se(read(fd, rbuffer, sizeof(rbuffer)) == 0);
+        assert_se(streq(rbuffer, ""));
+
+        fd = safe_close(fd);
+
+        random_bytes(wbuffer, sizeof(wbuffer));
+
+        fd = acquire_data_fd(wbuffer, sizeof(wbuffer), flags);
+        assert_se(fd >= 0);
+
+        zero(rbuffer);
+        assert_se(read(fd, rbuffer, sizeof(rbuffer)) == sizeof(rbuffer));
+        assert_se(memcmp(rbuffer, wbuffer, sizeof(rbuffer)) == 0);
+
+        fd = safe_close(fd);
+}
+
+static void test_acquire_data_fd(void) {
+
+        test_acquire_data_fd_one(0);
+        test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL);
+        test_acquire_data_fd_one(ACQUIRE_NO_MEMFD);
+        test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_MEMFD);
+        test_acquire_data_fd_one(ACQUIRE_NO_PIPE);
+        test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_PIPE);
+        test_acquire_data_fd_one(ACQUIRE_NO_MEMFD|ACQUIRE_NO_PIPE);
+        test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_MEMFD|ACQUIRE_NO_PIPE);
+        test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_MEMFD|ACQUIRE_NO_PIPE|ACQUIRE_NO_TMPFILE);
+}
+
 int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
@@ -1943,6 +1991,7 @@ int main(int argc, char *argv[]) {
         test_shell_maybe_quote();
         test_system_tasks_max();
         test_system_tasks_max_scale();
+        test_acquire_data_fd();
         return 0;
 }
SOURCES/0621-systemd-analyze-make-dump-work-for-large-of-units.patch
New file
@@ -0,0 +1,189 @@
From 6772555b226a116bff07b7d8af28b16032273866 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Wed, 9 May 2018 09:35:52 +0200
Subject: [PATCH] systemd-analyze: make dump work for large # of units
If there is a large number of units, the size of the generated dump
string can overstep DBus message size limit. So let's pass that string
via a fd.
(cherry picked from commit c0a1bfacfea9c65ea79fd07682a5b60b5d711a33)
Resolves: #1446095
---
 src/analyze/analyze.c                  | 57 ++++++++++++++++++++++++++++------
 src/core/dbus-manager.c                | 26 ++++++++++++++--
 src/core/org.freedesktop.systemd1.conf |  4 +++
 3 files changed, 76 insertions(+), 11 deletions(-)
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index ff84f6894..7116aaa88 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -29,6 +29,7 @@
 #include "sd-bus.h"
 #include "bus-util.h"
 #include "bus-error.h"
+#include "copy.h"
 #include "install.h"
 #include "log.h"
 #include "build.h"
@@ -1096,12 +1097,42 @@ static int dot(sd_bus *bus, char* patterns[]) {
         return 0;
 }
-static int dump(sd_bus *bus, char **args) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+static int dump_fallback(sd_bus *bus) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         const char *text = NULL;
         int r;
+        assert(bus);
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "Dump",
+                        &error,
+                        &reply,
+                        "");
+        if (r < 0) {
+                log_error("Failed to issue method call Dump: %s", bus_error_message(&error, -r));
+                return r;
+        }
+
+        r = sd_bus_message_read(reply, "s", &text);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        fputs(text, stdout);
+        return 0;
+}
+
+static int dump(sd_bus *bus, char **args) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        int fd = -1;
+        int r;
+
         if (!strv_isempty(args)) {
                 log_error("Too many arguments.");
                 return -E2BIG;
@@ -1109,26 +1140,34 @@ static int dump(sd_bus *bus, char **args) {
         pager_open_if_enabled();
+        if (!sd_bus_can_send(bus, SD_BUS_TYPE_UNIX_FD))
+                return dump_fallback(bus);
+
         r = sd_bus_call_method(
                         bus,
                        "org.freedesktop.systemd1",
                        "/org/freedesktop/systemd1",
                        "org.freedesktop.systemd1.Manager",
-                       "Dump",
+                       "DumpByFileDescriptor",
                        &error,
                        &reply,
                        "");
         if (r < 0) {
-                log_error("Failed issue method call: %s", bus_error_message(&error, -r));
-                return r;
+                /* fall back to Dump if DumpByFileDescriptor is not supported */
+                if (!IN_SET(r, -EACCES, -EBADR)) {
+                        log_error("Failed to issue method call DumpByFileDescriptor: %s", bus_error_message(&error, -r));
+                        return r;
+                }
+
+                return dump_fallback(bus);
         }
-        r = sd_bus_message_read(reply, "s", &text);
+        r = sd_bus_message_read(reply, "h", &fd);
         if (r < 0)
                 return bus_log_parse_error(r);
-        fputs(text, stdout);
-        return 0;
+        fflush(stdout);
+        return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0);
 }
 static int set_log_level(sd_bus *bus, char **args) {
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index d34ed042f..1766163b3 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -1064,7 +1064,7 @@ static int method_unsubscribe(sd_bus *bus, sd_bus_message *message, void *userda
         return sd_bus_reply_method_return(message, NULL);
 }
-static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int dump_impl(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error, int (*reply)(sd_bus_message *, char *)) {
         _cleanup_free_ char *dump = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         Manager *m = userdata;
@@ -1089,13 +1089,34 @@ static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata, sd_
         manager_dump_jobs(m, f, NULL);
         fflush(f);
-
         if (ferror(f))
                 return -ENOMEM;
+        return reply(message, dump);
+}
+
+static int reply_dump(sd_bus_message *message, char *dump) {
         return sd_bus_reply_method_return(message, "s", dump);
 }
+static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return dump_impl(bus, message, userdata, error, reply_dump);
+}
+
+static int reply_dump_by_fd(sd_bus_message *message, char *dump) {
+        _cleanup_close_ int fd = -1;
+
+        fd = acquire_data_fd(dump, strlen(dump), 0);
+        if (fd < 0)
+                return fd;
+
+        return sd_bus_reply_method_return(message, "h", fd);
+}
+
+static int method_dump_by_fd(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return dump_impl(bus, message, userdata, error, reply_dump_by_fd);
+}
+
 static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *path = NULL;
         Manager *m = userdata;
@@ -2092,6 +2113,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Dump", NULL, "s", method_dump, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("DumpByFileDescriptor", NULL, "h", method_dump_by_fd, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, 0),
         SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, 0),
         SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
index 3997dd0b4..8187cf173 100644
--- a/src/core/org.freedesktop.systemd1.conf
+++ b/src/core/org.freedesktop.systemd1.conf
@@ -96,6 +96,10 @@
                        send_interface="org.freedesktop.systemd1.Manager"
                        send_member="Dump"/>
+                <allow send_destination="org.freedesktop.systemd1"
+                       send_interface="org.freedesktop.systemd1.Manager"
+                       send_member="DumpByFileDescriptor"/>
+
                 <allow send_destination="org.freedesktop.systemd1"
                        send_interface="org.freedesktop.systemd1.Manager"
                        send_member="GetDefaultTarget"/>
SOURCES/0622-use-max.-message-size-allowed-by-DBus-spec-8936.patch
New file
@@ -0,0 +1,27 @@
From 191e504e9847ba3f46fe579922bbee64f02a04c1 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Wed, 9 May 2018 10:33:28 +0200
Subject: [PATCH] use max. message size allowed by DBus spec (#8936)
C.f. https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages.
(cherry picked from commit 33d8fe60573dd3e88fe98e368437bb4d29534b5a)
Related: #1446095
---
 src/libsystemd/sd-bus/bus-internal.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 6a106862e..9c1e5a35b 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -329,7 +329,7 @@ struct sd_bus {
 #define BUS_WQUEUE_MAX (192*1024)
 #define BUS_RQUEUE_MAX (192*1024)
-#define BUS_MESSAGE_SIZE_MAX (64*1024*1024)
+#define BUS_MESSAGE_SIZE_MAX (128*1024*1024)
 #define BUS_AUTH_SIZE_MAX (64*1024)
 #define BUS_CONTAINER_DEPTH 128
SOURCES/0623-cryptsetup-support-LUKS2-on-disk-format.patch
New file
@@ -0,0 +1,77 @@
From be973ab9f6585be762ea0888c81b011222eabb13 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Thu, 3 May 2018 11:21:27 +0200
Subject: [PATCH] cryptsetup: support LUKS2 on-disk format
Allow cryptsetup utility to activate LUKS2 devices (with appropriate
libcryptsetup)
The change itself doesn't enforce new libcryptsetup 2.x and is backward
compatible with versions 1.x
(cherry-picked from commit b3b4ebab02395933cde554b5a5d5c363dae3920d)
Resolves: #1573838
---
 src/cryptsetup/cryptsetup.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 69a015614..528c36c48 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -36,7 +36,15 @@
 #include "libudev.h"
 #include "udev-util.h"
-static const char *arg_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
+/* libcryptsetup define for any LUKS version, compatible with libcryptsetup 1.x */
+#ifndef CRYPT_LUKS
+#define CRYPT_LUKS NULL
+#endif
+
+/* internal helper */
+#define ANY_LUKS "LUKS"
+
+static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT or CRYPT_PLAIN */
 static char *arg_cipher = NULL;
 static unsigned arg_key_size = 0;
 static int arg_key_slot = CRYPT_ANY_SLOT;
@@ -98,7 +106,7 @@ static int parse_one_option(const char *option) {
         } else if (startswith(option, "key-slot=")) {
-                arg_type = CRYPT_LUKS1;
+                arg_type = ANY_LUKS;
                 if (safe_atoi(option+9, &arg_key_slot) < 0) {
                         log_error("key-slot= parse failure, ignoring.");
                         return 0;
@@ -138,7 +146,7 @@ static int parse_one_option(const char *option) {
                 arg_hash = t;
         } else if (startswith(option, "header=")) {
-                arg_type = CRYPT_LUKS1;
+                arg_type = ANY_LUKS;
                 if (!path_is_absolute(option+7)) {
                         log_error("Header path '%s' is not absolute, refusing.", option+7);
@@ -168,7 +176,7 @@ static int parse_one_option(const char *option) {
         else if (STR_IN_SET(option, "allow-discards", "discard"))
                 arg_discards = true;
         else if (streq(option, "luks"))
-                arg_type = CRYPT_LUKS1;
+                arg_type = ANY_LUKS;
         else if (streq(option, "tcrypt"))
                 arg_type = CRYPT_TCRYPT;
         else if (streq(option, "tcrypt-hidden")) {
@@ -430,8 +438,8 @@ static int attach_luks_or_plain(struct crypt_device *cd,
         assert(name);
         assert(key_file || passwords);
-        if (!arg_type || streq(arg_type, CRYPT_LUKS1)) {
-                r = crypt_load(cd, CRYPT_LUKS1, NULL);
+        if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)) {
+                r = crypt_load(cd, CRYPT_LUKS, NULL);
                 if (r < 0) {
                         log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
                         return r;
SOURCES/0624-core-scope-fix-missing-fragment_path.patch
New file
@@ -0,0 +1,56 @@
From f838bf376249b68205641d1736da2622c0279ed2 Mon Sep 17 00:00:00 2001
From: chenglin130 <cheng.lin130@zte.com.cn>
Date: Sat, 20 Jan 2018 17:45:27 +0800
Subject: [PATCH] core:scope: fix missing fragment_path
fragment_path in struct unit is a record of unit file, which will
be deleted (unlink) in unit_free().
After a daemon-reload process, the u->fragment_path of scope unit
will be missing (NULL). Then, the discarded session scope unit file
will be redundant until reboot.
Steps to Reproduce problem:
1. ssh access and login
2. systemctl daemon-reload
3. ssh logout
4. discarded session-xxx.scope file will be found in /run/systemd/system/
So in a daemon-reload case, scope_load() need unit_load_fragment() to reload
u->fragment_path.
---
 src/core/load-fragment.c | 5 +++++
 src/core/scope.c         | 4 ++++
 2 files changed, 9 insertions(+)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index da58bcc5c..f3d0851fe 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3950,6 +3950,11 @@ int unit_load_fragment(Unit *u) {
         assert(u->load_state == UNIT_STUB);
         assert(u->id);
+        if (u->transient && u->fragment_path) {
+                u->load_state = UNIT_LOADED;
+                return 0;
+        }
+
         /* First, try to find the unit under its id. We always look
          * for unit files in the default directories, to make it easy
          * to override things by placing things in /etc/systemd/system */
diff --git a/src/core/scope.c b/src/core/scope.c
index ae6614fbf..29954ba28 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -150,6 +150,10 @@ static int scope_load(Unit *u) {
         if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
                 return -ENOENT;
+        r = unit_load_fragment(u);
+        if (r < 0)
+                return r;
+
         u->load_state = UNIT_LOADED;
         r = unit_load_dropin(u);
SOURCES/0625-units-don-t-put-udev-to-its-own-mount-namespace-with.patch
New file
@@ -0,0 +1,27 @@
From 5c62e7afe2197c7b5bb00ed70bc6960b49a0317e Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Thu, 18 Jan 2018 19:23:56 +0100
Subject: [PATCH] units: don't put udev to its own mount namespace with slave
 propagation
Change in upstream was done mostly for political reasons to discourage
people from doing mounts in udev rules. RHEL is very bad place for
such experiments. Revert to default we shipped with RHEL-7 GA.
RHEL-only
Resolves: #1432211
---
 units/systemd-udevd.service.in | 1 -
 1 file changed, 1 deletion(-)
diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in
index 32f04d901..46b079515 100644
--- a/units/systemd-udevd.service.in
+++ b/units/systemd-udevd.service.in
@@ -21,5 +21,4 @@ Sockets=systemd-udevd-control.socket systemd-udevd-kernel.socket
 Restart=always
 RestartSec=0
 ExecStart=@rootlibexecdir@/systemd-udevd
-MountFlags=slave
 KillMode=mixed
SOURCES/0626-rules-disable-support-for-Lenovo-IR-cameras.patch
New file
@@ -0,0 +1,37 @@
From 647615bfa4015336eb88f6cb44dc111f1d713df7 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 13 Jun 2018 14:33:18 +0200
Subject: [PATCH] rules: disable support for Lenovo IR cameras
Resolves: #1540418
---
 Makefile.am                                    | 1 +
 rules/40-redhat-disable-lenovo-ir-camera.rules | 6 ++++++
 2 files changed, 7 insertions(+)
 create mode 100644 rules/40-redhat-disable-lenovo-ir-camera.rules
diff --git a/Makefile.am b/Makefile.am
index 8c73326fa..cbc120dad 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3522,6 +3522,7 @@ dist_udevrules_DATA += \
     rules/80-net-setup-link.rules \
     rules/95-udev-late.rules \
     rules/40-redhat.rules \
+    rules/40-redhat-disable-lenovo-ir-camera.rules \
     rules/73-idrac.rules \
         rules/80-net-name-slot.rules
diff --git a/rules/40-redhat-disable-lenovo-ir-camera.rules b/rules/40-redhat-disable-lenovo-ir-camera.rules
new file mode 100644
index 000000000..ea326d4ab
--- /dev/null
+++ b/rules/40-redhat-disable-lenovo-ir-camera.rules
@@ -0,0 +1,6 @@
+# Disable known IR cameras in Lenovo Notebooks
+SUBSYSTEM=="usb", ATTRS{idVendor}=="5986", ATTRS{idProduct}=="211a", ATTR{authorized}="0"
+SUBSYSTEM=="usb", ATTRS{idVendor}=="5986", ATTRS{idProduct}=="1141", ATTR{authorized}="0"
+SUBSYSTEM=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="b605", ATTR{authorized}="0"
+SUBSYSTEM=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="b613", ATTR{authorized}="0"
+SUBSYSTEM=="usb", ATTRS{idVendor}=="04f2", ATTRS{idProduct}=="b615", ATTR{authorized}="0"
\ No newline at end of file
SOURCES/0627-core-make-sure-systemctl-reload-or-try-restart-is-ac.patch
New file
@@ -0,0 +1,92 @@
From f7507f4bb5385ed0303451d812d220f14f341629 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 28 Jan 2016 18:48:42 +0100
Subject: [PATCH] core: make sure "systemctl reload-or-try-restart is actually
 a noop if a unit is not running
This makes sure we follow the same basic logic for try-restart if we have a try-reload.
Fixes #688
(cherry picked from commit 3282591dc30b2934a895c7403d2f0b0690260947)
Resolves: #1191920
---
 src/core/dbus-unit.c | 2 +-
 src/core/job.c       | 8 ++++++++
 src/core/job.h       | 3 +++
 src/core/unit.c      | 2 ++
 4 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 1d0d6f67c..f0f75e01b 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -850,7 +850,7 @@ int bus_unit_queue_job(
                 if (type == JOB_RESTART)
                         type = JOB_RELOAD_OR_START;
                 else if (type == JOB_TRY_RESTART)
-                        type = JOB_RELOAD;
+                        type = JOB_TRY_RELOAD;
         }
         r = mac_selinux_unit_access_check(
diff --git a/src/core/job.c b/src/core/job.c
index 1617e24c0..c9a43a4cb 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -404,6 +404,13 @@ JobType job_type_collapse(JobType t, Unit *u) {
                 return JOB_RESTART;
+        case JOB_TRY_RELOAD:
+                s = unit_active_state(u);
+                if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
+                        return JOB_NOP;
+
+                return JOB_RELOAD;
+
         case JOB_RELOAD_OR_START:
                 s = unit_active_state(u);
                 if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
@@ -1212,6 +1219,7 @@ static const char* const job_type_table[_JOB_TYPE_MAX] = {
         [JOB_RELOAD_OR_START] = "reload-or-start",
         [JOB_RESTART] = "restart",
         [JOB_TRY_RESTART] = "try-restart",
+        [JOB_TRY_RELOAD] = "try-reload",
         [JOB_NOP] = "nop",
 };
diff --git a/src/core/job.h b/src/core/job.h
index ce81607de..535052b48 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -63,6 +63,9 @@ enum JobType {
          * Thus we never need to merge it with anything. */
         JOB_TRY_RESTART = _JOB_TYPE_MAX_IN_TRANSACTION, /* if running, stop and then start */
+        /* Similar to JOB_TRY_RESTART but collapses to JOB_RELOAD or JOB_NOP */
+        JOB_TRY_RELOAD,
+
         /* JOB_RELOAD_OR_START won't enter into a transaction and cannot result
          * from transaction merging (there's no way for JOB_RELOAD and
          * JOB_START to meet in one transaction). It can result from a merge
diff --git a/src/core/unit.c b/src/core/unit.c
index 41d7b63d7..6d535ae12 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1868,6 +1868,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
                 case JOB_RELOAD:
                 case JOB_RELOAD_OR_START:
+                case JOB_TRY_RELOAD:
                         if (u->job->state == JOB_RUNNING) {
                                 if (ns == UNIT_ACTIVE)
@@ -2144,6 +2145,7 @@ bool unit_job_is_applicable(Unit *u, JobType j) {
                 return unit_can_start(u);
         case JOB_RELOAD:
+        case JOB_TRY_RELOAD:
                 return unit_can_reload(u);
         case JOB_RELOAD_OR_START:
SOURCES/0628-core-fix-confusing-logging-of-instantaneous-jobs.patch
New file
@@ -0,0 +1,247 @@
From 7bc07eb6c9a31f2c26d0fe3e6d7a26a13cbb2369 Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Thu, 16 Jul 2015 20:08:30 +0200
Subject: [PATCH] core: fix confusing logging of instantaneous jobs
For instantaneous jobs (e.g. starting of targets, sockets, slices, or
Type=simple services) the log shows the job completion
before starting:
        systemd[1]: Created slice -.slice.
        systemd[1]: Starting -.slice.
        systemd[1]: Created slice System Slice.
        systemd[1]: Starting System Slice.
        systemd[1]: Listening on Journal Audit Socket.
        systemd[1]: Starting Journal Audit Socket.
        systemd[1]: Reached target Timers.
        systemd[1]: Starting Timers.
        ...
The reason is that the job completes before the ->start() method returns
and only then does unit_start() print the "Starting ..." message.
The same thing happens when stopping units.
Rather than fixing the order of the messages, let's just not emit the
Starting/Stopping message at all when the job completes instantaneously.
The job completion message is sufficient in this case.
(cherry picked from commit d1a34ae9c20f1c02aab17884919eccef572b1d21)
Resolves: #1506256
---
 src/core/job.c  | 65 +++++++++++++++++++++++++++++++++++++++------------------
 src/core/unit.c | 36 +++++++++++---------------------
 src/core/unit.h |  1 +
 3 files changed, 58 insertions(+), 44 deletions(-)
diff --git a/src/core/job.c b/src/core/job.c
index c9a43a4cb..612caa604 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -504,10 +504,48 @@ static void job_change_type(Job *j, JobType newtype) {
         j->type = newtype;
 }
+static int job_perform_on_unit(Job **j) {
+        /* While we execute this operation the job might go away (for
+         * example: because it finishes immediately or is replaced by a new,
+         * conflicting job.) To make sure we don't access a freed job later on
+         * we store the id here, so that we can verify the job is still
+         * valid. */
+        Manager *m  = (*j)->manager;
+        Unit *u     = (*j)->unit;
+        JobType t   = (*j)->type;
+        uint32_t id = (*j)->id;
+        int r;
+
+        switch (t) {
+                case JOB_START:
+                        r = unit_start(u);
+                        break;
+
+                case JOB_RESTART:
+                        t = JOB_STOP;
+                case JOB_STOP:
+                        r = unit_stop(u);
+                        break;
+
+                case JOB_RELOAD:
+                        r = unit_reload(u);
+                        break;
+
+                default:
+                        assert_not_reached("Invalid job type");
+        }
+
+        /* Log if the job still exists and the start/stop/reload function
+         * actually did something. */
+        *j = manager_get_job(m, id);
+        if (*j && r > 0)
+                unit_status_emit_starting_stopping_reloading(u, t);
+
+        return r;
+}
+
 int job_run_and_invalidate(Job *j) {
         int r;
-        uint32_t id;
-        Manager *m = j->manager;
         assert(j);
         assert(j->installed);
@@ -526,23 +564,9 @@ int job_run_and_invalidate(Job *j) {
         job_set_state(j, JOB_RUNNING);
         job_add_to_dbus_queue(j);
-        /* While we execute this operation the job might go away (for
-         * example: because it is replaced by a new, conflicting
-         * job.) To make sure we don't access a freed job later on we
-         * store the id here, so that we can verify the job is still
-         * valid. */
-        id = j->id;
         switch (j->type) {
-                case JOB_START:
-                        r = unit_start(j->unit);
-
-                        /* If this unit cannot be started, then simply wait */
-                        if (r == -EBADR)
-                                r = 0;
-                        break;
-
                 case JOB_VERIFY_ACTIVE: {
                         UnitActiveState t = unit_active_state(j->unit);
                         if (UNIT_IS_ACTIVE_OR_RELOADING(t))
@@ -554,17 +578,19 @@ int job_run_and_invalidate(Job *j) {
                         break;
                 }
+                case JOB_START:
                 case JOB_STOP:
                 case JOB_RESTART:
-                        r = unit_stop(j->unit);
+                        r = job_perform_on_unit(&j);
-                        /* If this unit cannot stopped, then simply wait. */
+                        /* If the unit type does not support starting/stopping,
+                         * then simply wait. */
                         if (r == -EBADR)
                                 r = 0;
                         break;
                 case JOB_RELOAD:
-                        r = unit_reload(j->unit);
+                        r = job_perform_on_unit(&j);
                         break;
                 case JOB_NOP:
@@ -575,7 +601,6 @@ int job_run_and_invalidate(Job *j) {
                         assert_not_reached("Unknown job type");
         }
-        j = manager_get_job(m, id);
         if (j) {
                 if (r == -EALREADY)
                         r = job_finish_and_invalidate(j, JOB_DONE, true, true);
diff --git a/src/core/unit.c b/src/core/unit.c
index 6d535ae12..907a4bf7f 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1417,6 +1417,15 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
                         NULL);
 }
+void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
+
+        unit_status_log_starting_stopping_reloading(u, t);
+
+        /* Reload status messages have traditionally not been printed to console. */
+        if (t != JOB_RELOAD)
+                unit_status_print_starting_stopping(u, t);
+}
+
 /* Errors:
  *         -EBADR:     This unit type does not support starting.
  *         -EALREADY:  Unit is already started.
@@ -1427,7 +1436,6 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
 int unit_start(Unit *u) {
         UnitActiveState state;
         Unit *following;
-        int r;
         assert(u);
@@ -1481,14 +1489,7 @@ int unit_start(Unit *u) {
         unit_add_to_dbus_queue(u);
-        r = UNIT_VTABLE(u)->start(u);
-        if (r <= 0)
-                return r;
-
-        /* Log if the start function actually did something */
-        unit_status_log_starting_stopping_reloading(u, JOB_START);
-        unit_status_print_starting_stopping(u, JOB_START);
-        return r;
+        return UNIT_VTABLE(u)->start(u);
 }
 bool unit_can_start(Unit *u) {
@@ -1512,7 +1513,6 @@ bool unit_can_isolate(Unit *u) {
 int unit_stop(Unit *u) {
         UnitActiveState state;
         Unit *following;
-        int r;
         assert(u);
@@ -1531,13 +1531,7 @@ int unit_stop(Unit *u) {
         unit_add_to_dbus_queue(u);
-        r = UNIT_VTABLE(u)->stop(u);
-        if (r <= 0)
-                return r;
-
-        unit_status_log_starting_stopping_reloading(u, JOB_STOP);
-        unit_status_print_starting_stopping(u, JOB_STOP);
-        return r;
+        return UNIT_VTABLE(u)->stop(u);
 }
 /* Errors:
@@ -1548,7 +1542,6 @@ int unit_stop(Unit *u) {
 int unit_reload(Unit *u) {
         UnitActiveState state;
         Unit *following;
-        int r;
         assert(u);
@@ -1575,12 +1568,7 @@ int unit_reload(Unit *u) {
         unit_add_to_dbus_queue(u);
-        r = UNIT_VTABLE(u)->reload(u);
-        if (r <= 0)
-                return r;
-
-        unit_status_log_starting_stopping_reloading(u, JOB_RELOAD);
-        return r;
+        return UNIT_VTABLE(u)->reload(u);
 }
 bool unit_can_reload(Unit *u) {
diff --git a/src/core/unit.h b/src/core/unit.h
index 85f52df18..480e2e95f 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -562,6 +562,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency d);
 int unit_coldplug(Unit *u, Hashmap *deferred_work);
 void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
+void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t);
 bool unit_need_daemon_reload(Unit *u);
SOURCES/0629-core-correct-return-value-from-reload-methods.patch
New file
@@ -0,0 +1,43 @@
From bc54eb811caf738ee54867359f798dc0f4be9e7e Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Thu, 16 Jul 2015 21:39:56 +0200
Subject: [PATCH] core: correct return value from reload methods
Return 1 from *_reload() methods to signify "we did something", just
like in *_start(). This causes "Reloading foo..." messages to be logged.
"Reloaded foo." messages are already logged.
(cherry picked from commit 2d018ae23b838f050516d06859f50ecb9733d44b)
Related: #1506256
---
 src/core/mount.c   | 2 +-
 src/core/service.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/core/mount.c b/src/core/mount.c
index a6d93b869..f726d9659 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1081,7 +1081,7 @@ static int mount_reload(Unit *u) {
         assert(m->state == MOUNT_MOUNTED);
         mount_enter_remounting(m);
-        return 0;
+        return 1;
 }
 static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
diff --git a/src/core/service.c b/src/core/service.c
index 71ec5e37c..9622ce11f 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1939,7 +1939,7 @@ static int service_reload(Unit *u) {
         assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED);
         service_enter_reload(s);
-        return 0;
+        return 1;
 }
 _pure_ static bool service_can_reload(Unit *u) {
SOURCES/0630-core-always-try-harder-to-get-unit-status-message-fo.patch
New file
@@ -0,0 +1,91 @@
From c571dc5f7d593a4526da9e19b35ae3d1ed11bfaa Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Mon, 20 Jul 2015 17:18:13 +0200
Subject: [PATCH] core: always try harder to get unit status message format
 string
The starting/stopping messages are printed to the console only if the
corresponding format string is defined in the unit's vtable. To avoid
excessive messages on the console, the unit types whose start/stop
jobs are instantaneous had the format strings intentionally undefined.
When logging the same event to the journal, a fallback to generic
Starting/Stopping/Reloading messages is used.
The problem of excessive console messages with instantaneous jobs
is already resolved in a nicer way ("core: fix confusing logging of
instantaneous jobs"), so there's no longer a need to have two ways of
getting the format strings. Let's fold them into one function with
the fallback to generic message strings.
(cherry picked from commit a85ca902c9f7f5aa8f2f3e3299147733802cf09d)
Related: #1506256
---
 src/core/unit.c | 34 ++++++++++------------------------
 1 file changed, 10 insertions(+), 24 deletions(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index 907a4bf7f..a33cbdf73 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1328,32 +1328,21 @@ static bool unit_assert_test(Unit *u) {
 }
 _pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
-        const UnitStatusMessageFormats *format_table;
-
-        assert(u);
-        assert(t >= 0);
-        assert(t < _JOB_TYPE_MAX);
-
-        if (t != JOB_START && t != JOB_STOP)
-                return NULL;
-
-        format_table = &UNIT_VTABLE(u)->status_message_formats;
-        if (!format_table)
-                return NULL;
-
-        return format_table->starting_stopping[t == JOB_STOP];
-}
-
-_pure_ static const char *unit_get_status_message_format_try_harder(Unit *u, JobType t) {
         const char *format;
+        const UnitStatusMessageFormats *format_table;
         assert(u);
         assert(t >= 0);
         assert(t < _JOB_TYPE_MAX);
-        format = unit_get_status_message_format(u, t);
-        if (format)
-                return format;
+        if (t == JOB_START || t == JOB_STOP) {
+                format_table = &UNIT_VTABLE(u)->status_message_formats;
+                if (format_table) {
+                        format = format_table->starting_stopping[t == JOB_STOP];
+                        if (format)
+                                return format;
+                }
+        }
         /* Return generic strings */
         if (t == JOB_START)
@@ -1371,9 +1360,6 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) {
         assert(u);
-        /* We only print status messages for selected units on
-         * selected operations. */
-
         format = unit_get_status_message_format(u, t);
         if (!format)
                 return;
@@ -1398,7 +1384,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
         /* We log status messages for all units and all operations. */
-        format = unit_get_status_message_format_try_harder(u, t);
+        format = unit_get_status_message_format(u, t);
         if (!format)
                 return;
SOURCES/0631-core-unit_get_status_message_format-never-returns-NU.patch
New file
@@ -0,0 +1,63 @@
From 0204371780cbcae7635544abc61846d33d04c317 Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Mon, 20 Jul 2015 18:36:12 +0200
Subject: [PATCH] core: unit_get_status_message_format() never returns NULL
unit_get_status_message_format() is used only with one of JOB_START,
JOB_STOP, JOB_RELOAD, all of which have fallback message strings
defined, so the function may never return NULL.
(cherry picked from commit b5bf308ba50ab0bac0f0caec2d8e4d5c75c107d0)
Related: #1506256
---
 src/core/unit.c | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/src/core/unit.c b/src/core/unit.c
index a33cbdf73..22d9beed7 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1332,10 +1332,9 @@ _pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
         const UnitStatusMessageFormats *format_table;
         assert(u);
-        assert(t >= 0);
-        assert(t < _JOB_TYPE_MAX);
+        assert(t == JOB_START || t == JOB_STOP || t == JOB_RELOAD);
-        if (t == JOB_START || t == JOB_STOP) {
+        if (t != JOB_RELOAD) {
                 format_table = &UNIT_VTABLE(u)->status_message_formats;
                 if (format_table) {
                         format = format_table->starting_stopping[t == JOB_STOP];
@@ -1349,10 +1348,8 @@ _pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
                 return "Starting %s.";
         else if (t == JOB_STOP)
                 return "Stopping %s.";
-        else if (t == JOB_RELOAD)
+        else
                 return "Reloading %s.";
-
-        return NULL;
 }
 static void unit_status_print_starting_stopping(Unit *u, JobType t) {
@@ -1361,8 +1358,6 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) {
         assert(u);
         format = unit_get_status_message_format(u, t);
-        if (!format)
-                return;
         DISABLE_WARNING_FORMAT_NONLITERAL;
         unit_status_printf(u, "", format);
@@ -1385,8 +1380,6 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
         /* We log status messages for all units and all operations. */
         format = unit_get_status_message_format(u, t);
-        if (!format)
-                return;
         DISABLE_WARNING_FORMAT_NONLITERAL;
         snprintf(buf, sizeof(buf), format, unit_description(u));
SOURCES/0632-core-try-harder-to-get-job-completion-messages-too.patch
New file
@@ -0,0 +1,254 @@
From 50ce13182e07af7f240c61d03bf113e86a269917 Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Tue, 21 Jul 2015 14:54:24 +0200
Subject: [PATCH] core: try harder to get job completion messages too
This is similar to "core: always try harder to get unit status
message format string", but for job completion status messages.
It makes generic status messages applicable for printing to the console.
And it rewrites the functions in a more table-based style.
(cherry picked from commit aa49ab5f22c0fdc7a5381d4e452f40705f3d7bf8)
Related: #1506256
---
 src/core/job.c | 192 ++++++++++++++++++++-------------------------------------
 1 file changed, 68 insertions(+), 124 deletions(-)
diff --git a/src/core/job.c b/src/core/job.c
index 612caa604..f371f914d 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -622,156 +622,100 @@ int job_run_and_invalidate(Job *j) {
 }
 _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
+        const char *format;
         const UnitStatusMessageFormats *format_table;
+        static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = {
+                [JOB_DONE]        = "Started %s.",
+                [JOB_TIMEOUT]     = "Timed out starting %s.",
+                [JOB_FAILED]      = "Failed to start %s.",
+                [JOB_DEPENDENCY]  = "Dependency failed for %s.",
+                [JOB_ASSERT]      = "Assertion failed for %s.",
+                [JOB_UNSUPPORTED] = "Starting of %s not supported.",
+        };
+        static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = {
+                [JOB_DONE]        = "Stopped %s.",
+                [JOB_FAILED]      = "Stopped (with error) %s.",
+                [JOB_TIMEOUT]     = "Timed out stoppping %s.",
+        };
+        static const char *const generic_finished_reload_job[_JOB_RESULT_MAX] = {
+                [JOB_DONE]        = "Reloaded %s.",
+                [JOB_FAILED]      = "Reload failed for %s.",
+                [JOB_TIMEOUT]     = "Timed out reloading %s.",
+        };
+        /* When verify-active detects the unit is inactive, report it.
+         * Most likely a DEPEND warning from a requisiting unit will
+         * occur next and it's nice to see what was requisited. */
+        static const char *const generic_finished_verify_active_job[_JOB_RESULT_MAX] = {
+                [JOB_SKIPPED]     = "%s is not active.",
+        };
         assert(u);
         assert(t >= 0);
         assert(t < _JOB_TYPE_MAX);
-        format_table = &UNIT_VTABLE(u)->status_message_formats;
-        if (!format_table)
-                return NULL;
+        if (t == JOB_START || t == JOB_STOP || t == JOB_RESTART) {
+                format_table = &UNIT_VTABLE(u)->status_message_formats;
+                if (format_table) {
+                        format = t == JOB_START ? format_table->finished_start_job[result] :
+                                                  format_table->finished_stop_job[result];
+                        if (format)
+                                return format;
+                }
+        }
+        /* Return generic strings */
         if (t == JOB_START)
-                return format_table->finished_start_job[result];
+                return generic_finished_start_job[result];
         else if (t == JOB_STOP || t == JOB_RESTART)
-                return format_table->finished_stop_job[result];
-
-        return NULL;
-}
-
-_pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
-        const char *format;
-
-        assert(u);
-        assert(t >= 0);
-        assert(t < _JOB_TYPE_MAX);
-
-        format = job_get_status_message_format(u, t, result);
-        if (format)
-                return format;
-
-        /* Return generic strings */
-        if (t == JOB_START) {
-                if (result == JOB_DONE)
-                        return "Started %s.";
-                else if (result == JOB_TIMEOUT)
-                        return "Timed out starting %s.";
-                else if (result == JOB_FAILED)
-                        return "Failed to start %s.";
-                else if (result == JOB_DEPENDENCY)
-                        return "Dependency failed for %s.";
-                else if (result == JOB_ASSERT)
-                        return "Assertion failed for %s.";
-                else if (result == JOB_UNSUPPORTED)
-                        return "Starting of %s not supported.";
-        } else if (t == JOB_STOP || t == JOB_RESTART) {
-                if (result == JOB_DONE)
-                        return "Stopped %s.";
-                else if (result == JOB_FAILED)
-                        return "Stopped (with error) %s.";
-                else if (result == JOB_TIMEOUT)
-                        return "Timed out stoppping %s.";
-        } else if (t == JOB_RELOAD) {
-                if (result == JOB_DONE)
-                        return "Reloaded %s.";
-                else if (result == JOB_FAILED)
-                        return "Reload failed for %s.";
-                else if (result == JOB_TIMEOUT)
-                        return "Timed out reloading %s.";
-        }
+                return generic_finished_stop_job[result];
+        else if (t == JOB_RELOAD)
+                return generic_finished_reload_job[result];
+        else if (t == JOB_VERIFY_ACTIVE)
+                return generic_finished_verify_active_job[result];
         return NULL;
 }
 static void job_print_status_message(Unit *u, JobType t, JobResult result) {
         const char *format;
+        static const char* const job_result_status_table[_JOB_RESULT_MAX] = {
+                [JOB_DONE]        = ANSI_GREEN_ON            "  OK  " ANSI_HIGHLIGHT_OFF,
+                [JOB_TIMEOUT]     = ANSI_HIGHLIGHT_RED_ON    " TIME " ANSI_HIGHLIGHT_OFF,
+                [JOB_FAILED]      = ANSI_HIGHLIGHT_RED_ON    "FAILED" ANSI_HIGHLIGHT_OFF,
+                [JOB_DEPENDENCY]  = ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF,
+                [JOB_SKIPPED]     = ANSI_HIGHLIGHT_ON        " INFO " ANSI_HIGHLIGHT_OFF,
+                [JOB_ASSERT]      = ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF,
+                [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW_ON "UNSUPP" ANSI_HIGHLIGHT_OFF,
+        };
         assert(u);
         assert(t >= 0);
         assert(t < _JOB_TYPE_MAX);
-        DISABLE_WARNING_FORMAT_NONLITERAL;
-
-        if (t == JOB_START) {
-                format = job_get_status_message_format(u, t, result);
-                if (!format)
-                        return;
-
-                switch (result) {
-
-                case JOB_DONE:
-                        if (u->condition_result)
-                                unit_status_printf(u, ANSI_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, format);
-                        break;
-
-                case JOB_TIMEOUT:
-                        manager_flip_auto_status(u->manager, true);
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
-                        break;
-
-                case JOB_FAILED: {
-                        _cleanup_free_ char *quoted = NULL;
-
-                        quoted = shell_maybe_quote(u->id);
-
-                        manager_flip_auto_status(u->manager, true);
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
-                        manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted));
-                        break;
-                }
-
-                case JOB_DEPENDENCY:
-                        manager_flip_auto_status(u->manager, true);
-                        unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format);
-                        break;
-
-                case JOB_ASSERT:
-                        manager_flip_auto_status(u->manager, true);
-                        unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF, format);
-                        break;
-
-                case JOB_UNSUPPORTED:
-                        manager_flip_auto_status(u->manager, true);
-                        unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "UNSUPP" ANSI_HIGHLIGHT_OFF, format);
-                        break;
-
-                default:
-                        ;
-                }
-
-        } else if (t == JOB_STOP || t == JOB_RESTART) {
-
-                format = job_get_status_message_format(u, t, result);
-                if (!format)
-                        return;
+        /* Reload status messages have traditionally not been printed to console. */
+        if (t == JOB_RELOAD)
+                return;
-                switch (result) {
+        if (t == JOB_START && result == JOB_DONE && !u->condition_result)
+                return;
-                case JOB_TIMEOUT:
-                        manager_flip_auto_status(u->manager, true);
-                        unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
-                        break;
+        format = job_get_status_message_format(u, t, result);
+        if (!format)
+                return;
-                case JOB_DONE:
-                case JOB_FAILED:
-                        unit_status_printf(u, ANSI_GREEN_ON "  OK  " ANSI_HIGHLIGHT_OFF, format);
-                        break;
+        if (result != JOB_DONE)
+                manager_flip_auto_status(u->manager, true);
-                default:
-                        ;
-                }
+        DISABLE_WARNING_FORMAT_NONLITERAL;
+        unit_status_printf(u, job_result_status_table[result], format);
+        REENABLE_WARNING;
-        } else if (t == JOB_VERIFY_ACTIVE) {
+        if (t == JOB_START && result == JOB_FAILED) {
+                _cleanup_free_ char *quoted = shell_maybe_quote(u->id);
-                /* When verify-active detects the unit is inactive, report it.
-                 * Most likely a DEPEND warning from a requisiting unit will
-                 * occur next and it's nice to see what was requisited. */
-                if (result == JOB_SKIPPED)
-                        unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.");
+                manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL,
+                                      "See 'systemctl status %s' for details.", strna(quoted));
         }
-
-        REENABLE_WARNING;
 }
 static void job_log_status_message(Unit *u, JobType t, JobResult result) {
@@ -788,7 +732,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
         if (log_on_console())
                 return;
-        format = job_get_status_message_format_try_harder(u, t, result);
+        format = job_get_status_message_format(u, t, result);
         if (!format)
                 return;
SOURCES/0633-core-remove-generic-job-completion-messages-from-uni.patch
New file
@@ -0,0 +1,132 @@
From 60545c63716ecc720728c221c61d575b267fbfc8 Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Tue, 21 Jul 2015 15:51:16 +0200
Subject: [PATCH] core: remove generic job completion messages from unit
 vtables
These units' message format strings are identical to the generic
strings. Since we can always rely on the fallback, these are now
redundant.
(cherry picked from commit c382d69e3d39daedebcedb2da882beeb147a3cda)
Related: #1506256
---
 src/core/automount.c | 1 -
 src/core/busname.c   | 3 ---
 src/core/mount.c     | 1 -
 src/core/service.c   | 3 ---
 src/core/slice.c     | 1 -
 src/core/socket.c    | 1 -
 src/core/swap.c      | 1 -
 src/core/target.c    | 1 -
 8 files changed, 12 deletions(-)
diff --git a/src/core/automount.c b/src/core/automount.c
index 679fe071e..08519e49c 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -1126,7 +1126,6 @@ const UnitVTable automount_vtable = {
                 .finished_start_job = {
                         [JOB_DONE]       = "Set up automount %s.",
                         [JOB_FAILED]     = "Failed to set up automount %s.",
-                        [JOB_DEPENDENCY] = "Dependency failed for %s.",
                 },
                 .finished_stop_job = {
                         [JOB_DONE]       = "Unset automount %s.",
diff --git a/src/core/busname.c b/src/core/busname.c
index f626ba96d..a5e659049 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -1064,13 +1064,10 @@ const UnitVTable busname_vtable = {
                 .finished_start_job = {
                         [JOB_DONE]       = "Listening on %s.",
                         [JOB_FAILED]     = "Failed to listen on %s.",
-                        [JOB_DEPENDENCY] = "Dependency failed for %s.",
-                        [JOB_TIMEOUT]    = "Timed out starting %s.",
                 },
                 .finished_stop_job = {
                         [JOB_DONE]       = "Closed %s.",
                         [JOB_FAILED]     = "Failed stopping %s.",
-                        [JOB_TIMEOUT]    = "Timed out stopping %s.",
                 },
         },
 };
diff --git a/src/core/mount.c b/src/core/mount.c
index f726d9659..0dc67dde6 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -1978,7 +1978,6 @@ const UnitVTable mount_vtable = {
                 .finished_start_job = {
                         [JOB_DONE]       = "Mounted %s.",
                         [JOB_FAILED]     = "Failed to mount %s.",
-                        [JOB_DEPENDENCY] = "Dependency failed for %s.",
                         [JOB_TIMEOUT]    = "Timed out mounting %s.",
                 },
                 .finished_stop_job = {
diff --git a/src/core/service.c b/src/core/service.c
index 9622ce11f..8303a1e7e 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -3398,13 +3398,10 @@ const UnitVTable service_vtable = {
                 .finished_start_job = {
                         [JOB_DONE]       = "Started %s.",
                         [JOB_FAILED]     = "Failed to start %s.",
-                        [JOB_DEPENDENCY] = "Dependency failed for %s.",
-                        [JOB_TIMEOUT]    = "Timed out starting %s.",
                 },
                 .finished_stop_job = {
                         [JOB_DONE]       = "Stopped %s.",
                         [JOB_FAILED]     = "Stopped (with error) %s.",
-                        [JOB_TIMEOUT]    = "Timed out stopping %s.",
                 },
         },
 };
diff --git a/src/core/slice.c b/src/core/slice.c
index 9154558b7..1cce3e121 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -299,7 +299,6 @@ const UnitVTable slice_vtable = {
         .status_message_formats = {
                 .finished_start_job = {
                         [JOB_DONE]       = "Created slice %s.",
-                        [JOB_DEPENDENCY] = "Dependency failed for %s.",
                 },
                 .finished_stop_job = {
                         [JOB_DONE]       = "Removed slice %s.",
diff --git a/src/core/socket.c b/src/core/socket.c
index 771af0d24..efefe7ce5 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2736,7 +2736,6 @@ const UnitVTable socket_vtable = {
                 .finished_start_job = {
                         [JOB_DONE]       = "Listening on %s.",
                         [JOB_FAILED]     = "Failed to listen on %s.",
-                        [JOB_DEPENDENCY] = "Dependency failed for %s.",
                         [JOB_TIMEOUT]    = "Timed out starting %s.",
                 },
                 .finished_stop_job = {
diff --git a/src/core/swap.c b/src/core/swap.c
index 984be2d9a..e71de4e65 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -1525,7 +1525,6 @@ const UnitVTable swap_vtable = {
                 .finished_start_job = {
                         [JOB_DONE]       = "Activated swap %s.",
                         [JOB_FAILED]     = "Failed to activate swap %s.",
-                        [JOB_DEPENDENCY] = "Dependency failed for %s.",
                         [JOB_TIMEOUT]    = "Timed out activating swap %s.",
                 },
                 .finished_stop_job = {
diff --git a/src/core/target.c b/src/core/target.c
index 2411a8e75..45248ad02 100644
--- a/src/core/target.c
+++ b/src/core/target.c
@@ -231,7 +231,6 @@ const UnitVTable target_vtable = {
         .status_message_formats = {
                 .finished_start_job = {
                         [JOB_DONE]       = "Reached target %s.",
-                        [JOB_DEPENDENCY] = "Dependency failed for %s.",
                 },
                 .finished_stop_job = {
                         [JOB_DONE]       = "Stopped target %s.",
SOURCES/0634-core-do-not-log-done-failed-condition-jobs-as-if-uni.patch
New file
@@ -0,0 +1,67 @@
From 0fd062edc435d9cf39022e2e92c895bf8625ad0d Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Tue, 21 Jul 2015 16:15:19 +0200
Subject: [PATCH] core: do not log done failed-condition jobs as if unit
 started
It is misleading to see "Started foo." in the log when the unit's
condition was false.
(cherry picked from commit 30961fa300cad21b50fe47baee523beeadb5d0bc)
Related: #1506256
---
 src/core/job.c | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)
diff --git a/src/core/job.c b/src/core/job.c
index f371f914d..5e582b3d3 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -692,13 +692,6 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
         assert(t >= 0);
         assert(t < _JOB_TYPE_MAX);
-        /* Reload status messages have traditionally not been printed to console. */
-        if (t == JOB_RELOAD)
-                return;
-
-        if (t == JOB_START && result == JOB_DONE && !u->condition_result)
-                return;
-
         format = job_get_status_message_format(u, t, result);
         if (!format)
                 return;
@@ -768,6 +761,19 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
                                 NULL);
 }
+static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
+
+        /* No message if the job did not actually do anything due to failed condition. */
+        if (t == JOB_START && result == JOB_DONE && !u->condition_result)
+                return;
+
+        job_log_status_message(u, t, result);
+
+        /* Reload status messages have traditionally not been printed to console. */
+        if (t != JOB_RELOAD)
+                job_print_status_message(u, t, result);
+}
+
 int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) {
         Unit *u;
         Unit *other;
@@ -787,10 +793,8 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
                        u->id, job_type_to_string(t), job_result_to_string(result));
         /* If this job did nothing to respective unit we don't log the status message */
-        if (!already) {
-                job_print_status_message(u, t, result);
-                job_log_status_message(u, t, result);
-        }
+        if (!already)
+                job_emit_status_message(u, t, result);
         job_add_to_dbus_queue(j);
SOURCES/0635-core-log-completion-of-remaining-job-types.patch
New file
@@ -0,0 +1,42 @@
From 010b80c6215da7357114911f46742939772e18fc Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Tue, 21 Jul 2015 16:20:18 +0200
Subject: [PATCH] core: log completion of remaining job types
JOB_RESTART and failed JOB_VERIFY_ACTIVE completions were printed to
console but not to the log.
(cherry picked from commit 4f29c6fea6a6c5c2c9406ad091cd6f56da21e2cb)
Related: #1506256
---
 src/core/job.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/core/job.c b/src/core/job.c
index 5e582b3d3..086050aa7 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -743,8 +743,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
                                 LOG_MESSAGE("%s", buf),
                                 "RESULT=%s", job_result_to_string(result),
                                 NULL);
-
-        } else if (t == JOB_STOP)
+        } else if (t == JOB_STOP || t == JOB_RESTART)
                 log_unit_struct(u->id,
                                 result == JOB_DONE ? LOG_INFO : LOG_ERR,
                                 LOG_MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
@@ -759,6 +758,12 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
                                 LOG_MESSAGE("%s", buf),
                                 "RESULT=%s", job_result_to_string(result),
                                 NULL);
+        else
+                log_unit_struct(u->id,
+                                result == JOB_DONE ? LOG_INFO : LOG_ERR,
+                                LOG_MESSAGE("%s", buf),
+                                "RESULT=%s", job_result_to_string(result),
+                                NULL);
 }
 static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
SOURCES/0636-core-adjust-job-completion-message-log-levels.patch
New file
@@ -0,0 +1,75 @@
From ea366cda56dc0550b9829e4d9e733cb8b70ffb30 Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Tue, 21 Jul 2015 19:07:24 +0200
Subject: [PATCH] core: adjust job completion message log levels
We do not print all non-OK job completion status messages to the console
in red, because not all of them are plain errors. We do however log the
same messages as LOG_ERR.
Differentiate the log levels by deducing them from the job result in a
way that more or less matches the color of the console message.
(cherry picked from commit 64f575d2ab9a6743d3c7172b7591c88ba243cf1b)
Related: #1506256
---
 src/core/job.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/src/core/job.c b/src/core/job.c
index 086050aa7..1861c8a63 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -714,6 +714,17 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
 static void job_log_status_message(Unit *u, JobType t, JobResult result) {
         const char *format;
         char buf[LINE_MAX];
+        static const int job_result_log_level[_JOB_RESULT_MAX] = {
+                [JOB_DONE]        = LOG_INFO,
+                [JOB_CANCELED]    = LOG_INFO,
+                [JOB_TIMEOUT]     = LOG_ERR,
+                [JOB_FAILED]      = LOG_ERR,
+                [JOB_DEPENDENCY]  = LOG_WARNING,
+                [JOB_SKIPPED]     = LOG_NOTICE,
+                [JOB_INVALID]     = LOG_INFO,
+                [JOB_ASSERT]      = LOG_WARNING,
+                [JOB_UNSUPPORTED] = LOG_WARNING,
+        };
         assert(u);
         assert(t >= 0);
@@ -738,14 +749,14 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
                 mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
                 log_unit_struct(u->id,
-                                result == JOB_DONE ? LOG_INFO : LOG_ERR,
+                                job_result_log_level[result],
                                 LOG_MESSAGE_ID(mid),
                                 LOG_MESSAGE("%s", buf),
                                 "RESULT=%s", job_result_to_string(result),
                                 NULL);
         } else if (t == JOB_STOP || t == JOB_RESTART)
                 log_unit_struct(u->id,
-                                result == JOB_DONE ? LOG_INFO : LOG_ERR,
+                                job_result_log_level[result],
                                 LOG_MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
                                 LOG_MESSAGE("%s", buf),
                                 "RESULT=%s", job_result_to_string(result),
@@ -753,14 +764,14 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
         else if (t == JOB_RELOAD)
                 log_unit_struct(u->id,
-                                result == JOB_DONE ? LOG_INFO : LOG_ERR,
+                                job_result_log_level[result],
                                 LOG_MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
                                 LOG_MESSAGE("%s", buf),
                                 "RESULT=%s", job_result_to_string(result),
                                 NULL);
         else
                 log_unit_struct(u->id,
-                                result == JOB_DONE ? LOG_INFO : LOG_ERR,
+                                job_result_log_level[result],
                                 LOG_MESSAGE("%s", buf),
                                 "RESULT=%s", job_result_to_string(result),
                                 NULL);
SOURCES/0637-mount-add-new-LazyUnmount-setting-for-mount-units-ma.patch
New file
@@ -0,0 +1,111 @@
From 048ed4b2fecef7003925772740bab651cb08b260 Mon Sep 17 00:00:00 2001
From: brulon <barron@lexmark.com>
Date: Fri, 26 Aug 2016 11:57:22 -0400
Subject: [PATCH] mount: add new LazyUnmount= setting for mount units, mapping
 to umount(8)'s "-l" switch (#3827)
(cherry-picked commit from e520950a03419957875034bc27795b0b81d8e793)
Resolves: #1497264
---
 man/systemd.mount.xml                 | 13 +++++++++++++
 src/core/dbus-mount.c                 |  1 +
 src/core/load-fragment-gperf.gperf.m4 |  1 +
 src/core/mount.c                      |  8 ++++++--
 src/core/mount.h                      |  2 ++
 5 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
index dfa437b5d..1590c44ce 100644
--- a/man/systemd.mount.xml
+++ b/man/systemd.mount.xml
@@ -329,6 +329,19 @@
         off.</para></listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>LazyUnmount=</varname></term>
+
+        <listitem><para>Takes a boolean argument. If true, detach the
+        filesystem from the filesystem hierarchy at time of the unmount
+        operation, and clean up all references to the filesystem as
+        soon as they are not busy anymore.
+        This corresponds with
+        <citerefentry project='man-pages'><refentrytitle>umount</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
+        <parameter>-l</parameter> switch. Defaults to
+        off.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>DirectoryMode=</varname></term>
         <listitem><para>Directories of mount points (and any parent
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
index 04beba631..cbb842f70 100644
--- a/src/core/dbus-mount.c
+++ b/src/core/dbus-mount.c
@@ -110,6 +110,7 @@ const sd_bus_vtable bus_mount_vtable[] = {
         SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Mount, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Mount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SloppyOptions", "b", bus_property_get_bool, offsetof(Mount, sloppy_options), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LazyUnmount", "b", bus_property_get_bool, offsetof(Mount, lazy_unmount), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         BUS_EXEC_COMMAND_VTABLE("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
         BUS_EXEC_COMMAND_VTABLE("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index b2fe627af..664bba0ef 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -316,6 +316,7 @@ Mount.Type,                      config_parse_string,                0,
 Mount.TimeoutSec,                config_parse_sec,                   0,                             offsetof(Mount, timeout_usec)
 Mount.DirectoryMode,             config_parse_mode,                  0,                             offsetof(Mount, directory_mode)
 Mount.SloppyOptions,             config_parse_bool,                  0,                             offsetof(Mount, sloppy_options)
+Mount.LazyUnmount,               config_parse_bool,                  0,                             offsetof(Mount, lazy_unmount)
 EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
 CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
diff --git a/src/core/mount.c b/src/core/mount.c
index 0dc67dde6..5fd7a86dd 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -690,7 +690,8 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
                 "%sOptions: %s\n"
                 "%sFrom /proc/self/mountinfo: %s\n"
                 "%sFrom fragment: %s\n"
-                "%sDirectoryMode: %04o\n",
+                "%sDirectoryMode: %04o\n"
+                "%sLazyUnmount: %s\n",
                 prefix, mount_state_to_string(m->state),
                 prefix, mount_result_to_string(m->result),
                 prefix, m->where,
@@ -699,7 +700,8 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
                 prefix, p ? strna(p->options) : "n/a",
                 prefix, yes_no(m->from_proc_self_mountinfo),
                 prefix, yes_no(m->from_fragment),
-                prefix, m->directory_mode);
+                prefix, m->directory_mode,
+                prefix, yes_no(m->lazy_unmount));
         if (m->control_pid > 0)
                 fprintf(f,
@@ -891,6 +893,8 @@ static void mount_enter_unmounting(Mount *m) {
         m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
         r = exec_command_set(m->control_command, "/bin/umount", m->where, NULL);
+        if (r >= 0 && m->lazy_unmount)
+                r = exec_command_append(m->control_command, "-l", NULL);
         if (r < 0)
                 goto fail;
diff --git a/src/core/mount.h b/src/core/mount.h
index 353222000..4e870299c 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -90,6 +90,8 @@ struct Mount {
         bool sloppy_options;
+        bool lazy_unmount;
+
         MountResult result;
         MountResult reload_result;
SOURCES/0638-rules-Add-MODEL_ID-for-NVMe-device-7037.patch
New file
@@ -0,0 +1,42 @@
From 14ca846073e3b7accb71012a9612d0a7cb6b5ea6 Mon Sep 17 00:00:00 2001
From: gwendalcr <gwendal@chromium.org>
Date: Wed, 20 Jun 2018 16:54:05 +0200
Subject: [PATCH] rules: Add MODEL_ID for NVMe device (#7037)
To mimic MODEL_ID variable built for ATA and SCSI devices, add rules
to add MODEL_ID variable for NVMe devices.
TEST: Check on a system with NVMe device that MODEL_ID variable is
present:
 udevadm info --query=all -n /dev/nvme0n1p1 | grep ID_MODEL
and
 udevadm info --query=all -n /dev/nvme0n1p1 | grep ID_MODEL
return:
E: ID_MODEL=SAMSUNG...
(cherry picked from commit e2c2d70ba7cc7497b03c4a377bfb529035540aa7)
Resolves: #1397264
---
 rules/60-persistent-storage.rules | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/rules/60-persistent-storage.rules b/rules/60-persistent-storage.rules
index ba619633b..4aae97a9f 100644
--- a/rules/60-persistent-storage.rules
+++ b/rules/60-persistent-storage.rules
@@ -28,10 +28,12 @@ KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{wwid}=="?*"
 KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}"
 KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{wwid}=="?*", ENV{ID_WWN}="$attr{wwid}"
-KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}", OPTIONS="string_escape=replace"
+KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ATTRS{model}=="?*", ENV{ID_MODEL}="$attr{model}"
+KERNEL=="nvme*[0-9]n*[0-9]", ENV{DEVTYPE}=="disk", ENV{ID_MODEL}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$env{ID_MODEL}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}", OPTIONS="string_escape=replace"
 KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{serial}=="?*", ENV{ID_SERIAL_SHORT}="$attr{serial}"
-KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{model}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$attr{model}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n", OPTIONS="string_escape=replace"
+KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{model}=="?*", ENV{ID_MODEL}="$attr{model}"
+KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ENV{ID_MODEL}=="?*", ENV{ID_SERIAL_SHORT}=="?*", ENV{ID_SERIAL}="$env{ID_MODEL}_$env{ID_SERIAL_SHORT}", SYMLINK+="disk/by-id/nvme-$env{ID_SERIAL}-part%n", OPTIONS="string_escape=replace"
 # virtio-blk
 KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}"
SOURCES/0639-umount-always-use-MNT_FORCE-in-umount_all-7213.patch
File was renamed from SOURCES/0614-umount-always-use-MNT_FORCE-in-umount_all-7213.patch
@@ -1,4 +1,4 @@
From d9232a652080ac260c78ab647608860269b45d03 Mon Sep 17 00:00:00 2001
From 5bace483dedc9098da8191f39c823649948a7a3c Mon Sep 17 00:00:00 2001
From: NeilBrown <neil@brown.name>
Date: Wed, 8 Nov 2017 19:29:32 +1100
Subject: [PATCH] umount: always use MNT_FORCE in umount_all() (#7213)
SOURCES/0640-core-Implement-timeout-based-umount-remount-limit.patch
File was renamed from SOURCES/0615-core-Implement-timeout-based-umount-remount-limit.patch
@@ -1,4 +1,4 @@
From dd531b196e9dd794f7409f97320814e24f50081b Mon Sep 17 00:00:00 2001
From 5ccae46f2a192a9347feb604901127c55ce1e039 Mon Sep 17 00:00:00 2001
From: Kyle Walker <kwalker@redhat.com>
Date: Wed, 13 Dec 2017 12:49:26 -0500
Subject: [PATCH] core: Implement timeout based umount/remount limit
@@ -22,8 +22,8 @@
 src/shared/def.h          |   2 -
 src/shared/login-shared.c |   1 +
 src/shared/util.c         |  61 +++++++++++++++++++++++++
 src/shared/util.h         |  15 +++++++
 5 files changed, 167 insertions(+), 24 deletions(-)
 src/shared/util.h         |  16 +++++++
 5 files changed, 168 insertions(+), 24 deletions(-)
diff --git a/src/core/umount.c b/src/core/umount.c
index 91d67c06c..bd3896612 100644
@@ -204,12 +204,12 @@
 bool session_id_valid(const char *id) {
         assert(id);
diff --git a/src/shared/util.c b/src/shared/util.c
index af0953273..5e27a41da 100644
index 982f5e044..3216f004a 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -8893,3 +8893,64 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
@@ -9049,3 +9049,64 @@ try_dev_shm_without_o_tmpfile:
 
         return m / max;
         return -EOPNOTSUPP;
 }
+
+/*
@@ -273,7 +273,7 @@
+        return -EPROTO;
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index 526a6fe84..81aef034e 100644
index 9c4be0256..998f882bb 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -22,6 +22,7 @@
@@ -284,10 +284,10 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <time.h>
@@ -1112,3 +1113,17 @@ int parse_percent(const char *p);
@@ -1122,3 +1123,18 @@ enum {
 };
 
 uint64_t system_tasks_max(void);
 uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
 int acquire_data_fd(const void *data, size_t size, unsigned flags);
+
+int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout);
+
@@ -302,3 +302,4 @@
+                assert_se(sigprocmask_many(SIG_BLOCK, __VA_ARGS__, -1) >= 0);      \
+                _t;                                                                \
+        })
+
SOURCES/0641-core-Implement-sync_with_progress.patch
File was renamed from SOURCES/0616-core-Implement-sync_with_progress.patch
@@ -1,4 +1,4 @@
From ddc1464f3b129ea8490d7da3dd000ab1874b3a4d Mon Sep 17 00:00:00 2001
From db57bf73d3e5e650b261834a0c39c9d368f9eeea Mon Sep 17 00:00:00 2001
From: Kyle Walker <kwalker@redhat.com>
Date: Thu, 14 Dec 2017 11:46:03 -0500
Subject: [PATCH] core: Implement sync_with_progress()
SOURCES/0642-journal-fix-HMAC-calculation-when-appending-a-data-o.patch
New file
@@ -0,0 +1,48 @@
From 4f36220ccfe40621cd7df3595568278d7bca4f87 Mon Sep 17 00:00:00 2001
From: Franck Bui <fbui@suse.com>
Date: Fri, 23 Sep 2016 13:33:01 +0200
Subject: [PATCH] journal: fix HMAC calculation when appending a data object
Since commit 5996c7c295e073ce21d41305169132c8aa993ad0 (v190 !), the
calculation of the HMAC is broken because the hash for a data object
including a field is done in the wrong order: the field object is
hashed before the data object is.
However during verification, the hash is done in the opposite order as
objects are scanned sequentially.
(cherry picked from commit 33685a5a3a98c6ded64d0cc25e37d0180ceb0a6a)
---
 src/journal/journal-file.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 2bb3a9757..586f620e2 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -1099,6 +1099,12 @@ static int journal_file_append_data(
         if (r < 0)
                 return r;
+#ifdef HAVE_GCRYPT
+        r = journal_file_hmac_put_object(f, OBJECT_DATA, o, p);
+        if (r < 0)
+                return r;
+#endif
+
         /* The linking might have altered the window, so let's
          * refresh our pointer */
         r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
@@ -1123,12 +1129,6 @@ static int journal_file_append_data(
                 fo->field.head_data_offset = le64toh(p);
         }
-#ifdef HAVE_GCRYPT
-        r = journal_file_hmac_put_object(f, OBJECT_DATA, o, p);
-        if (r < 0)
-                return r;
-#endif
-
         if (ret)
                 *ret = o;
SOURCES/0643-journal-forward-messages-from-dev-log-unmodified-to-.patch
New file
@@ -0,0 +1,135 @@
From d82c40a2377b487ef83aa1fb907ec275a1b3e86e Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 30 May 2018 16:27:22 +0200
Subject: [PATCH] journal: forward messages from /dev/log unmodified to
 syslog.socket
(cherry picked from commit bb3ff70a86faff85fe482995c8ba5332b1a34f76)
Resolves: #1409659
---
 src/journal/journald-server.c |  2 +-
 src/journal/journald-syslog.c | 39 +++++++++++++++++++++++++--------------
 src/journal/journald-syslog.h |  2 +-
 3 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 7c69061f4..7e67e055e 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1294,7 +1294,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
         if (fd == s->syslog_fd) {
                 if (n > 0 && n_fds == 0)
-                        server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len);
+                        server_process_syslog_message(s, s->buffer, n, ucred, tv, label, label_len);
                 else if (n_fds > 0)
                         log_warning("Got file descriptors via syslog socket. Ignoring.");
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index b499a0d38..01d2bf69f 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -109,7 +109,7 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
                 log_debug_errno(errno, "Failed to forward syslog message: %m");
 }
-static void forward_syslog_raw(Server *s, int priority, const char *buffer, const struct ucred *ucred, const struct timeval *tv) {
+static void forward_syslog_raw(Server *s, int priority, const char *buffer, size_t buffer_len, const struct ucred *ucred, const struct timeval *tv) {
         struct iovec iovec;
         assert(s);
@@ -118,7 +118,9 @@ static void forward_syslog_raw(Server *s, int priority, const char *buffer, cons
         if (LOG_PRI(priority) > s->max_level_syslog)
                 return;
-        IOVEC_SET_STRING(iovec, buffer);
+        iovec.iov_base = (char *) buffer;
+        iovec.iov_len = buffer_len;
+
         forward_syslog_iovec(s, &iovec, 1, ucred, tv);
 }
@@ -311,40 +313,49 @@ static void syslog_skip_date(char **buf) {
 void server_process_syslog_message(
         Server *s,
         const char *buf,
+        size_t buf_len,
         const struct ucred *ucred,
         const struct timeval *tv,
         const char *label,
         size_t label_len) {
         char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)],
-             syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
+             syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)], *msg;
         const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
         struct iovec iovec[N_IOVEC_META_FIELDS + 6];
-        unsigned n = 0;
+        unsigned n = 0, i;
         int priority = LOG_USER | LOG_INFO;
         _cleanup_free_ char *identifier = NULL, *pid = NULL;
-        const char *orig;
         assert(s);
         assert(buf);
-        orig = buf;
-        syslog_parse_priority(&buf, &priority, true);
+        /* We are creating copy of the message because we want to forward original message verbatim to the legacy
+           syslog implementation */
+        for (i = buf_len; i > 0; i--)
+                if (!strchr(WHITESPACE, buf[i-1]))
+                        break;
+
+        msg = newa(char, i + 1);
+        *((char *) mempcpy(msg, buf, i)) = 0;
+        msg += strspn(msg, WHITESPACE);
+
+        syslog_parse_priority((const char **)&msg, &priority, true);
         if (s->forward_to_syslog)
-                forward_syslog_raw(s, priority, orig, ucred, tv);
+                forward_syslog_raw(s, priority, buf, buf_len, ucred, tv);
-        syslog_skip_date((char**) &buf);
-        syslog_parse_identifier(&buf, &identifier, &pid);
+        syslog_skip_date(&msg);
+        syslog_parse_identifier((const char**)&msg, &identifier, &pid);
         if (s->forward_to_kmsg)
-                server_forward_kmsg(s, priority, identifier, buf, ucred);
+                server_forward_kmsg(s, priority, identifier, msg, ucred);
         if (s->forward_to_console)
-                server_forward_console(s, priority, identifier, buf, ucred);
+                server_forward_console(s, priority, identifier, msg, ucred);
         if (s->forward_to_wall)
-                server_forward_wall(s, priority, identifier, buf, ucred);
+                server_forward_wall(s, priority, identifier, msg, ucred);
         IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog");
@@ -368,7 +379,7 @@ void server_process_syslog_message(
                         IOVEC_SET_STRING(iovec[n++], syslog_pid);
         }
-        message = strjoina("MESSAGE=", buf);
+        message = strjoina("MESSAGE=", msg);
         if (message)
                 IOVEC_SET_STRING(iovec[n++], message);
diff --git a/src/journal/journald-syslog.h b/src/journal/journald-syslog.h
index 3774ebdf0..e593be99a 100644
--- a/src/journal/journald-syslog.h
+++ b/src/journal/journald-syslog.h
@@ -29,7 +29,7 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid);
 void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred, const struct timeval *tv);
-void server_process_syslog_message(Server *s, const char *buf, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len);
+void server_process_syslog_message(Server *s, const char *buf, size_t buf_len, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len);
 int server_open_syslog_socket(Server *s);
 void server_maybe_warn_forward_syslog_missed(Server *s);
SOURCES/0644-tmpfiles-use-safe_glob.patch
New file
@@ -0,0 +1,158 @@
From 2f9ee3163c44a71c99fe104daf01d4d9ab51d2c9 Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Mon, 28 May 2018 10:52:52 +0200
Subject: [PATCH] tmpfiles: use safe_glob()
This filters out "." and ".." from glob results. Fixes #5655 and #5644.
Any judgements on whether the path is "safe" are removed. We will not remove
"/" under any name (including "/../" and such), but we will remove stuff that
is specified using paths that include "//", "/./" and "/../". Such paths can be
created when joining strings automatically, or for other reasons, and people
generally know what ".." and "." is.
Tests are added to make sure that the helper functions behave as expected.
Original commit: 84e72b5ef445ffb256bc4add4209c4c9c9855206
Resolves: #1436004
---
 src/shared/util.c       | 63 +++++++++++++++++++++++++++++++++++++++++++++++--
 src/shared/util.h       |  2 ++
 src/tmpfiles/tmpfiles.c | 11 +++------
 3 files changed, 66 insertions(+), 10 deletions(-)
diff --git a/src/shared/util.c b/src/shared/util.c
index 3216f004a..78967103a 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -49,7 +49,6 @@
 #include <dlfcn.h>
 #include <sys/wait.h>
 #include <sys/time.h>
-#include <glob.h>
 #include <grp.h>
 #include <sys/mman.h>
 #include <sys/vfs.h>
@@ -3370,7 +3369,7 @@ static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bo
         /* We refuse to clean the root file system with this
          * call. This is extra paranoia to never cause a really
          * seriously broken system. */
-        if (path_equal(path, "/")) {
+        if (path_equal_or_files_same(path, "/")) {
                 log_error("Attempted to remove entire root file system, and we can't allow that.");
                 return -EPERM;
         }
@@ -5096,6 +5095,66 @@ int in_group(const char *name) {
         return in_gid(gid);
 }
+static void closedir_wrapper(void* v) {
+        (void) closedir(v);
+}
+
+static bool dot_or_dot_dot(const char *path) {
+        if (!path)
+                return false;
+        if (path[0] != '.')
+                return false;
+        if (path[1] == 0)
+                return true;
+        if (path[1] != '.')
+                return false;
+
+        return path[2] == 0;
+}
+
+static struct dirent* readdir_no_dot(DIR *dirp) {
+        struct dirent* d;
+
+        for (;;) {
+                d = readdir(dirp);
+                if (d && dot_or_dot_dot(d->d_name))
+                        continue;
+                return d;
+        }
+}
+
+int safe_glob(const char *path, int flags, glob_t *pglob) {
+        int k;
+
+        /* We want to set GLOB_ALTDIRFUNC ourselves, don't allow it to be set. */
+        assert(!(flags & GLOB_ALTDIRFUNC));
+
+        if (!pglob->gl_closedir)
+                pglob->gl_closedir = closedir_wrapper;
+        if (!pglob->gl_readdir)
+                pglob->gl_readdir = (struct dirent *(*)(void *)) readdir_no_dot;
+        if (!pglob->gl_opendir)
+                pglob->gl_opendir = (void *(*)(const char *)) opendir;
+        if (!pglob->gl_lstat)
+                pglob->gl_lstat = lstat;
+        if (!pglob->gl_stat)
+                pglob->gl_stat = stat;
+
+        errno = 0;
+        k = glob(path, flags | GLOB_ALTDIRFUNC, NULL, pglob);
+
+        if (k == GLOB_NOMATCH)
+                return -ENOENT;
+        if (k == GLOB_NOSPACE)
+                return -ENOMEM;
+        if (k != 0)
+                return errno > 0 ? -errno : -EIO;
+        if (strv_isempty(pglob->gl_pathv))
+                return -ENOENT;
+
+        return 0;
+}
+
 int glob_exists(const char *path) {
         _cleanup_globfree_ glob_t g = {};
         int k;
diff --git a/src/shared/util.h b/src/shared/util.h
index 998f882bb..cf096aa07 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -44,6 +44,7 @@
 #include <mntent.h>
 #include <sys/socket.h>
 #include <sys/inotify.h>
+#include <glob.h>
 #if SIZEOF_PID_T == 4
 #  define PID_PRI PRIi32
@@ -595,6 +596,7 @@ char* gid_to_name(gid_t gid);
 int glob_exists(const char *path);
 int glob_extend(char ***strv, const char *path);
+int safe_glob(const char *path, int flags, glob_t *pglob);
 int dirent_ensure_type(DIR *d, struct dirent *de);
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 5212d72f5..8a75efb22 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -1095,19 +1095,14 @@ static int item_do_children(Item *i, const char *path, action_t action) {
 static int glob_item(Item *i, action_t action, bool recursive) {
         _cleanup_globfree_ glob_t g = {
-                .gl_closedir = (void (*)(void *)) closedir,
-                .gl_readdir = (struct dirent *(*)(void *)) readdir,
                 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
-                .gl_lstat = lstat,
-                .gl_stat = stat,
         };
         int r = 0, k;
         char **fn;
-        errno = 0;
-        k = glob(i->path, GLOB_NOSORT|GLOB_BRACE|GLOB_ALTDIRFUNC, NULL, &g);
-        if (k != 0 && k != GLOB_NOMATCH)
-                return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
+        k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g);
+        if (k < 0 && k != -ENOENT)
+                return log_error_errno(k, "glob(%s) failed: %m", i->path);
         STRV_FOREACH(fn, g.gl_pathv) {
                 k = action(i, *fn);
SOURCES/0645-Fix-SELinux-labels-in-cgroup-filesystem-root-directo.patch
New file
@@ -0,0 +1,52 @@
From c043ae5b2ef2e1e437bf738bbf522799c6213230 Mon Sep 17 00:00:00 2001
From: Krzysztof Nowicki <krzysztof.a.nowicki+github@gmail.com>
Date: Thu, 30 Nov 2017 11:59:29 +0100
Subject: [PATCH] Fix SELinux labels in cgroup filesystem root directory
 (#7496)
When using SELinux with legacy cgroups the tmpfs on /sys/fs/cgroup is by
default labelled as tmpfs_t. This label is also inherited by the "cpu"
and "cpuacct" symbolic links. Unfortunately the policy expects them to
be labelled as cgroup_t, which is used for all the actual cgroup
filesystems. Failure to do so results in a stream of denials.
This state cannot be fixed reliably when the cgroup filesystem structure
is set-up as the SELinux policy is not yet loaded at this
moment. It also cannot be fixed later as the root of the cgroup
filesystem is remounted read-only. In order to fix it the root of the
cgroup filesystem needs to be temporary remounted read-write, relabelled
and remounted back read-only.
(cherry picked from commit 8739f23e3c26bbf8b0296421578e56daa63cbf4b)
---
 src/core/mount-setup.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 521545e5c..7a2cae4a3 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -363,14 +363,22 @@ int mount_setup(bool loaded_policy) {
                 usec_t before_relabel, after_relabel;
                 char timespan[FORMAT_TIMESPAN_MAX];
+                mkdir_label("/run/systemd/policy-relabelling", 0755);
                 before_relabel = now(CLOCK_MONOTONIC);
                 nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
                 nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+                /* Temporarily remount the root cgroup filesystem to give it a proper label. */
+                (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
+                label_fix("/sys/fs/cgroup", false, false);
+                nftw("/sys/fs/cgroup", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+                (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
+
                 after_relabel = now(CLOCK_MONOTONIC);
-                log_info("Relabelled /dev and /run in %s.",
+                mkdir_label("/run/systemd/policy-relabelled", 0755);
+                log_info("Relabelled /dev, /run and /sys/fs/cgroup in %s.",
                          format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel, 0));
         }
 #endif
SOURCES/0646-core-dont-t-remount-sys-fs-cgroup-for-relabel-if-not.patch
New file
@@ -0,0 +1,91 @@
From 1707b9959e67e5e73987e1ff8a72189d24656fa0 Mon Sep 17 00:00:00 2001
From: Krzysztof Nowicki <krzysztof.a.nowicki+github@gmail.com>
Date: Wed, 28 Mar 2018 13:36:33 +0200
Subject: [PATCH] core: dont't remount /sys/fs/cgroup for relabel if not needed
 (#8595)
The initial fix for relabelling the cgroup filesystem for
SELinux delivered in commit 8739f23e3 was based on the assumption that
the cgroup filesystem is already populated once mount_setup() is
executed, which was true for my system. What I wasn't aware is that this
is the case only when another instance of systemd was running before
this one, which can happen if systemd is used in the initrd (for ex. by
dracut).
In case of a clean systemd start-up the cgroup filesystem is actually
being populated after mount_setup() and does not need relabelling as at
that moment the SELinux policy is already loaded. Since however the root
cgroup filesystem was remounted read-only in the meantime this operation
will now fail.
To fix this check for the filesystem mount flags before relabelling and
only remount ro->rw->ro if necessary and leave the filesystem read-write
otherwise.
Fixes #7901.
(cherry picked from commit 6f7729c1767998110c4460c85c94435c5782a613)
---
 src/core/mount-setup.c | 35 ++++++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 7a2cae4a3..ed493cbe3 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -25,6 +25,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
 #include <unistd.h>
 #include <ftw.h>
@@ -337,6 +339,31 @@ static int nftw_cb(
         return FTW_CONTINUE;
 };
+
+static int relabel_cgroup_filesystems(void) {
+        int r;
+        struct statfs st;
+
+        /* Temporarily remount the root cgroup filesystem to give it a proper label. Do this
+           only when the filesystem has been already populated by a previous instance of systemd
+           running from initrd. Otherwise don't remount anything and leave the filesystem read-write
+           for the cgroup filesystems to be mounted inside. */
+        r = statfs("/sys/fs/cgroup", &st);
+        if (r < 0) {
+                return log_error_errno(errno, "Failed to determine mount flags for /sys/fs/cgroup: %m");
+        }
+
+        if (st.f_flags & ST_RDONLY)
+                (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
+
+        (void) label_fix("/sys/fs/cgroup", false, false);
+        nftw("/sys/fs/cgroup", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+
+        if (st.f_flags & ST_RDONLY)
+                (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
+
+        return 0;
+}
 #endif
 int mount_setup(bool loaded_policy) {
@@ -369,11 +396,9 @@ int mount_setup(bool loaded_policy) {
                 nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
                 nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
-                /* Temporarily remount the root cgroup filesystem to give it a proper label. */
-                (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
-                label_fix("/sys/fs/cgroup", false, false);
-                nftw("/sys/fs/cgroup", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
-                (void) mount(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
+                r = relabel_cgroup_filesystems();
+                if (r < 0)
+                        return r;
                 after_relabel = now(CLOCK_MONOTONIC);
SOURCES/0647-fix-race-between-daemon-reload-and-other-commands.patch
New file
@@ -0,0 +1,188 @@
From 13bcf85ffab4b4e67039599246604a3f5b503975 Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Tue, 24 Apr 2018 15:19:38 +0200
Subject: [PATCH] fix race between daemon-reload and other commands
When "systemctl daemon-reload" is run at the same time as "systemctl
start foo", the latter might hang. That's because commands like start
wait for JobRemoved signal to know when the job is finished. But if the
job is finished during reloading, the signal is never sent.
The hang can be easily reproduced by running
    # for ((N=1; N>0; N++)) ; do echo $N ; systemctl daemon-reload ; done
    # for ((N=1; N>0; N++)) ; do echo $N ; systemctl start systemd-coredump.socket ; done
in two different terminals. The start command will hang after 1-2
iterations.
This keeps track of jobs that were started before reload and finished
during it and sends JobRemoved after the reload has finished.
(cherry picked from commit a7a7163df7fc8a9f794f6803b2f6c9c9b0745a1f)
---
 src/core/job.c     | 45 ++++++++++++++++++++++++++++++++++++++++-----
 src/core/job.h     |  2 ++
 src/core/manager.c | 15 +++++++++++++++
 src/core/manager.h |  3 +++
 4 files changed, 60 insertions(+), 5 deletions(-)
diff --git a/src/core/job.c b/src/core/job.c
index 1861c8a63..275503169 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -53,6 +53,7 @@ Job* job_new_raw(Unit *unit) {
         j->manager = unit->manager;
         j->unit = unit;
         j->type = _JOB_TYPE_INVALID;
+        j->reloaded = false;
         return j;
 }
@@ -74,7 +75,7 @@ Job* job_new(Unit *unit, JobType type) {
         return j;
 }
-void job_free(Job *j) {
+void job_unlink(Job *j) {
         assert(j);
         assert(!j->installed);
         assert(!j->transaction_prev);
@@ -82,13 +83,28 @@ void job_free(Job *j) {
         assert(!j->subject_list);
         assert(!j->object_list);
-        if (j->in_run_queue)
+        if (j->in_run_queue) {
                 LIST_REMOVE(run_queue, j->manager->run_queue, j);
+                j->in_run_queue = false;
+        }
-        if (j->in_dbus_queue)
+        if (j->in_dbus_queue) {
                 LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
+                j->in_dbus_queue = false;
+        }
+
+        j->timer_event_source = sd_event_source_unref(j->timer_event_source);
+}
+
+void job_free(Job *j) {
+        assert(j);
+        assert(!j->installed);
+        assert(!j->transaction_prev);
+        assert(!j->transaction_next);
+        assert(!j->subject_list);
+        assert(!j->object_list);
-        sd_event_source_unref(j->timer_event_source);
+        job_unlink(j);
         sd_bus_track_unref(j->clients);
         strv_free(j->deserialized_clients);
@@ -246,6 +262,7 @@ int job_install_deserialized(Job *j) {
         *pj = j;
         j->installed = true;
+        j->reloaded = true;
         if (j->state == JOB_RUNNING)
                 j->unit->manager->n_running_jobs++;
@@ -790,6 +807,19 @@ static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
                 job_print_status_message(u, t, result);
 }
+static int job_save_pending_finished_job(Job *j) {
+        int r;
+
+        assert(j);
+
+        r = set_ensure_allocated(&j->manager->pending_finished_jobs, NULL);
+        if (r < 0)
+                return r;
+
+        job_unlink(j);
+        return set_put(j->manager->pending_finished_jobs, j);
+}
+
 int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) {
         Unit *u;
         Unit *other;
@@ -829,7 +859,12 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
                 j->manager->n_failed_jobs ++;
         job_uninstall(j);
-        job_free(j);
+        /* Remember jobs started before the reload */
+        if (j->manager->n_reloading > 0 && j->reloaded) {
+                if (job_save_pending_finished_job(j) < 0)
+                        job_free(j);
+        } else
+                job_free(j);
         /* Fail depending jobs on failure */
         if (result != JOB_DONE && recursive) {
diff --git a/src/core/job.h b/src/core/job.h
index 535052b48..4ae6f2802 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -172,10 +172,12 @@ struct Job {
         bool sent_dbus_new_signal:1;
         bool ignore_order:1;
         bool irreversible:1;
+        bool reloaded:1;
 };
 Job* job_new(Unit *unit, JobType type);
 Job* job_new_raw(Unit *unit);
+void job_unlink(Job *job);
 void job_free(Job *job);
 Job* job_install(Job *j);
 int job_install_deserialized(Job *j);
diff --git a/src/core/manager.c b/src/core/manager.c
index 47b09e1e9..9c406bb5b 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2702,6 +2702,18 @@ finish:
         return r;
 }
+static void manager_flush_finished_jobs(Manager *m) {
+        Job *j;
+
+        while ((j = set_steal_first(m->pending_finished_jobs))) {
+                bus_job_send_removed_signal(j);
+                job_free(j);
+        }
+
+        set_free(m->pending_finished_jobs);
+        m->pending_finished_jobs = NULL;
+}
+
 int manager_reload(Manager *m) {
         int r, q;
         _cleanup_fclose_ FILE *f = NULL;
@@ -2784,6 +2796,9 @@ int manager_reload(Manager *m) {
         assert(m->n_reloading > 0);
         m->n_reloading--;
+        if (m->n_reloading <= 0)
+                manager_flush_finished_jobs(m);
+
         m->send_reloading_done = true;
         return r;
diff --git a/src/core/manager.h b/src/core/manager.h
index e91e7bd8b..90d2d982e 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -270,6 +270,9 @@ struct Manager {
         /* non-zero if we are reloading or reexecuting, */
         int n_reloading;
+        /* A set which contains all jobs that started before reload and finished
+         * during it */
+        Set *pending_finished_jobs;
         unsigned n_installed_jobs;
         unsigned n_failed_jobs;
SOURCES/0648-core-delay-adding-target-dependencies-until-all-unit.patch
New file
@@ -0,0 +1,223 @@
From 36226a9afe96bdffce9d0697be020f2ca9d7fe6f Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekletar@users.noreply.github.com>
Date: Fri, 23 Mar 2018 15:28:06 +0100
Subject: [PATCH] core: delay adding target dependencies until all units are
 loaded and aliases resolved (#8381)
Currently we add target dependencies while we are loading units. This
can create ordering loops even if configuration doesn't contain any
loop. Take for example following configuration,
$ systemctl get-default
multi-user.target
$ cat /etc/systemd/system/test.service
[Unit]
After=default.target
[Service]
ExecStart=/bin/true
[Install]
WantedBy=multi-user.target
If we encounter such unit file early during manager start-up (e.g. load
queue is dispatched while enumerating devices due to SYSTEMD_WANTS in
udev rules) we would add stub unit default.target and we order it Before
test.service. At the same time we add implicit Before to
multi-user.target. Later we merge two units and we create ordering cycle
in the process.
To fix the issue we will now never add any target dependencies until we
loaded all the unit files and resolved all the aliases.
(cherry picked from commit 19496554e23ea4861ce780430052dcf86a2ffcba)
Resolves: #1368856
---
 src/core/manager.c | 40 ++++++++++++++++++++++++++++++++++++++++
 src/core/manager.h |  3 +++
 src/core/unit.c    | 46 ++++++++++++++++------------------------------
 src/core/unit.h    |  5 +++++
 4 files changed, 64 insertions(+), 30 deletions(-)
diff --git a/src/core/manager.c b/src/core/manager.c
index 9c406bb5b..0466e4bb8 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1373,6 +1373,41 @@ Unit *manager_get_unit(Manager *m, const char *name) {
         return hashmap_get(m->units, name);
 }
+static int manager_dispatch_target_deps_queue(Manager *m) {
+        Unit *u;
+        unsigned k;
+        int r = 0;
+
+        static const UnitDependency deps[] = {
+                UNIT_REQUIRED_BY,
+                UNIT_REQUIRED_BY_OVERRIDABLE,
+                UNIT_WANTED_BY,
+                UNIT_BOUND_BY
+        };
+
+        assert(m);
+
+        while ((u = m->target_deps_queue)) {
+                assert(u->in_target_deps_queue);
+
+                LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
+                u->in_target_deps_queue = false;
+
+                for (k = 0; k < ELEMENTSOF(deps); k++) {
+                        Unit *target;
+                        Iterator i;
+
+                        SET_FOREACH(target, u->dependencies[deps[k]], i) {
+                                r = unit_add_default_target_dependency(u, target);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
+        }
+
+        return r;
+}
+
 unsigned manager_dispatch_load_queue(Manager *m) {
         Unit *u;
         unsigned n = 0;
@@ -1396,6 +1431,11 @@ unsigned manager_dispatch_load_queue(Manager *m) {
         }
         m->dispatching_load_queue = false;
+
+        /* Dispatch the units waiting for their target dependencies to be added now, as all targets that we know about
+         * should be loaded and have aliases resolved */
+        (void) manager_dispatch_target_deps_queue(m);
+
         return n;
 }
diff --git a/src/core/manager.h b/src/core/manager.h
index 90d2d982e..b0e4cad1f 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -114,6 +114,9 @@ struct Manager {
         /* Units that should be realized */
         LIST_HEAD(Unit, cgroup_queue);
+        /* Target units whose default target dependencies haven't been set yet */
+        LIST_HEAD(Unit, target_deps_queue);
+
         sd_event *event;
         /* We use two hash tables here, since the same PID might be
diff --git a/src/core/unit.c b/src/core/unit.c
index 22d9beed7..cfddce34d 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -519,6 +519,9 @@ void unit_free(Unit *u) {
                 u->manager->n_in_gc_queue--;
         }
+        if (u->in_target_deps_queue)
+                LIST_REMOVE(target_deps_queue, u->manager->target_deps_queue, u);
+
         if (u->in_cgroup_queue)
                 LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
@@ -1065,6 +1068,18 @@ int unit_load_fragment_and_dropin_optional(Unit *u) {
         return 0;
 }
+void unit_add_to_target_deps_queue(Unit *u) {
+        Manager *m = u->manager;
+
+        assert(u);
+
+        if (u->in_target_deps_queue)
+                return;
+
+        LIST_PREPEND(target_deps_queue, m->target_deps_queue, u);
+        u->in_target_deps_queue = true;
+}
+
 int unit_add_default_target_dependency(Unit *u, Unit *target) {
         assert(u);
         assert(target);
@@ -1091,32 +1106,6 @@ int unit_add_default_target_dependency(Unit *u, Unit *target) {
         return unit_add_dependency(target, UNIT_AFTER, u, true);
 }
-static int unit_add_target_dependencies(Unit *u) {
-
-        static const UnitDependency deps[] = {
-                UNIT_REQUIRED_BY,
-                UNIT_REQUIRED_BY_OVERRIDABLE,
-                UNIT_WANTED_BY,
-                UNIT_BOUND_BY
-        };
-
-        Unit *target;
-        Iterator i;
-        unsigned k;
-        int r = 0;
-
-        assert(u);
-
-        for (k = 0; k < ELEMENTSOF(deps); k++)
-                SET_FOREACH(target, u->dependencies[deps[k]], i) {
-                        r = unit_add_default_target_dependency(u, target);
-                        if (r < 0)
-                                return r;
-                }
-
-        return r;
-}
-
 static int unit_add_slice_dependencies(Unit *u) {
         assert(u);
@@ -1217,10 +1206,7 @@ int unit_load(Unit *u) {
         }
         if (u->load_state == UNIT_LOADED) {
-
-                r = unit_add_target_dependencies(u);
-                if (r < 0)
-                        goto fail;
+                unit_add_to_target_deps_queue(u);
                 r = unit_add_slice_dependencies(u);
                 if (r < 0)
diff --git a/src/core/unit.h b/src/core/unit.h
index 480e2e95f..dfec9cea0 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -162,6 +162,9 @@ struct Unit {
         /* CGroup realize members queue */
         LIST_FIELDS(Unit, cgroup_queue);
+        /* Target dependencies queue */
+        LIST_FIELDS(Unit, target_deps_queue);
+
         /* PIDs we keep an eye on. Note that a unit might have many
          * more, but these are the ones we care enough about to
          * process SIGCHLD for */
@@ -228,6 +231,7 @@ struct Unit {
         bool in_cleanup_queue:1;
         bool in_gc_queue:1;
         bool in_cgroup_queue:1;
+        bool in_target_deps_queue:1;
         bool sent_dbus_new_signal:1;
@@ -498,6 +502,7 @@ void unit_add_to_load_queue(Unit *u);
 void unit_add_to_dbus_queue(Unit *u);
 void unit_add_to_cleanup_queue(Unit *u);
 void unit_add_to_gc_queue(Unit *u);
+void unit_add_to_target_deps_queue(Unit *u);
 int unit_merge(Unit *u, Unit *other);
 int unit_merge_by_name(Unit *u, const char *other);
SOURCES/0649-man-correct-the-meaning-of-TimeoutStopSec.patch
New file
@@ -0,0 +1,35 @@
From 273a3d35df021128bd72e124d943cbb7b1c7194c Mon Sep 17 00:00:00 2001
From: Jan Synacek <jsynacek@redhat.com>
Date: Fri, 22 Jun 2018 09:11:49 +0200
Subject: [PATCH] man: correct the meaning of TimeoutStopSec=
Fixes: #9325
(cherry picked from commit 9a6da355a06e2b272717f2ac23e41945ce56eb6d)
Resolves: #1305509
---
 man/systemd.service.xml | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index a274db480..d147e449a 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -429,12 +429,12 @@
       <varlistentry>
         <term><varname>TimeoutStopSec=</varname></term>
-        <listitem><para>Configures the time to wait for stop. If a
-        service is asked to stop, but does not terminate in the
-        specified time, it will be terminated forcibly via
-        <constant>SIGTERM</constant>, and after another timeout of
-        equal duration with <constant>SIGKILL</constant> (see
-        <varname>KillMode=</varname> in
+        <listitem><para>This option serves two purposes. First, it configures the time to wait for each
+        <constant>ExecStop=</constant> command. If any of them times out, subsequent <constant>ExecStop=</constant> commands
+        are skipped and the service will be terminated by <constant>SIGTERM</constant>. If no <constant>ExecStop=</constant>
+        commands are specified, the service gets the <constant>SIGTERM</constant> immediately. Second, it configures the time
+        to wait for the service itself to stop. If it doesn't terminate in the specified time, it will be forcibly terminated
+        by <constant>SIGKILL</constant> (see <varname>KillMode=</varname> in
         <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
         Takes a unit-less value in seconds, or a time span value such
         as "5min 20s". Pass <literal>0</literal> to disable the
SOURCES/0650-rules-mark-hotplugged-memory-as-movable.patch
New file
@@ -0,0 +1,32 @@
From 7431c551954ad63fe61cda18888e1e89419bd631 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Fri, 20 Jul 2018 09:48:04 +0200
Subject: [PATCH] rules: mark hotplugged memory as movable
Otherwise the kernel is free to use to memory block also for storing
non-movable memory (any other memory except anonymous memory allocations
and page cache). If user later wants to hot unplug the memory the kernel
will return error in case that some non-movable memory has been place to
the memory block.
Marking hot plugged memory blocks as movable seems to be better
default. Users with specific needs are free to override this udev rule.
Resolves: #1563532
---
 rules/40-redhat.rules | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules
index 34a1df9c4..26f726001 100644
--- a/rules/40-redhat.rules
+++ b/rules/40-redhat.rules
@@ -4,7 +4,7 @@
 SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1"
 # Memory hotadd request
-SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online"
+SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online_movable"
 # reload sysctl.conf / sysctl.conf.d settings when the bridge module is loaded
 ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/bridge"
SOURCES/0651-udev-add-ID_INPUT_SWITCH-for-devices-with-switch-cap.patch
New file
@@ -0,0 +1,27 @@
From fa22d8e9697a0a896007998fdf2cabe7baf98bec Mon Sep 17 00:00:00 2001
From: Peter Hutterer <peter.hutterer@who-t.net>
Date: Tue, 10 Jan 2017 17:36:46 +1000
Subject: [PATCH] udev: add ID_INPUT_SWITCH for devices with switch capability
 (#5057)
(cherry picked from commit 64083a6078630372623bb1013a45d3bf31d8a836)
Resolves: #1597240
---
 src/udev/udev-builtin-input_id.c | 3 +++
 1 file changed, 3 insertions(+)
diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c
index 46f1c539d..d6ae07304 100644
--- a/src/udev/udev-builtin-input_id.c
+++ b/src/udev/udev-builtin-input_id.c
@@ -250,6 +250,9 @@ static int builtin_input_id(struct udev_device *dev, int argc, char *argv[], boo
                 get_cap_mask(dev, pdev, "capabilities/key", bitmask_key, sizeof(bitmask_key), test);
                 test_pointers(dev, bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel, test);
                 test_key(dev, bitmask_ev, bitmask_key, test);
+
+                if (test_bit(EV_SW, bitmask_ev))
+                        udev_builtin_add_property(dev, test, "ID_INPUT_SWITCH", "1");
         }
         devnode = udev_device_get_devnode(dev);
SOURCES/0652-rules-disable-support-for-Dell-IR-cameras.patch
New file
@@ -0,0 +1,32 @@
From e2a2326a283fe38463e637e34205c50ec3066424 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 18 Jul 2018 14:36:17 +0200
Subject: [PATCH] rules: disable support for Dell IR cameras
Resolves: #1591316
---
 Makefile.am                                  | 1 +
 rules/40-redhat-disable-dell-ir-camera.rules | 2 ++
 2 files changed, 3 insertions(+)
 create mode 100644 rules/40-redhat-disable-dell-ir-camera.rules
diff --git a/Makefile.am b/Makefile.am
index cbc120dad..40ebbe98e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3523,6 +3523,7 @@ dist_udevrules_DATA += \
     rules/95-udev-late.rules \
     rules/40-redhat.rules \
     rules/40-redhat-disable-lenovo-ir-camera.rules \
+    rules/40-redhat-disable-dell-ir-camera.rules \
     rules/73-idrac.rules \
         rules/80-net-name-slot.rules
diff --git a/rules/40-redhat-disable-dell-ir-camera.rules b/rules/40-redhat-disable-dell-ir-camera.rules
new file mode 100644
index 000000000..2806482a5
--- /dev/null
+++ b/rules/40-redhat-disable-dell-ir-camera.rules
@@ -0,0 +1,2 @@
+# Disable known IR cameras in Dell Notebooks
+SUBSYSTEM=="usb", ATTRS{idVendor}=="0BDA", ATTRS{idProduct}=="58F6", ATTR{authorized}="0"
SOURCES/0653-rpm-fix-systemd_user_post-macro.patch
New file
@@ -0,0 +1,36 @@
From dda4324fa0b1fb1e07dea18585df6962d8f34b0f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tadej=20Jane=C5=BE?= <tadej.j@nez.si>
Date: Sun, 22 Nov 2015 20:38:05 +0100
Subject: [PATCH] rpm: fix %systemd_user_post() macro.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Escape "--user" and "--global" arguments with "\\" since rpm treats
arguments starting with "-" as macro options which causes "Unknown
option" rpm error.
Use %{expand:...} to force expansion of the inner macro. Otherwise %{?*}
is recursively defined as "\--user \--global {%?*}" which causes
"Too many levels of recursion in macro expansion" rpm error.
Thanks to Michael Mráka for helping me fix the above issues.
(cherry picked from commit e67ba783696f21782ad5c2ba00515d387016e785)
Related: #1582383
---
 src/core/macros.systemd.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in
index bea6ef1da..662791ccc 100644
--- a/src/core/macros.systemd.in
+++ b/src/core/macros.systemd.in
@@ -43,7 +43,7 @@ if [ $1 -eq 1 ] ; then \
 fi \
 %{nil}
-%systemd_user_post() %systemd_post --user --global %{?*}
+%systemd_user_post() %{expand:%systemd_post \\--user \\--global %%{?*}}
 %systemd_preun() \
 if [ $1 -eq 0 ] ; then \
SOURCES/0654-rpm-remove-confusing-user-before-global.patch
New file
@@ -0,0 +1,35 @@
From 4bc18a925e964f10b4e7ed92e8e0d84bf985c6a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sat, 19 May 2018 13:01:55 +0200
Subject: [PATCH] rpm: remove confusing --user before --global
Fixes #9027.
(cherry picked from commit 28d36da64a7a23a55e8d0a139f2620384fd058b3)
Resolves: #1582383
---
 src/core/macros.systemd.in | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in
index 662791ccc..3d6e41274 100644
--- a/src/core/macros.systemd.in
+++ b/src/core/macros.systemd.in
@@ -43,7 +43,7 @@ if [ $1 -eq 1 ] ; then \
 fi \
 %{nil}
-%systemd_user_post() %{expand:%systemd_post \\--user \\--global %%{?*}}
+%systemd_user_post() %{expand:%systemd_post \\--global %%{?*}}
 %systemd_preun() \
 if [ $1 -eq 0 ] ; then \
@@ -56,7 +56,7 @@ fi \
 %systemd_user_preun() \
 if [ $1 -eq 0 ] ; then \
         # Package removal, not upgrade \
-        systemctl --no-reload --user --global disable %{?*} > /dev/null 2>&1 || : \
+        systemctl --global disable %{?*} > /dev/null 2>&1 || : \
 fi \
 %{nil}
SOURCES/0655-automount-handle-state-changes-of-the-corresponding-.patch
File was renamed from SOURCES/0617-automount-handle-state-changes-of-the-corresponding-.patch
@@ -1,4 +1,4 @@
From 6869506c0f4e34163af53decdc08585c25be57ce Mon Sep 17 00:00:00 2001
From b4f506932592b991363b8be11e40b62f861bd032 Mon Sep 17 00:00:00 2001
From: Michael Olbrich <m.olbrich@pengutronix.de>
Date: Fri, 24 Jul 2015 22:25:28 +0200
Subject: [PATCH] automount: handle state changes of the corresponding mount
@@ -16,7 +16,7 @@
 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/core/automount.c b/src/core/automount.c
index 679fe071e..9046caba3 100644
index 08519e49c..f57782b9b 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -499,6 +499,7 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) {
SOURCES/0656-man-document-that-SIGCONT-always-follows-SIGTERM.patch
New file
@@ -0,0 +1,32 @@
From 210c9e5dd1e3d0e37a16225a63840d71b473684c Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 15 Jun 2015 12:05:11 +0200
Subject: [PATCH] man: document that SIGCONT always follows SIGTERM
As requested in #199.
(cherry picked from commit e8c53936316288ea3b33b5997b175862f0efef92)
Resolves: #1601794
---
 man/systemd.kill.xml | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml
index e57f0e724..1292f4f51 100644
--- a/man/systemd.kill.xml
+++ b/man/systemd.kill.xml
@@ -136,7 +136,13 @@
         by <constant>SIGKILL</constant> (see above and below). For a
         list of valid signals, see
         <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
-        Defaults to <constant>SIGTERM</constant>. </para></listitem>
+        Defaults to <constant>SIGTERM</constant>. </para>
+
+        <para>Note that right after sending the signal specified in
+        this setting systemd will always send
+        <constant>SIGCONT</constant>, to ensure that even suspended
+        tasks can be terminated cleanly.</para>
+        </listitem>
       </varlistentry>
       <varlistentry>
SOURCES/0657-rules-add-udev-rule-that-automatically-offline-HW-at.patch
New file
@@ -0,0 +1,46 @@
From 6bc676b1a1bfa7145106f737a6747526ce662b93 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Mon, 23 Jul 2018 16:57:22 +0200
Subject: [PATCH] rules: add udev rule that automatically offline HW attached
 to ACPI container
Resolves: #1597958
---
 Makefile.am                     |  1 +
 rules/40-redhat-hotunplug.rules | 14 ++++++++++++++
 2 files changed, 15 insertions(+)
 create mode 100644 rules/40-redhat-hotunplug.rules
diff --git a/Makefile.am b/Makefile.am
index 40ebbe98e..3995dcce8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3524,6 +3524,7 @@ dist_udevrules_DATA += \
     rules/40-redhat.rules \
     rules/40-redhat-disable-lenovo-ir-camera.rules \
     rules/40-redhat-disable-dell-ir-camera.rules \
+    rules/40-redhat-hotunplug.rules \
     rules/73-idrac.rules \
         rules/80-net-name-slot.rules
diff --git a/rules/40-redhat-hotunplug.rules b/rules/40-redhat-hotunplug.rules
new file mode 100644
index 000000000..3befdaffc
--- /dev/null
+++ b/rules/40-redhat-hotunplug.rules
@@ -0,0 +1,14 @@
+# ACPI0004 container offline for Huawei Kunlun
+# do not edit this file, it will be overwritten on update
+
+SUBSYSTEM=="container", ACTION=="change", DEVPATH=="*/ACPI0004:??", \
+RUN+="/bin/sh -c ' \
+if [ $(cat /sys/$env{DEVPATH}/online) -eq 1 ]; then \
+        find -L /sys/$env{DEVPATH}/firmware_node/*/physical_node* -maxdepth 1 -name online | \
+        while read line; do \
+                if [ $(cat $line) -eq 1 ]; then \
+                        /bin/echo 0 > $line; \
+                fi \
+        done; \
+        /bin/echo 0 > /sys/$env{DEVPATH}/online; \
+fi'"
\ No newline at end of file
SOURCES/0658-Revert-rules-mark-hotplugged-memory-as-movable.patch
New file
@@ -0,0 +1,25 @@
From e1311df43e9c63e72b1a6b329f5ffc9bcd0f37e1 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Thu, 16 Aug 2018 08:38:31 +0000
Subject: [PATCH] Revert "rules: mark hotplugged memory as movable"
This reverts commit 7431c551954ad63fe61cda18888e1e89419bd631.
Resolves: #1614686
---
 rules/40-redhat.rules | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules
index 26f726001..34a1df9c4 100644
--- a/rules/40-redhat.rules
+++ b/rules/40-redhat.rules
@@ -4,7 +4,7 @@
 SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1"
 # Memory hotadd request
-SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online_movable"
+SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online"
 # reload sysctl.conf / sysctl.conf.d settings when the bridge module is loaded
 ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/bridge"
SOURCES/0659-rules-implement-new-memory-hotplug-policy.patch
New file
@@ -0,0 +1,49 @@
From c50b7bcbebcfebfce3a7e7fb77f88f4b590fb2b5 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Thu, 16 Aug 2018 09:31:51 +0000
Subject: [PATCH] rules: implement new memory hotplug policy
Our new policy is based on following motivations (assumptions),
  * we want to allow the system to use hotplugged memory
  * we want memory ballon inflation to work as expected in VMs (going for small
  to big in terms of memory footprint)
  * we want to allow memory hotplug and memory hot-unplug on high-end
  enterprise server (we assume that node0 will have sufficient memory
  resources and marking all memory as movable shouldn't be a problem)
Policy:
  * nevert online memory on s390 (on both physical and z/VM)
  * mark memory as "online_movable" on physical machines
  * mark memory as "online" in VMs
If you have the feeling that all this is very wrong and we shouldn't
encode complex policies in udev rules you are absolutely right. However,
for now, we don't have any better place where to put it. In ideal world
we would have a user-space daemon that would be able to configure the
system wrt. to currently present HW and user-defined policy.
Resolves: #1614686
---
 rules/40-redhat.rules | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/rules/40-redhat.rules b/rules/40-redhat.rules
index 34a1df9c4..1b10e173d 100644
--- a/rules/40-redhat.rules
+++ b/rules/40-redhat.rules
@@ -4,7 +4,14 @@
 SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1"
 # Memory hotadd request
-SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online"
+SUBSYSTEM!="memory", ACTION!="add", GOTO="memory_hotplug_end"
+PROGRAM="/bin/uname -p", RESULT=="s390*", GOTO="memory_hotplug_end"
+
+ENV{.state}="online"
+PROGRAM="/bin/systemd-detect-virt", RESULT=="none", ENV{.state}="online_movable"
+ATTR{state}=="offline", ATTR{state}="$env{.state}"
+
+LABEL="memory_hotplug_end"
 # reload sysctl.conf / sysctl.conf.d settings when the bridge module is loaded
 ACTION=="add", SUBSYSTEM=="module", KERNEL=="bridge", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/bridge"
SOURCES/0660-Revert-rules-add-udev-rule-that-automatically-offlin.patch
New file
@@ -0,0 +1,48 @@
From 4b451af437d5d51b98d11d32130aac6938307798 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Fri, 17 Aug 2018 13:10:22 +0000
Subject: [PATCH] Revert "rules: add udev rule that automatically offline HW
 attached to ACPI container"
This reverts commit 6bc676b1a1bfa7145106f737a6747526ce662b93.
Related: #1597958
---
 Makefile.am                     |  1 -
 rules/40-redhat-hotunplug.rules | 14 --------------
 2 files changed, 15 deletions(-)
 delete mode 100644 rules/40-redhat-hotunplug.rules
diff --git a/Makefile.am b/Makefile.am
index 3995dcce8..40ebbe98e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3524,7 +3524,6 @@ dist_udevrules_DATA += \
     rules/40-redhat.rules \
     rules/40-redhat-disable-lenovo-ir-camera.rules \
     rules/40-redhat-disable-dell-ir-camera.rules \
-    rules/40-redhat-hotunplug.rules \
     rules/73-idrac.rules \
         rules/80-net-name-slot.rules
diff --git a/rules/40-redhat-hotunplug.rules b/rules/40-redhat-hotunplug.rules
deleted file mode 100644
index 3befdaffc..000000000
--- a/rules/40-redhat-hotunplug.rules
+++ /dev/null
@@ -1,14 +0,0 @@
-# ACPI0004 container offline for Huawei Kunlun
-# do not edit this file, it will be overwritten on update
-
-SUBSYSTEM=="container", ACTION=="change", DEVPATH=="*/ACPI0004:??", \
-RUN+="/bin/sh -c ' \
-if [ $(cat /sys/$env{DEVPATH}/online) -eq 1 ]; then \
-        find -L /sys/$env{DEVPATH}/firmware_node/*/physical_node* -maxdepth 1 -name online | \
-        while read line; do \
-                if [ $(cat $line) -eq 1 ]; then \
-                        /bin/echo 0 > $line; \
-                fi \
-        done; \
-        /bin/echo 0 > /sys/$env{DEVPATH}/online; \
-fi'"
\ No newline at end of file
SOURCES/0661-cryptsetup-generator-introduce-basic-keydev-support.patch
New file
@@ -0,0 +1,258 @@
From aafa651e44df825abeec061f295f227862aad6d9 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Thu, 30 Aug 2018 08:45:11 +0000
Subject: [PATCH] cryptsetup-generator: introduce basic keydev support
Dracut has a support for unlocking encrypted drives with keyfile stored
on the external drive. This support is included in the generated initrd
only if systemd module is not included.
When systemd is used in initrd then attachment of encrypted drives is
handled by systemd-cryptsetup tools. Our generator has support for
keyfile, however, it didn't support keyfile on the external block
device (keydev).
This commit introduces basic keydev support. Keydev can be specified per
luks.uuid on the kernel command line. Keydev is automatically mounted
during boot and we look for keyfile in the keydev
mountpoint (i.e. keyfile path is prefixed with the keydev mount point
path). After crypt device is attached we automatically unmount
where keyfile resides.
Example:
        rd.luks.key=70bc876b-f627-4038-9049-3080d79d2165=/key:LABEL=KEYDEV
(cherry-picked from commit 70f5f48eb891b12e969577b464de61e15a2593da)
Resolves: #1619743
---
 man/systemd-cryptsetup-generator.xml  |  14 ++++
 src/cryptsetup/cryptsetup-generator.c | 122 ++++++++++++++++++++++++++++++++--
 2 files changed, 131 insertions(+), 5 deletions(-)
diff --git a/man/systemd-cryptsetup-generator.xml b/man/systemd-cryptsetup-generator.xml
index b6270358e..8cfd8b6a8 100644
--- a/man/systemd-cryptsetup-generator.xml
+++ b/man/systemd-cryptsetup-generator.xml
@@ -168,6 +168,20 @@
         to the one specified by <varname>rd.luks.key=</varname> or
         <varname>luks.key=</varname> of the corresponding UUID, or the
         password file that was specified without a UUID.</para>
+
+        <para>It is also possible to specify an external device which
+        should be mounted before we attempt to unlock the LUKS device.
+        systemd-cryptsetup will use password file stored on that
+        device. Device containing password file is specified by
+        appending colon and a device identifier to the password file
+        path. For example,
+        <varname>rd.luks.uuid=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40
+        <varname>rd.luks.key=</varname>b40f1abf-2a53-400a-889a-2eccc27eaa40=/keyfile:LABEL=keydev.
+        Hence, in this case, we will attempt to mount file system
+        residing on the block device with label <literal>keydev</literal>.
+        This syntax is for now only supported on a per-device basis,
+        i.e. you have to specify LUKS device UUID.</para>
+
         <para><varname>rd.luks.key=</varname>
         is honored only by initial RAM disk
         (initrd) while
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 5f29093f5..42c30c5ca 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -38,6 +38,7 @@
 typedef struct crypto_device {
         char *uuid;
         char *keyfile;
+        char *keydev;
         char *name;
         char *options;
         bool create;
@@ -51,14 +52,79 @@ static Hashmap *arg_disks = NULL;
 static char *arg_default_options = NULL;
 static char *arg_default_keyfile = NULL;
+static int generate_keydev_mount(const char *name, const char *keydev, char **unit, char **mount) {
+        _cleanup_free_ char *u = NULL, *what = NULL, *where = NULL, *p = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        assert(name);
+        assert(keydev);
+        assert(unit);
+        assert(mount);
+
+        r = mkdir_parents("/run/systemd/cryptsetup", 0755);
+        if (r < 0)
+                return r;
+
+        r = mkdir("/run/systemd/cryptsetup", 0700);
+        if (r < 0)
+                return r;
+
+        where = strjoin("/run/systemd/cryptsetup/keydev-", name, NULL);
+        if (!where)
+                return -ENOMEM;
+
+        r = mkdir(where, 0700);
+        if (r < 0)
+                return r;
+
+        u = unit_name_from_path(where, ".mount");
+        if (!u)
+                return -ENOMEM;
+
+        what = fstab_node_to_udev_node(keydev);
+        if (!what)
+                return -ENOMEM;
+
+        p = strjoin(arg_dest, "/", u, NULL);
+        if (!p)
+                return log_oom();
+
+        f = fopen(p, "wxe");
+        if (!f)
+                return log_error_errno(errno, "Failed to create unit file %s: %m", p);
+
+        fprintf(f,
+                "# Automatically generated by systemd-cryptsetup-generator\n\n"
+                "[Unit]\n"
+                "DefaultDependencies=no\n\n"
+                "[Mount]\n"
+                "What=%s\n"
+                "Where=%s\n"
+                "Options=ro\n", what, where);
+
+        r = fflush_and_check(f);
+        if (r < 0)
+                return r;
+
+        *unit = u;
+        u = NULL;
+
+        *mount = where;
+        where = NULL;
+
+        return 0;
+}
+
 static int create_disk(
                 const char *name,
                 const char *device,
+                const char *keydev,
                 const char *password,
                 const char *options) {
         _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *to = NULL, *e = NULL,
-                *filtered = NULL;
+                *filtered = NULL, *keydev_mount = NULL, *keyfile_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         bool noauto, nofail, tmp, swap, netdev;
         char *from;
@@ -98,6 +164,9 @@ static int create_disk(
         if (!d)
                 return log_oom();
+        if (keydev && !password)
+                return log_error_errno(-EINVAL, "Keydev is specified, but path to the password file is missing: %m");
+
         f = fopen(p, "wxe");
         if (!f)
                 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
@@ -115,6 +184,20 @@ static int create_disk(
                 "After=%s\n",
                 netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
+        if (keydev) {
+                _cleanup_free_ char *unit = NULL;
+
+                r = generate_keydev_mount(name, keydev, &unit, &keydev_mount);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate keydev mount unit: %m");
+
+                keyfile_path = prefix_root(keydev_mount, password);
+                if (!keyfile_path)
+                        return log_oom();
+
+                password = keyfile_path;
+        }
+
         if (!nofail)
                 fprintf(f,
                         "Before=%s\n",
@@ -181,6 +264,11 @@ static int create_disk(
                         "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
                         name);
+        if (keydev)
+                fprintf(f,
+                        "ExecStartPost=/bin/umount '%s'\n\n",
+                        keydev_mount);
+
         fflush(f);
         if (ferror(f))
                 return log_error_errno(errno, "Failed to write file %s: %m", p);
@@ -248,6 +336,7 @@ static void free_arg_disks(void) {
         while ((d = hashmap_steal_first(arg_disks))) {
                 free(d->uuid);
                 free(d->keyfile);
+                free(d->keydev);
                 free(d->name);
                 free(d->options);
                 free(d);
@@ -335,13 +424,36 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
                 r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
                 if (r == 2) {
+                        char *c;
+                        _cleanup_free_ char *keyfile = NULL, *keydev = NULL;
+
                         d = get_crypto_device(uuid);
                         if (!d)
                                 return log_oom();
+                        c = strrchr(uuid_value, ':');
+                        if (!c) {
+                                free(d->keyfile);
+                                d->keyfile = uuid_value;
+                                uuid_value = NULL;
+
+                                return 0;
+                        }
+
+                        *c = '\0';
+                        keyfile = strdup(uuid_value);
+                        keydev = strdup(++c);
+
+                        if (!keyfile || !keydev)
+                                return log_oom();
+
                         free(d->keyfile);
-                        d->keyfile = uuid_value;
-                        uuid_value = NULL;
+                        d->keyfile = keyfile;
+                        keyfile = NULL;
+
+                        free(d->keydev);
+                        d->keydev = keydev;
+                        keydev = NULL;
                 } else if (free_and_strdup(&arg_default_keyfile, value))
                         return log_oom();
@@ -420,7 +532,7 @@ static int add_crypttab_devices(void) {
                         continue;
                 }
-                r = create_disk(name, device, keyfile, (d && d->options) ? d->options : options);
+                r = create_disk(name, device, NULL, keyfile, (d && d->options) ? d->options : options);
                 if (r < 0)
                         return r;
@@ -460,7 +572,7 @@ static int add_proc_cmdline_devices(void) {
                 else
                         options = "timeout=0";
-                r = create_disk(d->name, device, d->keyfile ?: arg_default_keyfile, options);
+                r = create_disk(d->name, device, d->keydev, d->keyfile ?: arg_default_keyfile, options);
                 if (r < 0)
                         return r;
         }
SOURCES/0662-cryptsetup-generator-don-t-return-error-if-target-di.patch
New file
@@ -0,0 +1,38 @@
From 8f47d483dc4e0510977c8868278148c476f58c17 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Tue, 4 Sep 2018 19:51:14 +0200
Subject: [PATCH] cryptsetup-generator: don't return error if target directory
 already exists
Related: #1619743
---
 src/cryptsetup/cryptsetup-generator.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 42c30c5ca..a9598180c 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -63,11 +63,11 @@ static int generate_keydev_mount(const char *name, const char *keydev, char **un
         assert(mount);
         r = mkdir_parents("/run/systemd/cryptsetup", 0755);
-        if (r < 0)
+        if (r < 0 && r != -EEXIST)
                 return r;
         r = mkdir("/run/systemd/cryptsetup", 0700);
-        if (r < 0)
+        if (r < 0 && errno != EEXIST)
                 return r;
         where = strjoin("/run/systemd/cryptsetup/keydev-", name, NULL);
@@ -75,7 +75,7 @@ static int generate_keydev_mount(const char *name, const char *keydev, char **un
                 return -ENOMEM;
         r = mkdir(where, 0700);
-        if (r < 0)
+        if (r < 0 && errno != EEXIST)
                 return r;
         u = unit_name_from_path(where, ".mount");
SOURCES/0663-cryptsetup-generator-allow-whitespace-characters-in-.patch
New file
@@ -0,0 +1,62 @@
From afcf3919f5db85a00352a9937c9a5cb9c7b30269 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Tue, 4 Sep 2018 20:03:34 +0200
Subject: [PATCH] cryptsetup-generator: allow whitespace characters in keydev
 specification
For example, <luks.uuid>=/keyfile:LABEL="KEYFILE FS" previously wouldn't
work, because we truncated label at the first whitespace character,
i.e. LABEL="KEYFILE".
Related: #1619743
---
 src/cryptsetup/cryptsetup-generator.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index a9598180c..7b90d2615 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -421,27 +421,36 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
                         return log_oom();
         } else if (STR_IN_SET(key, "luks.key", "rd.luks.key") && value) {
+                int n;
-                r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
-                if (r == 2) {
+                r = sscanf(value, "%m[0-9a-fA-F-]=%n", &uuid, &n);
+                if (r == 1) {
                         char *c;
+                        const char *keyspec;
                         _cleanup_free_ char *keyfile = NULL, *keydev = NULL;
                         d = get_crypto_device(uuid);
                         if (!d)
                                 return log_oom();
-                        c = strrchr(uuid_value, ':');
+                        keyspec = value + n;
+
+                        c = strrchr(keyspec, ':');
                         if (!c) {
+                                /* No keydev specified */
+                                keyfile = strdup(keyspec);
+                                if (!keyfile)
+                                        return log_oom();
+
                                 free(d->keyfile);
-                                d->keyfile = uuid_value;
-                                uuid_value = NULL;