diff --git a/SOURCES/0018-Really-don-t-enable-systemd-journald-audit.socket.patch b/SOURCES/0018-Really-don-t-enable-systemd-journald-audit.socket.patch
new file mode 100644
index 0000000..1cb31e0
--- /dev/null
+++ b/SOURCES/0018-Really-don-t-enable-systemd-journald-audit.socket.patch
@@ -0,0 +1,25 @@
+From bdea01b16bedae5fdba3e9a12a864087cfb4b040 Mon Sep 17 00:00:00 2001
+From: David Tardon <dtardon@redhat.com>
+Date: Wed, 25 Aug 2021 16:03:04 +0200
+Subject: [PATCH] Really don't enable systemd-journald-audit.socket
+
+RHEL-only
+
+Resolves: #1973856
+---
+ units/systemd-journald.service.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in
+index d981273b07..f190dff5fb 100644
+--- a/units/systemd-journald.service.in
++++ b/units/systemd-journald.service.in
+@@ -33,7 +33,7 @@ RestrictRealtime=yes
+ RestrictSUIDSGID=yes
+ RuntimeDirectory=systemd/journal
+ RuntimeDirectoryPreserve=yes
+-Sockets=systemd-journald.socket systemd-journald-dev-log.socket systemd-journald-audit.socket
++Sockets=systemd-journald.socket systemd-journald-dev-log.socket
+ StandardOutput=null
+ SystemCallArchitectures=native
+ SystemCallErrorNumber=EPERM
diff --git a/SOURCES/0018-boot-don-t-build-bootctl-when-Dgnu-efi-false-is-set.patch b/SOURCES/0018-boot-don-t-build-bootctl-when-Dgnu-efi-false-is-set.patch
deleted file mode 100644
index 648a5b6..0000000
--- a/SOURCES/0018-boot-don-t-build-bootctl-when-Dgnu-efi-false-is-set.patch
+++ /dev/null
@@ -1,94 +0,0 @@
-From 7cea77bd5712260277e451d34908f01f14c467c4 Mon Sep 17 00:00:00 2001
-From: Michal Sekletar <msekleta@redhat.com>
-Date: Mon, 30 Aug 2021 18:38:09 +0200
-Subject: [PATCH] boot: don't build bootctl when -Dgnu-efi=false is set
-
-(cherry picked from commit fbe3a414e1d8f7b05dccf3d24d4fa475eb9c6bc9)
-
-Resolves: #1972223
----
- meson.build                       | 8 +++++---
- shell-completion/bash/meson.build | 2 +-
- shell-completion/zsh/meson.build  | 2 +-
- units/meson.build                 | 2 +-
- 4 files changed, 8 insertions(+), 6 deletions(-)
-
-diff --git a/meson.build b/meson.build
-index 738879eb21..d28f04607a 100644
---- a/meson.build
-+++ b/meson.build
-@@ -1608,6 +1608,10 @@ else
- endif
- conf.set10('ENABLE_EFI', have)
- 
-+subdir('src/fundamental')
-+subdir('src/boot/efi')
-+conf.set10('HAVE_GNU_EFI', have_gnu_efi)
-+
- ############################################################
- 
- build_bpf_skel_py = find_program('tools/build-bpf-skel.py')
-@@ -1660,7 +1664,6 @@ includes = [libsystemd_includes, include_directories('src/shared')]
- 
- subdir('po')
- subdir('catalog')
--subdir('src/fundamental')
- subdir('src/basic')
- subdir('src/libsystemd')
- subdir('src/shared')
-@@ -1751,7 +1754,6 @@ subdir('src/journal')
- subdir('src/libsystemd-network')
- 
- subdir('src/analyze')
--subdir('src/boot/efi')
- subdir('src/busctl')
- subdir('src/coredump')
- subdir('src/cryptenroll')
-@@ -2145,7 +2147,7 @@ if conf.get('HAVE_PAM') == 1
-                 install_dir : rootlibexecdir)
- endif
- 
--if conf.get('ENABLE_EFI') == 1 and conf.get('HAVE_BLKID') == 1
-+if conf.get('HAVE_BLKID') == 1 and conf.get('HAVE_GNU_EFI') == 1
-         public_programs += executable(
-                 'bootctl',
-                 'src/boot/bootctl.c',
-diff --git a/shell-completion/bash/meson.build b/shell-completion/bash/meson.build
-index c26b413d92..bfdd2b01f0 100644
---- a/shell-completion/bash/meson.build
-+++ b/shell-completion/bash/meson.build
-@@ -33,7 +33,7 @@ items = [['busctl',              ''],
-          ['systemd-run',         ''],
-          ['udevadm',             ''],
-          ['kernel-install',      ''],
--         ['bootctl',             'ENABLE_EFI'],
-+         ['bootctl',             'HAVE_GNU_EFI'],
-          ['coredumpctl',         'ENABLE_COREDUMP'],
-          ['homectl',             'ENABLE_HOMED'],
-          ['hostnamectl',         'ENABLE_HOSTNAMED'],
-diff --git a/shell-completion/zsh/meson.build b/shell-completion/zsh/meson.build
-index f5f9b0f993..3a92f303b8 100644
---- a/shell-completion/zsh/meson.build
-+++ b/shell-completion/zsh/meson.build
-@@ -28,7 +28,7 @@ items = [['_busctl',                   ''],
-          ['_sd_outputmodes',           ''],
-          ['_sd_unit_files',            ''],
-          ['_sd_machines',              ''],
--         ['_bootctl',                  'ENABLE_EFI'],
-+         ['_bootctl',                  'HAVE_GNU_EFI'],
-          ['_coredumpctl',              'ENABLE_COREDUMP'],
-          ['_hostnamectl',              'ENABLE_HOSTNAMED'],
-          ['_localectl',                'ENABLE_LOCALED'],
-diff --git a/units/meson.build b/units/meson.build
-index 68be8d0108..27a2b60137 100644
---- a/units/meson.build
-+++ b/units/meson.build
-@@ -102,7 +102,7 @@ units = [
-         ['systemd-ask-password-wall.path',      '',
-          'multi-user.target.wants/'],
-         ['systemd-ask-password-wall.service',   ''],
--        ['systemd-boot-system-token.service',   'ENABLE_EFI',
-+        ['systemd-boot-system-token.service',   'HAVE_GNU_EFI',
-          'sysinit.target.wants/'],
-         ['systemd-coredump.socket',             'ENABLE_COREDUMP',
-          'sockets.target.wants/'],
diff --git a/SOURCES/0019-rules-add-elevator-kernel-command-line-parameter.patch b/SOURCES/0019-rules-add-elevator-kernel-command-line-parameter.patch
index 0f0f7a7..aef4cd1 100644
--- a/SOURCES/0019-rules-add-elevator-kernel-command-line-parameter.patch
+++ b/SOURCES/0019-rules-add-elevator-kernel-command-line-parameter.patch
@@ -1,4 +1,4 @@
-From 7938e1e61c57441798d81124fd67b2e9bdd5e525 Mon Sep 17 00:00:00 2001
+From f583f3db3533bb2b3db1646d6afa74613fca46a6 Mon Sep 17 00:00:00 2001
 From: Lukas Nykryn <lnykryn@redhat.com>
 Date: Tue, 12 Feb 2019 16:58:16 +0100
 Subject: [PATCH] rules: add elevator= kernel command line parameter
@@ -8,7 +8,7 @@ it for rhel8 via udev rule.
 
 RHEL-only
 
-Resolves: #1998190
+Resolves: #2003002
 ---
  rules.d/40-elevator.rules | 20 ++++++++++++++++++++
  rules.d/meson.build       |  1 +
diff --git a/SOURCES/0020-boot-don-t-build-bootctl-when-Dgnu-efi-false-is-set.patch b/SOURCES/0020-boot-don-t-build-bootctl-when-Dgnu-efi-false-is-set.patch
new file mode 100644
index 0000000..5f5581f
--- /dev/null
+++ b/SOURCES/0020-boot-don-t-build-bootctl-when-Dgnu-efi-false-is-set.patch
@@ -0,0 +1,94 @@
+From 9c67a1570d89ff462cb51f4b2a6d2ed0af8e2e9c Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Mon, 30 Aug 2021 18:38:09 +0200
+Subject: [PATCH] boot: don't build bootctl when -Dgnu-efi=false is set
+
+(cherry picked from commit fbe3a414e1d8f7b05dccf3d24d4fa475eb9c6bc9)
+
+Resolves: #2003130
+---
+ meson.build                       | 8 +++++---
+ shell-completion/bash/meson.build | 2 +-
+ shell-completion/zsh/meson.build  | 2 +-
+ units/meson.build                 | 2 +-
+ 4 files changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/meson.build b/meson.build
+index 738879eb21..d28f04607a 100644
+--- a/meson.build
++++ b/meson.build
+@@ -1608,6 +1608,10 @@ else
+ endif
+ conf.set10('ENABLE_EFI', have)
+ 
++subdir('src/fundamental')
++subdir('src/boot/efi')
++conf.set10('HAVE_GNU_EFI', have_gnu_efi)
++
+ ############################################################
+ 
+ build_bpf_skel_py = find_program('tools/build-bpf-skel.py')
+@@ -1660,7 +1664,6 @@ includes = [libsystemd_includes, include_directories('src/shared')]
+ 
+ subdir('po')
+ subdir('catalog')
+-subdir('src/fundamental')
+ subdir('src/basic')
+ subdir('src/libsystemd')
+ subdir('src/shared')
+@@ -1751,7 +1754,6 @@ subdir('src/journal')
+ subdir('src/libsystemd-network')
+ 
+ subdir('src/analyze')
+-subdir('src/boot/efi')
+ subdir('src/busctl')
+ subdir('src/coredump')
+ subdir('src/cryptenroll')
+@@ -2145,7 +2147,7 @@ if conf.get('HAVE_PAM') == 1
+                 install_dir : rootlibexecdir)
+ endif
+ 
+-if conf.get('ENABLE_EFI') == 1 and conf.get('HAVE_BLKID') == 1
++if conf.get('HAVE_BLKID') == 1 and conf.get('HAVE_GNU_EFI') == 1
+         public_programs += executable(
+                 'bootctl',
+                 'src/boot/bootctl.c',
+diff --git a/shell-completion/bash/meson.build b/shell-completion/bash/meson.build
+index c26b413d92..bfdd2b01f0 100644
+--- a/shell-completion/bash/meson.build
++++ b/shell-completion/bash/meson.build
+@@ -33,7 +33,7 @@ items = [['busctl',              ''],
+          ['systemd-run',         ''],
+          ['udevadm',             ''],
+          ['kernel-install',      ''],
+-         ['bootctl',             'ENABLE_EFI'],
++         ['bootctl',             'HAVE_GNU_EFI'],
+          ['coredumpctl',         'ENABLE_COREDUMP'],
+          ['homectl',             'ENABLE_HOMED'],
+          ['hostnamectl',         'ENABLE_HOSTNAMED'],
+diff --git a/shell-completion/zsh/meson.build b/shell-completion/zsh/meson.build
+index f5f9b0f993..3a92f303b8 100644
+--- a/shell-completion/zsh/meson.build
++++ b/shell-completion/zsh/meson.build
+@@ -28,7 +28,7 @@ items = [['_busctl',                   ''],
+          ['_sd_outputmodes',           ''],
+          ['_sd_unit_files',            ''],
+          ['_sd_machines',              ''],
+-         ['_bootctl',                  'ENABLE_EFI'],
++         ['_bootctl',                  'HAVE_GNU_EFI'],
+          ['_coredumpctl',              'ENABLE_COREDUMP'],
+          ['_hostnamectl',              'ENABLE_HOSTNAMED'],
+          ['_localectl',                'ENABLE_LOCALED'],
+diff --git a/units/meson.build b/units/meson.build
+index 68be8d0108..27a2b60137 100644
+--- a/units/meson.build
++++ b/units/meson.build
+@@ -102,7 +102,7 @@ units = [
+         ['systemd-ask-password-wall.path',      '',
+          'multi-user.target.wants/'],
+         ['systemd-ask-password-wall.service',   ''],
+-        ['systemd-boot-system-token.service',   'ENABLE_EFI',
++        ['systemd-boot-system-token.service',   'HAVE_GNU_EFI',
+          'sysinit.target.wants/'],
+         ['systemd-coredump.socket',             'ENABLE_COREDUMP',
+          'sockets.target.wants/'],
diff --git a/SOURCES/0020-sd-device-introduce-device_has_devlink.patch b/SOURCES/0020-sd-device-introduce-device_has_devlink.patch
deleted file mode 100644
index 62c593d..0000000
--- a/SOURCES/0020-sd-device-introduce-device_has_devlink.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 76aebe6fec5894b05114fdf1e8aee54139bef69e Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Wed, 1 Sep 2021 09:22:15 +0900
-Subject: [PATCH] sd-device: introduce device_has_devlink()
-
-(cherry picked from commit b881ce16b9ccae4c3089c82e2ea1781cd9773a4f)
-
-Related: #1977994
----
- src/libsystemd/sd-device/device-private.h | 1 +
- src/libsystemd/sd-device/sd-device.c      | 7 +++++++
- 2 files changed, 8 insertions(+)
-
-diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h
-index fe268d7f2f..9bb5eff208 100644
---- a/src/libsystemd/sd-device/device-private.h
-+++ b/src/libsystemd/sd-device/device-private.h
-@@ -32,6 +32,7 @@ void device_set_db_persist(sd_device *device);
- void device_set_devlink_priority(sd_device *device, int priority);
- int device_ensure_usec_initialized(sd_device *device, sd_device *device_old);
- int device_add_devlink(sd_device *device, const char *devlink);
-+bool device_has_devlink(sd_device *device, const char *devlink);
- int device_add_property(sd_device *device, const char *property, const char *value);
- int device_add_tag(sd_device *device, const char *tag, bool both);
- void device_remove_tag(sd_device *device, const char *tag);
-diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
-index 388128bf33..8a9e4a33a1 100644
---- a/src/libsystemd/sd-device/sd-device.c
-+++ b/src/libsystemd/sd-device/sd-device.c
-@@ -1193,6 +1193,13 @@ int device_add_devlink(sd_device *device, const char *devlink) {
-         return 0;
- }
- 
-+bool device_has_devlink(sd_device *device, const char *devlink) {
-+        assert(device);
-+        assert(devlink);
-+
-+        return set_contains(device->devlinks, devlink);
-+}
-+
- static int device_add_property_internal_from_string(sd_device *device, const char *str) {
-         _cleanup_free_ char *key = NULL;
-         char *value;
diff --git a/SOURCES/0021-udev-node-split-out-permission-handling-from-udev_no.patch b/SOURCES/0021-udev-node-split-out-permission-handling-from-udev_no.patch
deleted file mode 100644
index 58d087c..0000000
--- a/SOURCES/0021-udev-node-split-out-permission-handling-from-udev_no.patch
+++ /dev/null
@@ -1,305 +0,0 @@
-From acf81f97412be44d60be03a0a2e3ca62f4a5146b Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Wed, 1 Sep 2021 09:24:15 +0900
-Subject: [PATCH] udev-node: split out permission handling from udev_node_add()
-
-And then merge udev_node_add() and udev_node_update_old_links().
-
-(cherry picked from commit 2f48561e0db3cd63f65e9311b4d69282b4ac605d)
-
-Related: #1977994
----
- src/udev/udev-event.c |   9 +-
- src/udev/udev-node.c  | 204 +++++++++++++++++++-----------------------
- src/udev/udev-node.h  |  12 ++-
- 3 files changed, 106 insertions(+), 119 deletions(-)
-
-diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
-index b28089be71..8b9f8aecfe 100644
---- a/src/udev/udev-event.c
-+++ b/src/udev/udev-event.c
-@@ -895,9 +895,6 @@ static int update_devnode(UdevEvent *event) {
-         if (r < 0)
-                 return log_device_error_errno(dev, r, "Failed to get devnum: %m");
- 
--        /* remove/update possible left-over symlinks from old database entry */
--        (void) udev_node_update_old_links(dev, event->dev_db_clone);
--
-         if (!uid_is_valid(event->uid)) {
-                 r = device_get_devnode_uid(dev, &event->uid);
-                 if (r < 0 && r != -ENOENT)
-@@ -921,7 +918,11 @@ static int update_devnode(UdevEvent *event) {
- 
-         bool apply_mac = device_for_action(dev, SD_DEVICE_ADD);
- 
--        return udev_node_add(dev, apply_mac, event->mode, event->uid, event->gid, event->seclabel_list);
-+        r = udev_node_apply_permissions(dev, apply_mac, event->mode, event->uid, event->gid, event->seclabel_list);
-+        if (r < 0)
-+                return log_device_error_errno(dev, r, "Failed to apply devnode permissions: %m");
-+
-+        return udev_node_update(dev, event->dev_db_clone);
- }
- 
- static int event_execute_rules_on_remove(
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 9e52906571..7cc9ee3670 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -356,45 +356,117 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
-         return i < LINK_UPDATE_MAX_RETRIES ? 0 : -ELOOP;
- }
- 
--int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) {
--        const char *name;
-+static int device_get_devpath_by_devnum(sd_device *dev, char **ret) {
-+        const char *subsystem;
-+        dev_t devnum;
-+        int r;
-+
-+        assert(dev);
-+        assert(ret);
-+
-+        r = sd_device_get_subsystem(dev, &subsystem);
-+        if (r < 0)
-+                return r;
-+
-+        r = sd_device_get_devnum(dev, &devnum);
-+        if (r < 0)
-+                return r;
-+
-+        return device_path_make_major_minor(streq(subsystem, "block") ? S_IFBLK : S_IFCHR, devnum, ret);
-+}
-+
-+int udev_node_update(sd_device *dev, sd_device *dev_old) {
-+        _cleanup_free_ char *filename = NULL;
-+        const char *devnode, *devlink;
-         int r;
- 
-         assert(dev);
-         assert(dev_old);
- 
--        /* update possible left-over symlinks */
--        FOREACH_DEVICE_DEVLINK(dev_old, name) {
--                const char *name_current;
--                bool found = false;
-+        r = sd_device_get_devname(dev, &devnode);
-+        if (r < 0)
-+                return log_device_debug_errno(dev, r, "Failed to get devnode: %m");
- 
--                /* check if old link name still belongs to this device */
--                FOREACH_DEVICE_DEVLINK(dev, name_current)
--                        if (streq(name, name_current)) {
--                                found = true;
--                                break;
--                        }
-+        if (DEBUG_LOGGING) {
-+                const char *id = NULL;
- 
--                if (found)
-+                (void) device_get_device_id(dev, &id);
-+                log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strna(id));
-+        }
-+
-+        /* update possible left-over symlinks */
-+        FOREACH_DEVICE_DEVLINK(dev_old, devlink) {
-+                /* check if old link name still belongs to this device */
-+                if (device_has_devlink(dev, devlink))
-                         continue;
- 
-                 log_device_debug(dev,
--                                 "Updating old device symlink '%s', which is no longer belonging to this device.",
--                                 name);
-+                                 "Removing/updating old device symlink '%s', which is no longer belonging to this device.",
-+                                 devlink);
- 
--                r = link_update(dev, name, false);
-+                r = link_update(dev, devlink, /* add = */ false);
-                 if (r < 0)
-                         log_device_warning_errno(dev, r,
--                                                 "Failed to update device symlink '%s', ignoring: %m",
--                                                 name);
-+                                                 "Failed to remove/update device symlink '%s', ignoring: %m",
-+                                                 devlink);
-         }
- 
-+        /* create/update symlinks, add symlinks to name index */
-+        FOREACH_DEVICE_DEVLINK(dev, devlink) {
-+                r = link_update(dev, devlink, /* add = */ true);
-+                if (r < 0)
-+                        log_device_warning_errno(dev, r,
-+                                                 "Failed to create/update device symlink '%s', ignoring: %m",
-+                                                 devlink);
-+        }
-+
-+        r = device_get_devpath_by_devnum(dev, &filename);
-+        if (r < 0)
-+                return log_device_debug_errno(dev, r, "Failed to get device path: %m");
-+
-+        /* always add /dev/{block,char}/$major:$minor */
-+        r = node_symlink(dev, devnode, filename);
-+        if (r < 0)
-+                return log_device_warning_errno(dev, r, "Failed to create device symlink '%s': %m", filename);
-+
-+        return 0;
-+}
-+
-+int udev_node_remove(sd_device *dev) {
-+        _cleanup_free_ char *filename = NULL;
-+        const char *devlink;
-+        int r;
-+
-+        assert(dev);
-+
-+        /* remove/update symlinks, remove symlinks from name index */
-+        FOREACH_DEVICE_DEVLINK(dev, devlink) {
-+                r = link_update(dev, devlink, /* add = */ false);
-+                if (r < 0)
-+                        log_device_warning_errno(dev, r,
-+                                                 "Failed to remove/update device symlink '%s', ignoring: %m",
-+                                                 devlink);
-+        }
-+
-+        r = device_get_devpath_by_devnum(dev, &filename);
-+        if (r < 0)
-+                return log_device_debug_errno(dev, r, "Failed to get device path: %m");
-+
-+        /* remove /dev/{block,char}/$major:$minor */
-+        if (unlink(filename) < 0 && errno != ENOENT)
-+                return log_device_debug_errno(dev, errno, "Failed to remove '%s': %m", filename);
-+
-         return 0;
- }
- 
--static int node_permissions_apply(sd_device *dev, bool apply_mac,
--                                  mode_t mode, uid_t uid, gid_t gid,
--                                  OrderedHashmap *seclabel_list) {
-+int udev_node_apply_permissions(
-+                sd_device *dev,
-+                bool apply_mac,
-+                mode_t mode,
-+                uid_t uid,
-+                gid_t gid,
-+                OrderedHashmap *seclabel_list) {
-+
-         const char *devnode, *subsystem, *id = NULL;
-         bool apply_mode, apply_uid, apply_gid;
-         _cleanup_close_ int node_fd = -1;
-@@ -511,95 +583,5 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
-         if (r < 0)
-                 log_device_debug_errno(dev, r, "Failed to adjust timestamp of node %s: %m", devnode);
- 
--        return r;
--}
--
--static int xsprintf_dev_num_path_from_sd_device(sd_device *dev, char **ret) {
--        const char *subsystem;
--        dev_t devnum;
--        int r;
--
--        assert(ret);
--
--        r = sd_device_get_subsystem(dev, &subsystem);
--        if (r < 0)
--                return r;
--
--        r = sd_device_get_devnum(dev, &devnum);
--        if (r < 0)
--                return r;
--
--        return device_path_make_major_minor(streq(subsystem, "block") ? S_IFBLK : S_IFCHR, devnum, ret);
--}
--
--int udev_node_add(sd_device *dev, bool apply,
--                  mode_t mode, uid_t uid, gid_t gid,
--                  OrderedHashmap *seclabel_list) {
--        const char *devnode, *devlink;
--        _cleanup_free_ char *filename = NULL;
--        int r;
--
--        assert(dev);
--
--        r = sd_device_get_devname(dev, &devnode);
--        if (r < 0)
--                return log_device_debug_errno(dev, r, "Failed to get devnode: %m");
--
--        if (DEBUG_LOGGING) {
--                const char *id = NULL;
--
--                (void) device_get_device_id(dev, &id);
--                log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strna(id));
--        }
--
--        r = node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list);
--        if (r < 0)
--                return r;
--
--        /* create/update symlinks, add symlinks to name index */
--        FOREACH_DEVICE_DEVLINK(dev, devlink) {
--                r = link_update(dev, devlink, true);
--                if (r < 0)
--                        log_device_warning_errno(dev, r,
--                                                 "Failed to update device symlink '%s', ignoring: %m",
--                                                 devlink);
--        }
--
--        r = xsprintf_dev_num_path_from_sd_device(dev, &filename);
--        if (r < 0)
--                return log_device_debug_errno(dev, r, "Failed to get device path: %m");
--
--        /* always add /dev/{block,char}/$major:$minor */
--        r = node_symlink(dev, devnode, filename);
--        if (r < 0)
--                return log_device_warning_errno(dev, r, "Failed to create device symlink '%s': %m", filename);
--
--        return 0;
--}
--
--int udev_node_remove(sd_device *dev) {
--        _cleanup_free_ char *filename = NULL;
--        const char *devlink;
--        int r;
--
--        assert(dev);
--
--        /* remove/update symlinks, remove symlinks from name index */
--        FOREACH_DEVICE_DEVLINK(dev, devlink) {
--                r = link_update(dev, devlink, false);
--                if (r < 0)
--                        log_device_warning_errno(dev, r,
--                                                 "Failed to update device symlink '%s', ignoring: %m",
--                                                 devlink);
--        }
--
--        r = xsprintf_dev_num_path_from_sd_device(dev, &filename);
--        if (r < 0)
--                return log_device_debug_errno(dev, r, "Failed to get device path: %m");
--
--        /* remove /dev/{block,char}/$major:$minor */
--        if (unlink(filename) < 0 && errno != ENOENT)
--                return log_device_debug_errno(dev, errno, "Failed to remove '%s': %m", filename);
--
-         return 0;
- }
-diff --git a/src/udev/udev-node.h b/src/udev/udev-node.h
-index 2349f9c471..a34af77146 100644
---- a/src/udev/udev-node.h
-+++ b/src/udev/udev-node.h
-@@ -8,10 +8,14 @@
- 
- #include "hashmap.h"
- 
--int udev_node_add(sd_device *dev, bool apply,
--                  mode_t mode, uid_t uid, gid_t gid,
--                  OrderedHashmap *seclabel_list);
-+int udev_node_apply_permissions(
-+                sd_device *dev,
-+                bool apply_mac,
-+                mode_t mode,
-+                uid_t uid,
-+                gid_t gid,
-+                OrderedHashmap *seclabel_list);
- int udev_node_remove(sd_device *dev);
--int udev_node_update_old_links(sd_device *dev, sd_device *dev_old);
-+int udev_node_update(sd_device *dev, sd_device *dev_old);
- 
- size_t udev_node_escape_path(const char *src, char *dest, size_t size);
diff --git a/SOURCES/0021-unit-install-the-systemd-bless-boot.service-only-if-.patch b/SOURCES/0021-unit-install-the-systemd-bless-boot.service-only-if-.patch
new file mode 100644
index 0000000..681d599
--- /dev/null
+++ b/SOURCES/0021-unit-install-the-systemd-bless-boot.service-only-if-.patch
@@ -0,0 +1,28 @@
+From 8f08b876d44d96b3f255ac5275a1daa3ccf9a801 Mon Sep 17 00:00:00 2001
+From: Frantisek Sumsal <frantisek@sumsal.cz>
+Date: Tue, 21 Sep 2021 22:47:42 +0200
+Subject: [PATCH] unit: install the systemd-bless-boot.service only if we have
+ gnu-efi
+
+Follow-up to #20591.
+
+(cherry picked from commit 220261ef940a126588b20a1765a2501811473839)
+
+Related: #2003130
+---
+ units/meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/units/meson.build b/units/meson.build
+index 27a2b60137..e06d883cd2 100644
+--- a/units/meson.build
++++ b/units/meson.build
+@@ -179,7 +179,7 @@ in_units = [
+         ['systemd-backlight@.service',           'ENABLE_BACKLIGHT'],
+         ['systemd-binfmt.service',               'ENABLE_BINFMT',
+          'sysinit.target.wants/'],
+-        ['systemd-bless-boot.service',           'ENABLE_EFI HAVE_BLKID'],
++        ['systemd-bless-boot.service',           'HAVE_GNU_EFI HAVE_BLKID'],
+         ['systemd-boot-check-no-failures.service', ''],
+         ['systemd-coredump@.service',            'ENABLE_COREDUMP'],
+         ['systemd-pstore.service',               'ENABLE_PSTORE'],
diff --git a/SOURCES/0022-udev-node-stack-directory-must-exist-when-adding-dev.patch b/SOURCES/0022-udev-node-stack-directory-must-exist-when-adding-dev.patch
deleted file mode 100644
index ca8894d..0000000
--- a/SOURCES/0022-udev-node-stack-directory-must-exist-when-adding-dev.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 18d2fb228bc155fc357262ec2dc5713318bab453 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Wed, 1 Sep 2021 04:14:42 +0900
-Subject: [PATCH] udev-node: stack directory must exist when adding device node
- symlink
-
-(cherry picked from commit 46070dbf26435ba0def099121f46a6253f3f19b6)
-
-Related: #1977994
----
- src/udev/udev-node.c | 11 ++++++-----
- 1 file changed, 6 insertions(+), 5 deletions(-)
-
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 7cc9ee3670..4496a2bd9b 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -161,12 +161,13 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir,
- 
-         dir = opendir(stackdir);
-         if (!dir) {
--                if (errno == ENOENT) {
--                        *ret = TAKE_PTR(target);
--                        return !!*ret;
--                }
-+                if (add) /* The stack directory must exist. */
-+                        return -errno;
-+                if (errno != ENOENT)
-+                        return -errno;
- 
--                return -errno;
-+                *ret = NULL;
-+                return 0;
-         }
- 
-         r = device_get_device_id(dev, &id);
diff --git a/SOURCES/0022-units-don-t-enable-tmp.mount-statically-in-local-fs..patch b/SOURCES/0022-units-don-t-enable-tmp.mount-statically-in-local-fs..patch
new file mode 100644
index 0000000..65ee29b
--- /dev/null
+++ b/SOURCES/0022-units-don-t-enable-tmp.mount-statically-in-local-fs..patch
@@ -0,0 +1,26 @@
+From ab1ecca56e5a1cc5ad120958b1bb94c7854f3795 Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Wed, 22 Sep 2021 14:38:00 +0200
+Subject: [PATCH] units: don't enable tmp.mount statically in local-fs.target
+
+RHEL-only
+
+Related: #2000927
+---
+ units/meson.build | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/units/meson.build b/units/meson.build
+index e06d883cd2..40487d123e 100644
+--- a/units/meson.build
++++ b/units/meson.build
+@@ -154,8 +154,7 @@ units = [
+         ['time-set.target',                     ''],
+         ['time-sync.target',                    ''],
+         ['timers.target',                       ''],
+-        ['tmp.mount',                           '',
+-         'local-fs.target.wants/'],
++        ['tmp.mount',                           ''],
+         ['umount.target',                       ''],
+         ['usb-gadget.target',                   ''],
+         ['user.slice',                          ''],
diff --git a/SOURCES/0023-pid1-bump-DefaultTasksMax-to-80-of-the-kernel-pid.ma.patch b/SOURCES/0023-pid1-bump-DefaultTasksMax-to-80-of-the-kernel-pid.ma.patch
new file mode 100644
index 0000000..c67bb3a
--- /dev/null
+++ b/SOURCES/0023-pid1-bump-DefaultTasksMax-to-80-of-the-kernel-pid.ma.patch
@@ -0,0 +1,59 @@
+From 50a744391dbb1130d38b44700ae7e6649fcc9ffb Mon Sep 17 00:00:00 2001
+From: rpm-build <rpm-build>
+Date: Wed, 1 Aug 2018 13:19:39 +0200
+Subject: [PATCH] pid1: bump DefaultTasksMax to 80% of the kernel pid.max value
+
+This should be hopefully high enough even for the very big deployments.
+
+RHEL-only
+
+Resolves: #2003031
+---
+ man/systemd-system.conf.xml | 4 ++--
+ src/core/main.c             | 2 +-
+ src/core/system.conf.in     | 2 +-
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
+index c11dd46143..72c8db5890 100644
+--- a/man/systemd-system.conf.xml
++++ b/man/systemd-system.conf.xml
+@@ -389,10 +389,10 @@
+         <listitem><para>Configure the default value for the per-unit <varname>TasksMax=</varname> setting. See
+         <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+         for details. This setting applies to all unit types that support resource control settings, with the exception
+-        of slice units. Defaults to 15% of the minimum of <varname>kernel.pid_max=</varname>, <varname>kernel.threads-max=</varname>
++        of slice units. Defaults to 80% of the minimum of <varname>kernel.pid_max=</varname>, <varname>kernel.threads-max=</varname>
+         and root cgroup <varname>pids.max</varname>.
+         Kernel has a default value for <varname>kernel.pid_max=</varname> and an algorithm of counting in case of more than 32 cores.
+-        For example with the default <varname>kernel.pid_max=</varname>, <varname>DefaultTasksMax=</varname> defaults to 4915,
++        For example with the default <varname>kernel.pid_max=</varname>, <varname>DefaultTasksMax=</varname> defaults to 26214,
+         but might be greater in other systems or smaller in OS containers.</para></listitem>
+       </varlistentry>
+ 
+diff --git a/src/core/main.c b/src/core/main.c
+index da6c50a1c4..f4fe7517fd 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -92,7 +92,7 @@
+ #include <sanitizer/lsan_interface.h>
+ #endif
+ 
+-#define DEFAULT_TASKS_MAX ((TasksMax) { 15U, 100U }) /* 15% */
++#define DEFAULT_TASKS_MAX ((TasksMax) { 80U, 100U }) /* 80% */
+ 
+ static enum {
+         ACTION_RUN,
+diff --git a/src/core/system.conf.in b/src/core/system.conf.in
+index e88280bd0a..f2c75fcd32 100644
+--- a/src/core/system.conf.in
++++ b/src/core/system.conf.in
+@@ -54,7 +54,7 @@
+ #DefaultBlockIOAccounting=no
+ #DefaultMemoryAccounting={{ 'yes' if MEMORY_ACCOUNTING_DEFAULT else 'no' }}
+ #DefaultTasksAccounting=yes
+-#DefaultTasksMax=15%
++#DefaultTasksMax=80%
+ #DefaultLimitCPU=
+ #DefaultLimitFSIZE=
+ #DefaultLimitDATA=
diff --git a/SOURCES/0023-udev-node-save-information-about-device-node-and-pri.patch b/SOURCES/0023-udev-node-save-information-about-device-node-and-pri.patch
deleted file mode 100644
index dcac706..0000000
--- a/SOURCES/0023-udev-node-save-information-about-device-node-and-pri.patch
+++ /dev/null
@@ -1,250 +0,0 @@
-From 9c68b5675ffd11f2a3f9123446b54c2d0eea4682 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Wed, 1 Sep 2021 04:16:21 +0900
-Subject: [PATCH] udev-node: save information about device node and priority in
- symlink
-
-Previously, we only store device IDs in /run/udev/links, and when
-creating/removing device node symlink, we create sd_device object
-corresponds to the IDs and read device node and priority from the
-object. That requires parsing uevent and udev database files.
-
-This makes link_find_prioritized() get the most prioritzed device node
-without parsing the files.
-
-(cherry picked from commit 377a83f0d80376456d9be203796f66f543a8b943)
-
-Related: #1977994
----
- src/udev/udev-node.c | 172 ++++++++++++++++++++++++++++++-------------
- 1 file changed, 121 insertions(+), 51 deletions(-)
-
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 4496a2bd9b..5d6aae0bd4 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -18,6 +18,7 @@
- #include "fs-util.h"
- #include "hexdecoct.h"
- #include "mkdir.h"
-+#include "parse-util.h"
- #include "path-util.h"
- #include "selinux-util.h"
- #include "smack-util.h"
-@@ -28,9 +29,9 @@
- #include "udev-node.h"
- #include "user-util.h"
- 
--#define CREATE_LINK_MAX_RETRIES 128
--#define LINK_UPDATE_MAX_RETRIES 128
--#define TOUCH_FILE_MAX_RETRIES  128
-+#define CREATE_LINK_MAX_RETRIES        128
-+#define LINK_UPDATE_MAX_RETRIES        128
-+#define CREATE_STACK_LINK_MAX_RETRIES  128
- #define UDEV_NODE_HASH_KEY SD_ID128_MAKE(b9,6a,f1,ce,40,31,44,1a,9e,19,ec,8b,ae,f3,e3,2f)
- 
- static int create_symlink(const char *target, const char *slink) {
-@@ -175,39 +176,67 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir,
-                 return r;
- 
-         FOREACH_DIRENT_ALL(dent, dir, break) {
--                _cleanup_(sd_device_unrefp) sd_device *dev_db = NULL;
--                const char *devnode;
--                int db_prio = 0;
-+                _cleanup_free_ char *path = NULL, *buf = NULL;
-+                int tmp_prio;
- 
--                if (dent->d_name[0] == '\0')
--                        break;
-                 if (dent->d_name[0] == '.')
-                         continue;
- 
--                log_device_debug(dev, "Found '%s' claiming '%s'", dent->d_name, stackdir);
--
--                /* did we find ourself? */
-+                /* skip ourself */
-                 if (streq(dent->d_name, id))
-                         continue;
- 
--                if (sd_device_new_from_device_id(&dev_db, dent->d_name) < 0)
--                        continue;
-+                path = path_join(stackdir, dent->d_name);
-+                if (!path)
-+                        return -ENOMEM;
- 
--                if (sd_device_get_devname(dev_db, &devnode) < 0)
--                        continue;
-+                if (readlink_malloc(path, &buf) >= 0) {
-+                        char *devnode;
- 
--                if (device_get_devlink_priority(dev_db, &db_prio) < 0)
--                        continue;
-+                        /* New format. The devnode and priority can be obtained from symlink. */
- 
--                if (target && db_prio <= priority)
--                        continue;
-+                        devnode = strchr(buf, ':');
-+                        if (!devnode || devnode == buf)
-+                                continue;
- 
--                log_device_debug(dev_db, "Device claims priority %i for '%s'", db_prio, stackdir);
-+                        *(devnode++) = '\0';
-+                        if (!path_startswith(devnode, "/dev"))
-+                                continue;
- 
--                r = free_and_strdup(&target, devnode);
--                if (r < 0)
--                        return r;
--                priority = db_prio;
-+                        if (safe_atoi(buf, &tmp_prio) < 0)
-+                                continue;
-+
-+                        if (target && tmp_prio <= priority)
-+                                continue;
-+
-+                        r = free_and_strdup(&target, devnode);
-+                        if (r < 0)
-+                                return r;
-+                } else {
-+                        _cleanup_(sd_device_unrefp) sd_device *tmp_dev = NULL;
-+                        const char *devnode;
-+
-+                        /* Old format. The devnode and priority must be obtained from uevent and
-+                         * udev database files. */
-+
-+                        if (sd_device_new_from_device_id(&tmp_dev, dent->d_name) < 0)
-+                                continue;
-+
-+                        if (device_get_devlink_priority(tmp_dev, &tmp_prio) < 0)
-+                                continue;
-+
-+                        if (target && tmp_prio <= priority)
-+                                continue;
-+
-+                        if (sd_device_get_devname(tmp_dev, &devnode) < 0)
-+                                continue;
-+
-+                        r = free_and_strdup(&target, devnode);
-+                        if (r < 0)
-+                                return r;
-+                }
-+
-+                priority = tmp_prio;
-         }
- 
-         *ret = TAKE_PTR(target);
-@@ -256,10 +285,72 @@ toolong:
-         return size - 1;
- }
- 
-+static int update_stack_directory(sd_device *dev, const char *dirname, bool add) {
-+        _cleanup_free_ char *filename = NULL, *data = NULL, *buf = NULL;
-+        const char *devname, *id;
-+        int priority, r;
-+
-+        assert(dev);
-+        assert(dirname);
-+
-+        r = device_get_device_id(dev, &id);
-+        if (r < 0)
-+                return log_device_debug_errno(dev, r, "Failed to get device id: %m");
-+
-+        filename = path_join(dirname, id);
-+        if (!filename)
-+                return log_oom_debug();
-+
-+        if (!add) {
-+                if (unlink(filename) < 0 && errno != ENOENT)
-+                        log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
-+
-+                (void) rmdir(dirname);
-+                return 0;
-+        }
-+
-+        r = sd_device_get_devname(dev, &devname);
-+        if (r < 0)
-+                return log_device_debug_errno(dev, r, "Failed to get device node: %m");
-+
-+        r = device_get_devlink_priority(dev, &priority);
-+        if (r < 0)
-+                return log_device_debug_errno(dev, r, "Failed to get priority of device node symlink: %m");
-+
-+        if (asprintf(&data, "%i:%s", priority, devname) < 0)
-+                return log_oom_debug();
-+
-+        if (readlink_malloc(filename, &buf) >= 0 && streq(buf, data))
-+                return 0;
-+
-+        if (unlink(filename) < 0 && errno != ENOENT)
-+                log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
-+
-+        for (unsigned j = 0; j < CREATE_STACK_LINK_MAX_RETRIES; j++) {
-+                /* This may fail with -ENOENT when the parent directory is removed during
-+                 * creating the file by another udevd worker. */
-+                r = mkdir_p(dirname, 0755);
-+                if (r == -ENOENT)
-+                        continue;
-+                if (r < 0)
-+                        return log_device_debug_errno(dev, r, "Failed to create directory %s: %m", dirname);
-+
-+                if (symlink(data, filename) < 0) {
-+                        if (errno == ENOENT)
-+                                continue;
-+                        return log_device_debug_errno(dev, errno, "Failed to create symbolic link %s: %m", filename);
-+                }
-+
-+                return 0;
-+        }
-+
-+        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ELOOP), "Failed to create symbolic link %s: %m", filename);
-+}
-+
- /* manage "stack of names" with possibly specified device priorities */
- static int link_update(sd_device *dev, const char *slink_in, bool add) {
--        _cleanup_free_ char *slink = NULL, *filename = NULL, *dirname = NULL;
--        const char *slink_name, *id;
-+        _cleanup_free_ char *slink = NULL, *dirname = NULL;
-+        const char *slink_name;
-         char name_enc[NAME_MAX+1];
-         int i, r, retries;
- 
-@@ -279,35 +370,14 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
-                 return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL),
-                                               "Invalid symbolic link of device node: %s", slink);
- 
--        r = device_get_device_id(dev, &id);
--        if (r < 0)
--                return log_device_debug_errno(dev, r, "Failed to get device id: %m");
--
-         (void) udev_node_escape_path(slink_name, name_enc, sizeof(name_enc));
--        dirname = path_join("/run/udev/links/", name_enc);
-+        dirname = path_join("/run/udev/links", name_enc);
-         if (!dirname)
-                 return log_oom_debug();
- 
--        filename = path_join(dirname, id);
--        if (!filename)
--                return log_oom_debug();
--
--        if (!add) {
--                if (unlink(filename) < 0 && errno != ENOENT)
--                        log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
--
--                (void) rmdir(dirname);
--        } else {
--                for (unsigned j = 0; j < TOUCH_FILE_MAX_RETRIES; j++) {
--                        /* This may fail with -ENOENT when the parent directory is removed during
--                         * creating the file by another udevd worker. */
--                        r = touch_file(filename, /* parents= */ true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
--                        if (r != -ENOENT)
--                                break;
--                }
--                if (r < 0)
--                        return log_device_debug_errno(dev, r, "Failed to create %s: %m", filename);
--        }
-+        r = update_stack_directory(dev, dirname, add);
-+        if (r < 0)
-+                return r;
- 
-         /* If the database entry is not written yet we will just do one iteration and possibly wrong symlink
-          * will be fixed in the second invocation. */
diff --git a/SOURCES/0024-sd-device-introduce-device_has_devlink.patch b/SOURCES/0024-sd-device-introduce-device_has_devlink.patch
new file mode 100644
index 0000000..c6fce49
--- /dev/null
+++ b/SOURCES/0024-sd-device-introduce-device_has_devlink.patch
@@ -0,0 +1,43 @@
+From 9c46b3e584fbb7be0a9e93471d30f2885bd194c9 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 1 Sep 2021 09:22:15 +0900
+Subject: [PATCH] sd-device: introduce device_has_devlink()
+
+(cherry picked from commit b881ce16b9ccae4c3089c82e2ea1781cd9773a4f)
+
+Related: #2005024
+---
+ src/libsystemd/sd-device/device-private.h | 1 +
+ src/libsystemd/sd-device/sd-device.c      | 7 +++++++
+ 2 files changed, 8 insertions(+)
+
+diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h
+index fe268d7f2f..9bb5eff208 100644
+--- a/src/libsystemd/sd-device/device-private.h
++++ b/src/libsystemd/sd-device/device-private.h
+@@ -32,6 +32,7 @@ void device_set_db_persist(sd_device *device);
+ void device_set_devlink_priority(sd_device *device, int priority);
+ int device_ensure_usec_initialized(sd_device *device, sd_device *device_old);
+ int device_add_devlink(sd_device *device, const char *devlink);
++bool device_has_devlink(sd_device *device, const char *devlink);
+ int device_add_property(sd_device *device, const char *property, const char *value);
+ int device_add_tag(sd_device *device, const char *tag, bool both);
+ void device_remove_tag(sd_device *device, const char *tag);
+diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
+index 388128bf33..8a9e4a33a1 100644
+--- a/src/libsystemd/sd-device/sd-device.c
++++ b/src/libsystemd/sd-device/sd-device.c
+@@ -1193,6 +1193,13 @@ int device_add_devlink(sd_device *device, const char *devlink) {
+         return 0;
+ }
+ 
++bool device_has_devlink(sd_device *device, const char *devlink) {
++        assert(device);
++        assert(devlink);
++
++        return set_contains(device->devlinks, devlink);
++}
++
+ static int device_add_property_internal_from_string(sd_device *device, const char *str) {
+         _cleanup_free_ char *key = NULL;
+         char *value;
diff --git a/SOURCES/0024-udev-node-always-update-timestamp-of-stack-directory.patch b/SOURCES/0024-udev-node-always-update-timestamp-of-stack-directory.patch
deleted file mode 100644
index fb3c52e..0000000
--- a/SOURCES/0024-udev-node-always-update-timestamp-of-stack-directory.patch
+++ /dev/null
@@ -1,146 +0,0 @@
-From 16a6007cc8881ef19cc97de676d3b2b36b2def82 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Wed, 1 Sep 2021 12:57:40 +0900
-Subject: [PATCH] udev-node: always update timestamp of stack directory
-
-Please see the comments in the code.
-
-(cherry picked from commit 6df797f75fa08bb1a9e657001229bd47903e6174)
-
-Related: #1977994
----
- src/udev/udev-node.c | 90 ++++++++++++++++++++++++++++++++++++++++++--
- 1 file changed, 87 insertions(+), 3 deletions(-)
-
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 5d6aae0bd4..0de848da19 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -32,6 +32,7 @@
- #define CREATE_LINK_MAX_RETRIES        128
- #define LINK_UPDATE_MAX_RETRIES        128
- #define CREATE_STACK_LINK_MAX_RETRIES  128
-+#define UPDATE_TIMESTAMP_MAX_RETRIES   128
- #define UDEV_NODE_HASH_KEY SD_ID128_MAKE(b9,6a,f1,ce,40,31,44,1a,9e,19,ec,8b,ae,f3,e3,2f)
- 
- static int create_symlink(const char *target, const char *slink) {
-@@ -285,9 +286,60 @@ toolong:
-         return size - 1;
- }
- 
-+static int update_timestamp(sd_device *dev, const char *path, struct stat *prev) {
-+        assert(path);
-+        assert(prev);
-+
-+        /* Even if a symlink in the stack directory is created/removed, the mtime of the directory may
-+         * not be changed. Why? Let's consider the following situation. For simplicity, let's assume
-+         * there exist three udev workers (A, B, and C) and all of them calls link_update() for the
-+         * same devlink simultaneously.
-+         *
-+         * 1. B creates/removes a symlink in the stack directory.
-+         * 2. A calls the first stat() in the loop of link_update().
-+         * 3. A calls link_find_prioritized().
-+         * 4. C creates/removes another symlink in the stack directory, so the result of the step 3 is outdated.
-+         * 5. B and C finish link_update().
-+         * 6. A creates/removes devlink according to the outdated result in the step 3.
-+         * 7. A calls the second stat() in the loop of link_update().
-+         *
-+         * If these 7 steps are processed in this order within a short time period that kernel's timer
-+         * does not increase, then even if the contents in the stack directory is changed, the results
-+         * of two stat() called by A shows the same timestamp, and A cannot detect the change.
-+         *
-+         * By calling this function after creating/removing symlinks in the stack directory, the
-+         * timestamp of the stack directory is always increased at least in the above step 5, so A can
-+         * detect the update. */
-+
-+        if ((prev->st_mode & S_IFMT) == 0)
-+                return 0; /* Does not exist, or previous stat() failed. */
-+
-+        for (unsigned i = 0; i < UPDATE_TIMESTAMP_MAX_RETRIES; i++) {
-+                struct stat st;
-+
-+                if (stat(path, &st) < 0)
-+                        return -errno;
-+
-+                if (!stat_inode_unmodified(prev, &st))
-+                        return 0;
-+
-+                log_device_debug(dev,
-+                                 "%s is modified, but its timestamp is not changed, "
-+                                 "updating timestamp after 10ms.",
-+                                 path);
-+
-+                (void) usleep(10 * USEC_PER_MSEC);
-+                if (utimensat(AT_FDCWD, path, NULL, 0) < 0)
-+                        return -errno;
-+        }
-+
-+        return -ELOOP;
-+}
-+
- static int update_stack_directory(sd_device *dev, const char *dirname, bool add) {
-         _cleanup_free_ char *filename = NULL, *data = NULL, *buf = NULL;
-         const char *devname, *id;
-+        struct stat st = {};
-         int priority, r;
- 
-         assert(dev);
-@@ -302,10 +354,31 @@ static int update_stack_directory(sd_device *dev, const char *dirname, bool add)
-                 return log_oom_debug();
- 
-         if (!add) {
--                if (unlink(filename) < 0 && errno != ENOENT)
--                        log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
-+                bool unlink_failed = false;
-+
-+                if (stat(dirname, &st) < 0) {
-+                        if (errno == ENOENT)
-+                                return 0; /* The stack directory is already removed. That's OK. */
-+                        log_device_debug_errno(dev, errno, "Failed to stat %s, ignoring: %m", dirname);
-+                }
-+
-+                if (unlink(filename) < 0) {
-+                        unlink_failed = true;
-+                        if (errno != ENOENT)
-+                                log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
-+                }
-+
-+                if (rmdir(dirname) >= 0 || errno == ENOENT)
-+                        return 0;
-+
-+                if (unlink_failed)
-+                        return 0; /* If we failed to remove the symlink, there is almost nothing we can do. */
-+
-+                /* The symlink was removed. Check if the timestamp of directory is changed. */
-+                r = update_timestamp(dev, dirname, &st);
-+                if (r < 0 && r != -ENOENT)
-+                        return log_device_debug_errno(dev, r, "Failed to update timestamp of %s: %m", dirname);
- 
--                (void) rmdir(dirname);
-                 return 0;
-         }
- 
-@@ -335,12 +408,23 @@ static int update_stack_directory(sd_device *dev, const char *dirname, bool add)
-                 if (r < 0)
-                         return log_device_debug_errno(dev, r, "Failed to create directory %s: %m", dirname);
- 
-+                if (stat(dirname, &st) < 0) {
-+                        if (errno == ENOENT)
-+                                continue;
-+                        return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
-+                }
-+
-                 if (symlink(data, filename) < 0) {
-                         if (errno == ENOENT)
-                                 continue;
-                         return log_device_debug_errno(dev, errno, "Failed to create symbolic link %s: %m", filename);
-                 }
- 
-+                /* The symlink was created. Check if the timestamp of directory is changed. */
-+                r = update_timestamp(dev, dirname, &st);
-+                if (r < 0)
-+                        return log_device_debug_errno(dev, r, "Failed to update timestamp of %s: %m", dirname);
-+
-                 return 0;
-         }
- 
diff --git a/SOURCES/0025-udev-node-assume-no-new-claim-to-a-symlink-if-run-ud.patch b/SOURCES/0025-udev-node-assume-no-new-claim-to-a-symlink-if-run-ud.patch
deleted file mode 100644
index d4bcdc1..0000000
--- a/SOURCES/0025-udev-node-assume-no-new-claim-to-a-symlink-if-run-ud.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 18936c8ee21fabb2036b1849a4bb7f5b64bee897 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Thu, 2 Sep 2021 06:58:59 +0900
-Subject: [PATCH] udev-node: assume no new claim to a symlink if
- /run/udev/links is not updated
-
-During creating a symlink to a device node, if another device node which
-requests the same symlink is added/removed, `stat_inode_unmodified()`
-should always detects that. We do not need to continue the loop
-unconditionally.
-
-(cherry picked from commit 8f27311eb2aec2411d1fb7d62e6c9d75d21ae8df)
-
-Related: #1977994
----
- src/udev/udev-node.c | 5 -----
- 1 file changed, 5 deletions(-)
-
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 0de848da19..1a34ea8128 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -491,11 +491,6 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
-                 r = node_symlink(dev, target, slink);
-                 if (r < 0)
-                         return r;
--                if (r == 1)
--                        /* We have replaced already existing symlink, possibly there is some other device trying
--                         * to claim the same symlink. Let's do one more iteration to give us a chance to fix
--                         * the error if other device actually claims the symlink with higher priority. */
--                        continue;
- 
-                 /* Skip the second stat() if the first failed, stat_inode_unmodified() would return false regardless. */
-                 if ((st1.st_mode & S_IFMT) != 0) {
diff --git a/SOURCES/0025-udev-node-split-out-permission-handling-from-udev_no.patch b/SOURCES/0025-udev-node-split-out-permission-handling-from-udev_no.patch
new file mode 100644
index 0000000..cddb90d
--- /dev/null
+++ b/SOURCES/0025-udev-node-split-out-permission-handling-from-udev_no.patch
@@ -0,0 +1,305 @@
+From a4fba2d79634d660ed2014e18cb85eea090b6413 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 1 Sep 2021 09:24:15 +0900
+Subject: [PATCH] udev-node: split out permission handling from udev_node_add()
+
+And then merge udev_node_add() and udev_node_update_old_links().
+
+(cherry picked from commit 2f48561e0db3cd63f65e9311b4d69282b4ac605d)
+
+Related: #2005024
+---
+ src/udev/udev-event.c |   9 +-
+ src/udev/udev-node.c  | 204 +++++++++++++++++++-----------------------
+ src/udev/udev-node.h  |  12 ++-
+ 3 files changed, 106 insertions(+), 119 deletions(-)
+
+diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
+index b28089be71..8b9f8aecfe 100644
+--- a/src/udev/udev-event.c
++++ b/src/udev/udev-event.c
+@@ -895,9 +895,6 @@ static int update_devnode(UdevEvent *event) {
+         if (r < 0)
+                 return log_device_error_errno(dev, r, "Failed to get devnum: %m");
+ 
+-        /* remove/update possible left-over symlinks from old database entry */
+-        (void) udev_node_update_old_links(dev, event->dev_db_clone);
+-
+         if (!uid_is_valid(event->uid)) {
+                 r = device_get_devnode_uid(dev, &event->uid);
+                 if (r < 0 && r != -ENOENT)
+@@ -921,7 +918,11 @@ static int update_devnode(UdevEvent *event) {
+ 
+         bool apply_mac = device_for_action(dev, SD_DEVICE_ADD);
+ 
+-        return udev_node_add(dev, apply_mac, event->mode, event->uid, event->gid, event->seclabel_list);
++        r = udev_node_apply_permissions(dev, apply_mac, event->mode, event->uid, event->gid, event->seclabel_list);
++        if (r < 0)
++                return log_device_error_errno(dev, r, "Failed to apply devnode permissions: %m");
++
++        return udev_node_update(dev, event->dev_db_clone);
+ }
+ 
+ static int event_execute_rules_on_remove(
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 9e52906571..7cc9ee3670 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -356,45 +356,117 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+         return i < LINK_UPDATE_MAX_RETRIES ? 0 : -ELOOP;
+ }
+ 
+-int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) {
+-        const char *name;
++static int device_get_devpath_by_devnum(sd_device *dev, char **ret) {
++        const char *subsystem;
++        dev_t devnum;
++        int r;
++
++        assert(dev);
++        assert(ret);
++
++        r = sd_device_get_subsystem(dev, &subsystem);
++        if (r < 0)
++                return r;
++
++        r = sd_device_get_devnum(dev, &devnum);
++        if (r < 0)
++                return r;
++
++        return device_path_make_major_minor(streq(subsystem, "block") ? S_IFBLK : S_IFCHR, devnum, ret);
++}
++
++int udev_node_update(sd_device *dev, sd_device *dev_old) {
++        _cleanup_free_ char *filename = NULL;
++        const char *devnode, *devlink;
+         int r;
+ 
+         assert(dev);
+         assert(dev_old);
+ 
+-        /* update possible left-over symlinks */
+-        FOREACH_DEVICE_DEVLINK(dev_old, name) {
+-                const char *name_current;
+-                bool found = false;
++        r = sd_device_get_devname(dev, &devnode);
++        if (r < 0)
++                return log_device_debug_errno(dev, r, "Failed to get devnode: %m");
+ 
+-                /* check if old link name still belongs to this device */
+-                FOREACH_DEVICE_DEVLINK(dev, name_current)
+-                        if (streq(name, name_current)) {
+-                                found = true;
+-                                break;
+-                        }
++        if (DEBUG_LOGGING) {
++                const char *id = NULL;
+ 
+-                if (found)
++                (void) device_get_device_id(dev, &id);
++                log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strna(id));
++        }
++
++        /* update possible left-over symlinks */
++        FOREACH_DEVICE_DEVLINK(dev_old, devlink) {
++                /* check if old link name still belongs to this device */
++                if (device_has_devlink(dev, devlink))
+                         continue;
+ 
+                 log_device_debug(dev,
+-                                 "Updating old device symlink '%s', which is no longer belonging to this device.",
+-                                 name);
++                                 "Removing/updating old device symlink '%s', which is no longer belonging to this device.",
++                                 devlink);
+ 
+-                r = link_update(dev, name, false);
++                r = link_update(dev, devlink, /* add = */ false);
+                 if (r < 0)
+                         log_device_warning_errno(dev, r,
+-                                                 "Failed to update device symlink '%s', ignoring: %m",
+-                                                 name);
++                                                 "Failed to remove/update device symlink '%s', ignoring: %m",
++                                                 devlink);
+         }
+ 
++        /* create/update symlinks, add symlinks to name index */
++        FOREACH_DEVICE_DEVLINK(dev, devlink) {
++                r = link_update(dev, devlink, /* add = */ true);
++                if (r < 0)
++                        log_device_warning_errno(dev, r,
++                                                 "Failed to create/update device symlink '%s', ignoring: %m",
++                                                 devlink);
++        }
++
++        r = device_get_devpath_by_devnum(dev, &filename);
++        if (r < 0)
++                return log_device_debug_errno(dev, r, "Failed to get device path: %m");
++
++        /* always add /dev/{block,char}/$major:$minor */
++        r = node_symlink(dev, devnode, filename);
++        if (r < 0)
++                return log_device_warning_errno(dev, r, "Failed to create device symlink '%s': %m", filename);
++
++        return 0;
++}
++
++int udev_node_remove(sd_device *dev) {
++        _cleanup_free_ char *filename = NULL;
++        const char *devlink;
++        int r;
++
++        assert(dev);
++
++        /* remove/update symlinks, remove symlinks from name index */
++        FOREACH_DEVICE_DEVLINK(dev, devlink) {
++                r = link_update(dev, devlink, /* add = */ false);
++                if (r < 0)
++                        log_device_warning_errno(dev, r,
++                                                 "Failed to remove/update device symlink '%s', ignoring: %m",
++                                                 devlink);
++        }
++
++        r = device_get_devpath_by_devnum(dev, &filename);
++        if (r < 0)
++                return log_device_debug_errno(dev, r, "Failed to get device path: %m");
++
++        /* remove /dev/{block,char}/$major:$minor */
++        if (unlink(filename) < 0 && errno != ENOENT)
++                return log_device_debug_errno(dev, errno, "Failed to remove '%s': %m", filename);
++
+         return 0;
+ }
+ 
+-static int node_permissions_apply(sd_device *dev, bool apply_mac,
+-                                  mode_t mode, uid_t uid, gid_t gid,
+-                                  OrderedHashmap *seclabel_list) {
++int udev_node_apply_permissions(
++                sd_device *dev,
++                bool apply_mac,
++                mode_t mode,
++                uid_t uid,
++                gid_t gid,
++                OrderedHashmap *seclabel_list) {
++
+         const char *devnode, *subsystem, *id = NULL;
+         bool apply_mode, apply_uid, apply_gid;
+         _cleanup_close_ int node_fd = -1;
+@@ -511,95 +583,5 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
+         if (r < 0)
+                 log_device_debug_errno(dev, r, "Failed to adjust timestamp of node %s: %m", devnode);
+ 
+-        return r;
+-}
+-
+-static int xsprintf_dev_num_path_from_sd_device(sd_device *dev, char **ret) {
+-        const char *subsystem;
+-        dev_t devnum;
+-        int r;
+-
+-        assert(ret);
+-
+-        r = sd_device_get_subsystem(dev, &subsystem);
+-        if (r < 0)
+-                return r;
+-
+-        r = sd_device_get_devnum(dev, &devnum);
+-        if (r < 0)
+-                return r;
+-
+-        return device_path_make_major_minor(streq(subsystem, "block") ? S_IFBLK : S_IFCHR, devnum, ret);
+-}
+-
+-int udev_node_add(sd_device *dev, bool apply,
+-                  mode_t mode, uid_t uid, gid_t gid,
+-                  OrderedHashmap *seclabel_list) {
+-        const char *devnode, *devlink;
+-        _cleanup_free_ char *filename = NULL;
+-        int r;
+-
+-        assert(dev);
+-
+-        r = sd_device_get_devname(dev, &devnode);
+-        if (r < 0)
+-                return log_device_debug_errno(dev, r, "Failed to get devnode: %m");
+-
+-        if (DEBUG_LOGGING) {
+-                const char *id = NULL;
+-
+-                (void) device_get_device_id(dev, &id);
+-                log_device_debug(dev, "Handling device node '%s', devnum=%s", devnode, strna(id));
+-        }
+-
+-        r = node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list);
+-        if (r < 0)
+-                return r;
+-
+-        /* create/update symlinks, add symlinks to name index */
+-        FOREACH_DEVICE_DEVLINK(dev, devlink) {
+-                r = link_update(dev, devlink, true);
+-                if (r < 0)
+-                        log_device_warning_errno(dev, r,
+-                                                 "Failed to update device symlink '%s', ignoring: %m",
+-                                                 devlink);
+-        }
+-
+-        r = xsprintf_dev_num_path_from_sd_device(dev, &filename);
+-        if (r < 0)
+-                return log_device_debug_errno(dev, r, "Failed to get device path: %m");
+-
+-        /* always add /dev/{block,char}/$major:$minor */
+-        r = node_symlink(dev, devnode, filename);
+-        if (r < 0)
+-                return log_device_warning_errno(dev, r, "Failed to create device symlink '%s': %m", filename);
+-
+-        return 0;
+-}
+-
+-int udev_node_remove(sd_device *dev) {
+-        _cleanup_free_ char *filename = NULL;
+-        const char *devlink;
+-        int r;
+-
+-        assert(dev);
+-
+-        /* remove/update symlinks, remove symlinks from name index */
+-        FOREACH_DEVICE_DEVLINK(dev, devlink) {
+-                r = link_update(dev, devlink, false);
+-                if (r < 0)
+-                        log_device_warning_errno(dev, r,
+-                                                 "Failed to update device symlink '%s', ignoring: %m",
+-                                                 devlink);
+-        }
+-
+-        r = xsprintf_dev_num_path_from_sd_device(dev, &filename);
+-        if (r < 0)
+-                return log_device_debug_errno(dev, r, "Failed to get device path: %m");
+-
+-        /* remove /dev/{block,char}/$major:$minor */
+-        if (unlink(filename) < 0 && errno != ENOENT)
+-                return log_device_debug_errno(dev, errno, "Failed to remove '%s': %m", filename);
+-
+         return 0;
+ }
+diff --git a/src/udev/udev-node.h b/src/udev/udev-node.h
+index 2349f9c471..a34af77146 100644
+--- a/src/udev/udev-node.h
++++ b/src/udev/udev-node.h
+@@ -8,10 +8,14 @@
+ 
+ #include "hashmap.h"
+ 
+-int udev_node_add(sd_device *dev, bool apply,
+-                  mode_t mode, uid_t uid, gid_t gid,
+-                  OrderedHashmap *seclabel_list);
++int udev_node_apply_permissions(
++                sd_device *dev,
++                bool apply_mac,
++                mode_t mode,
++                uid_t uid,
++                gid_t gid,
++                OrderedHashmap *seclabel_list);
+ int udev_node_remove(sd_device *dev);
+-int udev_node_update_old_links(sd_device *dev, sd_device *dev_old);
++int udev_node_update(sd_device *dev, sd_device *dev_old);
+ 
+ size_t udev_node_escape_path(const char *src, char *dest, size_t size);
diff --git a/SOURCES/0026-udev-node-always-atomically-create-symlink-to-device.patch b/SOURCES/0026-udev-node-always-atomically-create-symlink-to-device.patch
deleted file mode 100644
index b86e5e4..0000000
--- a/SOURCES/0026-udev-node-always-atomically-create-symlink-to-device.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-From 323f687e53737ccf7687482c31690374da90d8e7 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Wed, 1 Sep 2021 02:20:33 +0900
-Subject: [PATCH] udev-node: always atomically create symlink to device node
-
-By the previous commit, it is not necessary to distinguish if the devlink
-already exists. Also, I cannot find any significant advantages of the
-previous complecated logic, that is, first try to create directly, and then
-fallback to atomically creation. Moreover, such logic increases the chance
-of conflicts between multiple udev workers.
-
-This makes devlinks always created atomically. Hopefully, this reduces the
-conflicts between the workers.
-
-(cherry picked from commit 242d39ebc1391f4734f6e63ff13764de92bc5f70)
-
-Related: #1977994
----
- src/udev/udev-node.c | 42 +++++++++---------------------------------
- 1 file changed, 9 insertions(+), 33 deletions(-)
-
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 1a34ea8128..46c04fe00b 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -71,6 +71,13 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) {
-         assert(node);
-         assert(slink);
- 
-+        if (lstat(slink, &stats) >= 0) {
-+                if (!S_ISLNK(stats.st_mode))
-+                        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
-+                                                      "Conflicting inode '%s' found, link to '%s' will not be created.", slink, node);
-+        } else if (errno != ENOENT)
-+                return log_device_debug_errno(dev, errno, "Failed to lstat() '%s': %m", slink);
-+
-         r = path_extract_directory(slink, &slink_dirname);
-         if (r < 0)
-                 return log_device_debug_errno(dev, r, "Failed to get parent directory of '%s': %m", slink);
-@@ -80,41 +87,11 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) {
-         if (r < 0)
-                 return log_device_debug_errno(dev, r, "Failed to get relative path from '%s' to '%s': %m", slink, node);
- 
--        if (lstat(slink, &stats) >= 0) {
--                _cleanup_free_ char *buf = NULL;
--
--                if (!S_ISLNK(stats.st_mode))
--                        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
--                                                      "Conflicting inode '%s' found, link to '%s' will not be created.", slink, node);
--
--                if (readlink_malloc(slink, &buf) >= 0 &&
--                    path_equal(target, buf)) {
--                        /* preserve link with correct target, do not replace node of other device */
--                        log_device_debug(dev, "Preserve already existing symlink '%s' to '%s'", slink, target);
--
--                        (void) label_fix(slink, LABEL_IGNORE_ENOENT);
--                        (void) utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
--
--                        return 0;
--                }
--        } else if (errno == ENOENT) {
--                log_device_debug(dev, "Creating symlink '%s' to '%s'", slink, target);
--
--                r = create_symlink(target, slink);
--                if (r >= 0)
--                        return 0;
--
--                log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s', trying to replace '%s': %m", slink, target, slink);
--        } else
--                return log_device_debug_errno(dev, errno, "Failed to lstat() '%s': %m", slink);
--
--        log_device_debug(dev, "Atomically replace '%s'", slink);
--
-         r = device_get_device_id(dev, &id);
-         if (r < 0)
-                 return log_device_debug_errno(dev, r, "Failed to get device id: %m");
--        slink_tmp = strjoina(slink, ".tmp-", id);
- 
-+        slink_tmp = strjoina(slink, ".tmp-", id);
-         (void) unlink(slink_tmp);
- 
-         r = create_symlink(target, slink_tmp);
-@@ -127,8 +104,7 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) {
-                 return r;
-         }
- 
--        /* Tell caller that we replaced already existing symlink. */
--        return 1;
-+        return 0;
- }
- 
- static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, char **ret) {
diff --git a/SOURCES/0026-udev-node-stack-directory-must-exist-when-adding-dev.patch b/SOURCES/0026-udev-node-stack-directory-must-exist-when-adding-dev.patch
new file mode 100644
index 0000000..fa456bf
--- /dev/null
+++ b/SOURCES/0026-udev-node-stack-directory-must-exist-when-adding-dev.patch
@@ -0,0 +1,36 @@
+From 506dc32b2428936d67e9cf1a034d6b63dbc1cbb0 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 1 Sep 2021 04:14:42 +0900
+Subject: [PATCH] udev-node: stack directory must exist when adding device node
+ symlink
+
+(cherry picked from commit 46070dbf26435ba0def099121f46a6253f3f19b6)
+
+Related: #2005024
+---
+ src/udev/udev-node.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 7cc9ee3670..4496a2bd9b 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -161,12 +161,13 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir,
+ 
+         dir = opendir(stackdir);
+         if (!dir) {
+-                if (errno == ENOENT) {
+-                        *ret = TAKE_PTR(target);
+-                        return !!*ret;
+-                }
++                if (add) /* The stack directory must exist. */
++                        return -errno;
++                if (errno != ENOENT)
++                        return -errno;
+ 
+-                return -errno;
++                *ret = NULL;
++                return 0;
+         }
+ 
+         r = device_get_device_id(dev, &id);
diff --git a/SOURCES/0027-udev-node-check-stack-directory-change-even-if-devli.patch b/SOURCES/0027-udev-node-check-stack-directory-change-even-if-devli.patch
deleted file mode 100644
index f5cec3b..0000000
--- a/SOURCES/0027-udev-node-check-stack-directory-change-even-if-devli.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 6ecd6fdcc27f374debcce47366c2862967f99463 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Wed, 1 Sep 2021 09:44:26 +0900
-Subject: [PATCH] udev-node: check stack directory change even if devlink is
- removed
-
-Otherwise, when multiple device additions and removals occur
-simultaneously, symlink to unexisting devnode may be created.
-
-Hopefully fixes #19946.
-
-(cherry picked from commit 1cd4e325693007b3628f1a27297f0ab7114b24b8)
-
-Related: #1977994
----
- src/udev/udev-node.c | 15 ++++++---------
- 1 file changed, 6 insertions(+), 9 deletions(-)
-
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 46c04fe00b..28e6e8df94 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -468,15 +468,12 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
-                 if (r < 0)
-                         return r;
- 
--                /* Skip the second stat() if the first failed, stat_inode_unmodified() would return false regardless. */
--                if ((st1.st_mode & S_IFMT) != 0) {
--                        r = stat(dirname, &st2);
--                        if (r < 0 && errno != ENOENT)
--                                return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
--
--                        if (stat_inode_unmodified(&st1, &st2))
--                                break;
--                }
-+                if (stat(dirname, &st2) < 0 && errno != ENOENT)
-+                        return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
-+
-+                if (((st1.st_mode & S_IFMT) == 0 && (st2.st_mode & S_IFMT) == 0) ||
-+                    stat_inode_unmodified(&st1, &st2))
-+                        return 0;
-         }
- 
-         return i < LINK_UPDATE_MAX_RETRIES ? 0 : -ELOOP;
diff --git a/SOURCES/0027-udev-node-save-information-about-device-node-and-pri.patch b/SOURCES/0027-udev-node-save-information-about-device-node-and-pri.patch
new file mode 100644
index 0000000..efd691c
--- /dev/null
+++ b/SOURCES/0027-udev-node-save-information-about-device-node-and-pri.patch
@@ -0,0 +1,250 @@
+From 065209fc7a53d6f296f7fffd261f0a92fddc4485 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 1 Sep 2021 04:16:21 +0900
+Subject: [PATCH] udev-node: save information about device node and priority in
+ symlink
+
+Previously, we only store device IDs in /run/udev/links, and when
+creating/removing device node symlink, we create sd_device object
+corresponds to the IDs and read device node and priority from the
+object. That requires parsing uevent and udev database files.
+
+This makes link_find_prioritized() get the most prioritzed device node
+without parsing the files.
+
+(cherry picked from commit 377a83f0d80376456d9be203796f66f543a8b943)
+
+Related: #2005024
+---
+ src/udev/udev-node.c | 172 ++++++++++++++++++++++++++++++-------------
+ 1 file changed, 121 insertions(+), 51 deletions(-)
+
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 4496a2bd9b..5d6aae0bd4 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -18,6 +18,7 @@
+ #include "fs-util.h"
+ #include "hexdecoct.h"
+ #include "mkdir.h"
++#include "parse-util.h"
+ #include "path-util.h"
+ #include "selinux-util.h"
+ #include "smack-util.h"
+@@ -28,9 +29,9 @@
+ #include "udev-node.h"
+ #include "user-util.h"
+ 
+-#define CREATE_LINK_MAX_RETRIES 128
+-#define LINK_UPDATE_MAX_RETRIES 128
+-#define TOUCH_FILE_MAX_RETRIES  128
++#define CREATE_LINK_MAX_RETRIES        128
++#define LINK_UPDATE_MAX_RETRIES        128
++#define CREATE_STACK_LINK_MAX_RETRIES  128
+ #define UDEV_NODE_HASH_KEY SD_ID128_MAKE(b9,6a,f1,ce,40,31,44,1a,9e,19,ec,8b,ae,f3,e3,2f)
+ 
+ static int create_symlink(const char *target, const char *slink) {
+@@ -175,39 +176,67 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir,
+                 return r;
+ 
+         FOREACH_DIRENT_ALL(dent, dir, break) {
+-                _cleanup_(sd_device_unrefp) sd_device *dev_db = NULL;
+-                const char *devnode;
+-                int db_prio = 0;
++                _cleanup_free_ char *path = NULL, *buf = NULL;
++                int tmp_prio;
+ 
+-                if (dent->d_name[0] == '\0')
+-                        break;
+                 if (dent->d_name[0] == '.')
+                         continue;
+ 
+-                log_device_debug(dev, "Found '%s' claiming '%s'", dent->d_name, stackdir);
+-
+-                /* did we find ourself? */
++                /* skip ourself */
+                 if (streq(dent->d_name, id))
+                         continue;
+ 
+-                if (sd_device_new_from_device_id(&dev_db, dent->d_name) < 0)
+-                        continue;
++                path = path_join(stackdir, dent->d_name);
++                if (!path)
++                        return -ENOMEM;
+ 
+-                if (sd_device_get_devname(dev_db, &devnode) < 0)
+-                        continue;
++                if (readlink_malloc(path, &buf) >= 0) {
++                        char *devnode;
+ 
+-                if (device_get_devlink_priority(dev_db, &db_prio) < 0)
+-                        continue;
++                        /* New format. The devnode and priority can be obtained from symlink. */
+ 
+-                if (target && db_prio <= priority)
+-                        continue;
++                        devnode = strchr(buf, ':');
++                        if (!devnode || devnode == buf)
++                                continue;
+ 
+-                log_device_debug(dev_db, "Device claims priority %i for '%s'", db_prio, stackdir);
++                        *(devnode++) = '\0';
++                        if (!path_startswith(devnode, "/dev"))
++                                continue;
+ 
+-                r = free_and_strdup(&target, devnode);
+-                if (r < 0)
+-                        return r;
+-                priority = db_prio;
++                        if (safe_atoi(buf, &tmp_prio) < 0)
++                                continue;
++
++                        if (target && tmp_prio <= priority)
++                                continue;
++
++                        r = free_and_strdup(&target, devnode);
++                        if (r < 0)
++                                return r;
++                } else {
++                        _cleanup_(sd_device_unrefp) sd_device *tmp_dev = NULL;
++                        const char *devnode;
++
++                        /* Old format. The devnode and priority must be obtained from uevent and
++                         * udev database files. */
++
++                        if (sd_device_new_from_device_id(&tmp_dev, dent->d_name) < 0)
++                                continue;
++
++                        if (device_get_devlink_priority(tmp_dev, &tmp_prio) < 0)
++                                continue;
++
++                        if (target && tmp_prio <= priority)
++                                continue;
++
++                        if (sd_device_get_devname(tmp_dev, &devnode) < 0)
++                                continue;
++
++                        r = free_and_strdup(&target, devnode);
++                        if (r < 0)
++                                return r;
++                }
++
++                priority = tmp_prio;
+         }
+ 
+         *ret = TAKE_PTR(target);
+@@ -256,10 +285,72 @@ toolong:
+         return size - 1;
+ }
+ 
++static int update_stack_directory(sd_device *dev, const char *dirname, bool add) {
++        _cleanup_free_ char *filename = NULL, *data = NULL, *buf = NULL;
++        const char *devname, *id;
++        int priority, r;
++
++        assert(dev);
++        assert(dirname);
++
++        r = device_get_device_id(dev, &id);
++        if (r < 0)
++                return log_device_debug_errno(dev, r, "Failed to get device id: %m");
++
++        filename = path_join(dirname, id);
++        if (!filename)
++                return log_oom_debug();
++
++        if (!add) {
++                if (unlink(filename) < 0 && errno != ENOENT)
++                        log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
++
++                (void) rmdir(dirname);
++                return 0;
++        }
++
++        r = sd_device_get_devname(dev, &devname);
++        if (r < 0)
++                return log_device_debug_errno(dev, r, "Failed to get device node: %m");
++
++        r = device_get_devlink_priority(dev, &priority);
++        if (r < 0)
++                return log_device_debug_errno(dev, r, "Failed to get priority of device node symlink: %m");
++
++        if (asprintf(&data, "%i:%s", priority, devname) < 0)
++                return log_oom_debug();
++
++        if (readlink_malloc(filename, &buf) >= 0 && streq(buf, data))
++                return 0;
++
++        if (unlink(filename) < 0 && errno != ENOENT)
++                log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
++
++        for (unsigned j = 0; j < CREATE_STACK_LINK_MAX_RETRIES; j++) {
++                /* This may fail with -ENOENT when the parent directory is removed during
++                 * creating the file by another udevd worker. */
++                r = mkdir_p(dirname, 0755);
++                if (r == -ENOENT)
++                        continue;
++                if (r < 0)
++                        return log_device_debug_errno(dev, r, "Failed to create directory %s: %m", dirname);
++
++                if (symlink(data, filename) < 0) {
++                        if (errno == ENOENT)
++                                continue;
++                        return log_device_debug_errno(dev, errno, "Failed to create symbolic link %s: %m", filename);
++                }
++
++                return 0;
++        }
++
++        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(ELOOP), "Failed to create symbolic link %s: %m", filename);
++}
++
+ /* manage "stack of names" with possibly specified device priorities */
+ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+-        _cleanup_free_ char *slink = NULL, *filename = NULL, *dirname = NULL;
+-        const char *slink_name, *id;
++        _cleanup_free_ char *slink = NULL, *dirname = NULL;
++        const char *slink_name;
+         char name_enc[NAME_MAX+1];
+         int i, r, retries;
+ 
+@@ -279,35 +370,14 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+                 return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL),
+                                               "Invalid symbolic link of device node: %s", slink);
+ 
+-        r = device_get_device_id(dev, &id);
+-        if (r < 0)
+-                return log_device_debug_errno(dev, r, "Failed to get device id: %m");
+-
+         (void) udev_node_escape_path(slink_name, name_enc, sizeof(name_enc));
+-        dirname = path_join("/run/udev/links/", name_enc);
++        dirname = path_join("/run/udev/links", name_enc);
+         if (!dirname)
+                 return log_oom_debug();
+ 
+-        filename = path_join(dirname, id);
+-        if (!filename)
+-                return log_oom_debug();
+-
+-        if (!add) {
+-                if (unlink(filename) < 0 && errno != ENOENT)
+-                        log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
+-
+-                (void) rmdir(dirname);
+-        } else {
+-                for (unsigned j = 0; j < TOUCH_FILE_MAX_RETRIES; j++) {
+-                        /* This may fail with -ENOENT when the parent directory is removed during
+-                         * creating the file by another udevd worker. */
+-                        r = touch_file(filename, /* parents= */ true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
+-                        if (r != -ENOENT)
+-                                break;
+-                }
+-                if (r < 0)
+-                        return log_device_debug_errno(dev, r, "Failed to create %s: %m", filename);
+-        }
++        r = update_stack_directory(dev, dirname, add);
++        if (r < 0)
++                return r;
+ 
+         /* If the database entry is not written yet we will just do one iteration and possibly wrong symlink
+          * will be fixed in the second invocation. */
diff --git a/SOURCES/0028-udev-node-always-update-timestamp-of-stack-directory.patch b/SOURCES/0028-udev-node-always-update-timestamp-of-stack-directory.patch
new file mode 100644
index 0000000..58110ee
--- /dev/null
+++ b/SOURCES/0028-udev-node-always-update-timestamp-of-stack-directory.patch
@@ -0,0 +1,146 @@
+From a13bd62f6cb8332864ed3566fdf51eedfe240043 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 1 Sep 2021 12:57:40 +0900
+Subject: [PATCH] udev-node: always update timestamp of stack directory
+
+Please see the comments in the code.
+
+(cherry picked from commit 6df797f75fa08bb1a9e657001229bd47903e6174)
+
+Related: #2005024
+---
+ src/udev/udev-node.c | 90 ++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 87 insertions(+), 3 deletions(-)
+
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 5d6aae0bd4..0de848da19 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -32,6 +32,7 @@
+ #define CREATE_LINK_MAX_RETRIES        128
+ #define LINK_UPDATE_MAX_RETRIES        128
+ #define CREATE_STACK_LINK_MAX_RETRIES  128
++#define UPDATE_TIMESTAMP_MAX_RETRIES   128
+ #define UDEV_NODE_HASH_KEY SD_ID128_MAKE(b9,6a,f1,ce,40,31,44,1a,9e,19,ec,8b,ae,f3,e3,2f)
+ 
+ static int create_symlink(const char *target, const char *slink) {
+@@ -285,9 +286,60 @@ toolong:
+         return size - 1;
+ }
+ 
++static int update_timestamp(sd_device *dev, const char *path, struct stat *prev) {
++        assert(path);
++        assert(prev);
++
++        /* Even if a symlink in the stack directory is created/removed, the mtime of the directory may
++         * not be changed. Why? Let's consider the following situation. For simplicity, let's assume
++         * there exist three udev workers (A, B, and C) and all of them calls link_update() for the
++         * same devlink simultaneously.
++         *
++         * 1. B creates/removes a symlink in the stack directory.
++         * 2. A calls the first stat() in the loop of link_update().
++         * 3. A calls link_find_prioritized().
++         * 4. C creates/removes another symlink in the stack directory, so the result of the step 3 is outdated.
++         * 5. B and C finish link_update().
++         * 6. A creates/removes devlink according to the outdated result in the step 3.
++         * 7. A calls the second stat() in the loop of link_update().
++         *
++         * If these 7 steps are processed in this order within a short time period that kernel's timer
++         * does not increase, then even if the contents in the stack directory is changed, the results
++         * of two stat() called by A shows the same timestamp, and A cannot detect the change.
++         *
++         * By calling this function after creating/removing symlinks in the stack directory, the
++         * timestamp of the stack directory is always increased at least in the above step 5, so A can
++         * detect the update. */
++
++        if ((prev->st_mode & S_IFMT) == 0)
++                return 0; /* Does not exist, or previous stat() failed. */
++
++        for (unsigned i = 0; i < UPDATE_TIMESTAMP_MAX_RETRIES; i++) {
++                struct stat st;
++
++                if (stat(path, &st) < 0)
++                        return -errno;
++
++                if (!stat_inode_unmodified(prev, &st))
++                        return 0;
++
++                log_device_debug(dev,
++                                 "%s is modified, but its timestamp is not changed, "
++                                 "updating timestamp after 10ms.",
++                                 path);
++
++                (void) usleep(10 * USEC_PER_MSEC);
++                if (utimensat(AT_FDCWD, path, NULL, 0) < 0)
++                        return -errno;
++        }
++
++        return -ELOOP;
++}
++
+ static int update_stack_directory(sd_device *dev, const char *dirname, bool add) {
+         _cleanup_free_ char *filename = NULL, *data = NULL, *buf = NULL;
+         const char *devname, *id;
++        struct stat st = {};
+         int priority, r;
+ 
+         assert(dev);
+@@ -302,10 +354,31 @@ static int update_stack_directory(sd_device *dev, const char *dirname, bool add)
+                 return log_oom_debug();
+ 
+         if (!add) {
+-                if (unlink(filename) < 0 && errno != ENOENT)
+-                        log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
++                bool unlink_failed = false;
++
++                if (stat(dirname, &st) < 0) {
++                        if (errno == ENOENT)
++                                return 0; /* The stack directory is already removed. That's OK. */
++                        log_device_debug_errno(dev, errno, "Failed to stat %s, ignoring: %m", dirname);
++                }
++
++                if (unlink(filename) < 0) {
++                        unlink_failed = true;
++                        if (errno != ENOENT)
++                                log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
++                }
++
++                if (rmdir(dirname) >= 0 || errno == ENOENT)
++                        return 0;
++
++                if (unlink_failed)
++                        return 0; /* If we failed to remove the symlink, there is almost nothing we can do. */
++
++                /* The symlink was removed. Check if the timestamp of directory is changed. */
++                r = update_timestamp(dev, dirname, &st);
++                if (r < 0 && r != -ENOENT)
++                        return log_device_debug_errno(dev, r, "Failed to update timestamp of %s: %m", dirname);
+ 
+-                (void) rmdir(dirname);
+                 return 0;
+         }
+ 
+@@ -335,12 +408,23 @@ static int update_stack_directory(sd_device *dev, const char *dirname, bool add)
+                 if (r < 0)
+                         return log_device_debug_errno(dev, r, "Failed to create directory %s: %m", dirname);
+ 
++                if (stat(dirname, &st) < 0) {
++                        if (errno == ENOENT)
++                                continue;
++                        return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
++                }
++
+                 if (symlink(data, filename) < 0) {
+                         if (errno == ENOENT)
+                                 continue;
+                         return log_device_debug_errno(dev, errno, "Failed to create symbolic link %s: %m", filename);
+                 }
+ 
++                /* The symlink was created. Check if the timestamp of directory is changed. */
++                r = update_timestamp(dev, dirname, &st);
++                if (r < 0)
++                        return log_device_debug_errno(dev, r, "Failed to update timestamp of %s: %m", dirname);
++
+                 return 0;
+         }
+ 
diff --git a/SOURCES/0028-udev-node-shorten-code-a-bit-and-update-log-message.patch b/SOURCES/0028-udev-node-shorten-code-a-bit-and-update-log-message.patch
deleted file mode 100644
index b160155..0000000
--- a/SOURCES/0028-udev-node-shorten-code-a-bit-and-update-log-message.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From a075830244f699703a88a492413d931eaeb23a65 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Thu, 2 Sep 2021 08:23:35 +0900
-Subject: [PATCH] udev-node: shorten code a bit and update log message
-
-(cherry picked from commit 8424da2de88ceeed7be8544fb69221f0b0ea84ea)
-
-Related: #1977994
----
- src/udev/udev-node.c | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 28e6e8df94..2e7df899e4 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -447,13 +447,12 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
-                 _cleanup_free_ char *target = NULL;
-                 struct stat st1 = {}, st2 = {};
- 
--                r = stat(dirname, &st1);
--                if (r < 0 && errno != ENOENT)
-+                if (stat(dirname, &st1) < 0 && errno != ENOENT)
-                         return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
- 
-                 r = link_find_prioritized(dev, add, dirname, &target);
-                 if (r < 0)
--                        return log_device_debug_errno(dev, r, "Failed to determine highest priority for symlink '%s': %m", slink);
-+                        return log_device_debug_errno(dev, r, "Failed to determine device node with the highest priority for '%s': %m", slink);
-                 if (r == 0) {
-                         log_device_debug(dev, "No reference left for '%s', removing", slink);
- 
diff --git a/SOURCES/0029-udev-node-add-random-delay-on-conflict-in-updating-d.patch b/SOURCES/0029-udev-node-add-random-delay-on-conflict-in-updating-d.patch
deleted file mode 100644
index 3e78627..0000000
--- a/SOURCES/0029-udev-node-add-random-delay-on-conflict-in-updating-d.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From c484f91a87679fb26342408f20e7bdddf316f5a0 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Wed, 1 Sep 2021 04:34:48 +0900
-Subject: [PATCH] udev-node: add random delay on conflict in updating device
- node symlink
-
-To make multiple workers not update the same device node symlink
-simultaneously.
-
-(cherry picked from commit 0063fa23a1384dd4385d03b568dc629916b7e72a)
-
-Related: #1977994
----
- src/udev/udev-node.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 2e7df899e4..675e6ce313 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -20,12 +20,14 @@
- #include "mkdir.h"
- #include "parse-util.h"
- #include "path-util.h"
-+#include "random-util.h"
- #include "selinux-util.h"
- #include "smack-util.h"
- #include "stat-util.h"
- #include "stdio-util.h"
- #include "string-util.h"
- #include "strxcpyx.h"
-+#include "time-util.h"
- #include "udev-node.h"
- #include "user-util.h"
- 
-@@ -33,6 +35,8 @@
- #define LINK_UPDATE_MAX_RETRIES        128
- #define CREATE_STACK_LINK_MAX_RETRIES  128
- #define UPDATE_TIMESTAMP_MAX_RETRIES   128
-+#define MAX_RANDOM_DELAY (250 * USEC_PER_MSEC)
-+#define MIN_RANDOM_DELAY ( 50 * USEC_PER_MSEC)
- #define UDEV_NODE_HASH_KEY SD_ID128_MAKE(b9,6a,f1,ce,40,31,44,1a,9e,19,ec,8b,ae,f3,e3,2f)
- 
- static int create_symlink(const char *target, const char *slink) {
-@@ -447,6 +451,14 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
-                 _cleanup_free_ char *target = NULL;
-                 struct stat st1 = {}, st2 = {};
- 
-+                if (i > 0) {
-+                        usec_t delay = MIN_RANDOM_DELAY + random_u64_range(MAX_RANDOM_DELAY - MIN_RANDOM_DELAY);
-+
-+                        log_device_debug(dev, "Directory %s was updated, retrying to update devlink %s after %s.",
-+                                         dirname, slink, FORMAT_TIMESPAN(delay, USEC_PER_MSEC));
-+                        (void) usleep(delay);
-+                }
-+
-                 if (stat(dirname, &st1) < 0 && errno != ENOENT)
-                         return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
- 
diff --git a/SOURCES/0029-udev-node-assume-no-new-claim-to-a-symlink-if-run-ud.patch b/SOURCES/0029-udev-node-assume-no-new-claim-to-a-symlink-if-run-ud.patch
new file mode 100644
index 0000000..360bfa1
--- /dev/null
+++ b/SOURCES/0029-udev-node-assume-no-new-claim-to-a-symlink-if-run-ud.patch
@@ -0,0 +1,34 @@
+From cf49a46c165619a0480d361a0afebb89e998f61c Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Thu, 2 Sep 2021 06:58:59 +0900
+Subject: [PATCH] udev-node: assume no new claim to a symlink if
+ /run/udev/links is not updated
+
+During creating a symlink to a device node, if another device node which
+requests the same symlink is added/removed, `stat_inode_unmodified()`
+should always detects that. We do not need to continue the loop
+unconditionally.
+
+(cherry picked from commit 8f27311eb2aec2411d1fb7d62e6c9d75d21ae8df)
+
+Related: #2005024
+---
+ src/udev/udev-node.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 0de848da19..1a34ea8128 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -491,11 +491,6 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+                 r = node_symlink(dev, target, slink);
+                 if (r < 0)
+                         return r;
+-                if (r == 1)
+-                        /* We have replaced already existing symlink, possibly there is some other device trying
+-                         * to claim the same symlink. Let's do one more iteration to give us a chance to fix
+-                         * the error if other device actually claims the symlink with higher priority. */
+-                        continue;
+ 
+                 /* Skip the second stat() if the first failed, stat_inode_unmodified() would return false regardless. */
+                 if ((st1.st_mode & S_IFMT) != 0) {
diff --git a/SOURCES/0030-udev-node-always-atomically-create-symlink-to-device.patch b/SOURCES/0030-udev-node-always-atomically-create-symlink-to-device.patch
new file mode 100644
index 0000000..e6c01fd
--- /dev/null
+++ b/SOURCES/0030-udev-node-always-atomically-create-symlink-to-device.patch
@@ -0,0 +1,92 @@
+From 1561b9e2c9ea779ab611f52fd8b4eef616896e09 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 1 Sep 2021 02:20:33 +0900
+Subject: [PATCH] udev-node: always atomically create symlink to device node
+
+By the previous commit, it is not necessary to distinguish if the devlink
+already exists. Also, I cannot find any significant advantages of the
+previous complecated logic, that is, first try to create directly, and then
+fallback to atomically creation. Moreover, such logic increases the chance
+of conflicts between multiple udev workers.
+
+This makes devlinks always created atomically. Hopefully, this reduces the
+conflicts between the workers.
+
+(cherry picked from commit 242d39ebc1391f4734f6e63ff13764de92bc5f70)
+
+Related: #2005024
+---
+ src/udev/udev-node.c | 42 +++++++++---------------------------------
+ 1 file changed, 9 insertions(+), 33 deletions(-)
+
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 1a34ea8128..46c04fe00b 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -71,6 +71,13 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) {
+         assert(node);
+         assert(slink);
+ 
++        if (lstat(slink, &stats) >= 0) {
++                if (!S_ISLNK(stats.st_mode))
++                        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
++                                                      "Conflicting inode '%s' found, link to '%s' will not be created.", slink, node);
++        } else if (errno != ENOENT)
++                return log_device_debug_errno(dev, errno, "Failed to lstat() '%s': %m", slink);
++
+         r = path_extract_directory(slink, &slink_dirname);
+         if (r < 0)
+                 return log_device_debug_errno(dev, r, "Failed to get parent directory of '%s': %m", slink);
+@@ -80,41 +87,11 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) {
+         if (r < 0)
+                 return log_device_debug_errno(dev, r, "Failed to get relative path from '%s' to '%s': %m", slink, node);
+ 
+-        if (lstat(slink, &stats) >= 0) {
+-                _cleanup_free_ char *buf = NULL;
+-
+-                if (!S_ISLNK(stats.st_mode))
+-                        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
+-                                                      "Conflicting inode '%s' found, link to '%s' will not be created.", slink, node);
+-
+-                if (readlink_malloc(slink, &buf) >= 0 &&
+-                    path_equal(target, buf)) {
+-                        /* preserve link with correct target, do not replace node of other device */
+-                        log_device_debug(dev, "Preserve already existing symlink '%s' to '%s'", slink, target);
+-
+-                        (void) label_fix(slink, LABEL_IGNORE_ENOENT);
+-                        (void) utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
+-
+-                        return 0;
+-                }
+-        } else if (errno == ENOENT) {
+-                log_device_debug(dev, "Creating symlink '%s' to '%s'", slink, target);
+-
+-                r = create_symlink(target, slink);
+-                if (r >= 0)
+-                        return 0;
+-
+-                log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s', trying to replace '%s': %m", slink, target, slink);
+-        } else
+-                return log_device_debug_errno(dev, errno, "Failed to lstat() '%s': %m", slink);
+-
+-        log_device_debug(dev, "Atomically replace '%s'", slink);
+-
+         r = device_get_device_id(dev, &id);
+         if (r < 0)
+                 return log_device_debug_errno(dev, r, "Failed to get device id: %m");
+-        slink_tmp = strjoina(slink, ".tmp-", id);
+ 
++        slink_tmp = strjoina(slink, ".tmp-", id);
+         (void) unlink(slink_tmp);
+ 
+         r = create_symlink(target, slink_tmp);
+@@ -127,8 +104,7 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) {
+                 return r;
+         }
+ 
+-        /* Tell caller that we replaced already existing symlink. */
+-        return 1;
++        return 0;
+ }
+ 
+ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, char **ret) {
diff --git a/SOURCES/0030-udev-node-drop-redundant-trial-of-devlink-creation.patch b/SOURCES/0030-udev-node-drop-redundant-trial-of-devlink-creation.patch
deleted file mode 100644
index d2c37cb..0000000
--- a/SOURCES/0030-udev-node-drop-redundant-trial-of-devlink-creation.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-From 458a6cd748ee5555b6957888b69d475ac3f619c6 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Wed, 1 Sep 2021 09:29:42 +0900
-Subject: [PATCH] udev-node: drop redundant trial of devlink creation
-
-Previously, the devlink was created based on the priority saved in udev
-database. So, we needed to reevaluate devlinks after database is saved.
-
-But now the priority is stored in the symlink under /run/udev/links, and
-the loop of devlink creation is controlled with the timestamp of the
-directory. So, the double evaluation is not necessary anymore.
-
-(cherry picked from commit 7920d0a135fb6a08aa0bfc31e9d0a3f589fe7a1f)
-
-Related: #1977994
----
- src/udev/udev-event.c |  5 +----
- src/udev/udev-node.c  | 12 ++++--------
- 2 files changed, 5 insertions(+), 12 deletions(-)
-
-diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
-index 8b9f8aecfe..c77f55c67e 100644
---- a/src/udev/udev-event.c
-+++ b/src/udev/udev-event.c
-@@ -1060,10 +1060,7 @@ int udev_event_execute_rules(
- 
-         device_set_is_initialized(dev);
- 
--        /* Yes, we run update_devnode() twice, because in the first invocation, that is before update of udev database,
--         * it could happen that two contenders are replacing each other's symlink. Hence we run it again to make sure
--         * symlinks point to devices that claim them with the highest priority. */
--        return update_devnode(event);
-+        return 0;
- }
- 
- void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_signal) {
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 675e6ce313..bb551d86b0 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -416,7 +416,7 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
-         _cleanup_free_ char *slink = NULL, *dirname = NULL;
-         const char *slink_name;
-         char name_enc[NAME_MAX+1];
--        int i, r, retries;
-+        int r;
- 
-         assert(dev);
-         assert(slink_in);
-@@ -443,11 +443,7 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
-         if (r < 0)
-                 return r;
- 
--        /* If the database entry is not written yet we will just do one iteration and possibly wrong symlink
--         * will be fixed in the second invocation. */
--        retries = sd_device_get_is_initialized(dev) > 0 ? LINK_UPDATE_MAX_RETRIES : 1;
--
--        for (i = 0; i < retries; i++) {
-+        for (unsigned i = 0; i < LINK_UPDATE_MAX_RETRIES; i++) {
-                 _cleanup_free_ char *target = NULL;
-                 struct stat st1 = {}, st2 = {};
- 
-@@ -472,7 +468,7 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
-                                 log_device_debug_errno(dev, errno, "Failed to remove '%s', ignoring: %m", slink);
- 
-                         (void) rmdir_parents(slink, "/dev");
--                        break;
-+                        return 0;
-                 }
- 
-                 r = node_symlink(dev, target, slink);
-@@ -487,7 +483,7 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
-                         return 0;
-         }
- 
--        return i < LINK_UPDATE_MAX_RETRIES ? 0 : -ELOOP;
-+        return -ELOOP;
- }
- 
- static int device_get_devpath_by_devnum(sd_device *dev, char **ret) {
diff --git a/SOURCES/0031-udev-node-check-stack-directory-change-even-if-devli.patch b/SOURCES/0031-udev-node-check-stack-directory-change-even-if-devli.patch
new file mode 100644
index 0000000..0d20cea
--- /dev/null
+++ b/SOURCES/0031-udev-node-check-stack-directory-change-even-if-devli.patch
@@ -0,0 +1,44 @@
+From a3389b23db9b9ab1ad11f181f036be35aade8c31 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 1 Sep 2021 09:44:26 +0900
+Subject: [PATCH] udev-node: check stack directory change even if devlink is
+ removed
+
+Otherwise, when multiple device additions and removals occur
+simultaneously, symlink to unexisting devnode may be created.
+
+Hopefully fixes #19946.
+
+(cherry picked from commit 1cd4e325693007b3628f1a27297f0ab7114b24b8)
+
+Related: #2005024
+---
+ src/udev/udev-node.c | 15 ++++++---------
+ 1 file changed, 6 insertions(+), 9 deletions(-)
+
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 46c04fe00b..28e6e8df94 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -468,15 +468,12 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+                 if (r < 0)
+                         return r;
+ 
+-                /* Skip the second stat() if the first failed, stat_inode_unmodified() would return false regardless. */
+-                if ((st1.st_mode & S_IFMT) != 0) {
+-                        r = stat(dirname, &st2);
+-                        if (r < 0 && errno != ENOENT)
+-                                return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
+-
+-                        if (stat_inode_unmodified(&st1, &st2))
+-                                break;
+-                }
++                if (stat(dirname, &st2) < 0 && errno != ENOENT)
++                        return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
++
++                if (((st1.st_mode & S_IFMT) == 0 && (st2.st_mode & S_IFMT) == 0) ||
++                    stat_inode_unmodified(&st1, &st2))
++                        return 0;
+         }
+ 
+         return i < LINK_UPDATE_MAX_RETRIES ? 0 : -ELOOP;
diff --git a/SOURCES/0031-udev-node-simplify-the-example-of-race.patch b/SOURCES/0031-udev-node-simplify-the-example-of-race.patch
deleted file mode 100644
index dbdab4c..0000000
--- a/SOURCES/0031-udev-node-simplify-the-example-of-race.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From a5a14281160881fbb39d80a2572a18ecadbeedd5 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Sun, 12 Sep 2021 16:05:51 +0900
-Subject: [PATCH] udev-node: simplify the example of race
-
-(cherry picked from commit 3df566a66723490914ef3bae0ca8046044b70dce)
-
-Related: #1977994
----
- src/udev/udev-node.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index bb551d86b0..61cb9a449b 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -272,14 +272,14 @@ static int update_timestamp(sd_device *dev, const char *path, struct stat *prev)
- 
-         /* Even if a symlink in the stack directory is created/removed, the mtime of the directory may
-          * not be changed. Why? Let's consider the following situation. For simplicity, let's assume
--         * there exist three udev workers (A, B, and C) and all of them calls link_update() for the
--         * same devlink simultaneously.
-+         * there exist two udev workers (A and B) and all of them calls link_update() for the same
-+         * devlink simultaneously.
-          *
--         * 1. B creates/removes a symlink in the stack directory.
-+         * 1. A creates/removes a symlink in the stack directory.
-          * 2. A calls the first stat() in the loop of link_update().
-          * 3. A calls link_find_prioritized().
--         * 4. C creates/removes another symlink in the stack directory, so the result of the step 3 is outdated.
--         * 5. B and C finish link_update().
-+         * 4. B creates/removes another symlink in the stack directory, so the result of the step 3 is outdated.
-+         * 5. B finishes link_update().
-          * 6. A creates/removes devlink according to the outdated result in the step 3.
-          * 7. A calls the second stat() in the loop of link_update().
-          *
diff --git a/SOURCES/0032-udev-node-do-not-ignore-unexpected-errors-on-removin.patch b/SOURCES/0032-udev-node-do-not-ignore-unexpected-errors-on-removin.patch
deleted file mode 100644
index 5167506..0000000
--- a/SOURCES/0032-udev-node-do-not-ignore-unexpected-errors-on-removin.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 735971d9bffeccc0c17311a29909bdf5d693f806 Mon Sep 17 00:00:00 2001
-From: Yu Watanabe <watanabe.yu+github@gmail.com>
-Date: Sun, 12 Sep 2021 16:14:27 +0900
-Subject: [PATCH] udev-node: do not ignore unexpected errors on removing
- symlink in stack directory
-
-Only acceptable error here is -ENOENT.
-
-(cherry picked from commit 0706cdf4ec92d6bd40391da0e81a30d9bf851663)
-
-Related: #1977994
----
- src/udev/udev-node.c | 23 ++++++++++++++---------
- 1 file changed, 14 insertions(+), 9 deletions(-)
-
-diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
-index 61cb9a449b..e1fb387cb9 100644
---- a/src/udev/udev-node.c
-+++ b/src/udev/udev-node.c
-@@ -334,25 +334,30 @@ static int update_stack_directory(sd_device *dev, const char *dirname, bool add)
-                 return log_oom_debug();
- 
-         if (!add) {
--                bool unlink_failed = false;
-+                int unlink_error = 0, stat_error = 0;
- 
-                 if (stat(dirname, &st) < 0) {
-                         if (errno == ENOENT)
-                                 return 0; /* The stack directory is already removed. That's OK. */
--                        log_device_debug_errno(dev, errno, "Failed to stat %s, ignoring: %m", dirname);
-+                        stat_error = -errno;
-                 }
- 
--                if (unlink(filename) < 0) {
--                        unlink_failed = true;
--                        if (errno != ENOENT)
--                                log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
--                }
-+                if (unlink(filename) < 0)
-+                        unlink_error = -errno;
- 
-                 if (rmdir(dirname) >= 0 || errno == ENOENT)
-                         return 0;
- 
--                if (unlink_failed)
--                        return 0; /* If we failed to remove the symlink, there is almost nothing we can do. */
-+                if (unlink_error < 0) {
-+                        if (unlink_error == -ENOENT)
-+                                return 0;
-+
-+                        /* If we failed to remove the symlink, then there is almost nothing we can do. */
-+                        return log_device_debug_errno(dev, unlink_error, "Failed to remove %s: %m", filename);
-+                }
-+
-+                if (stat_error < 0)
-+                        return log_device_debug_errno(dev, stat_error, "Failed to stat %s: %m", dirname);
- 
-                 /* The symlink was removed. Check if the timestamp of directory is changed. */
-                 r = update_timestamp(dev, dirname, &st);
diff --git a/SOURCES/0032-udev-node-shorten-code-a-bit-and-update-log-message.patch b/SOURCES/0032-udev-node-shorten-code-a-bit-and-update-log-message.patch
new file mode 100644
index 0000000..c199706
--- /dev/null
+++ b/SOURCES/0032-udev-node-shorten-code-a-bit-and-update-log-message.patch
@@ -0,0 +1,32 @@
+From 52938c3ed27ebaadce97060ad8ebdcb351403d90 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Thu, 2 Sep 2021 08:23:35 +0900
+Subject: [PATCH] udev-node: shorten code a bit and update log message
+
+(cherry picked from commit 8424da2de88ceeed7be8544fb69221f0b0ea84ea)
+
+Related: #2005024
+---
+ src/udev/udev-node.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 28e6e8df94..2e7df899e4 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -447,13 +447,12 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+                 _cleanup_free_ char *target = NULL;
+                 struct stat st1 = {}, st2 = {};
+ 
+-                r = stat(dirname, &st1);
+-                if (r < 0 && errno != ENOENT)
++                if (stat(dirname, &st1) < 0 && errno != ENOENT)
+                         return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
+ 
+                 r = link_find_prioritized(dev, add, dirname, &target);
+                 if (r < 0)
+-                        return log_device_debug_errno(dev, r, "Failed to determine highest priority for symlink '%s': %m", slink);
++                        return log_device_debug_errno(dev, r, "Failed to determine device node with the highest priority for '%s': %m", slink);
+                 if (r == 0) {
+                         log_device_debug(dev, "No reference left for '%s', removing", slink);
+ 
diff --git a/SOURCES/0033-basic-time-util-introduce-FORMAT_TIMESPAN.patch b/SOURCES/0033-basic-time-util-introduce-FORMAT_TIMESPAN.patch
deleted file mode 100644
index 4f7fcc8..0000000
--- a/SOURCES/0033-basic-time-util-introduce-FORMAT_TIMESPAN.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From e1f53e60bdc368c81beba8b6173047ec8149f8e9 Mon Sep 17 00:00:00 2001
-From: Michal Sekletar <msekleta@redhat.com>
-Date: Tue, 21 Sep 2021 09:28:29 +0200
-Subject: [PATCH] basic/time-util: introduce FORMAT_TIMESPAN
-
-This is cherry-pick of the relevant part from the tree-wide change in
-5291f26d4a6.
-
-Related: #1977994
----
- src/basic/time-util.h | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/basic/time-util.h b/src/basic/time-util.h
-index 2bd947d6a8..8254913930 100644
---- a/src/basic/time-util.h
-+++ b/src/basic/time-util.h
-@@ -67,6 +67,7 @@ typedef enum TimestampStyle {
- #define FORMAT_TIMESTAMP_WIDTH 28U /* when outputting, assume this width */
- #define FORMAT_TIMESTAMP_RELATIVE_MAX 256U
- #define FORMAT_TIMESPAN_MAX 64U
-+#define FORMAT_TIMESPAN(t, accuracy) format_timespan((char[FORMAT_TIMESPAN_MAX]){}, FORMAT_TIMESPAN_MAX, t, accuracy)
- 
- #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
- 
diff --git a/SOURCES/0033-udev-node-add-random-delay-on-conflict-in-updating-d.patch b/SOURCES/0033-udev-node-add-random-delay-on-conflict-in-updating-d.patch
new file mode 100644
index 0000000..001ba0b
--- /dev/null
+++ b/SOURCES/0033-udev-node-add-random-delay-on-conflict-in-updating-d.patch
@@ -0,0 +1,59 @@
+From 75275ae07233e213fe03a1a33870efe10dbb2b39 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 1 Sep 2021 04:34:48 +0900
+Subject: [PATCH] udev-node: add random delay on conflict in updating device
+ node symlink
+
+To make multiple workers not update the same device node symlink
+simultaneously.
+
+(cherry picked from commit 0063fa23a1384dd4385d03b568dc629916b7e72a)
+
+Related: #2005024
+---
+ src/udev/udev-node.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 2e7df899e4..675e6ce313 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -20,12 +20,14 @@
+ #include "mkdir.h"
+ #include "parse-util.h"
+ #include "path-util.h"
++#include "random-util.h"
+ #include "selinux-util.h"
+ #include "smack-util.h"
+ #include "stat-util.h"
+ #include "stdio-util.h"
+ #include "string-util.h"
+ #include "strxcpyx.h"
++#include "time-util.h"
+ #include "udev-node.h"
+ #include "user-util.h"
+ 
+@@ -33,6 +35,8 @@
+ #define LINK_UPDATE_MAX_RETRIES        128
+ #define CREATE_STACK_LINK_MAX_RETRIES  128
+ #define UPDATE_TIMESTAMP_MAX_RETRIES   128
++#define MAX_RANDOM_DELAY (250 * USEC_PER_MSEC)
++#define MIN_RANDOM_DELAY ( 50 * USEC_PER_MSEC)
+ #define UDEV_NODE_HASH_KEY SD_ID128_MAKE(b9,6a,f1,ce,40,31,44,1a,9e,19,ec,8b,ae,f3,e3,2f)
+ 
+ static int create_symlink(const char *target, const char *slink) {
+@@ -447,6 +451,14 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+                 _cleanup_free_ char *target = NULL;
+                 struct stat st1 = {}, st2 = {};
+ 
++                if (i > 0) {
++                        usec_t delay = MIN_RANDOM_DELAY + random_u64_range(MAX_RANDOM_DELAY - MIN_RANDOM_DELAY);
++
++                        log_device_debug(dev, "Directory %s was updated, retrying to update devlink %s after %s.",
++                                         dirname, slink, FORMAT_TIMESPAN(delay, USEC_PER_MSEC));
++                        (void) usleep(delay);
++                }
++
+                 if (stat(dirname, &st1) < 0 && errno != ENOENT)
+                         return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
+ 
diff --git a/SOURCES/0034-udev-node-drop-redundant-trial-of-devlink-creation.patch b/SOURCES/0034-udev-node-drop-redundant-trial-of-devlink-creation.patch
new file mode 100644
index 0000000..4bc11ac
--- /dev/null
+++ b/SOURCES/0034-udev-node-drop-redundant-trial-of-devlink-creation.patch
@@ -0,0 +1,80 @@
+From c715be5f677ab61704ffe358716cf700d662b82d Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 1 Sep 2021 09:29:42 +0900
+Subject: [PATCH] udev-node: drop redundant trial of devlink creation
+
+Previously, the devlink was created based on the priority saved in udev
+database. So, we needed to reevaluate devlinks after database is saved.
+
+But now the priority is stored in the symlink under /run/udev/links, and
+the loop of devlink creation is controlled with the timestamp of the
+directory. So, the double evaluation is not necessary anymore.
+
+(cherry picked from commit 7920d0a135fb6a08aa0bfc31e9d0a3f589fe7a1f)
+
+Related: #2005024
+---
+ src/udev/udev-event.c |  5 +----
+ src/udev/udev-node.c  | 12 ++++--------
+ 2 files changed, 5 insertions(+), 12 deletions(-)
+
+diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
+index 8b9f8aecfe..c77f55c67e 100644
+--- a/src/udev/udev-event.c
++++ b/src/udev/udev-event.c
+@@ -1060,10 +1060,7 @@ int udev_event_execute_rules(
+ 
+         device_set_is_initialized(dev);
+ 
+-        /* Yes, we run update_devnode() twice, because in the first invocation, that is before update of udev database,
+-         * it could happen that two contenders are replacing each other's symlink. Hence we run it again to make sure
+-         * symlinks point to devices that claim them with the highest priority. */
+-        return update_devnode(event);
++        return 0;
+ }
+ 
+ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_signal) {
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 675e6ce313..bb551d86b0 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -416,7 +416,7 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+         _cleanup_free_ char *slink = NULL, *dirname = NULL;
+         const char *slink_name;
+         char name_enc[NAME_MAX+1];
+-        int i, r, retries;
++        int r;
+ 
+         assert(dev);
+         assert(slink_in);
+@@ -443,11 +443,7 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+         if (r < 0)
+                 return r;
+ 
+-        /* If the database entry is not written yet we will just do one iteration and possibly wrong symlink
+-         * will be fixed in the second invocation. */
+-        retries = sd_device_get_is_initialized(dev) > 0 ? LINK_UPDATE_MAX_RETRIES : 1;
+-
+-        for (i = 0; i < retries; i++) {
++        for (unsigned i = 0; i < LINK_UPDATE_MAX_RETRIES; i++) {
+                 _cleanup_free_ char *target = NULL;
+                 struct stat st1 = {}, st2 = {};
+ 
+@@ -472,7 +468,7 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+                                 log_device_debug_errno(dev, errno, "Failed to remove '%s', ignoring: %m", slink);
+ 
+                         (void) rmdir_parents(slink, "/dev");
+-                        break;
++                        return 0;
+                 }
+ 
+                 r = node_symlink(dev, target, slink);
+@@ -487,7 +483,7 @@ static int link_update(sd_device *dev, const char *slink_in, bool add) {
+                         return 0;
+         }
+ 
+-        return i < LINK_UPDATE_MAX_RETRIES ? 0 : -ELOOP;
++        return -ELOOP;
+ }
+ 
+ static int device_get_devpath_by_devnum(sd_device *dev, char **ret) {
diff --git a/SOURCES/0034-unit-install-the-systemd-bless-boot.service-only-if-.patch b/SOURCES/0034-unit-install-the-systemd-bless-boot.service-only-if-.patch
deleted file mode 100644
index 089cd8c..0000000
--- a/SOURCES/0034-unit-install-the-systemd-bless-boot.service-only-if-.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From aef14d77e157fd0748ef664c83e55fd3880ea787 Mon Sep 17 00:00:00 2001
-From: Frantisek Sumsal <frantisek@sumsal.cz>
-Date: Tue, 21 Sep 2021 22:47:42 +0200
-Subject: [PATCH] unit: install the systemd-bless-boot.service only if we have
- gnu-efi
-
-Follow-up to #20591.
-
-(cherry picked from commit 220261ef940a126588b20a1765a2501811473839)
-
-Related: #1972223
----
- units/meson.build | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/units/meson.build b/units/meson.build
-index 27a2b60137..e06d883cd2 100644
---- a/units/meson.build
-+++ b/units/meson.build
-@@ -179,7 +179,7 @@ in_units = [
-         ['systemd-backlight@.service',           'ENABLE_BACKLIGHT'],
-         ['systemd-binfmt.service',               'ENABLE_BINFMT',
-          'sysinit.target.wants/'],
--        ['systemd-bless-boot.service',           'ENABLE_EFI HAVE_BLKID'],
-+        ['systemd-bless-boot.service',           'HAVE_GNU_EFI HAVE_BLKID'],
-         ['systemd-boot-check-no-failures.service', ''],
-         ['systemd-coredump@.service',            'ENABLE_COREDUMP'],
-         ['systemd-pstore.service',               'ENABLE_PSTORE'],
diff --git a/SOURCES/0035-udev-node-simplify-the-example-of-race.patch b/SOURCES/0035-udev-node-simplify-the-example-of-race.patch
new file mode 100644
index 0000000..09e509e
--- /dev/null
+++ b/SOURCES/0035-udev-node-simplify-the-example-of-race.patch
@@ -0,0 +1,36 @@
+From 13293ddc7822025cb9f785262655f928634395f6 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Sun, 12 Sep 2021 16:05:51 +0900
+Subject: [PATCH] udev-node: simplify the example of race
+
+(cherry picked from commit 3df566a66723490914ef3bae0ca8046044b70dce)
+
+Related: #2005024
+---
+ src/udev/udev-node.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index bb551d86b0..61cb9a449b 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -272,14 +272,14 @@ static int update_timestamp(sd_device *dev, const char *path, struct stat *prev)
+ 
+         /* Even if a symlink in the stack directory is created/removed, the mtime of the directory may
+          * not be changed. Why? Let's consider the following situation. For simplicity, let's assume
+-         * there exist three udev workers (A, B, and C) and all of them calls link_update() for the
+-         * same devlink simultaneously.
++         * there exist two udev workers (A and B) and all of them calls link_update() for the same
++         * devlink simultaneously.
+          *
+-         * 1. B creates/removes a symlink in the stack directory.
++         * 1. A creates/removes a symlink in the stack directory.
+          * 2. A calls the first stat() in the loop of link_update().
+          * 3. A calls link_find_prioritized().
+-         * 4. C creates/removes another symlink in the stack directory, so the result of the step 3 is outdated.
+-         * 5. B and C finish link_update().
++         * 4. B creates/removes another symlink in the stack directory, so the result of the step 3 is outdated.
++         * 5. B finishes link_update().
+          * 6. A creates/removes devlink according to the outdated result in the step 3.
+          * 7. A calls the second stat() in the loop of link_update().
+          *
diff --git a/SOURCES/0035-units-don-t-enable-tmp.mount-statically-in-local-fs..patch b/SOURCES/0035-units-don-t-enable-tmp.mount-statically-in-local-fs..patch
deleted file mode 100644
index ee76475..0000000
--- a/SOURCES/0035-units-don-t-enable-tmp.mount-statically-in-local-fs..patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 532a10738745716620ef6af5813bc9c81c235f07 Mon Sep 17 00:00:00 2001
-From: Michal Sekletar <msekleta@redhat.com>
-Date: Wed, 22 Sep 2021 14:38:00 +0200
-Subject: [PATCH] units: don't enable tmp.mount statically in local-fs.target
-
-RHEL-only
-
-Related: #1959826
----
- units/meson.build | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-diff --git a/units/meson.build b/units/meson.build
-index e06d883cd2..40487d123e 100644
---- a/units/meson.build
-+++ b/units/meson.build
-@@ -154,8 +154,7 @@ units = [
-         ['time-set.target',                     ''],
-         ['time-sync.target',                    ''],
-         ['timers.target',                       ''],
--        ['tmp.mount',                           '',
--         'local-fs.target.wants/'],
-+        ['tmp.mount',                           ''],
-         ['umount.target',                       ''],
-         ['usb-gadget.target',                   ''],
-         ['user.slice',                          ''],
diff --git a/SOURCES/0036-pid1-bump-DefaultTasksMax-to-80-of-the-kernel-pid.ma.patch b/SOURCES/0036-pid1-bump-DefaultTasksMax-to-80-of-the-kernel-pid.ma.patch
deleted file mode 100644
index 06b0fe7..0000000
--- a/SOURCES/0036-pid1-bump-DefaultTasksMax-to-80-of-the-kernel-pid.ma.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 9ac22ee1e9d1ae32ff2d824e5a0e763a18b36d7e Mon Sep 17 00:00:00 2001
-From: rpm-build <rpm-build>
-Date: Wed, 1 Aug 2018 13:19:39 +0200
-Subject: [PATCH] pid1: bump DefaultTasksMax to 80% of the kernel pid.max value
-
-This should be hopefully high enough even for the very big deployments.
-
-RHEL-only
-
-Resolves: #1997200
----
- man/systemd-system.conf.xml | 4 ++--
- src/core/main.c             | 2 +-
- src/core/system.conf.in     | 2 +-
- 3 files changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
-index c11dd46143..72c8db5890 100644
---- a/man/systemd-system.conf.xml
-+++ b/man/systemd-system.conf.xml
-@@ -389,10 +389,10 @@
-         <listitem><para>Configure the default value for the per-unit <varname>TasksMax=</varname> setting. See
-         <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-         for details. This setting applies to all unit types that support resource control settings, with the exception
--        of slice units. Defaults to 15% of the minimum of <varname>kernel.pid_max=</varname>, <varname>kernel.threads-max=</varname>
-+        of slice units. Defaults to 80% of the minimum of <varname>kernel.pid_max=</varname>, <varname>kernel.threads-max=</varname>
-         and root cgroup <varname>pids.max</varname>.
-         Kernel has a default value for <varname>kernel.pid_max=</varname> and an algorithm of counting in case of more than 32 cores.
--        For example with the default <varname>kernel.pid_max=</varname>, <varname>DefaultTasksMax=</varname> defaults to 4915,
-+        For example with the default <varname>kernel.pid_max=</varname>, <varname>DefaultTasksMax=</varname> defaults to 26214,
-         but might be greater in other systems or smaller in OS containers.</para></listitem>
-       </varlistentry>
- 
-diff --git a/src/core/main.c b/src/core/main.c
-index da6c50a1c4..f4fe7517fd 100644
---- a/src/core/main.c
-+++ b/src/core/main.c
-@@ -92,7 +92,7 @@
- #include <sanitizer/lsan_interface.h>
- #endif
- 
--#define DEFAULT_TASKS_MAX ((TasksMax) { 15U, 100U }) /* 15% */
-+#define DEFAULT_TASKS_MAX ((TasksMax) { 80U, 100U }) /* 80% */
- 
- static enum {
-         ACTION_RUN,
-diff --git a/src/core/system.conf.in b/src/core/system.conf.in
-index e88280bd0a..f2c75fcd32 100644
---- a/src/core/system.conf.in
-+++ b/src/core/system.conf.in
-@@ -54,7 +54,7 @@
- #DefaultBlockIOAccounting=no
- #DefaultMemoryAccounting={{ 'yes' if MEMORY_ACCOUNTING_DEFAULT else 'no' }}
- #DefaultTasksAccounting=yes
--#DefaultTasksMax=15%
-+#DefaultTasksMax=80%
- #DefaultLimitCPU=
- #DefaultLimitFSIZE=
- #DefaultLimitDATA=
diff --git a/SOURCES/0036-udev-node-do-not-ignore-unexpected-errors-on-removin.patch b/SOURCES/0036-udev-node-do-not-ignore-unexpected-errors-on-removin.patch
new file mode 100644
index 0000000..f8adbfe
--- /dev/null
+++ b/SOURCES/0036-udev-node-do-not-ignore-unexpected-errors-on-removin.patch
@@ -0,0 +1,59 @@
+From 969b05b3f1dc644e821756205450b06a30c79d7f Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Sun, 12 Sep 2021 16:14:27 +0900
+Subject: [PATCH] udev-node: do not ignore unexpected errors on removing
+ symlink in stack directory
+
+Only acceptable error here is -ENOENT.
+
+(cherry picked from commit 0706cdf4ec92d6bd40391da0e81a30d9bf851663)
+
+Related: #2005024
+---
+ src/udev/udev-node.c | 23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 61cb9a449b..e1fb387cb9 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -334,25 +334,30 @@ static int update_stack_directory(sd_device *dev, const char *dirname, bool add)
+                 return log_oom_debug();
+ 
+         if (!add) {
+-                bool unlink_failed = false;
++                int unlink_error = 0, stat_error = 0;
+ 
+                 if (stat(dirname, &st) < 0) {
+                         if (errno == ENOENT)
+                                 return 0; /* The stack directory is already removed. That's OK. */
+-                        log_device_debug_errno(dev, errno, "Failed to stat %s, ignoring: %m", dirname);
++                        stat_error = -errno;
+                 }
+ 
+-                if (unlink(filename) < 0) {
+-                        unlink_failed = true;
+-                        if (errno != ENOENT)
+-                                log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
+-                }
++                if (unlink(filename) < 0)
++                        unlink_error = -errno;
+ 
+                 if (rmdir(dirname) >= 0 || errno == ENOENT)
+                         return 0;
+ 
+-                if (unlink_failed)
+-                        return 0; /* If we failed to remove the symlink, there is almost nothing we can do. */
++                if (unlink_error < 0) {
++                        if (unlink_error == -ENOENT)
++                                return 0;
++
++                        /* If we failed to remove the symlink, then there is almost nothing we can do. */
++                        return log_device_debug_errno(dev, unlink_error, "Failed to remove %s: %m", filename);
++                }
++
++                if (stat_error < 0)
++                        return log_device_debug_errno(dev, stat_error, "Failed to stat %s: %m", dirname);
+ 
+                 /* The symlink was removed. Check if the timestamp of directory is changed. */
+                 r = update_timestamp(dev, dirname, &st);
diff --git a/SOURCES/0037-basic-time-util-introduce-FORMAT_TIMESPAN.patch b/SOURCES/0037-basic-time-util-introduce-FORMAT_TIMESPAN.patch
new file mode 100644
index 0000000..07ae245
--- /dev/null
+++ b/SOURCES/0037-basic-time-util-introduce-FORMAT_TIMESPAN.patch
@@ -0,0 +1,25 @@
+From 1cbcfc6f69e50d309698b6aa16a48b7f282913f5 Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Tue, 21 Sep 2021 09:28:29 +0200
+Subject: [PATCH] basic/time-util: introduce FORMAT_TIMESPAN
+
+This is cherry-pick of the relevant part from the tree-wide change in
+5291f26d4a6.
+
+Related: #2005024
+---
+ src/basic/time-util.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/basic/time-util.h b/src/basic/time-util.h
+index 2bd947d6a8..8254913930 100644
+--- a/src/basic/time-util.h
++++ b/src/basic/time-util.h
+@@ -67,6 +67,7 @@ typedef enum TimestampStyle {
+ #define FORMAT_TIMESTAMP_WIDTH 28U /* when outputting, assume this width */
+ #define FORMAT_TIMESTAMP_RELATIVE_MAX 256U
+ #define FORMAT_TIMESPAN_MAX 64U
++#define FORMAT_TIMESPAN(t, accuracy) format_timespan((char[FORMAT_TIMESPAN_MAX]){}, FORMAT_TIMESPAN_MAX, t, accuracy)
+ 
+ #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
+ 
diff --git a/SOURCES/0037-udev-net-setup-link-change-the-default-MACAddressPol.patch b/SOURCES/0037-udev-net-setup-link-change-the-default-MACAddressPol.patch
deleted file mode 100644
index b031481..0000000
--- a/SOURCES/0037-udev-net-setup-link-change-the-default-MACAddressPol.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From ac965c0ae8c9ffa7d606bce9ffa3052fccbac0ce Mon Sep 17 00:00:00 2001
-From: Michal Sekletar <msekleta@redhat.com>
-Date: Tue, 21 Sep 2021 15:01:19 +0200
-Subject: [PATCH] udev/net-setup-link: change the default MACAddressPolicy to
- "none"
-
-While stable MAC address for interface types that don't have the
-address provided by HW could be useful it also breaks LACP based bonds.
-Let's err on the side of caution and don't change the MAC address from
-udev.
-
-Resolves: #1921094
----
- man/systemd.link.xml                       | 2 +-
- test/fuzz/fuzz-link-parser/99-default.link | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/man/systemd.link.xml b/man/systemd.link.xml
-index 1093e2e0b8..095d8b4873 100644
---- a/man/systemd.link.xml
-+++ b/man/systemd.link.xml
-@@ -816,7 +816,7 @@
- 
-       <programlisting>[Link]
- NamePolicy=kernel database onboard slot path
--MACAddressPolicy=persistent</programlisting>
-+MACAddressPolicy=none</programlisting>
-     </example>
- 
-     <example>
-diff --git a/test/fuzz/fuzz-link-parser/99-default.link b/test/fuzz/fuzz-link-parser/99-default.link
-index feb5b1fbb0..3d755898b4 100644
---- a/test/fuzz/fuzz-link-parser/99-default.link
-+++ b/test/fuzz/fuzz-link-parser/99-default.link
-@@ -9,4 +9,4 @@
- 
- [Link]
- NamePolicy=keep kernel database onboard slot path
--MACAddressPolicy=persistent
-+MACAddressPolicy=none
diff --git a/SOURCES/0038-udev-net-setup-link-change-the-default-MACAddressPol.patch b/SOURCES/0038-udev-net-setup-link-change-the-default-MACAddressPol.patch
new file mode 100644
index 0000000..26a6979
--- /dev/null
+++ b/SOURCES/0038-udev-net-setup-link-change-the-default-MACAddressPol.patch
@@ -0,0 +1,51 @@
+From 59bad0f7db6d56c359816bc048341b38b824e460 Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Tue, 21 Sep 2021 15:01:19 +0200
+Subject: [PATCH] udev/net-setup-link: change the default MACAddressPolicy to
+ "none"
+
+While stable MAC address for interface types that don't have the
+address provided by HW could be useful it also breaks LACP based bonds.
+Let's err on the side of caution and don't change the MAC address from
+udev.
+
+Resolves: #2009237
+---
+ man/systemd.link.xml                       | 2 +-
+ network/99-default.link                    | 2 +-
+ test/fuzz/fuzz-link-parser/99-default.link | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/man/systemd.link.xml b/man/systemd.link.xml
+index 1093e2e0b8..095d8b4873 100644
+--- a/man/systemd.link.xml
++++ b/man/systemd.link.xml
+@@ -816,7 +816,7 @@
+ 
+       <programlisting>[Link]
+ NamePolicy=kernel database onboard slot path
+-MACAddressPolicy=persistent</programlisting>
++MACAddressPolicy=none</programlisting>
+     </example>
+ 
+     <example>
+diff --git a/network/99-default.link b/network/99-default.link
+index bca660ac28..31aee37e75 100644
+--- a/network/99-default.link
++++ b/network/99-default.link
+@@ -13,4 +13,4 @@ OriginalName=*
+ [Link]
+ NamePolicy=keep kernel database onboard slot path
+ AlternativeNamesPolicy=database onboard slot path
+-MACAddressPolicy=persistent
++MACAddressPolicy=none
+diff --git a/test/fuzz/fuzz-link-parser/99-default.link b/test/fuzz/fuzz-link-parser/99-default.link
+index feb5b1fbb0..3d755898b4 100644
+--- a/test/fuzz/fuzz-link-parser/99-default.link
++++ b/test/fuzz/fuzz-link-parser/99-default.link
+@@ -9,4 +9,4 @@
+ 
+ [Link]
+ NamePolicy=keep kernel database onboard slot path
+-MACAddressPolicy=persistent
++MACAddressPolicy=none
diff --git a/SOURCES/0038-udev-net-setup-link-really-change-the-default-MACAdd.patch b/SOURCES/0038-udev-net-setup-link-really-change-the-default-MACAdd.patch
deleted file mode 100644
index bb7c122..0000000
--- a/SOURCES/0038-udev-net-setup-link-really-change-the-default-MACAdd.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From 19ab86202b9c4366ea5bd5ac820301f0ab6d1f95 Mon Sep 17 00:00:00 2001
-From: Michal Sekletar <msekleta@redhat.com>
-Date: Fri, 1 Oct 2021 11:46:23 +0200
-Subject: [PATCH] udev/net-setup-link: *really* change the default
- MACAddressPolicy to "none"
-
-Fix the oversight and change the policy in the link file, i.e. the
-place where it actually matters.
-
-Related: #1921094
----
- network/99-default.link | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/network/99-default.link b/network/99-default.link
-index bca660ac28..31aee37e75 100644
---- a/network/99-default.link
-+++ b/network/99-default.link
-@@ -13,4 +13,4 @@ OriginalName=*
- [Link]
- NamePolicy=keep kernel database onboard slot path
- AlternativeNamesPolicy=database onboard slot path
--MACAddressPolicy=persistent
-+MACAddressPolicy=none
diff --git a/SOURCES/0039-set-core-ulimit-to-0-like-on-RHEL-7.patch b/SOURCES/0039-set-core-ulimit-to-0-like-on-RHEL-7.patch
new file mode 100644
index 0000000..8c4c308
--- /dev/null
+++ b/SOURCES/0039-set-core-ulimit-to-0-like-on-RHEL-7.patch
@@ -0,0 +1,25 @@
+From 2edaafdfacc14088d7b6f04eec578bd048057103 Mon Sep 17 00:00:00 2001
+From: David Tardon <dtardon@redhat.com>
+Date: Mon, 25 Jan 2021 16:19:56 +0100
+Subject: [PATCH] set core ulimit to 0 like on RHEL-7
+
+RHEL-only
+
+Resolves: #1998509
+---
+ src/core/system.conf.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/core/system.conf.in b/src/core/system.conf.in
+index f2c75fcd32..c290b14b8b 100644
+--- a/src/core/system.conf.in
++++ b/src/core/system.conf.in
+@@ -59,7 +59,7 @@
+ #DefaultLimitFSIZE=
+ #DefaultLimitDATA=
+ #DefaultLimitSTACK=
+-#DefaultLimitCORE=
++DefaultLimitCORE=0:infinity
+ #DefaultLimitRSS=
+ #DefaultLimitNOFILE=1024:{{HIGH_RLIMIT_NOFILE}}
+ #DefaultLimitAS=
diff --git a/SOURCES/0040-test-don-t-install-test-network-generator-conversion.patch b/SOURCES/0040-test-don-t-install-test-network-generator-conversion.patch
new file mode 100644
index 0000000..953145b
--- /dev/null
+++ b/SOURCES/0040-test-don-t-install-test-network-generator-conversion.patch
@@ -0,0 +1,60 @@
+From 8efa0b5f989d977eca51617a314ec4fdc32fb3d1 Mon Sep 17 00:00:00 2001
+From: Frantisek Sumsal <frantisek@sumsal.cz>
+Date: Wed, 20 Oct 2021 19:43:34 +0200
+Subject: [PATCH] test: don't install test-network-generator-conversion.sh w/o
+ networkd
+
+otherwise TEST-02 will fail:
+
+```
+=== Failed test log ===
+--- test-network-generator-conversion.sh begin ---
++ [[ -n '' ]]
++ [[ -x /usr/lib/systemd/systemd-network-generator ]]
++ [[ -x /lib/systemd/systemd-network-generator ]]
++ exit 1
+--- test-network-generator-conversion.sh end ---
+```
+
+Before:
+```
+$ meson build -Dnetworkd=false -Dinstall-tests=true
+$ ninja -C build
+$ DESTDIR=$PWD/test-install ninja -C build install
+$ find test-install/ -name test-network-generator-conversion.sh
+test-install/usr/lib/systemd/tests/test-network-generator-conversion.sh
+```
+
+After:
+```
+$ find test-install/ -name test-network-generator-conversion.sh
+<no output>
+```
+
+(cherry picked from commit 140557021ad1a3946319fff1a87831eb02d6a1a0)
+
+Related: #2017035
+---
+ test/meson.build | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/test/meson.build b/test/meson.build
+index 47c7f4d49a..27b37a9ae7 100644
+--- a/test/meson.build
++++ b/test/meson.build
+@@ -98,9 +98,12 @@ if install_tests
+         install_data('run-unit-tests.py',
+                      install_mode : 'rwxr-xr-x',
+                      install_dir : testsdir)
+-        install_data('test-network-generator-conversion.sh',
+-                     install_mode : 'rwxr-xr-x',
+-                     install_dir : testsdir)
++
++        if conf.get('ENABLE_NETWORKD') == 1
++                install_data('test-network-generator-conversion.sh',
++                             install_mode : 'rwxr-xr-x',
++                             install_dir : testsdir)
++        endif
+ endif
+ 
+ ############################################################
diff --git a/SOURCES/0041-meson.build-change-operator-combining-bools-from-to-.patch b/SOURCES/0041-meson.build-change-operator-combining-bools-from-to-.patch
new file mode 100644
index 0000000..aa7e374
--- /dev/null
+++ b/SOURCES/0041-meson.build-change-operator-combining-bools-from-to-.patch
@@ -0,0 +1,32 @@
+From 7d7562db194f6b521d93ef370176922d0ac68331 Mon Sep 17 00:00:00 2001
+From: Dan Streetman <ddstreet@canonical.com>
+Date: Fri, 3 Sep 2021 12:43:33 -0400
+Subject: [PATCH] meson.build: change operator combining bools from + to and
+
+upstream meson stopped allowing combining boolean with the plus
+operator, and now requires using the logical and operator
+
+reference:
+https://github.com/mesonbuild/meson/commit/43302d3296baff6aeaf8e03f5d701b0402e37a6c
+
+Fixes: #20632
+(cherry picked from commit c29537f39e4f413a6cbfe9669fa121bdd6d8b36f)
+
+Related: #2017035
+---
+ meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/meson.build b/meson.build
+index d28f04607a..f21ec5bb94 100644
+--- a/meson.build
++++ b/meson.build
+@@ -35,7 +35,7 @@ conf.set10('BUILD_MODE_DEVELOPER', get_option('mode') == 'developer',
+ 
+ want_ossfuzz = get_option('oss-fuzz')
+ want_libfuzzer = get_option('llvm-fuzz')
+-if want_ossfuzz + want_libfuzzer > 1
++if want_ossfuzz and want_libfuzzer
+         error('only one of oss-fuzz or llvm-fuzz can be specified')
+ endif
+ 
diff --git a/SOURCES/0042-openssl-util-use-EVP-API-to-get-RSA-bits.patch b/SOURCES/0042-openssl-util-use-EVP-API-to-get-RSA-bits.patch
new file mode 100644
index 0000000..76d7d54
--- /dev/null
+++ b/SOURCES/0042-openssl-util-use-EVP-API-to-get-RSA-bits.patch
@@ -0,0 +1,37 @@
+From 387ba3f36092f2072ee6a05abeac27deaca177bd Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Wed, 29 Sep 2021 15:03:44 +0200
+Subject: [PATCH] openssl-util: use EVP API to get RSA bits
+
+(cherry picked from commit 7f12adc3000c08a370f74bd16c654506c8a99e92)
+
+Resolves: #2016042
+---
+ src/shared/openssl-util.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/src/shared/openssl-util.c b/src/shared/openssl-util.c
+index bb47ae5e87..bd728e6c7c 100644
+--- a/src/shared/openssl-util.c
++++ b/src/shared/openssl-util.c
+@@ -46,7 +46,6 @@ int rsa_pkey_to_suitable_key_size(
+                 size_t *ret_suitable_key_size) {
+ 
+         size_t suitable_key_size;
+-        const RSA *rsa;
+         int bits;
+ 
+         assert_se(pkey);
+@@ -58,11 +57,7 @@ int rsa_pkey_to_suitable_key_size(
+         if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA)
+                 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "X.509 certificate does not refer to RSA key.");
+ 
+-        rsa = EVP_PKEY_get0_RSA(pkey);
+-        if (!rsa)
+-                return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to acquire RSA public key from X.509 certificate.");
+-
+-        bits = RSA_bits(rsa);
++        bits = EVP_PKEY_bits(pkey);
+         log_debug("Bits in RSA key: %i", bits);
+ 
+         /* We use PKCS#1 padding for the RSA cleartext, hence let's leave some extra space for it, hence only
diff --git a/SOURCES/0043-procfs-util-fix-confusion-wrt.-quantity-limit-and-ma.patch b/SOURCES/0043-procfs-util-fix-confusion-wrt.-quantity-limit-and-ma.patch
new file mode 100644
index 0000000..048eb49
--- /dev/null
+++ b/SOURCES/0043-procfs-util-fix-confusion-wrt.-quantity-limit-and-ma.patch
@@ -0,0 +1,315 @@
+From 862ded47343a782d70f7d4421a6a2e4e33684e5e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Tue, 2 Nov 2021 18:18:21 +0100
+Subject: [PATCH] procfs-util: fix confusion wrt. quantity limit and maximum
+ value
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From packit/rawhide-arm64 logs:
+Assertion 'limit >= INT_MAX || get_process_ppid(limit+1, NULL) == -ESRCH' failed at src/test/test-process-util.c:855, function test_get_process_ppid(). Aborting.
+――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
+
+The kernel has a few different limits. In particular kernel.threads-max can be
+set to some lower value, and kernel.pid_max can be set to a higher value. This
+is nice because it reduces PID reuse, even if the number of threads that is
+allowed is limited. But the tests assumed that we cannot have a thread with
+PID above MIN(kernel.threads-max, kernel.pid_max-1), which is not valid.
+
+So let's rework the whole thing: let's expose the helpers to read
+kernel.threads-max and kernel.pid_max, and print what they return in tests.
+procfs_tasks_get_limit() was something that is only used in tests, and wasn't
+very well defined, so let's drop it.
+
+Fixes #21193.
+
+(cherry picked from commit c3dead53d50e334f2d072a2248256983d6dc9f8c)
+
+Related: #2017035
+---
+ src/basic/limits-util.c      | 50 ++++++++++++++++++++++++----------
+ src/basic/procfs-util.c      | 53 +++++++++---------------------------
+ src/basic/procfs-util.h      |  4 ++-
+ src/test/test-process-util.c | 10 +++++--
+ src/test/test-procfs-util.c  | 34 ++++++++++++++++-------
+ 5 files changed, 84 insertions(+), 67 deletions(-)
+
+diff --git a/src/basic/limits-util.c b/src/basic/limits-util.c
+index 9f8e26d46a..435a2a0efe 100644
+--- a/src/basic/limits-util.c
++++ b/src/basic/limits-util.c
+@@ -109,35 +109,57 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
+ }
+ 
+ uint64_t system_tasks_max(void) {
+-        uint64_t a = TASKS_MAX, b = TASKS_MAX;
++        uint64_t a = TASKS_MAX, b = TASKS_MAX, c = TASKS_MAX;
+         _cleanup_free_ char *root = NULL;
+         int r;
+ 
+-        /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
+-         * limit:
++        /* Determine the maximum number of tasks that may run on this system. We check three sources to
++         * determine this limit:
+          *
+-         * a) the maximum tasks value the kernel allows on this architecture
+-         * b) the cgroups pids_max attribute for the system
+-         * c) the kernel's configured maximum PID value
++         * a) kernel.threads-max sysctl: the maximum number of tasks (threads) the kernel allows.
+          *
+-         * And then pick the smallest of the three */
++         *    This puts a direct limit on the number of concurrent tasks.
++         *
++         * b) kernel.pid_max sysctl: the maximum PID value.
++         *
++         *    This limits the numeric range PIDs can take, and thus indirectly also limits the number of
++         *    concurrent threads. It's primarily a compatibility concept: some crappy old code used a signed
++         *    16bit type for PIDs, hence the kernel provides a way to ensure the PIDs never go beyond
++         *    INT16_MAX by default.
++         *
++         *    Also note the weird definition: PIDs assigned will be kept below this value, which means
++         *    the number of tasks that can be created is one lower, as PID 0 is not a valid process ID.
++         *
++         * c) pids.max on the root cgroup: the kernel's configured maximum number of tasks.
++         *
++         * and then pick the smallest of the three.
++         *
++         * By default pid_max is set to much lower values than threads-max, hence the limit people come into
++         * contact with first, as it's the lowest boundary they need to bump when they want higher number of
++         * processes.
++         */
++
++        r = procfs_get_threads_max(&a);
++        if (r < 0)
++                log_debug_errno(r, "Failed to read kernel.threads-max, ignoring: %m");
+ 
+-        r = procfs_tasks_get_limit(&a);
++        r = procfs_get_pid_max(&b);
+         if (r < 0)
+-                log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m");
++                log_debug_errno(r, "Failed to read kernel.pid_max, ignoring: %m");
++        else if (b > 0)
++                /* Subtract one from pid_max, since PID 0 is not a valid PID */
++                b--;
+ 
+         r = cg_get_root_path(&root);
+         if (r < 0)
+                 log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m");
+         else {
+-                r = cg_get_attribute_as_uint64("pids", root, "pids.max", &b);
++                r = cg_get_attribute_as_uint64("pids", root, "pids.max", &c);
+                 if (r < 0)
+-                        log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m");
++                        log_debug_errno(r, "Failed to read pids.max attribute of root cgroup, ignoring: %m");
+         }
+ 
+-        return MIN3(TASKS_MAX,
+-                    a <= 0 ? TASKS_MAX : a,
+-                    b <= 0 ? TASKS_MAX : b);
++        return MIN3(a, b, c);
+ }
+ 
+ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
+diff --git a/src/basic/procfs-util.c b/src/basic/procfs-util.c
+index 9234ccaf85..a29e776a3a 100644
+--- a/src/basic/procfs-util.c
++++ b/src/basic/procfs-util.c
+@@ -12,54 +12,34 @@
+ #include "stdio-util.h"
+ #include "string-util.h"
+ 
+-int procfs_tasks_get_limit(uint64_t *ret) {
++int procfs_get_pid_max(uint64_t *ret) {
+         _cleanup_free_ char *value = NULL;
+-        uint64_t pid_max, threads_max;
+         int r;
+ 
+         assert(ret);
+ 
+-        /* So there are two sysctl files that control the system limit of processes:
+-         *
+-         * 1. kernel.threads-max: this is probably the sysctl that makes more sense, as it directly puts a limit on
+-         *    concurrent tasks.
+-         *
+-         * 2. kernel.pid_max: this limits the numeric range PIDs can take, and thus indirectly also limits the number
+-         *    of concurrent threads. AFAICS it's primarily a compatibility concept: some crappy old code used a signed
+-         *    16bit type for PIDs, hence the kernel provides a way to ensure the PIDs never go beyond INT16_MAX by
+-         *    default.
+-         *
+-         * By default #2 is set to much lower values than #1, hence the limit people come into contact with first, as
+-         * it's the lowest boundary they need to bump when they want higher number of processes.
+-         *
+-         * Also note the weird definition of #2: PIDs assigned will be kept below this value, which means the number of
+-         * tasks that can be created is one lower, as PID 0 is not a valid process ID. */
+-
+         r = read_one_line_file("/proc/sys/kernel/pid_max", &value);
+         if (r < 0)
+                 return r;
+ 
+-        r = safe_atou64(value, &pid_max);
+-        if (r < 0)
+-                return r;
++        return safe_atou64(value, ret);
++}
+ 
+-        value = mfree(value);
+-        r = read_one_line_file("/proc/sys/kernel/threads-max", &value);
+-        if (r < 0)
+-                return r;
++int procfs_get_threads_max(uint64_t *ret) {
++        _cleanup_free_ char *value = NULL;
++        int r;
+ 
+-        r = safe_atou64(value, &threads_max);
++        assert(ret);
++
++        r = read_one_line_file("/proc/sys/kernel/threads-max", &value);
+         if (r < 0)
+                 return r;
+ 
+-        /* Subtract one from pid_max, since PID 0 is not a valid PID */
+-        *ret = MIN(pid_max-1, threads_max);
+-        return 0;
++        return safe_atou64(value, ret);
+ }
+ 
+ int procfs_tasks_set_limit(uint64_t limit) {
+         char buffer[DECIMAL_STR_MAX(uint64_t)+1];
+-        _cleanup_free_ char *value = NULL;
+         uint64_t pid_max;
+         int r;
+ 
+@@ -74,10 +54,7 @@ int procfs_tasks_set_limit(uint64_t limit) {
+          * set it to the maximum. */
+         limit = CLAMP(limit, 20U, TASKS_MAX);
+ 
+-        r = read_one_line_file("/proc/sys/kernel/pid_max", &value);
+-        if (r < 0)
+-                return r;
+-        r = safe_atou64(value, &pid_max);
++        r = procfs_get_pid_max(&pid_max);
+         if (r < 0)
+                 return r;
+ 
+@@ -98,14 +75,10 @@ int procfs_tasks_set_limit(uint64_t limit) {
+                 /* Hmm, we couldn't write this? If so, maybe it was already set properly? In that case let's not
+                  * generate an error */
+ 
+-                value = mfree(value);
+-                if (read_one_line_file("/proc/sys/kernel/threads-max", &value) < 0)
+-                        return r; /* return original error */
+-
+-                if (safe_atou64(value, &threads_max) < 0)
++                if (procfs_get_threads_max(&threads_max) < 0)
+                         return r; /* return original error */
+ 
+-                if (MIN(pid_max-1, threads_max) != limit)
++                if (MIN(pid_max - 1, threads_max) != limit)
+                         return r; /* return original error */
+ 
+                 /* Yay! Value set already matches what we were trying to set, hence consider this a success. */
+diff --git a/src/basic/procfs-util.h b/src/basic/procfs-util.h
+index 61fa71d479..eb8c7738b1 100644
+--- a/src/basic/procfs-util.h
++++ b/src/basic/procfs-util.h
+@@ -5,7 +5,9 @@
+ 
+ #include "time-util.h"
+ 
+-int procfs_tasks_get_limit(uint64_t *ret);
++int procfs_get_pid_max(uint64_t *ret);
++int procfs_get_threads_max(uint64_t *ret);
++
+ int procfs_tasks_set_limit(uint64_t limit);
+ int procfs_tasks_get_current(uint64_t *ret);
+ 
+diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c
+index 8c76392ae9..d89ce6e2db 100644
+--- a/src/test/test-process-util.c
++++ b/src/test/test-process-util.c
+@@ -850,8 +850,14 @@ static void test_get_process_ppid(void) {
+         assert_se(get_process_ppid(1, NULL) == -EADDRNOTAVAIL);
+ 
+         /* the process with the PID above the global limit definitely doesn't exist. Verify that */
+-        assert_se(procfs_tasks_get_limit(&limit) >= 0);
+-        assert_se(limit >= INT_MAX || get_process_ppid(limit+1, NULL) == -ESRCH);
++        assert_se(procfs_get_pid_max(&limit) >= 0);
++        log_debug("kernel.pid_max = %"PRIu64, limit);
++
++        if (limit < INT_MAX) {
++                r = get_process_ppid(limit + 1, NULL);
++                log_debug_errno(r, "get_process_limit(%"PRIu64") → %d/%m", limit + 1, r);
++                assert(r == -ESRCH);
++        }
+ 
+         for (pid_t pid = 0;;) {
+                 _cleanup_free_ char *c1 = NULL, *c2 = NULL;
+diff --git a/src/test/test-procfs-util.c b/src/test/test-procfs-util.c
+index b2679e30fb..876ef40dfd 100644
+--- a/src/test/test-procfs-util.c
++++ b/src/test/test-procfs-util.c
+@@ -6,12 +6,13 @@
+ #include "format-util.h"
+ #include "log.h"
+ #include "procfs-util.h"
++#include "process-util.h"
+ #include "tests.h"
+ 
+ int main(int argc, char *argv[]) {
+         char buf[CONST_MAX(FORMAT_TIMESPAN_MAX, FORMAT_BYTES_MAX)];
+         nsec_t nsec;
+-        uint64_t v;
++        uint64_t v, w;
+         int r;
+ 
+         log_parse_environment();
+@@ -26,26 +27,39 @@ int main(int argc, char *argv[]) {
+         assert_se(procfs_tasks_get_current(&v) >= 0);
+         log_info("Current number of tasks: %" PRIu64, v);
+ 
+-        r = procfs_tasks_get_limit(&v);
+-        if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r))
+-                return log_tests_skipped("can't read /proc/sys/kernel/pid_max");
++        v = TASKS_MAX;
++        r = procfs_get_pid_max(&v);
++        assert(r >= 0 || r == -ENOENT || ERRNO_IS_PRIVILEGE(r));
++        log_info("kernel.pid_max: %"PRIu64, v);
++
++        w = TASKS_MAX;
++        r = procfs_get_threads_max(&w);
++        assert(r >= 0 || r == -ENOENT || ERRNO_IS_PRIVILEGE(r));
++        log_info("kernel.threads-max: %"PRIu64, w);
++
++        v = MIN(v - (v > 0), w);
+ 
+         assert_se(r >= 0);
+         log_info("Limit of tasks: %" PRIu64, v);
+         assert_se(v > 0);
+-        assert_se(procfs_tasks_set_limit(v) >= 0);
++        r = procfs_tasks_set_limit(v);
++        if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r))
++                return log_tests_skipped("can't set task limits");
++        assert(r >= 0);
+ 
+         if (v > 100) {
+-                uint64_t w;
++                log_info("Reducing limit by one to %"PRIu64"…", v-1);
++
+                 r = procfs_tasks_set_limit(v-1);
+-                assert_se(IN_SET(r, 0, -EPERM, -EACCES, -EROFS));
++                log_info_errno(r, "procfs_tasks_set_limit: %m");
++                assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r));
+ 
+-                assert_se(procfs_tasks_get_limit(&w) >= 0);
+-                assert_se((r == 0 && w == v - 1) || (r < 0 && w == v));
++                assert_se(procfs_get_threads_max(&w) >= 0);
++                assert_se(r >= 0 ? w == v - 1 : w == v);
+ 
+                 assert_se(procfs_tasks_set_limit(v) >= 0);
+ 
+-                assert_se(procfs_tasks_get_limit(&w) >= 0);
++                assert_se(procfs_get_threads_max(&w) >= 0);
+                 assert_se(v == w);
+         }
+ 
diff --git a/SOURCES/0044-test-process-util-also-add-EROFS-to-the-list-of-good.patch b/SOURCES/0044-test-process-util-also-add-EROFS-to-the-list-of-good.patch
new file mode 100644
index 0000000..ae93bc0
--- /dev/null
+++ b/SOURCES/0044-test-process-util-also-add-EROFS-to-the-list-of-good.patch
@@ -0,0 +1,31 @@
+From e43e8caf2f2699de7da1f072bcc7c25e125313e4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Wed, 3 Nov 2021 09:39:16 +0100
+Subject: [PATCH] test-process-util: also add EROFS to the list of "good"
+ errors
+
+It is only added in the one place where we actually try to set the
+setting to a new value. Before we were testing if we can set to it the
+existing value, which was a noop. We could still get a permission error,
+but this is the first place where we would propagate EROFS.
+
+(cherry picked from commit 6434a83d01d96e9f9a17ed9ce1f04a7d64859950)
+
+Related: #2017035
+---
+ src/test/test-procfs-util.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/test/test-procfs-util.c b/src/test/test-procfs-util.c
+index 876ef40dfd..f19a41475d 100644
+--- a/src/test/test-procfs-util.c
++++ b/src/test/test-procfs-util.c
+@@ -52,7 +52,7 @@ int main(int argc, char *argv[]) {
+ 
+                 r = procfs_tasks_set_limit(v-1);
+                 log_info_errno(r, "procfs_tasks_set_limit: %m");
+-                assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r));
++                assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || r == -EROFS);
+ 
+                 assert_se(procfs_get_threads_max(&w) >= 0);
+                 assert_se(r >= 0 ? w == v - 1 : w == v);
diff --git a/SOURCES/0045-ci-use-C9S-chroots-in-Packit.patch b/SOURCES/0045-ci-use-C9S-chroots-in-Packit.patch
new file mode 100644
index 0000000..8b3991a
--- /dev/null
+++ b/SOURCES/0045-ci-use-C9S-chroots-in-Packit.patch
@@ -0,0 +1,27 @@
+From 5c8d698f3905c860eff17b84a32bb7acfb98d931 Mon Sep 17 00:00:00 2001
+From: Frantisek Sumsal <frantisek@sumsal.cz>
+Date: Thu, 4 Nov 2021 12:31:32 +0100
+Subject: [PATCH] ci: use C9S chroots in Packit
+
+rhel-only
+Related: #2017035
+---
+ .packit.yml | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/.packit.yml b/.packit.yml
+index 3461bccbc5..ce8782aae2 100644
+--- a/.packit.yml
++++ b/.packit.yml
+@@ -37,9 +37,8 @@ jobs:
+   trigger: pull_request
+   metadata:
+     targets:
+-      # FIXME: change to CentOS 9 once it's available
+-      - fedora-34-x86_64
+-      - fedora-34-aarch64
++      - centos-stream-9-x86_64
++      - centos-stream-9-aarch64
+ 
+ # TODO: can't use TFT yet due to https://pagure.io/fedora-ci/general/issue/184
+ # Run tests (via testing farm)
diff --git a/SOURCES/0046-test-mountpointutil-util-do-not-assert-in-test_mnt_i.patch b/SOURCES/0046-test-mountpointutil-util-do-not-assert-in-test_mnt_i.patch
new file mode 100644
index 0000000..1fa73eb
--- /dev/null
+++ b/SOURCES/0046-test-mountpointutil-util-do-not-assert-in-test_mnt_i.patch
@@ -0,0 +1,136 @@
+From 5a86b79c5f79215a17f6617ae925dc76b25396a6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Mon, 14 Sep 2020 17:58:03 +0200
+Subject: [PATCH] test-mountpointutil-util: do not assert in test_mnt_id()
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1803070
+
+I *think* this a kernel bug: the mnt_id as listed in /proc/self/mountinfo is different
+than the one we get from /proc/self/fdinfo/. This only matters when both statx and
+name_to_handle_at are unavailable and we hit the fallback path that goes through fdinfo:
+
+(gdb) !uname -r
+5.6.19-200.fc31.ppc64le
+
+(gdb) !cat /proc/self/mountinfo
+697 664 253:0 /var/lib/mock/fedora-31-ppc64le/root / rw,relatime shared:298 master:1 - xfs /dev/mapper/fedora_rh--power--vm14-root rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
+698 697 253:0 /var/cache/mock/fedora-31-ppc64le/yum_cache /var/cache/yum rw,relatime shared:299 master:1 - xfs /dev/mapper/fedora_rh--power--vm14-root rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
+699 697 253:0 /var/cache/mock/fedora-31-ppc64le/dnf_cache /var/cache/dnf rw,relatime shared:300 master:1 - xfs /dev/mapper/fedora_rh--power--vm14-root rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
+700 697 0:32 /mock-selinux-plugin.7me9bfpi /proc/filesystems rw,nosuid,nodev shared:301 master:18 - tmpfs tmpfs rw,seclabel <==========================================================
+701 697 0:41 / /sys ro,nosuid,nodev,noexec,relatime shared:302 - sysfs sysfs ro,seclabel
+702 701 0:21 / /sys/fs/selinux ro,nosuid,nodev,noexec,relatime shared:306 master:8 - selinuxfs selinuxfs rw
+703 697 0:42 / /dev rw,nosuid shared:303 - tmpfs tmpfs rw,seclabel,mode=755
+704 703 0:43 / /dev/shm rw,nosuid,nodev shared:304 - tmpfs tmpfs rw,seclabel
+705 703 0:45 / /dev/pts rw,nosuid,noexec,relatime shared:307 - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=666
+706 703 0:6 /btrfs-control /dev/btrfs-control rw,nosuid shared:308 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+707 703 0:6 /loop-control /dev/loop-control rw,nosuid shared:309 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+708 703 0:6 /loop0 /dev/loop0 rw,nosuid shared:310 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+709 703 0:6 /loop1 /dev/loop1 rw,nosuid shared:311 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+710 703 0:6 /loop10 /dev/loop10 rw,nosuid shared:312 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+711 703 0:6 /loop11 /dev/loop11 rw,nosuid shared:313 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+712 703 0:6 /loop2 /dev/loop2 rw,nosuid shared:314 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+713 703 0:6 /loop3 /dev/loop3 rw,nosuid shared:315 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+714 703 0:6 /loop4 /dev/loop4 rw,nosuid shared:316 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+715 703 0:6 /loop5 /dev/loop5 rw,nosuid shared:317 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+716 703 0:6 /loop6 /dev/loop6 rw,nosuid shared:318 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+717 703 0:6 /loop7 /dev/loop7 rw,nosuid shared:319 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+718 703 0:6 /loop8 /dev/loop8 rw,nosuid shared:320 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+719 703 0:6 /loop9 /dev/loop9 rw,nosuid shared:321 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
+720 697 0:44 / /run rw,nosuid,nodev shared:305 - tmpfs tmpfs rw,seclabel,mode=755
+721 720 0:25 /systemd/nspawn/propagate/9cc8a155d0244558b273f773d2b92142 /run/systemd/nspawn/incoming ro master:12 - tmpfs tmpfs rw,seclabel,mode=755
+722 697 0:32 /mock-resolv.dvml91hp /etc/resolv.conf rw,nosuid,nodev shared:322 master:18 - tmpfs tmpfs rw,seclabel
+725 697 0:47 / /proc rw,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
+603 725 0:47 /sys /proc/sys ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
+604 725 0:44 /systemd/inaccessible/reg /proc/kallsyms ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
+605 725 0:44 /systemd/inaccessible/reg /proc/kcore ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
+606 725 0:44 /systemd/inaccessible/reg /proc/keys ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
+607 725 0:44 /systemd/inaccessible/reg /proc/sysrq-trigger ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
+608 725 0:44 /systemd/inaccessible/reg /proc/timer_list ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
+609 725 0:47 /bus /proc/bus ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
+610 725 0:47 /fs /proc/fs ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
+611 725 0:47 /irq /proc/irq ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
+612 725 0:47 /scsi /proc/scsi ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
+613 703 0:46 / /dev/mqueue rw,nosuid,nodev,noexec,relatime shared:324 - mqueue mqueue rw,seclabel
+614 701 0:26 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime shared:325 - cgroup2 cgroup rw,seclabel,nsdelegate
+615 603 0:44 /.#proc-sys-kernel-random-boot-id4fbdce67af46d1c2//deleted /proc/sys/kernel/random/boot_id ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
+616 725 0:44 /.#proc-sys-kernel-random-boot-id4fbdce67af46d1c2//deleted /proc/sys/kernel/random/boot_id rw,nosuid,nodev shared:305 - tmpfs tmpfs rw,seclabel,mode=755
+617 725 0:44 /.#proc-kmsg5b7a8bcfe6717139//deleted /proc/kmsg rw,nosuid,nodev shared:305 - tmpfs tmpfs rw,seclabel,mode=755
+
+The test process does
+name_to_handle_at("/proc/filesystems") which returns -EOPNOTSUPP, and then
+openat(AT_FDCWD, "/proc/filesystems") which returns 4, and then
+read(open("/proc/self/fdinfo/4", ...)) which gives
+"pos:\t0\nflags:\t012100000\nmnt_id:\t725\n"
+
+and the "725" is clearly inconsistent with "700" in /proc/self/mountinfo.
+
+We could either drop the fallback path (and fail name_to_handle_at() is not
+avaliable) or ignore the error in the test. Not sure what is better. I think
+this issue only occurs sometimes and with older kernels, so probably continuing
+with the current flaky implementation is better than ripping out the fallback.
+
+Another strace:
+writev(2</dev/pts/0>, [{iov_base="mnt ids of /proc/sys is 603", iov_len=27}, {iov_base="\n", iov_len=1}], 2mnt ids of /proc/sys is 603
+) = 28
+name_to_handle_at(AT_FDCWD, "/", {handle_bytes=128 => 12, handle_type=129, f_handle=0x52748401000000008b93e20d}, [697], 0) = 0
+writev(2</dev/pts/0>, [{iov_base="mnt ids of / is 697", iov_len=19}, {iov_base="\n", iov_len=1}], 2mnt ids of / is 697
+) = 20
+name_to_handle_at(AT_FDCWD, "/proc/kcore", {handle_bytes=128 => 12, handle_type=1, f_handle=0x92ddcfcd2e802d0100000000}, [605], 0) = 0
+writev(2</dev/pts/0>, [{iov_base="mnt ids of /proc/kcore is 605", iov_len=29}, {iov_base="\n", iov_len=1}], 2mnt ids of /proc/kcore is 605
+) = 30
+name_to_handle_at(AT_FDCWD, "/dev", {handle_bytes=128 => 12, handle_type=1, f_handle=0x8ae269160c802d0100000000}, [703], 0) = 0
+writev(2</dev/pts/0>, [{iov_base="mnt ids of /dev is 703", iov_len=22}, {iov_base="\n", iov_len=1}], 2mnt ids of /dev is 703
+) = 23
+name_to_handle_at(AT_FDCWD, "/proc/filesystems", {handle_bytes=128}, 0x7fffe36ddb84, 0) = -1 EOPNOTSUPP (Operation not supported)
+openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH) = 4</proc/filesystems>
+openat(AT_FDCWD, "/proc/self/fdinfo/4", O_RDONLY|O_CLOEXEC) = 5</proc/20/fdinfo/4>
+fstat(5</proc/20/fdinfo/4>, {st_mode=S_IFREG|0400, st_size=0, ...}) = 0
+fstat(5</proc/20/fdinfo/4>, {st_mode=S_IFREG|0400, st_size=0, ...}) = 0
+read(5</proc/20/fdinfo/4>, "pos:\t0\nflags:\t012100000\nmnt_id:\t725\n", 2048) = 36
+read(5</proc/20/fdinfo/4>, "", 1024)    = 0
+close(5</proc/20/fdinfo/4>)             = 0
+close(4</proc/filesystems>)             = 0
+writev(2</dev/pts/0>, [{iov_base="mnt ids of /proc/filesystems are 700, 725", iov_len=41}, {iov_base="\n", iov_len=1}], 2mnt ids of /proc/filesystems are 700, 725
+) = 42
+writev(2</dev/pts/0>, [{iov_base="the other path for mnt id 725 is /proc", iov_len=38}, {iov_base="\n", iov_len=1}], 2the other path for mnt id 725 is /proc
+) = 39
+writev(2</dev/pts/0>, [{iov_base="Assertion 'path_equal(p, t)' failed at src/test/test-mountpoint-util.c:94, function test_mnt_id(). Aborting.", iov_len=108}, {iov_base="\n", iov_len=1}], 2Assertion 'path_equal(p, t)' failed at src/test/test-mountpoint-util.c:94, function test_mnt_id(). Aborting.
+) = 109
+rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0
+rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], [], 8) = 0
+getpid()                                = 20
+gettid()                                = 20
+tgkill(20, 20, SIGABRT)                 = 0
+rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
+
+RHEL notes: af918c4 should mitigate this issue, but in some build
+systems (Copr, brew, etc.) we don't have enough privileges to create a
+new mount namespace
+
+Cherry-picked manually from https://github.com/systemd/systemd/pull/17050.
+
+rhel-only
+Related: #2017035
+---
+ src/test/test-mountpoint-util.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c
+index 983e1842d6..66d476d06d 100644
+--- a/src/test/test-mountpoint-util.c
++++ b/src/test/test-mountpoint-util.c
+@@ -91,8 +91,12 @@ static void test_mnt_id(void) {
+                 /* The ids don't match? If so, then there are two mounts on the same path, let's check if
+                  * that's really the case */
+                 char *t = hashmap_get(h, INT_TO_PTR(mnt_id2));
+-                log_debug("the other path for mnt id %i is %s\n", mnt_id2, t);
+-                assert_se(path_equal(p, t));
++                log_debug("Path for mnt id %i from /proc/self/mountinfo is %s\n", mnt_id2, t);
++
++                if (!path_equal(p, t))
++                        /* Apparent kernel bug in /proc/self/fdinfo */
++                        log_warning("Bad mount id given for %s: %d, should be %d",
++                                    p, mnt_id2, mnt_id);
+         }
+ }
+ 
diff --git a/SOURCES/0047-core-mount-add-implicit-unit-dependencies-even-if-wh.patch b/SOURCES/0047-core-mount-add-implicit-unit-dependencies-even-if-wh.patch
new file mode 100644
index 0000000..7b1650d
--- /dev/null
+++ b/SOURCES/0047-core-mount-add-implicit-unit-dependencies-even-if-wh.patch
@@ -0,0 +1,30 @@
+From ea4ebf86d25fb9c489d1cf1ca42371b7e2e782aa Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Sun, 29 Aug 2021 21:20:43 +0900
+Subject: [PATCH] core/mount: add implicit unit dependencies even if when mount
+ unit is generated from /proc/self/mountinfo
+
+Hopefully fixes #20566.
+
+(cherry picked from commit aebff2e7ce209fc2d75b894a3ae8b80f6f36ec11)
+
+Resolves: #2019468
+---
+ src/core/mount.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/core/mount.c b/src/core/mount.c
+index 1fd3102ad3..f2c85e0e5d 100644
+--- a/src/core/mount.c
++++ b/src/core/mount.c
+@@ -1582,6 +1582,10 @@ static int mount_setup_new_unit(
+         if (r < 0)
+                 return r;
+ 
++        r = mount_add_non_exec_dependencies(MOUNT(u));
++        if (r < 0)
++                return r;
++
+         /* This unit was generated because /proc/self/mountinfo reported it. Remember this, so that by the time we load
+          * the unit file for it (and thus add in extra deps right after) we know what source to attributes the deps
+          * to. */
diff --git a/SOURCES/f58b96d3e8d1cb0dd3666bc74fa673918b586612.patch b/SOURCES/f58b96d3e8d1cb0dd3666bc74fa673918b586612.patch
deleted file mode 100644
index 84497ad..0000000
--- a/SOURCES/f58b96d3e8d1cb0dd3666bc74fa673918b586612.patch
+++ /dev/null
@@ -1,129 +0,0 @@
-From f58b96d3e8d1cb0dd3666bc74fa673918b586612 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
-Date: Mon, 14 Sep 2020 17:58:03 +0200
-Subject: [PATCH] test-mountpointutil-util: do not assert in test_mnt_id()
-
-https://bugzilla.redhat.com/show_bug.cgi?id=1803070
-
-I *think* this a kernel bug: the mnt_id as listed in /proc/self/mountinfo is different
-than the one we get from /proc/self/fdinfo/. This only matters when both statx and
-name_to_handle_at are unavailable and we hit the fallback path that goes through fdinfo:
-
-(gdb) !uname -r
-5.6.19-200.fc31.ppc64le
-
-(gdb) !cat /proc/self/mountinfo
-697 664 253:0 /var/lib/mock/fedora-31-ppc64le/root / rw,relatime shared:298 master:1 - xfs /dev/mapper/fedora_rh--power--vm14-root rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
-698 697 253:0 /var/cache/mock/fedora-31-ppc64le/yum_cache /var/cache/yum rw,relatime shared:299 master:1 - xfs /dev/mapper/fedora_rh--power--vm14-root rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
-699 697 253:0 /var/cache/mock/fedora-31-ppc64le/dnf_cache /var/cache/dnf rw,relatime shared:300 master:1 - xfs /dev/mapper/fedora_rh--power--vm14-root rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
-700 697 0:32 /mock-selinux-plugin.7me9bfpi /proc/filesystems rw,nosuid,nodev shared:301 master:18 - tmpfs tmpfs rw,seclabel <==========================================================
-701 697 0:41 / /sys ro,nosuid,nodev,noexec,relatime shared:302 - sysfs sysfs ro,seclabel
-702 701 0:21 / /sys/fs/selinux ro,nosuid,nodev,noexec,relatime shared:306 master:8 - selinuxfs selinuxfs rw
-703 697 0:42 / /dev rw,nosuid shared:303 - tmpfs tmpfs rw,seclabel,mode=755
-704 703 0:43 / /dev/shm rw,nosuid,nodev shared:304 - tmpfs tmpfs rw,seclabel
-705 703 0:45 / /dev/pts rw,nosuid,noexec,relatime shared:307 - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=666
-706 703 0:6 /btrfs-control /dev/btrfs-control rw,nosuid shared:308 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-707 703 0:6 /loop-control /dev/loop-control rw,nosuid shared:309 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-708 703 0:6 /loop0 /dev/loop0 rw,nosuid shared:310 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-709 703 0:6 /loop1 /dev/loop1 rw,nosuid shared:311 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-710 703 0:6 /loop10 /dev/loop10 rw,nosuid shared:312 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-711 703 0:6 /loop11 /dev/loop11 rw,nosuid shared:313 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-712 703 0:6 /loop2 /dev/loop2 rw,nosuid shared:314 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-713 703 0:6 /loop3 /dev/loop3 rw,nosuid shared:315 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-714 703 0:6 /loop4 /dev/loop4 rw,nosuid shared:316 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-715 703 0:6 /loop5 /dev/loop5 rw,nosuid shared:317 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-716 703 0:6 /loop6 /dev/loop6 rw,nosuid shared:318 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-717 703 0:6 /loop7 /dev/loop7 rw,nosuid shared:319 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-718 703 0:6 /loop8 /dev/loop8 rw,nosuid shared:320 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-719 703 0:6 /loop9 /dev/loop9 rw,nosuid shared:321 master:9 - devtmpfs devtmpfs rw,seclabel,size=4107840k,nr_inodes=64185,mode=755
-720 697 0:44 / /run rw,nosuid,nodev shared:305 - tmpfs tmpfs rw,seclabel,mode=755
-721 720 0:25 /systemd/nspawn/propagate/9cc8a155d0244558b273f773d2b92142 /run/systemd/nspawn/incoming ro master:12 - tmpfs tmpfs rw,seclabel,mode=755
-722 697 0:32 /mock-resolv.dvml91hp /etc/resolv.conf rw,nosuid,nodev shared:322 master:18 - tmpfs tmpfs rw,seclabel
-725 697 0:47 / /proc rw,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
-603 725 0:47 /sys /proc/sys ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
-604 725 0:44 /systemd/inaccessible/reg /proc/kallsyms ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
-605 725 0:44 /systemd/inaccessible/reg /proc/kcore ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
-606 725 0:44 /systemd/inaccessible/reg /proc/keys ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
-607 725 0:44 /systemd/inaccessible/reg /proc/sysrq-trigger ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
-608 725 0:44 /systemd/inaccessible/reg /proc/timer_list ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
-609 725 0:47 /bus /proc/bus ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
-610 725 0:47 /fs /proc/fs ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
-611 725 0:47 /irq /proc/irq ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
-612 725 0:47 /scsi /proc/scsi ro,nosuid,nodev,noexec,relatime shared:323 - proc proc rw
-613 703 0:46 / /dev/mqueue rw,nosuid,nodev,noexec,relatime shared:324 - mqueue mqueue rw,seclabel
-614 701 0:26 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime shared:325 - cgroup2 cgroup rw,seclabel,nsdelegate
-615 603 0:44 /.#proc-sys-kernel-random-boot-id4fbdce67af46d1c2//deleted /proc/sys/kernel/random/boot_id ro,nosuid,nodev,noexec shared:305 - tmpfs tmpfs rw,seclabel,mode=755
-616 725 0:44 /.#proc-sys-kernel-random-boot-id4fbdce67af46d1c2//deleted /proc/sys/kernel/random/boot_id rw,nosuid,nodev shared:305 - tmpfs tmpfs rw,seclabel,mode=755
-617 725 0:44 /.#proc-kmsg5b7a8bcfe6717139//deleted /proc/kmsg rw,nosuid,nodev shared:305 - tmpfs tmpfs rw,seclabel,mode=755
-
-The test process does
-name_to_handle_at("/proc/filesystems") which returns -EOPNOTSUPP, and then
-openat(AT_FDCWD, "/proc/filesystems") which returns 4, and then
-read(open("/proc/self/fdinfo/4", ...)) which gives
-"pos:\t0\nflags:\t012100000\nmnt_id:\t725\n"
-
-and the "725" is clearly inconsistent with "700" in /proc/self/mountinfo.
-
-We could either drop the fallback path (and fail name_to_handle_at() is not
-avaliable) or ignore the error in the test. Not sure what is better. I think
-this issue only occurs sometimes and with older kernels, so probably continuing
-with the current flaky implementation is better than ripping out the fallback.
-
-Another strace:
-writev(2</dev/pts/0>, [{iov_base="mnt ids of /proc/sys is 603", iov_len=27}, {iov_base="\n", iov_len=1}], 2mnt ids of /proc/sys is 603
-) = 28
-name_to_handle_at(AT_FDCWD, "/", {handle_bytes=128 => 12, handle_type=129, f_handle=0x52748401000000008b93e20d}, [697], 0) = 0
-writev(2</dev/pts/0>, [{iov_base="mnt ids of / is 697", iov_len=19}, {iov_base="\n", iov_len=1}], 2mnt ids of / is 697
-) = 20
-name_to_handle_at(AT_FDCWD, "/proc/kcore", {handle_bytes=128 => 12, handle_type=1, f_handle=0x92ddcfcd2e802d0100000000}, [605], 0) = 0
-writev(2</dev/pts/0>, [{iov_base="mnt ids of /proc/kcore is 605", iov_len=29}, {iov_base="\n", iov_len=1}], 2mnt ids of /proc/kcore is 605
-) = 30
-name_to_handle_at(AT_FDCWD, "/dev", {handle_bytes=128 => 12, handle_type=1, f_handle=0x8ae269160c802d0100000000}, [703], 0) = 0
-writev(2</dev/pts/0>, [{iov_base="mnt ids of /dev is 703", iov_len=22}, {iov_base="\n", iov_len=1}], 2mnt ids of /dev is 703
-) = 23
-name_to_handle_at(AT_FDCWD, "/proc/filesystems", {handle_bytes=128}, 0x7fffe36ddb84, 0) = -1 EOPNOTSUPP (Operation not supported)
-openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH) = 4</proc/filesystems>
-openat(AT_FDCWD, "/proc/self/fdinfo/4", O_RDONLY|O_CLOEXEC) = 5</proc/20/fdinfo/4>
-fstat(5</proc/20/fdinfo/4>, {st_mode=S_IFREG|0400, st_size=0, ...}) = 0
-fstat(5</proc/20/fdinfo/4>, {st_mode=S_IFREG|0400, st_size=0, ...}) = 0
-read(5</proc/20/fdinfo/4>, "pos:\t0\nflags:\t012100000\nmnt_id:\t725\n", 2048) = 36
-read(5</proc/20/fdinfo/4>, "", 1024)    = 0
-close(5</proc/20/fdinfo/4>)             = 0
-close(4</proc/filesystems>)             = 0
-writev(2</dev/pts/0>, [{iov_base="mnt ids of /proc/filesystems are 700, 725", iov_len=41}, {iov_base="\n", iov_len=1}], 2mnt ids of /proc/filesystems are 700, 725
-) = 42
-writev(2</dev/pts/0>, [{iov_base="the other path for mnt id 725 is /proc", iov_len=38}, {iov_base="\n", iov_len=1}], 2the other path for mnt id 725 is /proc
-) = 39
-writev(2</dev/pts/0>, [{iov_base="Assertion 'path_equal(p, t)' failed at src/test/test-mountpoint-util.c:94, function test_mnt_id(). Aborting.", iov_len=108}, {iov_base="\n", iov_len=1}], 2Assertion 'path_equal(p, t)' failed at src/test/test-mountpoint-util.c:94, function test_mnt_id(). Aborting.
-) = 109
-rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0
-rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], [], 8) = 0
-getpid()                                = 20
-gettid()                                = 20
-tgkill(20, 20, SIGABRT)                 = 0
-rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
---- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=20, si_uid=0} ---
-+++ killed by SIGABRT (core dumped) +++
----
- src/test/test-mountpoint-util.c | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c
-index 30b00ae4d8b..ffe5144b04a 100644
---- a/src/test/test-mountpoint-util.c
-+++ b/src/test/test-mountpoint-util.c
-@@ -89,8 +89,12 @@ static void test_mnt_id(void) {
-                 /* The ids don't match? If so, then there are two mounts on the same path, let's check if
-                  * that's really the case */
-                 char *t = hashmap_get(h, INT_TO_PTR(mnt_id2));
--                log_debug("the other path for mnt id %i is %s\n", mnt_id2, t);
--                assert_se(path_equal(p, t));
-+                log_debug("Path for mnt id %i from /proc/self/mountinfo is %s\n", mnt_id2, t);
-+
-+                if (!path_equal(p, t))
-+                        /* Apparent kernel bug in /proc/self/fdinfo */
-+                        log_warning("Bad mount id given for %s: %d, should be %d",
-+                                    p, mnt_id2, mnt_id);
-         }
- }
- 
diff --git a/SOURCES/rc.local b/SOURCES/rc.local
new file mode 100644
index 0000000..4666070
--- /dev/null
+++ b/SOURCES/rc.local
@@ -0,0 +1,14 @@
+#!/bin/bash
+# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
+#
+# It is highly advisable to create own systemd services or udev rules
+# to run scripts during boot instead of using this file.
+#
+# In contrast to previous versions due to parallel execution during boot
+# this script will NOT be run after all other services.
+#
+# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
+# that this script will be executed during boot.
+
+touch /var/lock/subsys/local
+
diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec
index e328be9..811d033 100644
--- a/SPECS/systemd.spec
+++ b/SPECS/systemd.spec
@@ -21,7 +21,7 @@
 Name:           systemd
 Url:            https://www.freedesktop.org/wiki/Software/systemd
 Version:        249
