diff --git a/SOURCES/18886.patch b/SOURCES/18886.patch
new file mode 100644
index 0000000..2dc80ae
--- /dev/null
+++ b/SOURCES/18886.patch
@@ -0,0 +1,56 @@
+From f975f1cc748929942188ae1490cf8480f8a64877 Mon Sep 17 00:00:00 2001
+From: Anita Zhang <the.anitazha@gmail.com>
+Date: Thu, 4 Mar 2021 19:56:16 -0800
+Subject: [PATCH 1/2] shutdown: set always_reopen_console
+
+Back in v232 systemd-shutdown would log to /dev/console. However after
+the addition of always_reopen_console (v233) it would log to STDERR.
+This caused some debugging issues as container systemd-shutdown logs
+weren't being logged to console as the arg `--log-target=console` suggested.
+
+Since it appears that always_reopen_console was intended for pid1, set
+it in systemd-shutdown as well so logs will go to /dev/console.
+---
+ src/shutdown/shutdown.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c
+index 0d07865542e..c1fdc885afb 100644
+--- a/src/shutdown/shutdown.c
++++ b/src/shutdown/shutdown.c
+@@ -322,6 +322,9 @@ int main(int argc, char *argv[]) {
+         log_set_prohibit_ipc(true);
+         log_parse_environment();
+ 
++        if (getpid_cached() == 1)
++                log_set_always_reopen_console(true);
++
+         r = parse_argv(argc, argv);
+         if (r < 0)
+                 goto error;
+
+From 016f36ae72611210d6517b37429bfbdc26c5e31c Mon Sep 17 00:00:00 2001
+From: Anita Zhang <the.anitazha@gmail.com>
+Date: Thu, 4 Mar 2021 20:00:05 -0800
+Subject: [PATCH 2/2] shutdown: log on container exit
+
+---
+ src/shutdown/shutdown.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c
+index c1fdc885afb..06b6618ff4c 100644
+--- a/src/shutdown/shutdown.c
++++ b/src/shutdown/shutdown.c
+@@ -559,8 +559,10 @@ int main(int argc, char *argv[]) {
+                 sync_with_progress();
+ 
+         if (streq(arg_verb, "exit")) {
+-                if (in_container)
++                if (in_container) {
++                        log_info("Exiting container.");
+                         return arg_exit_code;
++                }
+ 
+                 cmd = RB_POWER_OFF; /* We cannot exit() on the host, fallback on another method. */
+         }
diff --git a/SOURCES/18955.patch b/SOURCES/18955.patch
new file mode 100644
index 0000000..b6a3953
--- /dev/null
+++ b/SOURCES/18955.patch
@@ -0,0 +1,1168 @@
+From 1677b88d01729f514dd17145e3aefaa5db6cdf95 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 10 Mar 2021 11:49:02 +0100
+Subject: [PATCH 1/9] fstab-generator: do not propagate error if we fail to
+ canonicalize
+
+r is used for the return value of the function, so we shouldn't
+use it a non-fatal check.
+---
+ src/fstab-generator/fstab-generator.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
+index 0910a9aa61b..7cb4ea286dc 100644
+--- a/src/fstab-generator/fstab-generator.c
++++ b/src/fstab-generator/fstab-generator.c
+@@ -611,11 +611,11 @@ static int parse_fstab(bool initrd) {
+                          * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
+                          * where a symlink refers to another mount target; this works assuming the sub-mountpoint
+                          * target is the final directory. */
+-                        r = chase_symlinks(where, initrd ? "/sysroot" : NULL,
++                        k = chase_symlinks(where, initrd ? "/sysroot" : NULL,
+                                            CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
+                                            &canonical_where, NULL);
+-                        if (r < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
+-                                log_debug_errno(r, "Failed to read symlink target for %s, ignoring: %m", where);
++                        if (k < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
++                                log_debug_errno(k, "Failed to read symlink target for %s, ignoring: %m", where);
+                         else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
+                                 canonical_where = mfree(canonical_where);
+                         else
+
+From 924f65030529d5a232c2be4ab6e2642dfdc2ea71 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 10 Mar 2021 13:20:47 +0100
+Subject: [PATCH 2/9] generators: warn but ignore failure to write timeouts
+
+When we failed to split the options (because of disallowed quoting syntax, which
+might be a bug in its own), we would silently fail. Instead, let's emit a warning.
+Since we ignore the value if we cannot parse it anyway, let's ignore this error
+too.
+---
+ src/shared/generator.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/shared/generator.c b/src/shared/generator.c
+index 8b95c772db1..41922d67d8c 100644
+--- a/src/shared/generator.c
++++ b/src/shared/generator.c
+@@ -216,8 +216,12 @@ int generator_write_timeouts(
+         r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
+                                        "x-systemd.device-timeout\0",
+                                  NULL, &timeout, filtered);
+-        if (r <= 0)
+-                return r;
++        if (r < 0) {
++                log_warning_errno(r, "Failed to parse fstab options, ignoring: %m");
++                return 0;
++        }
++        if (r == 0)
++                return 0;
+ 
+         r = parse_sec_fix_0(timeout, &u);
+         if (r < 0) {
+
+From 5fa2da125157a1beca508792ee5d9be833c2c0cb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 10 Mar 2021 13:35:26 +0100
+Subject: [PATCH 3/9] shared/fstab-util: immediately drop empty options again
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In the conversion from strv_split() to strv_split_full() done in
+7bb553bb98a57b4e03804f8192bdc5a534325582, EXTRACT_DONT_COALESCE_SEPARATORS was
+added. I think this was just by mistake… We never look for "empty options", so
+whether we immediately ignore the extra separator or store the empty string in
+strv, should make no difference.
+---
+ src/shared/fstab-util.c    | 2 +-
+ src/test/test-fstab-util.c | 6 +++++-
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
+index 292b97cd692..1ddcd371cfc 100644
+--- a/src/shared/fstab-util.c
++++ b/src/shared/fstab-util.c
+@@ -140,7 +140,7 @@ int fstab_filter_options(const char *opts, const char *names,
+                                 break;
+                 }
+         } else {
+-                r = strv_split_full(&stor, opts, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
++                r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS);
+                 if (r < 0)
+                         return r;
+ 
+diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c
+index 222ffbb2a75..ebbdd05ca62 100644
+--- a/src/test/test-fstab-util.c
++++ b/src/test/test-fstab-util.c
+@@ -91,9 +91,13 @@ static void test_fstab_filter_options(void) {
+         do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL);
+         do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, NULL, NULL, NULL);
+ 
+-        /* check function will NULL args */
++        /* check function with NULL args */
+         do_fstab_filter_options(NULL, "opt\0", 0, NULL, NULL, "");
+         do_fstab_filter_options("", "opt\0", 0, NULL, NULL, "");
++
++        /* unnecessary comma separators */
++        do_fstab_filter_options("opt=x,,,,", "opt\0", 1, "opt", "x", "");
++        do_fstab_filter_options(",,,opt=x,,,,", "opt\0", 1, "opt", "x", "");
+ }
+ 
+ static void test_fstab_find_pri(void) {
+
+From 8723c716c795b4083372b11dd7065bca2aadbc70 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 10 Mar 2021 14:23:23 +0100
+Subject: [PATCH 4/9] basic/extract_word: try to explain what the various
+ options do
+
+A test for stripping of escaped backslashes without any flags was explicitly
+added back in 4034a06ddb82ec9868cd52496fef2f5faa25575f. So it seems to be on
+purpose, though I would say that this is at least surprising and hence deserves
+a comment.
+
+In test-extract-word, add tests for standalone EXTRACT_UNESCAPE_SEPARATORS.
+Only behaviour combined with EXTRACT_CUNESCAPE was tested.
+---
+ src/basic/extract-word.h     | 16 +++++++++-------
+ src/test/test-extract-word.c | 21 +++++++++++++++++++++
+ 2 files changed, 30 insertions(+), 7 deletions(-)
+
+diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h
+index d1de32e5806..3c1e7d98b64 100644
+--- a/src/basic/extract-word.h
++++ b/src/basic/extract-word.h
+@@ -4,13 +4,15 @@
+ #include "macro.h"
+ 
+ typedef enum ExtractFlags {
+-        EXTRACT_RELAX                    = 1 << 0,
+-        EXTRACT_CUNESCAPE                = 1 << 1,
+-        EXTRACT_CUNESCAPE_RELAX          = 1 << 2,
+-        EXTRACT_UNESCAPE_SEPARATORS      = 1 << 3,
+-        EXTRACT_UNQUOTE                  = 1 << 4,
+-        EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5,
+-        EXTRACT_RETAIN_ESCAPE            = 1 << 6,
++        EXTRACT_RELAX                    = 1 << 0, /* Allow unbalanced quote and eat up trailing backslash. */
++        EXTRACT_CUNESCAPE                = 1 << 1, /* Unescape known escape sequences. */
++        EXTRACT_CUNESCAPE_RELAX          = 1 << 2, /* Allow and keep unknown escape sequences, allow and keep trailing backslash. */
++        EXTRACT_UNESCAPE_SEPARATORS      = 1 << 3, /* Unescape separators (those specified, or whitespace by default). */
++        EXTRACT_UNQUOTE                  = 1 << 4, /* Remove quoting with "" and ''. */
++        EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5, /* Don't treat multiple adjacent separators as one */
++        EXTRACT_RETAIN_ESCAPE            = 1 << 6, /* Treat escape character '\' as any other character without special meaning */
++
++        /* Note that if no flags are specified, escaped escape characters will be silently stripped. */
+ } ExtractFlags;
+ 
+ int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
+diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c
+index 56b516fe40a..f718556d399 100644
+--- a/src/test/test-extract-word.c
++++ b/src/test/test-extract-word.c
+@@ -344,6 +344,27 @@ static void test_extract_first_word(void) {
+         free(t);
+         assert_se(p == NULL);
+ 
++        p = "\\:";
++        assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
++        assert_se(streq(t, ":"));
++        free(t);
++        assert_se(p == NULL);
++
++        p = "a\\:b";
++        assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
++        assert_se(streq(t, "a:b"));
++        free(t);
++        assert_se(p == NULL);
++
++        p = "a\\ b:c";
++        assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
++        assert_se(streq(t, "a b"));
++        free(t);
++        assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
++        assert_se(streq(t, "c"));
++        free(t);
++        assert_se(p == NULL);
++
+         p = "\\:";
+         assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
+         assert_se(streq(t, ":"));
+
+From 76c4e48ee603593822b3076c4cf5b63768ec55e3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 10 Mar 2021 15:17:56 +0100
+Subject: [PATCH 5/9] basic/extract-word: allow escape character to be escaped
+
+With EXTRACT_UNESCAPE_SEPARATORS, backslash is used to escape the separator.
+But it wasn't possible to insert the backslash itself. Let's allow this and
+add test.
+---
+ src/basic/extract-word.c     |  4 ++--
+ src/test/test-extract-word.c | 24 ++++++++++++++++++++++++
+ 2 files changed, 26 insertions(+), 2 deletions(-)
+
+diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
+index 4e4e7e8ce93..06b813c031a 100644
+--- a/src/basic/extract-word.c
++++ b/src/basic/extract-word.c
+@@ -102,8 +102,8 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
+                                         else
+                                                 sz += utf8_encode_unichar(s + sz, u);
+                                 } else if ((flags & EXTRACT_UNESCAPE_SEPARATORS) &&
+-                                           strchr(separators, **p))
+-                                        /* An escaped separator char */
++                                           (strchr(separators, **p) || **p == '\\'))
++                                        /* An escaped separator char or the escape char itself */
+                                         s[sz++] = c;
+                                 else if (flags & EXTRACT_CUNESCAPE_RELAX) {
+                                         s[sz++] = '\\';
+diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c
+index f718556d399..217c600dac6 100644
+--- a/src/test/test-extract-word.c
++++ b/src/test/test-extract-word.c
+@@ -365,6 +365,18 @@ static void test_extract_first_word(void) {
+         free(t);
+         assert_se(p == NULL);
+ 
++        p = "a\\ b:c\\x";
++        assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == -EINVAL);
++
++        p = "a\\\\ b:c\\\\x";
++        assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
++        assert_se(streq(t, "a\\ b"));
++        free(t);
++        assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1);
++        assert_se(streq(t, "c\\x"));
++        free(t);
++        assert_se(p == NULL);
++
+         p = "\\:";
+         assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
+         assert_se(streq(t, ":"));
+@@ -386,6 +398,18 @@ static void test_extract_first_word(void) {
+         free(t);
+         assert_se(p == NULL);
+ 
++        p = "a\\ b:c\\x";
++        assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == -EINVAL);
++
++        p = "a\\\\ b:c\\\\x";
++        assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
++        assert_se(streq(t, "a\\ b"));
++        free(t);
++        assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1);
++        assert_se(streq(t, "c\\x"));
++        free(t);
++        assert_se(p == NULL);
++
+         p = "\\:";
+         assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE) == -EINVAL);
+ 
+
+From 3141089f53274849ecedb84aacc6a35fd679d3c2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 10 Mar 2021 15:39:47 +0100
+Subject: [PATCH 6/9] basic/extract-word: rename flag
+
+The flag enables "relaxed mode" for all kinds of unescaping, not just c-unescaping.
+---
+ src/basic/extract-word.c     | 16 ++++++++--------
+ src/basic/extract-word.h     |  2 +-
+ src/resolve/resolved-conf.c  |  2 +-
+ src/test/test-extract-word.c | 22 +++++++++++-----------
+ src/test/test-strv.c         |  4 ++--
+ 5 files changed, 23 insertions(+), 23 deletions(-)
+
+diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
+index 06b813c031a..d1af11318a8 100644
+--- a/src/basic/extract-word.c
++++ b/src/basic/extract-word.c
+@@ -69,14 +69,14 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
+                                 return -ENOMEM;
+ 
+                         if (c == 0) {
+-                                if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
++                                if ((flags & EXTRACT_UNESCAPE_RELAX) &&
+                                     (quote == 0 || flags & EXTRACT_RELAX)) {
+                                         /* If we find an unquoted trailing backslash and we're in
+-                                         * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
++                                         * EXTRACT_UNESCAPE_RELAX mode, keep it verbatim in the
+                                          * output.
+                                          *
+                                          * Unbalanced quotes will only be allowed in EXTRACT_RELAX
+-                                         * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
++                                         * mode, EXTRACT_UNESCAPE_RELAX mode does not allow them.
+                                          */
+                                         s[sz++] = '\\';
+                                         goto finish_force_terminate;
+@@ -105,7 +105,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
+                                            (strchr(separators, **p) || **p == '\\'))
+                                         /* An escaped separator char or the escape char itself */
+                                         s[sz++] = c;
+-                                else if (flags & EXTRACT_CUNESCAPE_RELAX) {
++                                else if (flags & EXTRACT_UNESCAPE_RELAX) {
+                                         s[sz++] = '\\';
+                                         s[sz++] = c;
+                                 } else
+@@ -196,7 +196,7 @@ int extract_first_word_and_warn(
+                 const char *rvalue) {
+ 
+         /* Try to unquote it, if it fails, warn about it and try again
+-         * but this time using EXTRACT_CUNESCAPE_RELAX to keep the
++         * but this time using EXTRACT_UNESCAPE_RELAX to keep the
+          * backslashes verbatim in invalid escape sequences. */
+ 
+         const char *save;
+@@ -207,11 +207,11 @@ int extract_first_word_and_warn(
+         if (r >= 0)
+                 return r;
+ 
+-        if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
++        if (r == -EINVAL && !(flags & EXTRACT_UNESCAPE_RELAX)) {
+ 
+-                /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
++                /* Retry it with EXTRACT_UNESCAPE_RELAX. */
+                 *p = save;
+-                r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
++                r = extract_first_word(p, ret, separators, flags|EXTRACT_UNESCAPE_RELAX);
+                 if (r >= 0) {
+                         /* It worked this time, hence it must have been an invalid escape sequence. */
+                         log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Ignoring unknown escape sequences: \"%s\"", *ret);
+diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h
+index 3c1e7d98b64..0e9e77e93d3 100644
+--- a/src/basic/extract-word.h
++++ b/src/basic/extract-word.h
+@@ -6,7 +6,7 @@
+ typedef enum ExtractFlags {
+         EXTRACT_RELAX                    = 1 << 0, /* Allow unbalanced quote and eat up trailing backslash. */
+         EXTRACT_CUNESCAPE                = 1 << 1, /* Unescape known escape sequences. */
+-        EXTRACT_CUNESCAPE_RELAX          = 1 << 2, /* Allow and keep unknown escape sequences, allow and keep trailing backslash. */
++        EXTRACT_UNESCAPE_RELAX           = 1 << 2, /* Allow and keep unknown escape sequences, allow and keep trailing backslash. */
+         EXTRACT_UNESCAPE_SEPARATORS      = 1 << 3, /* Unescape separators (those specified, or whitespace by default). */
+         EXTRACT_UNQUOTE                  = 1 << 4, /* Remove quoting with "" and ''. */
+         EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5, /* Don't treat multiple adjacent separators as one */
+diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
+index f2a33162517..87d1794a741 100644
+--- a/src/resolve/resolved-conf.c
++++ b/src/resolve/resolved-conf.c
+@@ -348,7 +348,7 @@ int config_parse_dnssd_txt(
+                 int r;
+ 
+                 r = extract_first_word(&rvalue, &word, NULL,
+-                                       EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX);
++                                       EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX);
+                 if (r == 0)
+                         break;
+                 if (r == -ENOMEM)
+diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c
+index 217c600dac6..f1085266df2 100644
+--- a/src/test/test-extract-word.c
++++ b/src/test/test-extract-word.c
+@@ -172,19 +172,19 @@ static void test_extract_first_word(void) {
+         assert_se(isempty(p));
+ 
+         p = original = "fooo\\";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0);
+         assert_se(streq(t, "fooo\\"));
+         free(t);
+         assert_se(isempty(p));
+ 
+         p = original = "fooo\\";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+         assert_se(streq(t, "fooo\\"));
+         free(t);
+         assert_se(isempty(p));
+ 
+         p = original = "fooo\\";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
+         assert_se(streq(t, "fooo\\"));
+         free(t);
+         assert_se(isempty(p));
+@@ -230,17 +230,17 @@ static void test_extract_first_word(void) {
+         assert_se(isempty(p));
+ 
+         p = original = "\"foo\\";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX) == -EINVAL);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_UNESCAPE_RELAX) == -EINVAL);
+         assert_se(p == original + 5);
+ 
+         p = original = "\"foo\\";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+         assert_se(streq(t, "foo\\"));
+         free(t);
+         assert_se(isempty(p));
+ 
+         p = original = "\"foo\\";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+         assert_se(streq(t, "foo\\"));
+         free(t);
+         assert_se(isempty(p));
+@@ -252,13 +252,13 @@ static void test_extract_first_word(void) {
+         assert_se(p == original + 10);
+ 
+         p = original = "fooo\\ bar quux";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0);
+         assert_se(streq(t, "fooo bar"));
+         free(t);
+         assert_se(p == original + 10);
+ 
+         p = original = "fooo\\ bar quux";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+         assert_se(streq(t, "fooo bar"));
+         free(t);
+         assert_se(p == original + 10);
+@@ -268,7 +268,7 @@ static void test_extract_first_word(void) {
+         assert_se(p == original + 5);
+ 
+         p = original = "fooo\\ bar quux";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
+         assert_se(streq(t, "fooo\\ bar"));
+         free(t);
+         assert_se(p == original + 10);
+@@ -278,13 +278,13 @@ static void test_extract_first_word(void) {
+         assert_se(p == original + 1);
+ 
+         p = original = "\\w+@\\K[\\d.]+";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
+         assert_se(streq(t, "\\w+@\\K[\\d.]+"));
+         free(t);
+         assert_se(isempty(p));
+ 
+         p = original = "\\w+\\b";
+-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
++        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0);
+         assert_se(streq(t, "\\w+\b"));
+         free(t);
+         assert_se(isempty(p));
+diff --git a/src/test/test-strv.c b/src/test/test-strv.c
+index 162d8bed951..039bb2c78af 100644
+--- a/src/test/test-strv.c
++++ b/src/test/test-strv.c
+@@ -333,12 +333,12 @@ static void test_strv_split(void) {
+         l = strv_free_erase(l);
+ 
+         assert_se(strv_split_full(&l, "    'one'  \"  two\t three \"' four  five", NULL,
+-                                     EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_CUNESCAPE_RELAX) == 2);
++                                     EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_UNESCAPE_RELAX) == 2);
+         assert_se(strv_equal(l, (char**) input_table_quoted_joined));
+ 
+         l = strv_free_erase(l);
+ 
+-        assert_se(strv_split_full(&l, "\\", NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_CUNESCAPE_RELAX) == 1);
++        assert_se(strv_split_full(&l, "\\", NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_UNESCAPE_RELAX) == 1);
+         assert_se(strv_equal(l, STRV_MAKE("\\")));
+ }
+ 
+
+From 0264b404b9f193b70a19db0f600cf6bab3a05368 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 10 Mar 2021 16:53:38 +0100
+Subject: [PATCH 7/9] shared/fstab-util: pass through the escape character
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+… when not used to escape the separator (,) or the escape character (\).
+This mostly restores behaviour from before 0645b83a40d1c782f173c4d8440ab2fc82a75006,
+but still allows "," to be escaped.
+
+Partially fixes #18952.
+---
+ src/shared/fstab-util.c    | 20 ++++++++++++--------
+ src/test/test-fstab-util.c |  4 ++++
+ 2 files changed, 16 insertions(+), 8 deletions(-)
+
+diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
+index 1ddcd371cfc..8dc1733c0de 100644
+--- a/src/shared/fstab-util.c
++++ b/src/shared/fstab-util.c
+@@ -97,16 +97,18 @@ int fstab_filter_options(const char *opts, const char *names,
+                 for (const char *word = opts;;) {
+                         const char *end = word;
+ 
+-                        /* Look for an *non-escaped* comma separator. Only commas can be escaped, so "\," is
+-                         * the only valid escape sequence, so we can do a very simple test here. */
++                        /* Look for a *non-escaped* comma separator. Only commas and backslashes can be
++                         * escaped, so "\," and "\\" are the only valid escape sequences, and we can do a
++                         * very simple test here. */
+                         for (;;) {
+-                                size_t n = strcspn(end, ",");
++                                end += strcspn(end, ",\\");
+ 
+-                                end += n;
+-                                if (n > 0 && end[-1] == '\\')
+-                                        end++;
+-                                else
++                                if (IN_SET(*end, ',', '\0'))
+                                         break;
++                                assert(*end == '\\');
++                                end ++;                 /* Skip the backslash */
++                                if (*end != '\0')
++                                        end ++;         /* Skip the escaped char, but watch out for a trailing commma */
+                         }
+ 
+                         NULSTR_FOREACH(name, names) {
+@@ -140,7 +142,9 @@ int fstab_filter_options(const char *opts, const char *names,
+                                 break;
+                 }
+         } else {
+-                r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS);
++                /* For backwards compatibility, we need to pass-through escape characters.
++                 * The only ones we "consume" are the ones used as "\," or "\\". */
++                r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS | EXTRACT_UNESCAPE_RELAX);
+                 if (r < 0)
+                         return r;
+ 
+diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c
+index ebbdd05ca62..3a7ec170d65 100644
+--- a/src/test/test-fstab-util.c
++++ b/src/test/test-fstab-util.c
+@@ -98,6 +98,10 @@ static void test_fstab_filter_options(void) {
+         /* unnecessary comma separators */
+         do_fstab_filter_options("opt=x,,,,", "opt\0", 1, "opt", "x", "");
+         do_fstab_filter_options(",,,opt=x,,,,", "opt\0", 1, "opt", "x", "");
++
++        /* escaped characters */
++        do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt1\0", 1, "opt1", "\\", "opt2=\\xff");
++        do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, "opt2", "\\xff", "opt1=\\");
+ }
+ 
+ static void test_fstab_find_pri(void) {
+
+From ff0c31bc2722eed528eae6644a104e85ed97f2f1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Thu, 11 Mar 2021 10:37:36 +0100
+Subject: [PATCH 8/9] shared/fstab-util: teach fstab_filter_options() a mode
+ where all values are returned
+
+Apart from tests, the new argument isn't used anywhere, so there should be no
+functional change. Note that the two arms of the big conditional are switched, so the
+diff is artificially inflated. The actual code change is rather small. I dropped the
+path which extracts ret_value manually, because it wasn't supporting unescaping of the
+escape character properly.
+---
+ src/core/mount.c                      |   2 +-
+ src/cryptsetup/cryptsetup-generator.c |   9 +-
+ src/fstab-generator/fstab-generator.c |   2 +-
+ src/shared/fstab-util.c               | 124 +++++++++++++----------
+ src/shared/fstab-util.h               |  12 ++-
+ src/shared/generator.c                |   2 +-
+ src/test/test-fstab-util.c            | 139 +++++++++++++++-----------
+ 7 files changed, 169 insertions(+), 121 deletions(-)
+
+diff --git a/src/core/mount.c b/src/core/mount.c
+index 23b558859c2..ca5d0939a18 100644
+--- a/src/core/mount.c
++++ b/src/core/mount.c
+@@ -1019,7 +1019,7 @@ static void mount_enter_mounting(Mount *m) {
+         if (p) {
+                 _cleanup_free_ char *opts = NULL;
+ 
+-                r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts);
++                r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, NULL, &opts);
+                 if (r < 0)
+                         goto fail;
+ 
+diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
+index 74f739b5139..98c8408da54 100644
+--- a/src/cryptsetup/cryptsetup-generator.c
++++ b/src/cryptsetup/cryptsetup-generator.c
+@@ -301,7 +301,9 @@ static int create_disk(
+         netdev = fstab_test_option(options, "_netdev\0");
+         attach_in_initrd = fstab_test_option(options, "x-initrd.attach\0");
+ 
+-        keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", NULL, &keyfile_timeout_value, NULL);
++        keyfile_can_timeout = fstab_filter_options(options,
++                                                   "keyfile-timeout\0",
++                                                   NULL, &keyfile_timeout_value, NULL, NULL);
+         if (keyfile_can_timeout < 0)
+                 return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m");
+ 
+@@ -310,11 +312,12 @@ static int create_disk(
+                 "header\0",
+                 NULL,
+                 &header_path,
++                NULL,
+                 headerdev ? &filtered_header : NULL);
+         if (detached_header < 0)
+                 return log_error_errno(detached_header, "Failed to parse header= option value: %m");
+ 
+-        tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL);
++        tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL, NULL);
+         if (tmp < 0)
+                 return log_error_errno(tmp, "Failed to parse tmp= option value: %m");
+ 
+@@ -602,7 +605,7 @@ static int filter_header_device(const char *options,
+         assert(ret_headerdev);
+         assert(ret_filtered_headerdev_options);
+ 
+-        r = fstab_filter_options(options, "header\0", NULL, &headerspec, &filtered_headerspec);
++        r = fstab_filter_options(options, "header\0", NULL, &headerspec, NULL, &filtered_headerspec);
+         if (r < 0)
+                 return log_error_errno(r, "Failed to parse header= option value: %m");
+ 
+diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
+index 7cb4ea286dc..b454a5980d4 100644
+--- a/src/fstab-generator/fstab-generator.c
++++ b/src/fstab-generator/fstab-generator.c
+@@ -200,7 +200,7 @@ static int write_timeout(
+         usec_t u;
+         int r;
+ 
+-        r = fstab_filter_options(opts, filter, NULL, &timeout, NULL);
++        r = fstab_filter_options(opts, filter, NULL, &timeout, NULL, NULL);
+         if (r < 0)
+                 return log_warning_errno(r, "Failed to parse options: %m");
+         if (r == 0)
+diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
+index 8dc1733c0de..6674ed4a19f 100644
+--- a/src/shared/fstab-util.c
++++ b/src/shared/fstab-util.c
+@@ -79,21 +79,80 @@ int fstab_is_mount_point(const char *mount) {
+         return false;
+ }
+ 
+-int fstab_filter_options(const char *opts, const char *names,
+-                         const char **ret_namefound, char **ret_value, char **ret_filtered) {
++int fstab_filter_options(
++                const char *opts,
++                const char *names,
++                const char **ret_namefound,
++                char **ret_value,
++                char ***ret_values,
++                char **ret_filtered) {
++
+         const char *name, *namefound = NULL, *x;
+-        _cleanup_strv_free_ char **stor = NULL;
+-        _cleanup_free_ char *v = NULL, **strv = NULL;
++        _cleanup_strv_free_ char **stor = NULL, **values = NULL;
++        _cleanup_free_ char *value = NULL, **filtered = NULL;
+         int r;
+ 
+         assert(names && *names);
++        assert(!(ret_value && ret_values));
+ 
+         if (!opts)
+                 goto answer;
+ 
+-        /* If !ret_value and !ret_filtered, this function is not allowed to fail. */
++        /* Finds any options matching 'names', and returns:
++         * - the last matching option name in ret_namefound,
++         * - the last matching value in ret_value,
++         * - any matching values in ret_values,
++         * - the rest of the option string in ret_filtered.
++         *
++         * If !ret_value and !ret_values and !ret_filtered, this function is not allowed to fail.
++         *
++         * Returns negative on error, true if any matching options were found, false otherwise. */
++
++        if (ret_filtered || ret_value || ret_values) {
++                /* For backwards compatibility, we need to pass-through escape characters.
++                 * The only ones we "consume" are the ones used as "\," or "\\". */
++                r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS | EXTRACT_UNESCAPE_RELAX);
++                if (r < 0)
++                        return r;
++
++                filtered = memdup(stor, sizeof(char*) * (strv_length(stor) + 1));
++                if (!filtered)
++                        return -ENOMEM;
++
++                char **t = filtered;
++                for (char **s = t; *s; s++) {
++                        NULSTR_FOREACH(name, names) {
++                                x = startswith(*s, name);
++                                if (!x)
++                                        continue;
++                                /* Match name, but when ret_values, only when followed by assignment. */
++                                if (*x == '=' || (!ret_values && *x == '\0'))
++                                        goto found;
++                        }
++
++                        *t = *s;
++                        t++;
++                        continue;
++                found:
++                        /* Keep the last occurrence found */
++                        namefound = name;
++
++                        if (ret_value || ret_values) {
++                                assert(IN_SET(*x, '=', '\0'));
+ 
+-        if (!ret_filtered) {
++                                if (ret_value) {
++                                        r = free_and_strdup(&value, *x == '=' ? x + 1 : NULL);
++                                        if (r < 0)
++                                                return r;
++                                } else if (*x) {
++                                        r = strv_extend(&values, x + 1);
++                                        if (r < 0)
++                                                return r;
++                                }
++                        }
++                }
++                *t = NULL;
++        } else
+                 for (const char *word = opts;;) {
+                         const char *end = word;
+ 
+@@ -121,17 +180,6 @@ int fstab_filter_options(const char *opts, const char *names,
+                                 x = word + strlen(name);
+                                 if (IN_SET(*x, '\0', '=', ',')) {
+                                         namefound = name;
+-                                        if (ret_value) {
+-                                                bool eq = *x == '=';
+-                                                assert(eq || IN_SET(*x, ',', '\0'));
+-
+-                                                r = free_and_strndup(&v,
+-                                                                     eq ? x + 1 : NULL,
+-                                                                     eq ? end - x - 1 : 0);
+-                                                if (r < 0)
+-                                                        return r;
+-                                        }
+-
+                                         break;
+                                 }
+                         }
+@@ -141,40 +189,6 @@ int fstab_filter_options(const char *opts, const char *names,
+                         else
+                                 break;
+                 }
+-        } else {
+-                /* For backwards compatibility, we need to pass-through escape characters.
+-                 * The only ones we "consume" are the ones used as "\," or "\\". */
+-                r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS | EXTRACT_UNESCAPE_RELAX);
+-                if (r < 0)
+-                        return r;
+-
+-                strv = memdup(stor, sizeof(char*) * (strv_length(stor) + 1));
+-                if (!strv)
+-                        return -ENOMEM;
+-
+-                char **t = strv;
+-                for (char **s = strv; *s; s++) {
+-                        NULSTR_FOREACH(name, names) {
+-                                x = startswith(*s, name);
+-                                if (x && IN_SET(*x, '\0', '='))
+-                                        goto found;
+-                        }
+-
+-                        *t = *s;
+-                        t++;
+-                        continue;
+-                found:
+-                        /* Keep the last occurrence found */
+-                        namefound = name;
+-                        if (ret_value) {
+-                                assert(IN_SET(*x, '=', '\0'));
+-                                r = free_and_strdup(&v, *x == '=' ? x + 1 : NULL);
+-                                if (r < 0)
+-                                        return r;
+-                        }
+-                }
+-                *t = NULL;
+-        }
+ 
+ answer:
+         if (ret_namefound)
+@@ -182,14 +196,16 @@ int fstab_filter_options(const char *opts, const char *names,
+         if (ret_filtered) {
+                 char *f;
+ 
+-                f = strv_join_full(strv, ",", NULL, true);
++                f = strv_join_full(filtered, ",", NULL, true);
+                 if (!f)
+                         return -ENOMEM;
+ 
+                 *ret_filtered = f;
+         }
+         if (ret_value)
+-                *ret_value = TAKE_PTR(v);
++                *ret_value = TAKE_PTR(value);
++        if (ret_values)
++                *ret_values = TAKE_PTR(values);
+ 
+         return !!namefound;
+ }
+@@ -229,7 +245,7 @@ int fstab_find_pri(const char *options, int *ret) {
+ 
+         assert(ret);
+ 
+-        r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL);
++        r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL, NULL);
+         if (r < 0)
+                 return r;
+         if (r == 0 || !opt)
+diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
+index 1a602cb56b2..97f40221afb 100644
+--- a/src/shared/fstab-util.h
++++ b/src/shared/fstab-util.h
+@@ -10,12 +10,18 @@ bool fstab_is_extrinsic(const char *mount, const char *opts);
+ int fstab_is_mount_point(const char *mount);
+ int fstab_has_fstype(const char *fstype);
+ 
+-int fstab_filter_options(const char *opts, const char *names, const char **namefound, char **value, char **filtered);
++int fstab_filter_options(
++                const char *opts,
++                const char *names,
++                const char **ret_namefound,
++                char **ret_value,
++                char ***ret_values,
++                char **ret_filtered);
+ 
+ int fstab_extract_values(const char *opts, const char *name, char ***values);
+ 
+ static inline bool fstab_test_option(const char *opts, const char *names) {
+-        return !!fstab_filter_options(opts, names, NULL, NULL, NULL);
++        return !!fstab_filter_options(opts, names, NULL, NULL, NULL, NULL);
+ }
+ 
+ int fstab_find_pri(const char *options, int *ret);
+@@ -26,7 +32,7 @@ static inline bool fstab_test_yes_no_option(const char *opts, const char *yes_no
+         /* If first name given is last, return 1.
+          * If second name given is last or neither is found, return 0. */
+ 
+-        assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL) >= 0);
++        assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL, NULL) >= 0);
+ 
+         return opt == yes_no;
+ }
+diff --git a/src/shared/generator.c b/src/shared/generator.c
+index 41922d67d8c..5b9c4325271 100644
+--- a/src/shared/generator.c
++++ b/src/shared/generator.c
+@@ -215,7 +215,7 @@ int generator_write_timeouts(
+ 
+         r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
+                                        "x-systemd.device-timeout\0",
+-                                 NULL, &timeout, filtered);
++                                 NULL, &timeout, NULL, filtered);
+         if (r < 0) {
+                 log_warning_errno(r, "Failed to parse fstab options, ignoring: %m");
+                 return 0;
+diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c
+index 3a7ec170d65..d2f20185265 100644
+--- a/src/test/test-fstab-util.c
++++ b/src/test/test-fstab-util.c
+@@ -6,102 +6,125 @@
+ #include "fstab-util.h"
+ #include "log.h"
+ #include "string-util.h"
++#include "strv.h"
+ 
+ /*
+-int fstab_filter_options(const char *opts, const char *names,
+-                         const char **namefound, char **value, char **filtered);
++int fstab_filter_options(
++        const char *opts,
++        const char *names,
++        const char **ret_namefound,
++        const char **ret_value,
++        const char **ret_values,
++        char **ret_filtered);
+ */
+ 
+ static void do_fstab_filter_options(const char *opts,
+                                     const char *remove,
+                                     int r_expected,
++                                    int r_values_expected,
+                                     const char *name_expected,
+                                     const char *value_expected,
++                                    const char *values_expected,
+                                     const char *filtered_expected) {
+         int r;
+         const char *name;
+-        _cleanup_free_ char *value = NULL, *filtered = NULL;
++        _cleanup_free_ char *value = NULL, *filtered = NULL, *joined = NULL;
++        _cleanup_strv_free_ char **values = NULL;
+ 
+-        r = fstab_filter_options(opts, remove, &name, &value, &filtered);
+-        log_info("\"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"",
+-                 opts, r, name, value, filtered,
++        /* test mode which returns the last value */
++
++        r = fstab_filter_options(opts, remove, &name, &value, NULL, &filtered);
++        log_info("1: \"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"",
++                 opts, r, strnull(name), value, filtered,
+                  r_expected, name_expected, value_expected, filtered_expected ?: opts);
+         assert_se(r == r_expected);
+         assert_se(streq_ptr(name, name_expected));
+         assert_se(streq_ptr(value, value_expected));
+         assert_se(streq_ptr(filtered, filtered_expected ?: opts));
+ 
++        /* test mode which returns all the values */
++
++        r = fstab_filter_options(opts, remove, &name, NULL, &values, NULL);
++        assert_se(joined = strv_join(values, ":"));
++        log_info("2: \"%s\" → %d, \"%s\", \"%s\", expected %d, \"%s\", \"%s\"",
++                 opts, r, strnull(name), joined,
++                 r_values_expected, name_expected, values_expected);
++        assert_se(r == r_values_expected);
++        assert_se(streq_ptr(name, r_values_expected > 0 ? name_expected : NULL));
++        assert_se(streq_ptr(joined, values_expected));
++
+         /* also test the malloc-less mode */
+-        r = fstab_filter_options(opts, remove, &name, NULL, NULL);
+-        log_info("\"%s\" → %d, \"%s\", expected %d, \"%s\"\n-",
+-                 opts, r, name,
++        r = fstab_filter_options(opts, remove, &name, NULL, NULL, NULL);
++        log_info("3: \"%s\" → %d, \"%s\", expected %d, \"%s\"\n-",
++                 opts, r, strnull(name),
+                  r_expected, name_expected);
+         assert_se(r == r_expected);
+         assert_se(streq_ptr(name, name_expected));
+ }
+ 
+ static void test_fstab_filter_options(void) {
+-        do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, "opt", "0", "");
+-        do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, "opt", "0", "");
+-        do_fstab_filter_options("opt", "opt\0x-opt\0", 1, "opt", NULL, "");
+-        do_fstab_filter_options("opt", "x-opt\0opt\0", 1, "opt", NULL, "");
+-        do_fstab_filter_options("x-opt", "x-opt\0opt\0", 1, "x-opt", NULL, "");
+-
+-        do_fstab_filter_options("opt=0,other", "opt\0x-opt\0", 1, "opt", "0", "other");
+-        do_fstab_filter_options("opt=0,other", "x-opt\0opt\0", 1, "opt", "0", "other");
+-        do_fstab_filter_options("opt,other", "opt\0x-opt\0", 1, "opt", NULL, "other");
+-        do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, "opt", NULL, "other");
+-        do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, "x-opt", NULL, "other");
+-
+-        do_fstab_filter_options("opt=0\\,1,other", "opt\0x-opt\0", 1, "opt", "0,1", "other");
+-        do_fstab_filter_options("opt=0,other,x-opt\\,foobar", "x-opt\0opt\0", 1, "opt", "0", "other,x-opt\\,foobar");
+-        do_fstab_filter_options("opt,other,x-opt\\,part", "opt\0x-opt\0", 1, "opt", NULL, "other,x-opt\\,part");
+-        do_fstab_filter_options("opt,other,part\\,x-opt", "x-opt\0opt\0", 1, "opt", NULL, "other,part\\,x-opt");
+-        do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, "opt", NULL, "other\\,\\,\\,opt,x-part");
+-
+-        do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
+-        do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
+-        do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL);
+-
+-        do_fstab_filter_options("first,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first");
+-        do_fstab_filter_options("first=1,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first=1");
+-        do_fstab_filter_options("first,opt=", "opt\0x-opt\0", 1, "opt", "", "first");
+-        do_fstab_filter_options("first=1,opt", "opt\0x-opt\0", 1, "opt", NULL, "first=1");
+-        do_fstab_filter_options("first=1,x-opt", "opt\0x-opt\0", 1, "x-opt", NULL, "first=1");
+-
+-        do_fstab_filter_options("first,opt=0,last=1", "opt\0x-opt\0", 1, "opt", "0", "first,last=1");
+-        do_fstab_filter_options("first=1,opt=0,last=2", "x-opt\0opt\0", 1, "opt", "0", "first=1,last=2");
+-        do_fstab_filter_options("first,opt,last", "opt\0", 1, "opt", NULL, "first,last");
+-        do_fstab_filter_options("first=1,opt,last", "x-opt\0opt\0", 1, "opt", NULL, "first=1,last");
+-        do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, "opt", NULL, "first=,last");
++        do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "");
++        do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "");
++        do_fstab_filter_options("opt", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "");
++        do_fstab_filter_options("opt", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "");
++        do_fstab_filter_options("x-opt", "x-opt\0opt\0", 1, 0, "x-opt", NULL, "", "");
++
++        do_fstab_filter_options("opt=0,other", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "other");
++        do_fstab_filter_options("opt=0,other", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "other");
++        do_fstab_filter_options("opt,other", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other");
++        do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "other");
++        do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, 0, "x-opt", NULL, "", "other");
++
++        do_fstab_filter_options("opt=0\\,1,other", "opt\0x-opt\0", 1, 1, "opt", "0,1", "0,1", "other");
++        do_fstab_filter_options("opt=0,other,x-opt\\,foobar", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "other,x-opt\\,foobar");
++        do_fstab_filter_options("opt,other,x-opt\\,part", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other,x-opt\\,part");
++        do_fstab_filter_options("opt,other,part\\,x-opt", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "other,part\\,x-opt");
++        do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other\\,\\,\\,opt,x-part");
++
++        do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
++        do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
++        do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
++
++        do_fstab_filter_options("first,opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first");
++        do_fstab_filter_options("first=1,opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first=1");
++        do_fstab_filter_options("first,opt=", "opt\0x-opt\0", 1, 1, "opt", "", "", "first");
++        do_fstab_filter_options("first=1,opt", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "first=1");
++        do_fstab_filter_options("first=1,x-opt", "opt\0x-opt\0", 1, 0, "x-opt", NULL, "", "first=1");
++
++        do_fstab_filter_options("first,opt=0,last=1", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first,last=1");
++        do_fstab_filter_options("first=1,opt=0,last=2", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "first=1,last=2");
++        do_fstab_filter_options("first,opt,last", "opt\0", 1, 0, "opt", NULL, "", "first,last");
++        do_fstab_filter_options("first=1,opt,last", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "first=1,last");
++        do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, 0, "opt", NULL, "", "first=,last");
+ 
+         /* check repeated options */
+-        do_fstab_filter_options("first,opt=0,noopt=1,last=1", "opt\0noopt\0", 1, "noopt", "1", "first,last=1");
+-        do_fstab_filter_options("first=1,opt=0,last=2,opt=1", "opt\0", 1, "opt", "1", "first=1,last=2");
+-        do_fstab_filter_options("x-opt=0,x-opt=1", "opt\0x-opt\0", 1, "x-opt", "1", "");
+-        do_fstab_filter_options("opt=0,x-opt=1", "opt\0x-opt\0", 1, "x-opt", "1", "");
++        do_fstab_filter_options("first,opt=0,noopt=1,last=1", "opt\0noopt\0", 1, 1, "noopt", "1", "0:1", "first,last=1");
++        do_fstab_filter_options("first=1,opt=0,last=2,opt=1", "opt\0", 1, 1, "opt", "1", "0:1", "first=1,last=2");
++        do_fstab_filter_options("x-opt=0,x-opt=1", "opt\0x-opt\0", 1, 1, "x-opt", "1", "0:1", "");
++        do_fstab_filter_options("opt=0,x-opt=1", "opt\0x-opt\0", 1, 1, "x-opt", "1", "0:1", "");
++        do_fstab_filter_options("opt=0,opt=1,opt=,opt=,opt=2", "opt\0noopt\0", 1, 1, "opt", "2", "0:1:::2", "");
+ 
+         /* check that semicolons are not misinterpreted */
+-        do_fstab_filter_options("opt=0;", "opt\0", 1, "opt", "0;", "");
+-        do_fstab_filter_options("opt;=0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL);
+-        do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, NULL, NULL, NULL);
++        do_fstab_filter_options("opt=0;", "opt\0", 1, 1, "opt", "0;", "0;", "");
++        do_fstab_filter_options("opt;=0", "x-opt\0opt\0noopt\0x-noopt\0", 0, 0, NULL, NULL, "", NULL);
++        do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
+ 
+         /* check that spaces are not misinterpreted */
+-        do_fstab_filter_options("opt=0 ", "opt\0", 1, "opt", "0 ", "");
+-        do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL);
+-        do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, NULL, NULL, NULL);
++        do_fstab_filter_options("opt=0 ", "opt\0", 1, 1, "opt", "0 ", "0 ", "");
++        do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, 0, NULL, NULL, "", NULL);
++        do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL);
+ 
+         /* check function with NULL args */
+-        do_fstab_filter_options(NULL, "opt\0", 0, NULL, NULL, "");
+-        do_fstab_filter_options("", "opt\0", 0, NULL, NULL, "");
++        do_fstab_filter_options(NULL, "opt\0", 0, 0, NULL, NULL, "", "");
++        do_fstab_filter_options("", "opt\0", 0, 0, NULL, NULL, "", "");
+ 
+         /* unnecessary comma separators */
+-        do_fstab_filter_options("opt=x,,,,", "opt\0", 1, "opt", "x", "");
+-        do_fstab_filter_options(",,,opt=x,,,,", "opt\0", 1, "opt", "x", "");
++        do_fstab_filter_options("opt=x,,,,", "opt\0", 1, 1, "opt", "x", "x", "");
++        do_fstab_filter_options(",,,opt=x,,,,", "opt\0", 1, 1, "opt", "x", "x", "");
+ 
+         /* escaped characters */
+-        do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt1\0", 1, "opt1", "\\", "opt2=\\xff");
+-        do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, "opt2", "\\xff", "opt1=\\");
++        do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt1\0", 1, 1, "opt1", "\\", "\\", "opt2=\\xff");
++        do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, 1, "opt2", "\\xff", "\\xff", "opt1=\\");
+ }
+ 
+ static void test_fstab_find_pri(void) {
+
+From d6cef552dcb4764a89269ce9603eb21f348d911a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Thu, 11 Mar 2021 11:10:32 +0100
+Subject: [PATCH 9/9] fstab-generator: get rid of fstab_extract_values()
+
+This was a parallel implementation of option parsing that didn't
+support escaping of separators. Let's port this over to the common code.
+
+Fixes #18952.
+---
+ src/fstab-generator/fstab-generator.c | 14 ++++++-------
+ src/shared/fstab-util.c               | 29 ---------------------------
+ src/shared/fstab-util.h               |  2 --
+ 3 files changed, 7 insertions(+), 38 deletions(-)
+
+diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
+index b454a5980d4..8c1087a9a33 100644
+--- a/src/fstab-generator/fstab-generator.c
++++ b/src/fstab-generator/fstab-generator.c
+@@ -241,7 +241,7 @@ static int write_dependency(
+         assert(f);
+         assert(opts);
+ 
+-        r = fstab_extract_values(opts, filter, &names);
++        r = fstab_filter_options(opts, filter, NULL, NULL, &names, NULL);
+         if (r < 0)
+                 return log_warning_errno(r, "Failed to parse options: %m");
+         if (r == 0)
+@@ -274,17 +274,17 @@ static int write_dependency(
+ 
+ static int write_after(FILE *f, const char *opts) {
+         return write_dependency(f, opts,
+-                                "x-systemd.after", "After=%1$s\n");
++                                "x-systemd.after\0", "After=%1$s\n");
+ }
+ 
+ static int write_requires_after(FILE *f, const char *opts) {
+         return write_dependency(f, opts,
+-                                "x-systemd.requires", "After=%1$s\nRequires=%1$s\n");
++                                "x-systemd.requires\0", "After=%1$s\nRequires=%1$s\n");
+ }
+ 
+ static int write_before(FILE *f, const char *opts) {
+         return write_dependency(f, opts,
+-                                "x-systemd.before", "Before=%1$s\n");
++                                "x-systemd.before\0", "Before=%1$s\n");
+ }
+ 
+ static int write_requires_mounts_for(FILE *f, const char *opts) {
+@@ -295,7 +295,7 @@ static int write_requires_mounts_for(FILE *f, const char *opts) {
+         assert(f);
+         assert(opts);
+ 
+-        r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths);
++        r = fstab_filter_options(opts, "x-systemd.requires-mounts-for\0", NULL, NULL, &paths, NULL);
+         if (r < 0)
+                 return log_warning_errno(r, "Failed to parse options: %m");
+         if (r == 0)
+@@ -376,11 +376,11 @@ static int add_mount(
+             mount_point_ignore(where))
+                 return 0;
+ 
+-        r = fstab_extract_values(opts, "x-systemd.wanted-by", &wanted_by);
++        r = fstab_filter_options(opts, "x-systemd.wanted-by\0", NULL, NULL, &wanted_by, NULL);
+         if (r < 0)
+                 return r;
+ 
+-        r = fstab_extract_values(opts, "x-systemd.required-by", &required_by);
++        r = fstab_filter_options(opts, "x-systemd.required-by\0", NULL, NULL, &required_by, NULL);
+         if (r < 0)
+                 return r;
+ 
+diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
+index 6674ed4a19f..7fd3d9c2c34 100644
+--- a/src/shared/fstab-util.c
++++ b/src/shared/fstab-util.c
+@@ -210,35 +210,6 @@ int fstab_filter_options(
+         return !!namefound;
+ }
+ 
+-int fstab_extract_values(const char *opts, const char *name, char ***values) {
+-        _cleanup_strv_free_ char **optsv = NULL, **res = NULL;
+-        char **s;
+-
+-        assert(opts);
+-        assert(name);
+-        assert(values);
+-
+-        optsv = strv_split(opts, ",");
+-        if (!optsv)
+-                return -ENOMEM;
+-
+-        STRV_FOREACH(s, optsv) {
+-                char *arg;
+-                int r;
+-
+-                arg = startswith(*s, name);
+-                if (!arg || *arg != '=')
+-                        continue;
+-                r = strv_extend(&res, arg + 1);
+-                if (r < 0)
+-                        return r;
+-        }
+-
+-        *values = TAKE_PTR(res);
+-
+-        return !!*values;
+-}
+-
+ int fstab_find_pri(const char *options, int *ret) {
+         _cleanup_free_ char *opt = NULL;
+         int r, pri;
+diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
+index 97f40221afb..6b596baafa1 100644
+--- a/src/shared/fstab-util.h
++++ b/src/shared/fstab-util.h
+@@ -18,8 +18,6 @@ int fstab_filter_options(
+                 char ***ret_values,
+                 char **ret_filtered);
+ 
+-int fstab_extract_values(const char *opts, const char *name, char ***values);
+-
+ static inline bool fstab_test_option(const char *opts, const char *names) {
+         return !!fstab_filter_options(opts, names, NULL, NULL, NULL, NULL);
+ }
diff --git a/SOURCES/disable-broken-tests-for-binutils-bug.patch b/SOURCES/disable-broken-tests-for-binutils-bug.patch
deleted file mode 100644
index fc77cb1..0000000
--- a/SOURCES/disable-broken-tests-for-binutils-bug.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-diff -Naur a/src/test/meson.build b/src/test/meson.build
---- a/src/test/meson.build	2021-02-02 07:29:47.000000000 -0800
-+++ b/src/test/meson.build	2021-02-19 10:58:19.188785027 -0800
-@@ -61,11 +61,6 @@
-           libmount,
-           libblkid]],
- 
--        [['src/test/test-emergency-action.c'],
--         [libcore,
--          libshared],
--         []],
--
-         [['src/test/test-chown-rec.c'],
-          [libcore,
-           libshared],
-@@ -522,24 +517,6 @@
-          [],
-          []],
- 
--        [['src/test/test-tables.c',
--          'src/shared/test-tables.h',
--          'src/journal/journald-server.c',
--          'src/journal/journald-server.h'],
--         [libcore,
--          libjournal_core,
--          libudev_core,
--          libudev_static,
--          libsystemd_network,
--          libshared],
--         [threads,
--          libseccomp,
--          libmount,
--          libxz,
--          liblz4,
--          libblkid],
--         '', '', [], libudev_core_includes],
--
-         [['src/test/test-prioq.c'],
-          [],
-          []],
-@@ -621,11 +598,6 @@
-          [],
-          []],
- 
--        [['src/test/test-cgroup-cpu.c'],
--         [libcore,
--          libshared],
--         []],
--
-         [['src/test/test-cgroup-unit-default.c'],
-          [libcore,
-           libshared],
-@@ -1168,10 +1140,6 @@
-          [],
-          []],
- 
--        [['src/analyze/test-verify.c', 'src/analyze/analyze-verify.c', 'src/analyze/analyze-verify.h'],
--         [libcore, libshared],
--         []],
--
-         [['src/login/test-inhibit.c'],
-          [],
-          [],
diff --git a/SOURCES/fa67d9c0d652dc41574b546f542909e9c8157237.patch b/SOURCES/fa67d9c0d652dc41574b546f542909e9c8157237.patch
new file mode 100644
index 0000000..51d09b1
--- /dev/null
+++ b/SOURCES/fa67d9c0d652dc41574b546f542909e9c8157237.patch
@@ -0,0 +1,49 @@
+From fa67d9c0d652dc41574b546f542909e9c8157237 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Tue, 12 Jan 2021 21:36:54 +0100
+Subject: [PATCH] extract-word: don't rely on C's downgrade-to-bool feature for
+ chars
+
+The `quote` char variable ectually contains a character, not a pointer
+or boolean. hence do an explicit comparison rather than rely on C's
+downgrade to bool feature, as per our coding style.
+---
+ src/basic/extract-word.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
+index 76b3fe12e3b..4104dac9a74 100644
+--- a/src/basic/extract-word.c
++++ b/src/basic/extract-word.c
+@@ -20,11 +20,10 @@
+ int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
+         _cleanup_free_ char *s = NULL;
+         size_t allocated = 0, sz = 0;
+-        char c;
+-        int r;
+-
+         char quote = 0;                 /* 0 or ' or " */
+         bool backslash = false;         /* whether we've just seen a backslash */
++        char c;
++        int r;
+ 
+         assert(p);
+         assert(ret);
+@@ -71,7 +70,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
+ 
+                         if (c == 0) {
+                                 if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
+-                                    (!quote || flags & EXTRACT_RELAX)) {
++                                    (quote == 0 || flags & EXTRACT_RELAX)) {
+                                         /* If we find an unquoted trailing backslash and we're in
+                                          * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
+                                          * output.
+@@ -116,7 +115,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
+ 
+                         backslash = false;
+ 
+-                } else if (quote) {     /* inside either single or double quotes */
++                } else if (quote != 0) {     /* inside either single or double quotes */
+                         for (;; (*p)++, c = **p) {
+                                 if (c == 0) {
+                                         if (flags & EXTRACT_RELAX)
diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec
index 8e5d699..859e47d 100644
--- a/SPECS/systemd.spec
+++ b/SPECS/systemd.spec
@@ -16,12 +16,12 @@
 # cryptsetup, e.g. when re-building cryptsetup on a json-c SONAME-bump.
 %bcond_with    bootstrap
 %bcond_without tests
-%bcond_without lto
+%bcond_with    lto
 
 Name:           systemd
 Url:            https://www.freedesktop.org/wiki/Software/systemd
 Version:        247.3
-Release:        3%{?dist}
+Release:        4%{?dist}
 # For a breakdown of the licensing, see README
 License:        LGPLv2+ and MIT and GPLv2+
 Summary:        System and Service Manager
@@ -71,13 +71,17 @@ Patch0001:      https://github.com/systemd/systemd/pull/17872.patch
 %if 0%{?facebook}
 # 17495: Fixes BPF pinning post-coldplug
 Patch0002:      https://github.com/systemd/systemd/pull/17495.patch
+# 18886: systemd-shutdown logs to /dev/console not stderr
+Patch0003:      https://github.com/systemd/systemd/pull/18886.patch
 %endif
+# Commit to make #18955 apply cleanly
+Patch0004:      https://github.com/systemd/systemd/commit/fa67d9c0d652dc41574b546f542909e9c8157237.patch
+#18955: Fixes fstab parsing
+Patch0005:      https://github.com/systemd/systemd/pull/18955.patch
 
 # Downstream-only patches (0500–9999)
 # https://github.com/systemd/systemd/pull/17050
 Patch0501:      https://github.com/systemd/systemd/pull/17050/commits/f58b96d3e8d1cb0dd3666bc74fa673918b586612.patch
-# workaround for https://pagure.io/centos-sig-hyperscale/sig/issue/13
-Patch0502:      disable-broken-tests-for-binutils-bug.patch
 
 %ifarch %{ix86} x86_64 aarch64
 %global have_gnu_efi 1
@@ -870,6 +874,11 @@ fi
 %files tests -f .file-list-tests
 
 %changelog
+* Wed Mar 17 2021 Anita Zhang <anitazha@fb.com> - 247.3-4
+- Backport PR #18955 (Fixes fstab parsing)
+- FB only backport PR #18886 (systemd-shutdown logs to /dev/console not stderr)
+- Reenable tests by disabling LTO (work around binutils bug)
+
 * Wed Feb 24 2021 Davide Cavalca <dcavalca@fb.com> - 247.3-3
 - Remove careinversion usage to make the package usable on older mock versions