-Release:        7%{?dist}
+Release:        9%{?dist}
 # For a breakdown of the licensing, see README
 License:        LGPLv2+ and MIT and GPLv2+
 Summary:        System and Service Manager
@@ -63,6 +63,7 @@ Source21:       macros.sysusers
 Source22:       sysusers.attr
 Source23:       sysusers.prov
 Source24:       sysusers.generate-pre.sh
+Source25:       rc.local
 
 %if 0
 GIT_DIR=../../src/systemd/.git git format-patch-ab --no-signature -M -N v235..v235-stable
@@ -94,31 +95,38 @@ Patch0014: 0014-random-util-increase-random-seed-size-to-1024.patch
 Patch0015: 0015-journal-don-t-enable-systemd-journald-audit.socket-b.patch
 Patch0016: 0016-journald.conf-don-t-touch-current-audit-settings.patch
 Patch0017: 0017-Revert-udev-remove-WAIT_FOR-key.patch
-Patch0018: 0018-boot-don-t-build-bootctl-when-Dgnu-efi-false-is-set.patch
+Patch0018: 0018-Really-don-t-enable-systemd-journald-audit.socket.patch
 Patch0019: 0019-rules-add-elevator-kernel-command-line-parameter.patch
-Patch0020: 0020-sd-device-introduce-device_has_devlink.patch
-Patch0021: 0021-udev-node-split-out-permission-handling-from-udev_no.patch
-Patch0022: 0022-udev-node-stack-directory-must-exist-when-adding-dev.patch
-Patch0023: 0023-udev-node-save-information-about-device-node-and-pri.patch
-Patch0024: 0024-udev-node-always-update-timestamp-of-stack-directory.patch
-Patch0025: 0025-udev-node-assume-no-new-claim-to-a-symlink-if-run-ud.patch
-Patch0026: 0026-udev-node-always-atomically-create-symlink-to-device.patch
-Patch0027: 0027-udev-node-check-stack-directory-change-even-if-devli.patch
-Patch0028: 0028-udev-node-shorten-code-a-bit-and-update-log-message.patch
-Patch0029: 0029-udev-node-add-random-delay-on-conflict-in-updating-d.patch
-Patch0030: 0030-udev-node-drop-redundant-trial-of-devlink-creation.patch
-Patch0031: 0031-udev-node-simplify-the-example-of-race.patch
-Patch0032: 0032-udev-node-do-not-ignore-unexpected-errors-on-removin.patch
-Patch0033: 0033-basic-time-util-introduce-FORMAT_TIMESPAN.patch
-Patch0034: 0034-unit-install-the-systemd-bless-boot.service-only-if-.patch
-Patch0035: 0035-units-don-t-enable-tmp.mount-statically-in-local-fs..patch
-Patch0036: 0036-pid1-bump-DefaultTasksMax-to-80-of-the-kernel-pid.ma.patch
-Patch0037: 0037-udev-net-setup-link-change-the-default-MACAddressPol.patch
-Patch0038: 0038-udev-net-setup-link-really-change-the-default-MACAdd.patch
+Patch0020: 0020-boot-don-t-build-bootctl-when-Dgnu-efi-false-is-set.patch
+Patch0021: 0021-unit-install-the-systemd-bless-boot.service-only-if-.patch
+Patch0022: 0022-units-don-t-enable-tmp.mount-statically-in-local-fs..patch
+Patch0023: 0023-pid1-bump-DefaultTasksMax-to-80-of-the-kernel-pid.ma.patch
+Patch0024: 0024-sd-device-introduce-device_has_devlink.patch
+Patch0025: 0025-udev-node-split-out-permission-handling-from-udev_no.patch
+Patch0026: 0026-udev-node-stack-directory-must-exist-when-adding-dev.patch
+Patch0027: 0027-udev-node-save-information-about-device-node-and-pri.patch
+Patch0028: 0028-udev-node-always-update-timestamp-of-stack-directory.patch
+Patch0029: 0029-udev-node-assume-no-new-claim-to-a-symlink-if-run-ud.patch
+Patch0030: 0030-udev-node-always-atomically-create-symlink-to-device.patch
+Patch0031: 0031-udev-node-check-stack-directory-change-even-if-devli.patch
+Patch0032: 0032-udev-node-shorten-code-a-bit-and-update-log-message.patch
+Patch0033: 0033-udev-node-add-random-delay-on-conflict-in-updating-d.patch
+Patch0034: 0034-udev-node-drop-redundant-trial-of-devlink-creation.patch
+Patch0035: 0035-udev-node-simplify-the-example-of-race.patch
+Patch0036: 0036-udev-node-do-not-ignore-unexpected-errors-on-removin.patch
+Patch0037: 0037-basic-time-util-introduce-FORMAT_TIMESPAN.patch
+Patch0038: 0038-udev-net-setup-link-change-the-default-MACAddressPol.patch
+Patch0039: 0039-set-core-ulimit-to-0-like-on-RHEL-7.patch
+Patch0040: 0040-test-don-t-install-test-network-generator-conversion.patch
+Patch0041: 0041-meson.build-change-operator-combining-bools-from-to-.patch
+Patch0042: 0042-openssl-util-use-EVP-API-to-get-RSA-bits.patch
+Patch0043: 0043-procfs-util-fix-confusion-wrt.-quantity-limit-and-ma.patch
+Patch0044: 0044-test-process-util-also-add-EROFS-to-the-list-of-good.patch
+Patch0045: 0045-ci-use-C9S-chroots-in-Packit.patch
+Patch0046: 0046-test-mountpointutil-util-do-not-assert-in-test_mnt_i.patch
+Patch0047: 0047-core-mount-add-implicit-unit-dependencies-even-if-wh.patch
 
 # Downstream-only patches (9000–9999)
-# https://github.com/systemd/systemd/pull/17050
-Patch9001:      https://github.com/systemd/systemd/pull/17050/commits/f58b96d3e8d1cb0dd3666bc74fa673918b586612.patch
 
 BuildRequires:  gcc
 BuildRequires:  gcc-c++
@@ -363,6 +371,7 @@ MulticastDNS resolver and responder.
 Summary:        A userspace out-of-memory (OOM) killer
 Requires:       %{name}%{?_isa} = %{version}-%{release}
 License:        LGPLv2+
+Provides:       %{name}-oomd-defaults = %{version}-%{release}
 
 %description oomd
 systemd-oomd is a system service that uses cgroups-v2 and pressure stall
@@ -461,7 +470,7 @@ CONFIGURE_OPTS=(
 %endif
         -Db_ndebug=false
         -Dman=true
-        -Dversion-tag=%{version}-%{release}
+        -Dversion-tag=v%{version}-%{release}
 %if 0%{?fedora}
         -Dfallback-hostname=fedora
 %else
@@ -558,6 +567,11 @@ touch %{buildroot}%{_sysconfdir}/udev/hwdb.bin
 touch %{buildroot}%{_localstatedir}/lib/systemd/random-seed
 touch %{buildroot}%{_localstatedir}/lib/private/systemd/journal-upload/state
 
+# Install rc.local
+mkdir -p %{buildroot}%{_sysconfdir}/rc.d/
+install -m 0644 %{SOURCE25} %{buildroot}%{_sysconfdir}/rc.d/rc.local
+ln -s rc.d/rc.local %{buildroot}%{_sysconfdir}/rc.local
+
 # Install yum protection fragment
 install -Dm0644 %{SOURCE4} %{buildroot}/etc/dnf/protected.d/systemd.conf
 
@@ -616,6 +630,8 @@ python3 %{SOURCE2} %buildroot <<EOF
 %ghost %config(noreplace) /etc/locale.conf
 %ghost %config(noreplace) /etc/machine-id
 %ghost %config(noreplace) /etc/machine-info
+%config(noreplace) %{_sysconfdir}/rc.d/rc.local
+%{_sysconfdir}/rc.local
 %ghost %attr(0700,root,root) %dir /var/cache/private
 %ghost %attr(0700,root,root) %dir /var/lib/private
 %ghost %dir /var/lib/private/systemd
@@ -633,6 +649,10 @@ python3 %{SOURCE2} %buildroot <<EOF
 %ghost %attr(0700,root,root) %dir /var/log/private
 EOF
 
+%check
+%if %{with tests}
+meson test -C %{_vpath_builddir} -t 6 --print-errorlogs
+%endif
 
 #############################################################################################
 
@@ -873,34 +893,40 @@ getent passwd systemd-oom &>/dev/null || useradd -r -l -g systemd-oom -d / -s /s
 %files standalone-sysusers -f .file-list-standalone-sysusers
 
 %changelog
-* Fri Oct 01 2021 systemd maintenance team <systemd-maint@redhat.com> - 249-7
-- spec: make sure version string starts with version number (#1921094)
-
-* Fri Oct 01 2021 systemd maintenance team <systemd-maint@redhat.com> - 249-6
-- udev/net-setup-link: *really* change the default MACAddressPolicy to "none" (#1921094)
-- spec: Use -Dgnu-efi=false instead of -Defi=false (#1972223)
-
-* Thu Sep 30 2021 systemd maintenance team <systemd-maint@redhat.com> - 249-5
-- boot: don't build bootctl when -Dgnu-efi=false is set (#1972223)
-- rules: add elevator= kernel command line parameter (#1998190)
-- sd-device: introduce device_has_devlink() (#1977994)
-- udev-node: split out permission handling from udev_node_add() (#1977994)
-- udev-node: stack directory must exist when adding device node symlink (#1977994)
-- udev-node: save information about device node and priority in symlink (#1977994)
-- udev-node: always update timestamp of stack directory (#1977994)
-- udev-node: assume no new claim to a symlink if /run/udev/links is not updated (#1977994)
-- udev-node: always atomically create symlink to device node (#1977994)
-- udev-node: check stack directory change even if devlink is removed (#1977994)
-- udev-node: shorten code a bit and update log message (#1977994)
-- udev-node: add random delay on conflict in updating device node symlink (#1977994)
-- udev-node: drop redundant trial of devlink creation (#1977994)
-- udev-node: simplify the example of race (#1977994)
-- udev-node: do not ignore unexpected errors on removing symlink in stack directory (#1977994)
-- basic/time-util: introduce FORMAT_TIMESPAN (#1977994)
-- unit: install the systemd-bless-boot.service only if we have gnu-efi (#1972223)
-- units: don't enable tmp.mount statically in local-fs.target (#1959826)
-- pid1: bump DefaultTasksMax to 80% of the kernel pid.max value (#1997200)
-- udev/net-setup-link: change the default MACAddressPolicy to "none" (#1921094)
+* Thu Nov 18 2021 systemd maintenance team <systemd-maint@redhat.com> - 249-9
+- test: don't install test-network-generator-conversion.sh w/o networkd (#2017035)
+- meson.build: change operator combining bools from + to and (#2017035)
+- openssl-util: use EVP API to get RSA bits (#2016042)
+- procfs-util: fix confusion wrt. quantity limit and maximum value (#2017035)
+- test-process-util: also add EROFS to the list of "good" errors (#2017035)
+- ci: use C9S chroots in Packit (#2017035)
+- test-mountpointutil-util: do not assert in test_mnt_id() (#2017035)
+- core/mount: add implicit unit dependencies even if when mount unit is generated from /proc/self/mountinfo (#2019468)
+- Drop Patch9001 - https://github.com/systemd/systemd/pull/17050 - Replaced by Patch0046
+
+* Tue Oct 12 2021 systemd maintenance team <systemd-maint@redhat.com> - 249-8
+- Really don't enable systemd-journald-audit.socket (#1973856)
+- rules: add elevator= kernel command line parameter (#2003002)
+- boot: don't build bootctl when -Dgnu-efi=false is set (#2003130)
+- unit: install the systemd-bless-boot.service only if we have gnu-efi (#2003130)
+- units: don't enable tmp.mount statically in local-fs.target (#2000927)
+- pid1: bump DefaultTasksMax to 80% of the kernel pid.max value (#2003031)
+- sd-device: introduce device_has_devlink() (#2005024)
+- udev-node: split out permission handling from udev_node_add() (#2005024)
+- udev-node: stack directory must exist when adding device node symlink (#2005024)
+- udev-node: save information about device node and priority in symlink (#2005024)
+- udev-node: always update timestamp of stack directory (#2005024)
+- udev-node: assume no new claim to a symlink if /run/udev/links is not updated (#2005024)
+- udev-node: always atomically create symlink to device node (#2005024)
+- udev-node: check stack directory change even if devlink is removed (#2005024)
+- udev-node: shorten code a bit and update log message (#2005024)
+- udev-node: add random delay on conflict in updating device node symlink (#2005024)
+- udev-node: drop redundant trial of devlink creation (#2005024)
+- udev-node: simplify the example of race (#2005024)
+- udev-node: do not ignore unexpected errors on removing symlink in stack directory (#2005024)
+- basic/time-util: introduce FORMAT_TIMESPAN (#2005024)
+- udev/net-setup-link: change the default MACAddressPolicy to "none" (#2009237)
+- set core ulimit to 0 like on RHEL-7 (#1998509)
 
 * Fri Aug 20 2021 systemd maintenance team <systemd-maint@redhat.com> - 249-4
 - Revert "udev: remove WAIT_FOR key" (#1982666)