diff --git a/SOURCES/0001-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch b/SOURCES/0001-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch
deleted file mode 100644
index 08b6900..0000000
--- a/SOURCES/0001-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 7e92ef334af165a5e50b33ddff98e18f1c8a18d0 Mon Sep 17 00:00:00 2001
-From: Xiao Ni <xni@redhat.com>
-Date: Thu, 24 Feb 2022 11:37:34 +0800
-Subject: [PATCH 1/1] Revert "mdadm: fix coredump of mdadm --monitor -r"
-
-This reverts commit 546047688e1c64638f462147c755b58119cabdc8.
-
-This is a rhel ony patch. We have sent patch to upstream. But
-it hasn't been merged. We will remove this patch once upstream
-merges our patch.
-
-Signed-off-by: Xiao Ni <xni@redhat.com>
----
- ReadMe.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/ReadMe.c b/ReadMe.c
-index 81399765..ee457a54 100644
---- a/ReadMe.c
-+++ b/ReadMe.c
-@@ -81,11 +81,11 @@ char Version[] = "mdadm - v" VERSION " - " VERS_DATE EXTRAVERSION "\n";
-  *     found, it is started.
-  */
- 
--char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:r:n:x:u:c:d:z:U:N:safRSow1tye:k";
-+char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
- char short_bitmap_options[]=
--		"-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:r:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
-+		"-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
- char short_bitmap_auto_options[]=
--		"-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:r:n:x:u:c:d:z:U:N:sa:rfRSow1tye:k:";
-+		"-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sa:rfRSow1tye:k:";
- 
- struct option long_options[] = {
-     {"manage",    0, 0, ManageOpt},
--- 
-2.31.1
-
diff --git a/SOURCES/0001-Unify-error-message.patch b/SOURCES/0001-Unify-error-message.patch
new file mode 100644
index 0000000..b4ceb95
--- /dev/null
+++ b/SOURCES/0001-Unify-error-message.patch
@@ -0,0 +1,47 @@
+From f1cc8ab9ab6a92c3cd94ab7590b46285e214681e Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Tue, 15 Mar 2022 09:30:30 +0100
+Subject: [PATCH 01/12] Unify error message.
+
+Provide the same error message for the same error that can occur in Grow.c and super-intel.c.
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Grow.c        | 4 ++--
+ super-intel.c | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index 9c6fc95e..9a947204 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1001,8 +1001,8 @@ int remove_disks_for_takeover(struct supertype *st,
+ 				rv = 1;
+ 			sysfs_free(arrays);
+ 			if (rv) {
+-				pr_err("Error. Cannot perform operation on /dev/%s\n", st->devnm);
+-				pr_err("For this operation it MUST be single array in container\n");
++				pr_err("Error. Cannot perform operation on %s- for this operation "
++				       "it MUST be single array in container\n", st->devnm);
+ 				return rv;
+ 			}
+ 		}
+diff --git a/super-intel.c b/super-intel.c
+index d5fad102..5ffa7636 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -11683,8 +11683,8 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 		struct imsm_super *mpb = super->anchor;
+ 
+ 		if (mpb->num_raid_devs > 1) {
+-			pr_err("Error. Cannot perform operation on %s- for this operation it MUST be single array in container\n",
+-			       geo->dev_name);
++			pr_err("Error. Cannot perform operation on %s- for this operation "
++			       "it MUST be single array in container\n", geo->dev_name);
+ 			change = -1;
+ 		}
+ 	}
+-- 
+2.31.1
+
diff --git a/SOURCES/0002-mdadm-Fix-double-free.patch b/SOURCES/0002-mdadm-Fix-double-free.patch
new file mode 100644
index 0000000..d3e1db1
--- /dev/null
+++ b/SOURCES/0002-mdadm-Fix-double-free.patch
@@ -0,0 +1,33 @@
+From 5ce5a15f0bf007e850e15259bba4f53736605fb2 Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Fri, 25 Mar 2022 12:48:59 +0100
+Subject: [PATCH 02/12] mdadm: Fix double free
+
+If there was a size mismatch after creation it would get fixed on grow
+in imsm_fix_size_mismatch(), but due to double free "double free or corruption (fasttop)"
+error occurs and grow cannot proceed.
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 5ffa7636..6ff336ee 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -11783,9 +11783,8 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
+ 			st->update_tail = &st->updates;
+ 		} else {
+ 			imsm_sync_metadata(st);
++			free(update);
+ 		}
+-
+-		free(update);
+ 	}
+ 	ret_val = 0;
+ exit:
+-- 
+2.31.1
+
diff --git a/SOURCES/0003-Grow_reshape-Add-r0-grow-size-error-message-and-upda.patch b/SOURCES/0003-Grow_reshape-Add-r0-grow-size-error-message-and-upda.patch
new file mode 100644
index 0000000..a36866b
--- /dev/null
+++ b/SOURCES/0003-Grow_reshape-Add-r0-grow-size-error-message-and-upda.patch
@@ -0,0 +1,83 @@
+From fea026b4849182fc8413014c81456e7215af28d9 Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Wed, 23 Mar 2022 15:05:19 +0100
+Subject: [PATCH 03/12] Grow_reshape: Add r0 grow size error message and update
+ man
+
+Grow size on r0 is not supported for imsm and native metadata.
+Add proper error message.
+Update man for proper use of --size.
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Grow.c     |  6 ++++++
+ mdadm.8.in | 19 ++++++++++++-------
+ 2 files changed, 18 insertions(+), 7 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index 9a947204..aa72490b 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1998,6 +1998,12 @@ int Grow_reshape(char *devname, int fd,
+ 			goto release;
+ 		}
+ 
++		if (array.level == 0) {
++			pr_err("Component size change is not supported for RAID0\n");
++			rv = 1;
++			goto release;
++		}
++
+ 		if (reshape_super(st, s->size, UnSet, UnSet, 0, 0, UnSet, NULL,
+ 				  devname, APPLY_METADATA_CHANGES,
+ 				  c->verbose > 0)) {
+diff --git a/mdadm.8.in b/mdadm.8.in
+index be902dba..e2a42425 100644
+--- a/mdadm.8.in
++++ b/mdadm.8.in
+@@ -459,7 +459,8 @@ number of spare devices.
+ 
+ .TP
+ .BR \-z ", " \-\-size=
+-Amount (in Kilobytes) of space to use from each drive in RAID levels 1/4/5/6.
++Amount (in Kilobytes) of space to use from each drive in RAID levels 1/4/5/6/10
++and for RAID 0 on external metadata.
+ This must be a multiple of the chunk size, and must leave about 128Kb
+ of space at the end of the drive for the RAID superblock.
+ If this is not specified
+@@ -478,10 +479,19 @@ To guard against this it can be useful to set the initial size
+ slightly smaller than the smaller device with the aim that it will
+ still be larger than any replacement.
+ 
++This option can be used with
++.B \-\-create
++for determining initial size of an array. For external metadata,
++it can be used on a volume, but not on a container itself.
++Setting initial size of
++.B RAID 0
++array is only valid for external metadata.
++
+ This value can be set with
+ .B \-\-grow
+-for RAID level 1/4/5/6 though
++for RAID level 1/4/5/6/10 though
+ DDF arrays may not be able to support this.
++RAID 0 array size cannot be changed.
+ If the array was created with a size smaller than the currently
+ active drives, the extra space can be accessed using
+ .BR \-\-grow .
+@@ -501,11 +511,6 @@ problems the array can be made bigger again with no loss with another
+ .B "\-\-grow \-\-size="
+ command.
+ 
+-This value cannot be used when creating a
+-.B CONTAINER
+-such as with DDF and IMSM metadata, though it perfectly valid when
+-creating an array inside a container.
+-
+ .TP
+ .BR \-Z ", " \-\-array\-size=
+ This is only meaningful with
+-- 
+2.31.1
+
diff --git a/SOURCES/0004-udev-adapt-rules-to-systemd-v247.patch b/SOURCES/0004-udev-adapt-rules-to-systemd-v247.patch
new file mode 100644
index 0000000..c1bcb29
--- /dev/null
+++ b/SOURCES/0004-udev-adapt-rules-to-systemd-v247.patch
@@ -0,0 +1,67 @@
+From cf9a109209aad285372b67306d54118af6fc522b Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Fri, 14 Jan 2022 16:44:33 +0100
+Subject: [PATCH 04/12] udev: adapt rules to systemd v247
+
+New events have been added in kernel 4.14 ("bind" and "unbind").
+Systemd maintainer suggests to modify "add|change" branches.
+This patches implements their suggestions. There is no issue yet because
+new event types are not used in md.
+
+Please see systemd announcement for details[1].
+
+[1] https://lists.freedesktop.org/archives/systemd-devel/2020-November/045646.html
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ udev-md-raid-arrays.rules        | 2 +-
+ udev-md-raid-assembly.rules      | 5 +++--
+ udev-md-raid-safe-timeouts.rules | 2 +-
+ 3 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/udev-md-raid-arrays.rules b/udev-md-raid-arrays.rules
+index 13c9076e..2967ace1 100644
+--- a/udev-md-raid-arrays.rules
++++ b/udev-md-raid-arrays.rules
+@@ -3,7 +3,7 @@
+ SUBSYSTEM!="block", GOTO="md_end"
+ 
+ # handle md arrays
+-ACTION!="add|change", GOTO="md_end"
++ACTION=="remove", GOTO="md_end"
+ KERNEL!="md*", GOTO="md_end"
+ 
+ # partitions have no md/{array_state,metadata_version}, but should not
+diff --git a/udev-md-raid-assembly.rules b/udev-md-raid-assembly.rules
+index d668cddd..39b4344b 100644
+--- a/udev-md-raid-assembly.rules
++++ b/udev-md-raid-assembly.rules
+@@ -30,8 +30,9 @@ LABEL="md_inc"
+ 
+ # remember you can limit what gets auto/incrementally assembled by
+ # mdadm.conf(5)'s 'AUTO' and selectively whitelist using 'ARRAY'
+-ACTION=="add|change", IMPORT{program}="BINDIR/mdadm --incremental --export $devnode --offroot $env{DEVLINKS}"
+-ACTION=="add|change", ENV{MD_STARTED}=="*unsafe*", ENV{MD_FOREIGN}=="no", ENV{SYSTEMD_WANTS}+="mdadm-last-resort@$env{MD_DEVICE}.timer"
++ACTION!="remove", IMPORT{program}="BINDIR/mdadm --incremental --export $devnode --offroot $env{DEVLINKS}"
++ACTION!="remove", ENV{MD_STARTED}=="*unsafe*", ENV{MD_FOREIGN}=="no", ENV{SYSTEMD_WANTS}+="mdadm-last-resort@$env{MD_DEVICE}.timer"
++
+ ACTION=="remove", ENV{ID_PATH}=="?*", RUN+="BINDIR/mdadm -If $name --path $env{ID_PATH}"
+ ACTION=="remove", ENV{ID_PATH}!="?*", RUN+="BINDIR/mdadm -If $name"
+ 
+diff --git a/udev-md-raid-safe-timeouts.rules b/udev-md-raid-safe-timeouts.rules
+index 12bdcaa8..2e185cee 100644
+--- a/udev-md-raid-safe-timeouts.rules
++++ b/udev-md-raid-safe-timeouts.rules
+@@ -50,7 +50,7 @@ ENV{DEVTYPE}!="partition", GOTO="md_timeouts_end"
+ 
+ IMPORT{program}="/sbin/mdadm --examine --export $devnode"
+ 
+-ACTION=="add|change", \
++ACTION!="remove", \
+   ENV{ID_FS_TYPE}=="linux_raid_member", \
+   ENV{MD_LEVEL}=="raid[1-9]*", \
+   TEST=="/sys/block/$parent/device/timeout", \
+-- 
+2.31.1
+
diff --git a/SOURCES/0005-Replace-error-prone-signal-with-sigaction.patch b/SOURCES/0005-Replace-error-prone-signal-with-sigaction.patch
new file mode 100644
index 0000000..34552bb
--- /dev/null
+++ b/SOURCES/0005-Replace-error-prone-signal-with-sigaction.patch
@@ -0,0 +1,252 @@
+From 83a379cfbd283b387919fe05d44eb4c49e155ad6 Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Mon, 21 Feb 2022 13:05:20 +0100
+Subject: [PATCH 05/12] Replace error prone signal() with sigaction()
+
+Up to this date signal() was used which implementation could vary [1].
+Sigaction() call is preferred. This commit introduces replacement
+from signal() to sigaction() by the use of signal_s() wrapper.
+Also remove redundant signal.h header includes.
+
+[1] https://man7.org/linux/man-pages/man2/signal.2.html
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Grow.c       |  4 ++--
+ Monitor.c    |  5 +++--
+ managemon.c  |  1 -
+ mdadm.h      | 22 ++++++++++++++++++++++
+ mdmon.c      |  1 -
+ monitor.c    |  1 -
+ probe_roms.c |  6 +++---
+ raid6check.c | 25 +++++++++++++++----------
+ util.c       |  1 -
+ 9 files changed, 45 insertions(+), 21 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index aa72490b..18c5719b 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -26,7 +26,6 @@
+ #include	<sys/mman.h>
+ #include	<stddef.h>
+ #include	<stdint.h>
+-#include	<signal.h>
+ #include	<sys/wait.h>
+ 
+ #if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN)
+@@ -3566,7 +3565,8 @@ started:
+ 		fd = -1;
+ 	mlockall(MCL_FUTURE);
+ 
+-	signal(SIGTERM, catch_term);
++	if (signal_s(SIGTERM, catch_term) == SIG_ERR)
++		goto release;
+ 
+ 	if (st->ss->external) {
+ 		/* metadata handler takes it from here */
+diff --git a/Monitor.c b/Monitor.c
+index 30c031a2..c0ab5412 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -26,7 +26,6 @@
+ #include	"md_p.h"
+ #include	"md_u.h"
+ #include	<sys/wait.h>
+-#include	<signal.h>
+ #include	<limits.h>
+ #include	<syslog.h>
+ #ifndef NO_LIBUDEV
+@@ -435,8 +434,10 @@ static void alert(char *event, char *dev, char *disc, struct alert_info *info)
+ 		if (mp) {
+ 			FILE *mdstat;
+ 			char hname[256];
++
+ 			gethostname(hname, sizeof(hname));
+-			signal(SIGPIPE, SIG_IGN);
++			signal_s(SIGPIPE, SIG_IGN);
++
+ 			if (info->mailfrom)
+ 				fprintf(mp, "From: %s\n", info->mailfrom);
+ 			else
+diff --git a/managemon.c b/managemon.c
+index bb7334cf..0e9bdf00 100644
+--- a/managemon.c
++++ b/managemon.c
+@@ -106,7 +106,6 @@
+ #include	"mdmon.h"
+ #include	<sys/syscall.h>
+ #include	<sys/socket.h>
+-#include	<signal.h>
+ 
+ static void close_aa(struct active_array *aa)
+ {
+diff --git a/mdadm.h b/mdadm.h
+index c7268a71..26e7e5cd 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -46,6 +46,7 @@ extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
+ #include	<string.h>
+ #include	<syslog.h>
+ #include	<stdbool.h>
++#include	<signal.h>
+ /* Newer glibc requires sys/sysmacros.h directly for makedev() */
+ #include	<sys/sysmacros.h>
+ #ifdef __dietlibc__
+@@ -1729,6 +1730,27 @@ static inline char *to_subarray(struct mdstat_ent *ent, char *container)
+ 	return &ent->metadata_version[10+strlen(container)+1];
+ }
+ 
++/**
++ * signal_s() - Wrapper for sigaction() with signal()-like interface.
++ * @sig: The signal to set the signal handler to.
++ * @handler: The signal handler.
++ *
++ * Return: previous handler or SIG_ERR on failure.
++ */
++static inline sighandler_t signal_s(int sig, sighandler_t handler)
++{
++	struct sigaction new_act;
++	struct sigaction old_act;
++
++	new_act.sa_handler = handler;
++	new_act.sa_flags = 0;
++
++	if (sigaction(sig, &new_act, &old_act) == 0)
++		return old_act.sa_handler;
++
++	return SIG_ERR;
++}
++
+ #ifdef DEBUG
+ #define dprintf(fmt, arg...) \
+ 	fprintf(stderr, "%s: %s: "fmt, Name, __func__, ##arg)
+diff --git a/mdmon.c b/mdmon.c
+index c71e62c6..5570574b 100644
+--- a/mdmon.c
++++ b/mdmon.c
+@@ -56,7 +56,6 @@
+ #include	<errno.h>
+ #include	<string.h>
+ #include	<fcntl.h>
+-#include	<signal.h>
+ #include	<dirent.h>
+ #ifdef USE_PTHREADS
+ #include	<pthread.h>
+diff --git a/monitor.c b/monitor.c
+index e0d3be67..b877e595 100644
+--- a/monitor.c
++++ b/monitor.c
+@@ -22,7 +22,6 @@
+ #include "mdmon.h"
+ #include <sys/syscall.h>
+ #include <sys/select.h>
+-#include <signal.h>
+ 
+ static char *array_states[] = {
+ 	"clear", "inactive", "suspended", "readonly", "read-auto",
+diff --git a/probe_roms.c b/probe_roms.c
+index 7ea04c7a..94c80c2c 100644
+--- a/probe_roms.c
++++ b/probe_roms.c
+@@ -22,7 +22,6 @@
+ #include "probe_roms.h"
+ #include "mdadm.h"
+ #include <unistd.h>
+-#include <signal.h>
+ #include <fcntl.h>
+ #include <sys/mman.h>
+ #include <sys/stat.h>
+@@ -69,7 +68,8 @@ static int probe_address16(const __u16 *ptr, __u16 *val)
+ 
+ void probe_roms_exit(void)
+ {
+-	signal(SIGBUS, SIG_DFL);
++	signal_s(SIGBUS, SIG_DFL);
++
+ 	if (rom_fd >= 0) {
+ 		close(rom_fd);
+ 		rom_fd = -1;
+@@ -98,7 +98,7 @@ int probe_roms_init(unsigned long align)
+ 	if (roms_init())
+ 		return -1;
+ 
+-	if (signal(SIGBUS, sigbus) == SIG_ERR)
++	if (signal_s(SIGBUS, sigbus) == SIG_ERR)
+ 		rc = -1;
+ 	if (rc == 0) {
+ 		fd = open("/dev/mem", O_RDONLY);
+diff --git a/raid6check.c b/raid6check.c
+index a8e6005b..99477761 100644
+--- a/raid6check.c
++++ b/raid6check.c
+@@ -24,7 +24,6 @@
+ 
+ #include "mdadm.h"
+ #include <stdint.h>
+-#include <signal.h>
+ #include <sys/mman.h>
+ 
+ #define CHECK_PAGE_BITS (12)
+@@ -130,30 +129,36 @@ void raid6_stats(int *disk, int *results, int raid_disks, int chunk_size)
+ }
+ 
+ int lock_stripe(struct mdinfo *info, unsigned long long start,
+-		int chunk_size, int data_disks, sighandler_t *sig) {
++		int chunk_size, int data_disks, sighandler_t *sig)
++{
+ 	int rv;
++
++	sig[0] = signal_s(SIGTERM, SIG_IGN);
++	sig[1] = signal_s(SIGINT, SIG_IGN);
++	sig[2] = signal_s(SIGQUIT, SIG_IGN);
++
++	if (sig[0] == SIG_ERR || sig[1] == SIG_ERR || sig[2] == SIG_ERR)
++		return 1;
++
+ 	if(mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
+ 		return 2;
+ 	}
+ 
+-	sig[0] = signal(SIGTERM, SIG_IGN);
+-	sig[1] = signal(SIGINT, SIG_IGN);
+-	sig[2] = signal(SIGQUIT, SIG_IGN);
+-
+ 	rv = sysfs_set_num(info, NULL, "suspend_lo", start * chunk_size * data_disks);
+ 	rv |= sysfs_set_num(info, NULL, "suspend_hi", (start + 1) * chunk_size * data_disks);
+ 	return rv * 256;
+ }
+ 
+-int unlock_all_stripes(struct mdinfo *info, sighandler_t *sig) {
++int unlock_all_stripes(struct mdinfo *info, sighandler_t *sig)
++{
+ 	int rv;
+ 	rv = sysfs_set_num(info, NULL, "suspend_lo", 0x7FFFFFFFFFFFFFFFULL);
+ 	rv |= sysfs_set_num(info, NULL, "suspend_hi", 0);
+ 	rv |= sysfs_set_num(info, NULL, "suspend_lo", 0);
+ 
+-	signal(SIGQUIT, sig[2]);
+-	signal(SIGINT, sig[1]);
+-	signal(SIGTERM, sig[0]);
++	signal_s(SIGQUIT, sig[2]);
++	signal_s(SIGINT, sig[1]);
++	signal_s(SIGTERM, sig[0]);
+ 
+ 	if(munlockall() != 0)
+ 		return 3;
+diff --git a/util.c b/util.c
+index 3d05d074..cc94f96e 100644
+--- a/util.c
++++ b/util.c
+@@ -35,7 +35,6 @@
+ #include	<poll.h>
+ #include	<ctype.h>
+ #include	<dirent.h>
+-#include	<signal.h>
+ #include	<dlfcn.h>
+ 
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0006-mdadm-Respect-config-file-location-in-man.patch b/SOURCES/0006-mdadm-Respect-config-file-location-in-man.patch
new file mode 100644
index 0000000..c5885b6
--- /dev/null
+++ b/SOURCES/0006-mdadm-Respect-config-file-location-in-man.patch
@@ -0,0 +1,1533 @@
+From e9dd5644843e2013a7dd1a8a5da2b9fa35837416 Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Fri, 18 Mar 2022 09:26:04 +0100
+Subject: [PATCH 06/12] mdadm: Respect config file location in man
+
+Default config file location could differ depending on OS (e.g. Debian family).
+This patch takes default config file into consideration when creating mdadm.man
+file as well as mdadm.conf.man.
+
+Rename mdadm.conf.5 to mdadm.conf.5.in. Now mdadm.conf.5 is generated automatically.
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ .gitignore      |   1 +
+ Makefile        |   7 +-
+ mdadm.8.in      |  16 +-
+ mdadm.conf.5    | 706 ------------------------------------------------
+ mdadm.conf.5.in | 706 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 721 insertions(+), 715 deletions(-)
+ delete mode 100644 mdadm.conf.5
+ create mode 100644 mdadm.conf.5.in
+
+diff --git a/.gitignore b/.gitignore
+index 217fe76d..8d791c6f 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -3,6 +3,7 @@
+ /*-stamp
+ /mdadm
+ /mdadm.8
++/mdadm.conf.5
+ /mdadm.udeb
+ /mdassemble
+ /mdmon
+diff --git a/Makefile b/Makefile
+index 2a51d813..bf126033 100644
+--- a/Makefile
++++ b/Makefile
+@@ -227,7 +227,12 @@ raid6check : raid6check.o mdadm.h $(CHECK_OBJS)
+ 
+ mdadm.8 : mdadm.8.in
+ 	sed -e 's/{DEFAULT_METADATA}/$(DEFAULT_METADATA)/g' \
+-	-e 's,{MAP_PATH},$(MAP_PATH),g'  mdadm.8.in > mdadm.8
++	-e 's,{MAP_PATH},$(MAP_PATH),g' -e 's,{CONFFILE},$(CONFFILE),g' \
++	-e 's,{CONFFILE2},$(CONFFILE2),g'  mdadm.8.in > mdadm.8
++
++mdadm.conf.5 : mdadm.conf.5.in
++	sed -e 's,{CONFFILE},$(CONFFILE),g' \
++	-e 's,{CONFFILE2},$(CONFFILE2),g'  mdadm.conf.5.in > mdadm.conf.5
+ 
+ mdadm.man : mdadm.8
+ 	man -l mdadm.8 > mdadm.man
+diff --git a/mdadm.8.in b/mdadm.8.in
+index e2a42425..8b21ffd4 100644
+--- a/mdadm.8.in
++++ b/mdadm.8.in
+@@ -267,13 +267,13 @@ the exact meaning of this option in different contexts.
+ .TP
+ .BR \-c ", " \-\-config=
+ Specify the config file or directory.  Default is to use
+-.B /etc/mdadm.conf
++.B {CONFFILE}
+ and
+-.BR /etc/mdadm.conf.d ,
++.BR {CONFFILE}.d ,
+ or if those are missing then
+-.B /etc/mdadm/mdadm.conf
++.B {CONFFILE2}
+ and
+-.BR /etc/mdadm/mdadm.conf.d .
++.BR {CONFFILE2}.d .
+ If the config file given is
+ .B "partitions"
+ then nothing will be read, but
+@@ -2014,9 +2014,9 @@ The config file is only used if explicitly named with
+ or requested with (a possibly implicit)
+ .BR \-\-scan .
+ In the later case,
+-.B /etc/mdadm.conf
++.B {CONFFILE}
+ or
+-.B /etc/mdadm/mdadm.conf
++.B {CONFFILE2}
+ is used.
+ 
+ If
+@@ -3344,7 +3344,7 @@ uses this to find arrays when
+ is given in Misc mode, and to monitor array reconstruction
+ on Monitor mode.
+ 
+-.SS /etc/mdadm.conf
++.SS {CONFFILE} (or {CONFFILE2})
+ 
+ The config file lists which devices may be scanned to see if
+ they contain MD super block, and gives identifying information
+@@ -3352,7 +3352,7 @@ they contain MD super block, and gives identifying information
+ .BR mdadm.conf (5)
+ for more details.
+ 
+-.SS /etc/mdadm.conf.d
++.SS {CONFFILE}.d (or {CONFFILE2}.d)
+ 
+ A directory containing configuration files which are read in lexical
+ order.
+diff --git a/mdadm.conf.5 b/mdadm.conf.5
+deleted file mode 100644
+index 74a21c5f..00000000
+--- a/mdadm.conf.5
++++ /dev/null
+@@ -1,706 +0,0 @@
+-.\" Copyright Neil Brown and others.
+-.\"   This program is free software; you can redistribute it and/or modify
+-.\"   it under the terms of the GNU General Public License as published by
+-.\"   the Free Software Foundation; either version 2 of the License, or
+-.\"   (at your option) any later version.
+-.\" See file COPYING in distribution for details.
+-.TH MDADM.CONF 5
+-.SH NAME
+-mdadm.conf \- configuration for management of Software RAID with mdadm
+-.SH SYNOPSIS
+-/etc/mdadm.conf
+-.SH DESCRIPTION
+-.PP
+-.I mdadm
+-is a tool for creating, managing, and monitoring RAID devices using the
+-.B md
+-driver in Linux.
+-.PP
+-Some common tasks, such as assembling all arrays, can be simplified
+-by describing the devices and arrays in this configuration file.
+-
+-.SS SYNTAX
+-The file should be seen as a collection of words separated by white
+-space (space, tab, or newline).
+-Any word that beings with a hash sign (#) starts a comment and that
+-word together with the remainder of the line is ignored.
+-
+-Spaces can be included in a word using quotation characters.  Either
+-single quotes
+-.RB ( ' )
+-or double quotes (\fB"\fP)
+-may be used.  All the characters from one quotation character to
+-next identical character are protected and will not be used to
+-separate words to start new quoted strings.  To include a single quote
+-it must be between double quotes.  To include a double quote it must
+-be between single quotes.
+-
+-Any line that starts with white space (space or tab) is treated as
+-though it were a continuation of the previous line.
+-
+-Empty lines are ignored, but otherwise each (non continuation) line
+-must start with a keyword as listed below.  The keywords are case
+-insensitive and can be abbreviated to 3 characters.
+-
+-The keywords are:
+-.TP
+-.B DEVICE
+-A
+-.B device
+-line lists the devices (whole devices or partitions) that might contain
+-a component of an MD array.  When looking for the components of an
+-array,
+-.I mdadm
+-will scan these devices (or any devices listed on the command line).
+-
+-The
+-.B device
+-line may contain a number of different devices (separated by spaces)
+-and each device name can contain wild cards as defined by
+-.BR glob (7).
+-
+-Also, there may be several device lines present in the file.
+-
+-Alternatively, a
+-.B device
+-line can contain either or both of the  words
+-.B containers
+-and
+-.BR partitions .
+-The word
+-.B containers
+-will cause
+-.I mdadm
+-to look for assembled CONTAINER arrays and included them as a source
+-for assembling further arrays.
+-
+-The word
+-.I partitions
+-will cause
+-.I mdadm
+-to read
+-.I /proc/partitions
+-and include all devices and partitions found therein.
+-.I mdadm
+-does not use the names from
+-.I /proc/partitions
+-but only the major and minor device numbers.  It scans
+-.I /dev
+-to find the name that matches the numbers.
+-
+-If no DEVICE line is present, then "DEVICE partitions containers" is assumed.
+-
+-For example:
+-.IP
+-DEVICE /dev/hda* /dev/hdc*
+-.br
+-DEV    /dev/sd*
+-.br
+-DEVICE /dev/disk/by-path/pci*
+-.br
+-DEVICE partitions
+-
+-.TP
+-.B ARRAY
+-The ARRAY lines identify actual arrays.  The second word on the line
+-may be the name of the device where the array is normally
+-assembled, such as
+-.B /dev/md1
+-or
+-.BR /dev/md/backup .
+-If the name does not start with a slash
+-.RB (' / '),
+-it is treated as being in
+-.BR /dev/md/ .
+-Alternately the word
+-.B <ignore>
+-(complete with angle brackets) can be given in which case any array
+-which matches the rest of the line will never be automatically assembled.
+-If no device name is given,
+-.I mdadm
+-will use various heuristics to determine an appropriate name.
+-
+-Subsequent words identify the array, or identify the array as a member
+-of a group. If multiple identities are given,
+-then a component device must match ALL identities to be considered a
+-match.  Each identity word has a tag, and equals sign, and some value.
+-The tags are:
+-.RS 4
+-.TP
+-.B uuid=
+-The value should be a 128 bit uuid in hexadecimal, with punctuation
+-interspersed if desired.  This must match the uuid stored in the
+-superblock.
+-.TP
+-.B name=
+-The value should be a simple textual name as was given to
+-.I mdadm
+-when the array was created.  This must match the name stored in the
+-superblock on a device for that device to be included in the array.
+-Not all superblock formats support names.
+-.TP
+-.B super\-minor=
+-The value is an integer which indicates the minor number that was
+-stored in the superblock when the array was created. When an array is
+-created as /dev/mdX, then the minor number X is stored.
+-.TP
+-.B devices=
+-The value is a comma separated list of device names or device name
+-patterns.
+-Only devices with names which match one entry in the list will be used
+-to assemble the array.  Note that the devices
+-listed there must also be listed on a DEVICE line.
+-.TP
+-.B level=
+-The value is a RAID level.  This is not normally used to
+-identify an array, but is supported so that the output of
+-
+-.B "mdadm \-\-examine \-\-scan"
+-
+-can be use directly in the configuration file.
+-.TP
+-.B num\-devices=
+-The value is the number of devices in a complete active array.  As with
+-.B level=
+-this is mainly for compatibility with the output of
+-
+-.BR "mdadm \-\-examine \-\-scan" .
+-
+-.TP
+-.B spares=
+-The value is a number of spare devices to expect the array to have.
+-The sole use of this keyword and value is as follows:
+-.B mdadm \-\-monitor
+-will report an array if it is found to have fewer than this number of
+-spares when
+-.B \-\-monitor
+-starts or when
+-.B \-\-oneshot
+-is used.
+-
+-.TP
+-.B spare\-group=
+-The value is a textual name for a group of arrays.  All arrays with
+-the same
+-.B spare\-group
+-name are considered to be part of the same group.  The significance of
+-a group of arrays is that
+-.I mdadm
+-will, when monitoring the arrays, move a spare drive from one array in
+-a group to another array in that group if the first array had a failed
+-or missing drive but no spare.
+-
+-.TP
+-.B auto=
+-This option is rarely needed with mdadm-3.0, particularly if use with
+-the Linux kernel v2.6.28 or later.
+-It tells
+-.I mdadm
+-whether to use partitionable array or non-partitionable arrays and,
+-in the absence of
+-.IR udev ,
+-how many partition devices to create.  From 2.6.28 all md array
+-devices are partitionable, hence this option is not needed.
+-
+-The value of this option can be "yes" or "md" to indicate that a
+-traditional, non-partitionable md array should be created, or "mdp",
+-"part" or "partition" to indicate that a partitionable md array (only
+-available in linux 2.6 and later) should be used.  This later set can
+-also have a number appended to indicate how many partitions to create
+-device files for, e.g.
+-.BR auto=mdp5 .
+-The default is 4.
+-
+-.TP
+-.B bitmap=
+-The option specifies a file in which a write-intent bitmap should be
+-found.  When assembling the array,
+-.I mdadm
+-will provide this file to the
+-.B md
+-driver as the bitmap file.  This has the same function as the
+-.B \-\-bitmap\-file
+-option to
+-.BR \-\-assemble .
+-
+-.TP
+-.B metadata=
+-Specify the metadata format that the array has.  This is mainly
+-recognised for comparability with the output of
+-.BR "mdadm \-Es" .
+-
+-.TP
+-.B container=
+-Specify that this array is a member array of some container.  The
+-value given can be either a path name in /dev, or a UUID of the
+-container array.
+-
+-.TP
+-.B member=
+-Specify that this array is a member array of some container.  Each
+-type of container has some way to enumerate member arrays, often a
+-simple sequence number.  The value identifies which member of a
+-container the array is.  It will usually accompany a "container=" word.
+-.RE
+-
+-.TP
+-.B MAILADDR
+-The
+-.B mailaddr
+-line gives an E-mail address that alerts should be
+-sent to when
+-.I mdadm
+-is running in
+-.B \-\-monitor
+-mode (and was given the
+-.B \-\-scan
+-option).  There should only be one
+-.B MAILADDR
+-line and it should have only one address.  Any subsequent addresses
+-are silently ignored.
+-
+-.TP
+-.B MAILFROM
+-The
+-.B mailfrom
+-line (which can only be abbreviated to at least 5 characters) gives an
+-address to appear in the "From" address for alert mails.  This can be
+-useful if you want to explicitly set a domain, as the default from
+-address is "root" with no domain.  All words on this line are
+-catenated with spaces to form the address.
+-
+-Note that this value cannot be set via the
+-.I mdadm
+-commandline.  It is only settable via the config file.
+-
+-.TP
+-.B PROGRAM
+-The
+-.B program
+-line gives the name of a program to be run when
+-.B "mdadm \-\-monitor"
+-detects potentially interesting events on any of the arrays that it
+-is monitoring.  This program gets run with two or three arguments, they
+-being the Event, the md device, and possibly the related component
+-device.
+-
+-There should only be one
+-.B program
+-line and it should be give only one program.
+-
+-
+-.TP
+-.B CREATE
+-The
+-.B create
+-line gives default values to be used when creating arrays, new members
+-of arrays, and device entries for arrays.
+-These include:
+-
+-.RS 4
+-.TP
+-.B owner=
+-.TP
+-.B group=
+-These can give user/group ids or names to use instead of system
+-defaults (root/wheel or root/disk).
+-.TP
+-.B mode=
+-An octal file mode such as 0660 can be given to override the default
+-of 0600.
+-.TP
+-.B auto=
+-This corresponds to the
+-.B \-\-auto
+-flag to mdadm.  Give
+-.BR yes ,
+-.BR md ,
+-.BR mdp ,
+-.B part
+-\(em possibly followed by a number of partitions \(em to indicate how
+-missing device entries should be created.
+-
+-.TP
+-.B metadata=
+-The name of the metadata format to use if none is explicitly given.
+-This can be useful to impose a system-wide default of version-1 superblocks.
+-
+-.TP
+-.B symlinks=no
+-Normally when creating devices in
+-.B /dev/md/
+-.I mdadm
+-will create a matching symlink from
+-.B /dev/
+-with a name starting
+-.B md
+-or
+-.BR md_ .
+-Give
+-.B symlinks=no
+-to suppress this symlink creation.
+-
+-.TP
+-.B names=yes
+-Since Linux 2.6.29 it has been possible to create
+-.B md
+-devices with a name like
+-.B md_home
+-rather than just a number, like
+-.BR md3 .
+-.I mdadm
+-will use the numeric alternative by default as other tools that interact
+-with md arrays may expect only numbers.
+-If
+-.B names=yes
+-is given in
+-.I mdadm.conf
+-then
+-.I mdadm
+-will use a name when appropriate.
+-If
+-.B names=no
+-is given, then non-numeric
+-.I md
+-device names will not be used even if the default changes in a future
+-release of
+-.IR mdadm .
+-
+-.TP
+-.B bbl=no
+-By default,
+-.I mdadm
+-will reserve space for a bad block list (bbl) on all devices
+-included in or added to any array that supports them.  Setting
+-.B bbl=no
+-will prevent this, so newly added devices will not have a bad
+-block log.
+-.RE
+-
+-.TP
+-.B HOMEHOST
+-The
+-.B homehost
+-line gives a default value for the
+-.B \-\-homehost=
+-option to mdadm.  There should normally be only one other word on the line.
+-It should either be a host name, or one of the special words
+-.BR <system>,
+-.B <none>
+-and
+-.BR <ignore> .
+-If
+-.B <system>
+-is given, then the
+-.BR gethostname ( 2 )
+-systemcall is used to get the host name.  This is the default.
+-
+-If
+-.B <ignore>
+-is given, then a flag is set so that when arrays are being
+-auto-assembled the checking of the recorded
+-.I homehost
+-is disabled.
+-If
+-.B <ignore>
+-is given it is also possible to give an explicit name which will be
+-used when creating arrays.  This is the only case when there can be
+-more that one other word on the
+-.B HOMEHOST
+-line.  If there are other words, or other
+-.B HOMEHOST
+-lines, they are silently ignored.
+-
+-If
+-.B <none>
+-is given, then the default of using
+-.BR gethostname ( 2 )
+-is over-ridden and no homehost name is assumed.
+-
+-When arrays are created, this host name will be stored in the
+-metadata.  When arrays are assembled using auto-assembly, arrays which
+-do not record the correct homehost name in their metadata will be
+-assembled using a "foreign" name.  A "foreign" name alway ends with a
+-digit string preceded by an underscore to differentiate it
+-from any possible local name. e.g.
+-.B /dev/md/1_1
+-or
+-.BR /dev/md/home_0 .
+-.TP
+-.B AUTO
+-A list of names of metadata format can be given, each preceded by a
+-plus or minus sign.  Also the word
+-.I homehost
+-is allowed as is
+-.I all
+-preceded by plus or minus sign.
+-.I all
+-is usually last.
+-
+-When
+-.I mdadm
+-is auto-assembling an array, either via
+-.I \-\-assemble
+-or
+-.I \-\-incremental
+-and it finds metadata of a given type, it checks that metadata type
+-against those listed in this line.  The first match wins, where
+-.I all
+-matches anything.
+-If a match is found that was preceded by a plus sign, the auto
+-assembly is allowed.  If the match was preceded by a minus sign, the
+-auto assembly is disallowed.  If no match is found, the auto assembly
+-is allowed.
+-
+-If the metadata indicates that the array was created for
+-.I this
+-host, and the word
+-.I homehost
+-appears before any other match, then the array is treated as a valid
+-candidate for auto-assembly.
+-
+-This can be used to disable all auto-assembly (so that only arrays
+-explicitly listed in mdadm.conf or on the command line are assembled),
+-or to disable assembly of certain metadata types which might be
+-handled by other software.  It can also be used to disable assembly of
+-all foreign arrays - normally such arrays are assembled but given a
+-non-deterministic name in
+-.BR /dev/md/ .
+-
+-The known metadata types are
+-.BR 0.90 ,
+-.BR 1.x ,
+-.BR ddf ,
+-.BR imsm .
+-
+-.B AUTO
+-should be given at most once.  Subsequent lines are silently ignored.
+-Thus an earlier config file in a config directory will over-ride
+-the setting in a later config file.
+-
+-.TP
+-.B POLICY
+-This is used to specify what automatic behavior is allowed on devices
+-newly appearing in the system and provides a way of marking spares that can
+-be moved to other arrays as well as the migration domains.
+-.I Domain
+-can be defined through
+-.I policy
+-line by specifying a domain name for a number of paths from
+-.BR /dev/disk/by-path/ .
+-A device may belong to several domains. The domain of an array is a union
+-of domains of all devices in that array.  A spare can be automatically
+-moved from one array to another if the set of the destination array's
+-.I domains
+-contains all the
+-.I domains
+-of the new disk or if both arrays have the same
+-.IR spare-group .
+-
+-To update hot plug configuration it is necessary to execute
+-.B mdadm \-\-udev\-rules
+-command after changing the config file
+-
+-Keywords used in the
+-.I POLICY
+-line and supported values are:
+-
+-.RS 4
+-.TP
+-.B domain=
+-any arbitrary string
+-.TP
+-.B metadata=
+-0.9 1.x ddf or imsm
+-.TP
+-.B path=
+-file glob matching anything from
+-.B /dev/disk/by-path
+-.TP
+-.B type=
+-either
+-.B disk
+-or
+-.BR part .
+-.TP
+-.B action=
+-include, re-add, spare, spare-same-slot, or force-spare
+-.TP
+-.B auto=
+-yes, no, or homehost.
+-
+-.P
+-The
+-.I action
+-item determines the automatic behavior allowed for devices matching the
+-.I path
+-and
+-.I type
+-in the same line.  If a device matches several lines with different
+-.I  actions
+-then the most permissive will apply. The ordering of policy lines
+-is irrelevant to the end result.
+-.TP
+-.B include
+-allows adding a disk to an array if metadata on that disk matches that array
+-.TP
+-.B re\-add
+-will include the device in the array if it appears to be a current member
+-or a member that was recently removed and the array has a
+-write-intent-bitmap to allow the
+-.B re\-add
+-functionality.
+-.TP
+-.B spare
+-as above and additionally: if the device is bare it can
+-become a spare if there is any array that it is a candidate for based
+-on domains and metadata.
+-.TP
+-.B spare\-same\-slot
+-as above and additionally if given slot was used by an array that went
+-degraded recently and the device plugged in has no metadata then it will
+-be automatically added to that array (or it's container)
+-.TP
+-.B force\-spare
+-as above and the disk will become a spare in remaining cases
+-.RE
+-
+-.TP
+-.B PART-POLICY
+-This is similar to
+-.B POLICY
+-and accepts the same keyword assignments.  It allows a consistent set
+-of policies to applied to each of the partitions of a device.
+-
+-A
+-.B PART-POLICY
+-line should set
+-.I type=disk
+-and identify the path to one or more disk devices.  Each partition on
+-these disks will be treated according to the
+-.I action=
+-setting  from this line.  If a
+-.I domain
+-is set in the line, then the domain associated with each patition will
+-be based on the domain, but with
+-.RB \(dq -part N\(dq
+-appended, when N is the partition number for the partition that was
+-found.
+-
+-.TP
+-.B SYSFS
+-The
+-.B SYSFS
+-line lists custom values of MD device's sysfs attributes which will be
+-stored in sysfs after the array is assembled. Multiple lines are allowed and each
+-line has to contain the uuid or the name of the device to which it relates.
+-.RS 4
+-.TP
+-.B uuid=
+-hexadecimal identifier of MD device. This has to match the uuid stored in the
+-superblock.
+-.TP
+-.B name=
+-name of the MD device as was given to
+-.I mdadm
+-when the array was created. It will be ignored if
+-.B uuid
+-is not empty.
+-.RE
+-
+-.TP
+-.B MONITORDELAY
+-The
+-.B monitordelay
+-line gives a delay in seconds
+-.I mdadm
+-shall wait before pooling md arrays
+-when
+-.I mdadm
+-is running in
+-.B \-\-monitor
+-mode.
+-.B \-d/\-\-delay
+-command line argument takes precedence over the config file
+-
+-.SH EXAMPLE
+-DEVICE /dev/sd[bcdjkl]1
+-.br
+-DEVICE /dev/hda1 /dev/hdb1
+-
+-# /dev/md0 is known by its UUID.
+-.br
+-ARRAY /dev/md0 UUID=3aaa0122:29827cfa:5331ad66:ca767371
+-.br
+-# /dev/md1 contains all devices with a minor number of
+-.br
+-#   1 in the superblock.
+-.br
+-ARRAY /dev/md1 superminor=1
+-.br
+-# /dev/md2 is made from precisely these two devices
+-.br
+-ARRAY /dev/md2 devices=/dev/hda1,/dev/hdb1
+-
+-# /dev/md4 and /dev/md5 are a spare-group and spares
+-.br
+-#  can be moved between them
+-.br
+-ARRAY /dev/md4 uuid=b23f3c6d:aec43a9f:fd65db85:369432df
+-.br
+-           spare\-group=group1
+-.br
+-ARRAY /dev/md5 uuid=19464854:03f71b1b:e0df2edd:246cc977
+-.br
+-           spare\-group=group1
+-.br
+-# /dev/md/home is created if need to be a partitionable md array
+-.br
+-# any spare device number is allocated.
+-.br
+-ARRAY /dev/md/home UUID=9187a482:5dde19d9:eea3cc4a:d646ab8b
+-.br
+-           auto=part
+-.br
+-# The name of this array contains a space.
+-.br
+-ARRAY /dev/md9 name='Data Storage'
+-.sp
+-POLICY domain=domain1 metadata=imsm path=pci-0000:00:1f.2-scsi-*
+-.br
+-           action=spare
+-.br
+-POLICY domain=domain1 metadata=imsm path=pci-0000:04:00.0-scsi-[01]*
+-.br
+-           action=include
+-.br
+-# One domain comprising of devices attached to specified paths is defined.
+-.br
+-# Bare device matching first path will be made an imsm spare on hot plug.
+-.br
+-# If more than one array is created on devices belonging to domain1 and
+-.br
+-# one of them becomes degraded, then any imsm spare matching any path for
+-.br
+-# given domain name can be migrated.
+-.br
+-MAILADDR root@mydomain.tld
+-.br
+-PROGRAM /usr/sbin/handle\-mdadm\-events
+-.br
+-CREATE group=system mode=0640 auto=part\-8
+-.br
+-HOMEHOST <system>
+-.br
+-AUTO +1.x homehost \-all
+-.br
+-SYSFS name=/dev/md/raid5 group_thread_cnt=4 sync_speed_max=1000000
+-.br
+-SYSFS uuid=bead5eb6:31c17a27:da120ba2:7dfda40d group_thread_cnt=4
+-sync_speed_max=1000000
+-.br
+-MONITORDELAY 60
+-
+-.SH SEE ALSO
+-.BR mdadm (8),
+-.BR md (4).
+diff --git a/mdadm.conf.5.in b/mdadm.conf.5.in
+new file mode 100644
+index 00000000..83edd008
+--- /dev/null
++++ b/mdadm.conf.5.in
+@@ -0,0 +1,706 @@
++.\" Copyright Neil Brown and others.
++.\"   This program is free software; you can redistribute it and/or modify
++.\"   it under the terms of the GNU General Public License as published by
++.\"   the Free Software Foundation; either version 2 of the License, or
++.\"   (at your option) any later version.
++.\" See file COPYING in distribution for details.
++.TH MDADM.CONF 5
++.SH NAME
++mdadm.conf \- configuration for management of Software RAID with mdadm
++.SH SYNOPSIS
++{CONFFILE}
++.SH DESCRIPTION
++.PP
++.I mdadm
++is a tool for creating, managing, and monitoring RAID devices using the
++.B md
++driver in Linux.
++.PP
++Some common tasks, such as assembling all arrays, can be simplified
++by describing the devices and arrays in this configuration file.
++
++.SS SYNTAX
++The file should be seen as a collection of words separated by white
++space (space, tab, or newline).
++Any word that beings with a hash sign (#) starts a comment and that
++word together with the remainder of the line is ignored.
++
++Spaces can be included in a word using quotation characters.  Either
++single quotes
++.RB ( ' )
++or double quotes (\fB"\fP)
++may be used.  All the characters from one quotation character to
++next identical character are protected and will not be used to
++separate words to start new quoted strings.  To include a single quote
++it must be between double quotes.  To include a double quote it must
++be between single quotes.
++
++Any line that starts with white space (space or tab) is treated as
++though it were a continuation of the previous line.
++
++Empty lines are ignored, but otherwise each (non continuation) line
++must start with a keyword as listed below.  The keywords are case
++insensitive and can be abbreviated to 3 characters.
++
++The keywords are:
++.TP
++.B DEVICE
++A
++.B device
++line lists the devices (whole devices or partitions) that might contain
++a component of an MD array.  When looking for the components of an
++array,
++.I mdadm
++will scan these devices (or any devices listed on the command line).
++
++The
++.B device
++line may contain a number of different devices (separated by spaces)
++and each device name can contain wild cards as defined by
++.BR glob (7).
++
++Also, there may be several device lines present in the file.
++
++Alternatively, a
++.B device
++line can contain either or both of the  words
++.B containers
++and
++.BR partitions .
++The word
++.B containers
++will cause
++.I mdadm
++to look for assembled CONTAINER arrays and included them as a source
++for assembling further arrays.
++
++The word
++.I partitions
++will cause
++.I mdadm
++to read
++.I /proc/partitions
++and include all devices and partitions found therein.
++.I mdadm
++does not use the names from
++.I /proc/partitions
++but only the major and minor device numbers.  It scans
++.I /dev
++to find the name that matches the numbers.
++
++If no DEVICE line is present, then "DEVICE partitions containers" is assumed.
++
++For example:
++.IP
++DEVICE /dev/hda* /dev/hdc*
++.br
++DEV    /dev/sd*
++.br
++DEVICE /dev/disk/by-path/pci*
++.br
++DEVICE partitions
++
++.TP
++.B ARRAY
++The ARRAY lines identify actual arrays.  The second word on the line
++may be the name of the device where the array is normally
++assembled, such as
++.B /dev/md1
++or
++.BR /dev/md/backup .
++If the name does not start with a slash
++.RB (' / '),
++it is treated as being in
++.BR /dev/md/ .
++Alternately the word
++.B <ignore>
++(complete with angle brackets) can be given in which case any array
++which matches the rest of the line will never be automatically assembled.
++If no device name is given,
++.I mdadm
++will use various heuristics to determine an appropriate name.
++
++Subsequent words identify the array, or identify the array as a member
++of a group. If multiple identities are given,
++then a component device must match ALL identities to be considered a
++match.  Each identity word has a tag, and equals sign, and some value.
++The tags are:
++.RS 4
++.TP
++.B uuid=
++The value should be a 128 bit uuid in hexadecimal, with punctuation
++interspersed if desired.  This must match the uuid stored in the
++superblock.
++.TP
++.B name=
++The value should be a simple textual name as was given to
++.I mdadm
++when the array was created.  This must match the name stored in the
++superblock on a device for that device to be included in the array.
++Not all superblock formats support names.
++.TP
++.B super\-minor=
++The value is an integer which indicates the minor number that was
++stored in the superblock when the array was created. When an array is
++created as /dev/mdX, then the minor number X is stored.
++.TP
++.B devices=
++The value is a comma separated list of device names or device name
++patterns.
++Only devices with names which match one entry in the list will be used
++to assemble the array.  Note that the devices
++listed there must also be listed on a DEVICE line.
++.TP
++.B level=
++The value is a RAID level.  This is not normally used to
++identify an array, but is supported so that the output of
++
++.B "mdadm \-\-examine \-\-scan"
++
++can be use directly in the configuration file.
++.TP
++.B num\-devices=
++The value is the number of devices in a complete active array.  As with
++.B level=
++this is mainly for compatibility with the output of
++
++.BR "mdadm \-\-examine \-\-scan" .
++
++.TP
++.B spares=
++The value is a number of spare devices to expect the array to have.
++The sole use of this keyword and value is as follows:
++.B mdadm \-\-monitor
++will report an array if it is found to have fewer than this number of
++spares when
++.B \-\-monitor
++starts or when
++.B \-\-oneshot
++is used.
++
++.TP
++.B spare\-group=
++The value is a textual name for a group of arrays.  All arrays with
++the same
++.B spare\-group
++name are considered to be part of the same group.  The significance of
++a group of arrays is that
++.I mdadm
++will, when monitoring the arrays, move a spare drive from one array in
++a group to another array in that group if the first array had a failed
++or missing drive but no spare.
++
++.TP
++.B auto=
++This option is rarely needed with mdadm-3.0, particularly if use with
++the Linux kernel v2.6.28 or later.
++It tells
++.I mdadm
++whether to use partitionable array or non-partitionable arrays and,
++in the absence of
++.IR udev ,
++how many partition devices to create.  From 2.6.28 all md array
++devices are partitionable, hence this option is not needed.
++
++The value of this option can be "yes" or "md" to indicate that a
++traditional, non-partitionable md array should be created, or "mdp",
++"part" or "partition" to indicate that a partitionable md array (only
++available in linux 2.6 and later) should be used.  This later set can
++also have a number appended to indicate how many partitions to create
++device files for, e.g.
++.BR auto=mdp5 .
++The default is 4.
++
++.TP
++.B bitmap=
++The option specifies a file in which a write-intent bitmap should be
++found.  When assembling the array,
++.I mdadm
++will provide this file to the
++.B md
++driver as the bitmap file.  This has the same function as the
++.B \-\-bitmap\-file
++option to
++.BR \-\-assemble .
++
++.TP
++.B metadata=
++Specify the metadata format that the array has.  This is mainly
++recognised for comparability with the output of
++.BR "mdadm \-Es" .
++
++.TP
++.B container=
++Specify that this array is a member array of some container.  The
++value given can be either a path name in /dev, or a UUID of the
++container array.
++
++.TP
++.B member=
++Specify that this array is a member array of some container.  Each
++type of container has some way to enumerate member arrays, often a
++simple sequence number.  The value identifies which member of a
++container the array is.  It will usually accompany a "container=" word.
++.RE
++
++.TP
++.B MAILADDR
++The
++.B mailaddr
++line gives an E-mail address that alerts should be
++sent to when
++.I mdadm
++is running in
++.B \-\-monitor
++mode (and was given the
++.B \-\-scan
++option).  There should only be one
++.B MAILADDR
++line and it should have only one address.  Any subsequent addresses
++are silently ignored.
++
++.TP
++.B MAILFROM
++The
++.B mailfrom
++line (which can only be abbreviated to at least 5 characters) gives an
++address to appear in the "From" address for alert mails.  This can be
++useful if you want to explicitly set a domain, as the default from
++address is "root" with no domain.  All words on this line are
++catenated with spaces to form the address.
++
++Note that this value cannot be set via the
++.I mdadm
++commandline.  It is only settable via the config file.
++
++.TP
++.B PROGRAM
++The
++.B program
++line gives the name of a program to be run when
++.B "mdadm \-\-monitor"
++detects potentially interesting events on any of the arrays that it
++is monitoring.  This program gets run with two or three arguments, they
++being the Event, the md device, and possibly the related component
++device.
++
++There should only be one
++.B program
++line and it should be give only one program.
++
++
++.TP
++.B CREATE
++The
++.B create
++line gives default values to be used when creating arrays, new members
++of arrays, and device entries for arrays.
++These include:
++
++.RS 4
++.TP
++.B owner=
++.TP
++.B group=
++These can give user/group ids or names to use instead of system
++defaults (root/wheel or root/disk).
++.TP
++.B mode=
++An octal file mode such as 0660 can be given to override the default
++of 0600.
++.TP
++.B auto=
++This corresponds to the
++.B \-\-auto
++flag to mdadm.  Give
++.BR yes ,
++.BR md ,
++.BR mdp ,
++.B part
++\(em possibly followed by a number of partitions \(em to indicate how
++missing device entries should be created.
++
++.TP
++.B metadata=
++The name of the metadata format to use if none is explicitly given.
++This can be useful to impose a system-wide default of version-1 superblocks.
++
++.TP
++.B symlinks=no
++Normally when creating devices in
++.B /dev/md/
++.I mdadm
++will create a matching symlink from
++.B /dev/
++with a name starting
++.B md
++or
++.BR md_ .
++Give
++.B symlinks=no
++to suppress this symlink creation.
++
++.TP
++.B names=yes
++Since Linux 2.6.29 it has been possible to create
++.B md
++devices with a name like
++.B md_home
++rather than just a number, like
++.BR md3 .
++.I mdadm
++will use the numeric alternative by default as other tools that interact
++with md arrays may expect only numbers.
++If
++.B names=yes
++is given in
++.I mdadm.conf
++then
++.I mdadm
++will use a name when appropriate.
++If
++.B names=no
++is given, then non-numeric
++.I md
++device names will not be used even if the default changes in a future
++release of
++.IR mdadm .
++
++.TP
++.B bbl=no
++By default,
++.I mdadm
++will reserve space for a bad block list (bbl) on all devices
++included in or added to any array that supports them.  Setting
++.B bbl=no
++will prevent this, so newly added devices will not have a bad
++block log.
++.RE
++
++.TP
++.B HOMEHOST
++The
++.B homehost
++line gives a default value for the
++.B \-\-homehost=
++option to mdadm.  There should normally be only one other word on the line.
++It should either be a host name, or one of the special words
++.BR <system>,
++.B <none>
++and
++.BR <ignore> .
++If
++.B <system>
++is given, then the
++.BR gethostname ( 2 )
++systemcall is used to get the host name.  This is the default.
++
++If
++.B <ignore>
++is given, then a flag is set so that when arrays are being
++auto-assembled the checking of the recorded
++.I homehost
++is disabled.
++If
++.B <ignore>
++is given it is also possible to give an explicit name which will be
++used when creating arrays.  This is the only case when there can be
++more that one other word on the
++.B HOMEHOST
++line.  If there are other words, or other
++.B HOMEHOST
++lines, they are silently ignored.
++
++If
++.B <none>
++is given, then the default of using
++.BR gethostname ( 2 )
++is over-ridden and no homehost name is assumed.
++
++When arrays are created, this host name will be stored in the
++metadata.  When arrays are assembled using auto-assembly, arrays which
++do not record the correct homehost name in their metadata will be
++assembled using a "foreign" name.  A "foreign" name alway ends with a
++digit string preceded by an underscore to differentiate it
++from any possible local name. e.g.
++.B /dev/md/1_1
++or
++.BR /dev/md/home_0 .
++.TP
++.B AUTO
++A list of names of metadata format can be given, each preceded by a
++plus or minus sign.  Also the word
++.I homehost
++is allowed as is
++.I all
++preceded by plus or minus sign.
++.I all
++is usually last.
++
++When
++.I mdadm
++is auto-assembling an array, either via
++.I \-\-assemble
++or
++.I \-\-incremental
++and it finds metadata of a given type, it checks that metadata type
++against those listed in this line.  The first match wins, where
++.I all
++matches anything.
++If a match is found that was preceded by a plus sign, the auto
++assembly is allowed.  If the match was preceded by a minus sign, the
++auto assembly is disallowed.  If no match is found, the auto assembly
++is allowed.
++
++If the metadata indicates that the array was created for
++.I this
++host, and the word
++.I homehost
++appears before any other match, then the array is treated as a valid
++candidate for auto-assembly.
++
++This can be used to disable all auto-assembly (so that only arrays
++explicitly listed in mdadm.conf or on the command line are assembled),
++or to disable assembly of certain metadata types which might be
++handled by other software.  It can also be used to disable assembly of
++all foreign arrays - normally such arrays are assembled but given a
++non-deterministic name in
++.BR /dev/md/ .
++
++The known metadata types are
++.BR 0.90 ,
++.BR 1.x ,
++.BR ddf ,
++.BR imsm .
++
++.B AUTO
++should be given at most once.  Subsequent lines are silently ignored.
++Thus an earlier config file in a config directory will over-ride
++the setting in a later config file.
++
++.TP
++.B POLICY
++This is used to specify what automatic behavior is allowed on devices
++newly appearing in the system and provides a way of marking spares that can
++be moved to other arrays as well as the migration domains.
++.I Domain
++can be defined through
++.I policy
++line by specifying a domain name for a number of paths from
++.BR /dev/disk/by-path/ .
++A device may belong to several domains. The domain of an array is a union
++of domains of all devices in that array.  A spare can be automatically
++moved from one array to another if the set of the destination array's
++.I domains
++contains all the
++.I domains
++of the new disk or if both arrays have the same
++.IR spare-group .
++
++To update hot plug configuration it is necessary to execute
++.B mdadm \-\-udev\-rules
++command after changing the config file
++
++Keywords used in the
++.I POLICY
++line and supported values are:
++
++.RS 4
++.TP
++.B domain=
++any arbitrary string
++.TP
++.B metadata=
++0.9 1.x ddf or imsm
++.TP
++.B path=
++file glob matching anything from
++.B /dev/disk/by-path
++.TP
++.B type=
++either
++.B disk
++or
++.BR part .
++.TP
++.B action=
++include, re-add, spare, spare-same-slot, or force-spare
++.TP
++.B auto=
++yes, no, or homehost.
++
++.P
++The
++.I action
++item determines the automatic behavior allowed for devices matching the
++.I path
++and
++.I type
++in the same line.  If a device matches several lines with different
++.I  actions
++then the most permissive will apply. The ordering of policy lines
++is irrelevant to the end result.
++.TP
++.B include
++allows adding a disk to an array if metadata on that disk matches that array
++.TP
++.B re\-add
++will include the device in the array if it appears to be a current member
++or a member that was recently removed and the array has a
++write-intent-bitmap to allow the
++.B re\-add
++functionality.
++.TP
++.B spare
++as above and additionally: if the device is bare it can
++become a spare if there is any array that it is a candidate for based
++on domains and metadata.
++.TP
++.B spare\-same\-slot
++as above and additionally if given slot was used by an array that went
++degraded recently and the device plugged in has no metadata then it will
++be automatically added to that array (or it's container)
++.TP
++.B force\-spare
++as above and the disk will become a spare in remaining cases
++.RE
++
++.TP
++.B PART-POLICY
++This is similar to
++.B POLICY
++and accepts the same keyword assignments.  It allows a consistent set
++of policies to applied to each of the partitions of a device.
++
++A
++.B PART-POLICY
++line should set
++.I type=disk
++and identify the path to one or more disk devices.  Each partition on
++these disks will be treated according to the
++.I action=
++setting  from this line.  If a
++.I domain
++is set in the line, then the domain associated with each patition will
++be based on the domain, but with
++.RB \(dq -part N\(dq
++appended, when N is the partition number for the partition that was
++found.
++
++.TP
++.B SYSFS
++The
++.B SYSFS
++line lists custom values of MD device's sysfs attributes which will be
++stored in sysfs after the array is assembled. Multiple lines are allowed and each
++line has to contain the uuid or the name of the device to which it relates.
++.RS 4
++.TP
++.B uuid=
++hexadecimal identifier of MD device. This has to match the uuid stored in the
++superblock.
++.TP
++.B name=
++name of the MD device as was given to
++.I mdadm
++when the array was created. It will be ignored if
++.B uuid
++is not empty.
++.RE
++
++.TP
++.B MONITORDELAY
++The
++.B monitordelay
++line gives a delay in seconds
++.I mdadm
++shall wait before pooling md arrays
++when
++.I mdadm
++is running in
++.B \-\-monitor
++mode.
++.B \-d/\-\-delay
++command line argument takes precedence over the config file
++
++.SH EXAMPLE
++DEVICE /dev/sd[bcdjkl]1
++.br
++DEVICE /dev/hda1 /dev/hdb1
++
++# /dev/md0 is known by its UUID.
++.br
++ARRAY /dev/md0 UUID=3aaa0122:29827cfa:5331ad66:ca767371
++.br
++# /dev/md1 contains all devices with a minor number of
++.br
++#   1 in the superblock.
++.br
++ARRAY /dev/md1 superminor=1
++.br
++# /dev/md2 is made from precisely these two devices
++.br
++ARRAY /dev/md2 devices=/dev/hda1,/dev/hdb1
++
++# /dev/md4 and /dev/md5 are a spare-group and spares
++.br
++#  can be moved between them
++.br
++ARRAY /dev/md4 uuid=b23f3c6d:aec43a9f:fd65db85:369432df
++.br
++           spare\-group=group1
++.br
++ARRAY /dev/md5 uuid=19464854:03f71b1b:e0df2edd:246cc977
++.br
++           spare\-group=group1
++.br
++# /dev/md/home is created if need to be a partitionable md array
++.br
++# any spare device number is allocated.
++.br
++ARRAY /dev/md/home UUID=9187a482:5dde19d9:eea3cc4a:d646ab8b
++.br
++           auto=part
++.br
++# The name of this array contains a space.
++.br
++ARRAY /dev/md9 name='Data Storage'
++.sp
++POLICY domain=domain1 metadata=imsm path=pci-0000:00:1f.2-scsi-*
++.br
++           action=spare
++.br
++POLICY domain=domain1 metadata=imsm path=pci-0000:04:00.0-scsi-[01]*
++.br
++           action=include
++.br
++# One domain comprising of devices attached to specified paths is defined.
++.br
++# Bare device matching first path will be made an imsm spare on hot plug.
++.br
++# If more than one array is created on devices belonging to domain1 and
++.br
++# one of them becomes degraded, then any imsm spare matching any path for
++.br
++# given domain name can be migrated.
++.br
++MAILADDR root@mydomain.tld
++.br
++PROGRAM /usr/sbin/handle\-mdadm\-events
++.br
++CREATE group=system mode=0640 auto=part\-8
++.br
++HOMEHOST <system>
++.br
++AUTO +1.x homehost \-all
++.br
++SYSFS name=/dev/md/raid5 group_thread_cnt=4 sync_speed_max=1000000
++.br
++SYSFS uuid=bead5eb6:31c17a27:da120ba2:7dfda40d group_thread_cnt=4
++sync_speed_max=1000000
++.br
++MONITORDELAY 60
++
++.SH SEE ALSO
++.BR mdadm (8),
++.BR md (4).
+-- 
+2.31.1
+
diff --git a/SOURCES/0007-mdadm-Update-ReadMe.patch b/SOURCES/0007-mdadm-Update-ReadMe.patch
new file mode 100644
index 0000000..90ce556
--- /dev/null
+++ b/SOURCES/0007-mdadm-Update-ReadMe.patch
@@ -0,0 +1,48 @@
+From c23400377bb3d8e98e810cd92dba478dac1dff82 Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Fri, 18 Mar 2022 09:26:05 +0100
+Subject: [PATCH 07/12] mdadm: Update ReadMe
+
+Instead of hardcoded config file path give reference to config manual.
+
+Add missing monitordelay and homecluster parameters.
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ ReadMe.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/ReadMe.c b/ReadMe.c
+index 81399765..8f873c48 100644
+--- a/ReadMe.c
++++ b/ReadMe.c
+@@ -613,7 +613,6 @@ char Help_incr[] =
+ ;
+ 
+ char Help_config[] =
+-"The /etc/mdadm.conf config file:\n\n"
+ " The config file contains, apart from blank lines and comment lines that\n"
+ " start with a hash(#), array lines, device lines, and various\n"
+ " configuration lines.\n"
+@@ -636,10 +635,12 @@ char Help_config[] =
+ " than a device must match all of them to be considered.\n"
+ "\n"
+ " Other configuration lines include:\n"
+-"  mailaddr, mailfrom, program     used for --monitor mode\n"
+-"  create, auto                    used when creating device names in /dev\n"
+-"  homehost, policy, part-policy   used to guide policy in various\n"
+-"                                  situations\n"
++"  mailaddr, mailfrom, program, monitordelay    used for --monitor mode\n"
++"  create, auto                                 used when creating device names in /dev\n"
++"  homehost, homecluster, policy, part-policy   used to guide policy in various\n"
++"                                               situations\n"
++"\n"
++"For more details see mdadm.conf(5).\n"
+ "\n"
+ ;
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0008-mdadm-Update-config-man-regarding-default-files-and-.patch b/SOURCES/0008-mdadm-Update-config-man-regarding-default-files-and-.patch
new file mode 100644
index 0000000..8375fd9
--- /dev/null
+++ b/SOURCES/0008-mdadm-Update-config-man-regarding-default-files-and-.patch
@@ -0,0 +1,203 @@
+From 24e075c659d0a8718aabefe5af4c97195a188af7 Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Fri, 18 Mar 2022 09:26:06 +0100
+Subject: [PATCH 08/12] mdadm: Update config man regarding default files and
+ multi-keyword behavior
+
+Simplify default and alternative config file and directory location references
+from mdadm(8) as references to mdadm.conf(5). Add FILE section in config man
+and explain order and conditions in which default and alternative config files
+and directories are used.
+
+Update config man behavior regarding parsing order when multiple keywords/config
+files are involved.
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ mdadm.8.in      | 30 +++++++++--------------
+ mdadm.conf.5.in | 65 ++++++++++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 71 insertions(+), 24 deletions(-)
+
+diff --git a/mdadm.8.in b/mdadm.8.in
+index 8b21ffd4..0be02e4a 100644
+--- a/mdadm.8.in
++++ b/mdadm.8.in
+@@ -266,14 +266,11 @@ the exact meaning of this option in different contexts.
+ 
+ .TP
+ .BR \-c ", " \-\-config=
+-Specify the config file or directory.  Default is to use
+-.B {CONFFILE}
+-and
+-.BR {CONFFILE}.d ,
+-or if those are missing then
+-.B {CONFFILE2}
+-and
+-.BR {CONFFILE2}.d .
++Specify the config file or directory.  If not specified, default config file
++and default conf.d directory will be used.  See
++.BR mdadm.conf (5)
++for more details.
++
+ If the config file given is
+ .B "partitions"
+ then nothing will be read, but
+@@ -2013,11 +2010,9 @@ The config file is only used if explicitly named with
+ .B \-\-config
+ or requested with (a possibly implicit)
+ .BR \-\-scan .
+-In the later case,
+-.B {CONFFILE}
+-or
+-.B {CONFFILE2}
+-is used.
++In the later case, default config file is used.  See
++.BR mdadm.conf (5)
++for more details.
+ 
+ If
+ .B \-\-scan
+@@ -3346,16 +3341,15 @@ on Monitor mode.
+ 
+ .SS {CONFFILE} (or {CONFFILE2})
+ 
+-The config file lists which devices may be scanned to see if
+-they contain MD super block, and gives identifying information
+-(e.g. UUID) about known MD arrays.  See
++Default config file.  See
+ .BR mdadm.conf (5)
+ for more details.
+ 
+ .SS {CONFFILE}.d (or {CONFFILE2}.d)
+ 
+-A directory containing configuration files which are read in lexical
+-order.
++Default directory containing configuration files.  See
++.BR mdadm.conf (5)
++for more details.
+ 
+ .SS {MAP_PATH}
+ When
+diff --git a/mdadm.conf.5.in b/mdadm.conf.5.in
+index 83edd008..dd331a6a 100644
+--- a/mdadm.conf.5.in
++++ b/mdadm.conf.5.in
+@@ -88,7 +88,8 @@ but only the major and minor device numbers.  It scans
+ .I /dev
+ to find the name that matches the numbers.
+ 
+-If no DEVICE line is present, then "DEVICE partitions containers" is assumed.
++If no DEVICE line is present in any config file,
++then "DEVICE partitions containers" is assumed.
+ 
+ For example:
+ .IP
+@@ -272,6 +273,10 @@ catenated with spaces to form the address.
+ Note that this value cannot be set via the
+ .I mdadm
+ commandline.  It is only settable via the config file.
++There should only be one
++.B MAILADDR
++line and it should have only one address.  Any subsequent addresses
++are silently ignored.
+ 
+ .TP
+ .B PROGRAM
+@@ -286,7 +291,8 @@ device.
+ 
+ There should only be one
+ .B program
+-line and it should be give only one program.
++line and it should be given only one program.  Any subsequent programs
++are silently ignored.
+ 
+ 
+ .TP
+@@ -295,7 +301,14 @@ The
+ .B create
+ line gives default values to be used when creating arrays, new members
+ of arrays, and device entries for arrays.
+-These include:
++
++There should only be one
++.B create
++line.  Any subsequent lines will override the previous settings.
++
++Keywords used in the
++.I CREATE
++line and supported values are:
+ 
+ .RS 4
+ .TP
+@@ -475,8 +488,8 @@ The known metadata types are
+ 
+ .B AUTO
+ should be given at most once.  Subsequent lines are silently ignored.
+-Thus an earlier config file in a config directory will over-ride
+-the setting in a later config file.
++Thus a later config file in a config directory will not overwrite
++the setting in an earlier config file.
+ 
+ .TP
+ .B POLICY
+@@ -594,6 +607,7 @@ The
+ line lists custom values of MD device's sysfs attributes which will be
+ stored in sysfs after the array is assembled. Multiple lines are allowed and each
+ line has to contain the uuid or the name of the device to which it relates.
++Lines are applied in reverse order.
+ .RS 4
+ .TP
+ .B uuid=
+@@ -621,7 +635,46 @@ is running in
+ .B \-\-monitor
+ mode.
+ .B \-d/\-\-delay
+-command line argument takes precedence over the config file
++command line argument takes precedence over the config file.
++
++If multiple
++.B MINITORDELAY
++lines are provided, only first non-zero value is considered.
++
++.SH FILES
++
++.SS {CONFFILE}
++
++The default config file location, used when
++.I mdadm
++is running without --config option.
++
++.SS {CONFFILE}.d
++
++The default directory with config files. Used when
++.I mdadm
++is running without --config option, after successful reading of the
++.B {CONFFILE}
++default config file. Files in that directory
++are read in lexical order.
++
++
++.SS {CONFFILE2}
++
++Alternative config file that is read, when
++.I mdadm
++is running without --config option and the
++.B {CONFFILE}
++default config file was not opened successfully.
++
++.SS {CONFFILE2}.d
++
++The alternative directory with config files. Used when
++.I mdadm
++is runninng without --config option, after reading the
++.B {CONFFILE2}
++alternative config file whether it was successful or not. Files in
++that directory are read in lexical order.
+ 
+ .SH EXAMPLE
+ DEVICE /dev/sd[bcdjkl]1
+-- 
+2.31.1
+
diff --git a/SOURCES/0009-mdadm-Update-config-manual.patch b/SOURCES/0009-mdadm-Update-config-manual.patch
new file mode 100644
index 0000000..313b2c9
--- /dev/null
+++ b/SOURCES/0009-mdadm-Update-config-manual.patch
@@ -0,0 +1,45 @@
+From c33bbda5b0e127bb161fd4ad44bcfaa2a5daf153 Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Fri, 18 Mar 2022 09:26:07 +0100
+Subject: [PATCH 09/12] mdadm: Update config manual
+
+Add missing HOMECLUSTER keyword description.
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ mdadm.conf.5.in | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/mdadm.conf.5.in b/mdadm.conf.5.in
+index dd331a6a..cd4e6a9d 100644
+--- a/mdadm.conf.5.in
++++ b/mdadm.conf.5.in
+@@ -439,6 +439,23 @@ from any possible local name. e.g.
+ .B /dev/md/1_1
+ or
+ .BR /dev/md/home_0 .
++
++.TP
++.B HOMECLUSTER
++The
++.B homcluster
++line gives a default value for the
++.B \-\-homecluster=
++option to mdadm.  It specifies  the  cluster name for the md device.
++The md device can be assembled only on the cluster which matches
++the name specified. If
++.B homcluster
++is not provided, mdadm tries to detect the cluster name automatically.
++
++There should only be one
++.B homecluster
++line.  Any subsequent lines will be silently ignored.
++
+ .TP
+ .B AUTO
+ A list of names of metadata format can be given, each preceded by a
+-- 
+2.31.1
+
diff --git a/SOURCES/0010-Create-Build-use-default_layout.patch b/SOURCES/0010-Create-Build-use-default_layout.patch
new file mode 100644
index 0000000..a15ae3e
--- /dev/null
+++ b/SOURCES/0010-Create-Build-use-default_layout.patch
@@ -0,0 +1,153 @@
+From 913f07d1db4a0078acc26d6ccabe1c315cf9273c Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Thu, 20 Jan 2022 13:18:32 +0100
+Subject: [PATCH 10/12] Create, Build: use default_layout()
+
+This code is duplicated for Build mode so make default_layout() extern
+and use it. Simplify the function structure.
+
+It introduced change for Build mode, now for raid0 RAID0_ORIG_LAYOUT
+will be returned same as for Create.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Build.c  | 23 +------------------
+ Create.c | 67 ++++++++++++++++++++++++++++++++++----------------------
+ mdadm.h  |  1 +
+ 3 files changed, 43 insertions(+), 48 deletions(-)
+
+diff --git a/Build.c b/Build.c
+index 962c2e37..8d6f6f58 100644
+--- a/Build.c
++++ b/Build.c
+@@ -71,28 +71,7 @@ int Build(char *mddev, struct mddev_dev *devlist,
+ 	}
+ 
+ 	if (s->layout == UnSet)
+-		switch(s->level) {
+-		default: /* no layout */
+-			s->layout = 0;
+-			break;
+-		case 10:
+-			s->layout = 0x102; /* near=2, far=1 */
+-			if (c->verbose > 0)
+-				pr_err("layout defaults to n1\n");
+-			break;
+-		case 5:
+-		case 6:
+-			s->layout = map_name(r5layout, "default");
+-			if (c->verbose > 0)
+-				pr_err("layout defaults to %s\n", map_num(r5layout, s->layout));
+-			break;
+-		case LEVEL_FAULTY:
+-			s->layout = map_name(faultylayout, "default");
+-
+-			if (c->verbose > 0)
+-				pr_err("layout defaults to %s\n", map_num(faultylayout, s->layout));
+-			break;
+-		}
++		s->layout = default_layout(NULL, s->level, c->verbose);
+ 
+ 	/* We need to create the device.  It can have no name. */
+ 	map_lock(&map);
+diff --git a/Create.c b/Create.c
+index 0ff1922d..9ea19de0 100644
+--- a/Create.c
++++ b/Create.c
+@@ -39,39 +39,54 @@ static int round_size_and_verify(unsigned long long *size, int chunk)
+ 	return 0;
+ }
+ 
+-static int default_layout(struct supertype *st, int level, int verbose)
++/**
++ * default_layout() - Get default layout for level.
++ * @st: metadata requested, could be NULL.
++ * @level: raid level requested.
++ * @verbose: verbose level.
++ *
++ * Try to ask metadata handler first, otherwise use global defaults.
++ *
++ * Return: Layout or &UnSet, return value meaning depends of level used.
++ */
++int default_layout(struct supertype *st, int level, int verbose)
+ {
+ 	int layout = UnSet;
++	mapping_t *layout_map = NULL;
++	char *layout_name = NULL;
+ 
+ 	if (st && st->ss->default_geometry)
+ 		st->ss->default_geometry(st, &level, &layout, NULL);
+ 
+-	if (layout == UnSet)
+-		switch(level) {
+-		default: /* no layout */
+-			layout = 0;
+-			break;
+-		case 0:
+-			layout = RAID0_ORIG_LAYOUT;
+-			break;
+-		case 10:
+-			layout = 0x102; /* near=2, far=1 */
+-			if (verbose > 0)
+-				pr_err("layout defaults to n2\n");
+-			break;
+-		case 5:
+-		case 6:
+-			layout = map_name(r5layout, "default");
+-			if (verbose > 0)
+-				pr_err("layout defaults to %s\n", map_num(r5layout, layout));
+-			break;
+-		case LEVEL_FAULTY:
+-			layout = map_name(faultylayout, "default");
++	if (layout != UnSet)
++		return layout;
+ 
+-			if (verbose > 0)
+-				pr_err("layout defaults to %s\n", map_num(faultylayout, layout));
+-			break;
+-		}
++	switch (level) {
++	default: /* no layout */
++		layout = 0;
++		break;
++	case 0:
++		layout = RAID0_ORIG_LAYOUT;
++		break;
++	case 10:
++		layout = 0x102; /* near=2, far=1 */
++		layout_name = "n2";
++		break;
++	case 5:
++	case 6:
++		layout_map = r5layout;
++		break;
++	case LEVEL_FAULTY:
++		layout_map = faultylayout;
++		break;
++	}
++
++	if (layout_map) {
++		layout = map_name(layout_map, "default");
++		layout_name = map_num(layout_map, layout);
++	}
++	if (layout_name && verbose > 0)
++		pr_err("layout defaults to %s\n", layout_name);
+ 
+ 	return layout;
+ }
+diff --git a/mdadm.h b/mdadm.h
+index 26e7e5cd..cd72e711 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1512,6 +1512,7 @@ extern int get_linux_version(void);
+ extern int mdadm_version(char *version);
+ extern unsigned long long parse_size(char *size);
+ extern int parse_uuid(char *str, int uuid[4]);
++int default_layout(struct supertype *st, int level, int verbose);
+ extern int is_near_layout_10(int layout);
+ extern int parse_layout_10(char *layout);
+ extern int parse_layout_faulty(char *layout);
+-- 
+2.31.1
+
diff --git a/SOURCES/0011-mdadm-add-map_num_s.patch b/SOURCES/0011-mdadm-add-map_num_s.patch
new file mode 100644
index 0000000..196d47d
--- /dev/null
+++ b/SOURCES/0011-mdadm-add-map_num_s.patch
@@ -0,0 +1,382 @@
+From 5f21d67472ad08c1e96b4385254adba79aa1c467 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Thu, 20 Jan 2022 13:18:33 +0100
+Subject: [PATCH 11/12] mdadm: add map_num_s()
+
+map_num() returns NULL if key is not defined. This patch adds
+alternative, non NULL version for cases where NULL is not expected.
+
+There are many printf() calls where map_num() is called on variable
+without NULL verification. It works, even if NULL is passed because
+gcc is able to ignore NULL argument quietly but the behavior is
+undefined. For safety reasons such usages will use map_num_s() now.
+It is a potential point of regression.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c    |  6 ++----
+ Create.c      |  2 +-
+ Detail.c      |  4 ++--
+ Grow.c        | 16 ++++++++--------
+ Query.c       |  4 ++--
+ maps.c        | 24 ++++++++++++++++++++++++
+ mdadm.c       | 20 ++++++++++----------
+ mdadm.h       |  2 +-
+ super-ddf.c   |  6 +++---
+ super-intel.c |  2 +-
+ super0.c      |  2 +-
+ super1.c      |  2 +-
+ sysfs.c       |  9 +++++----
+ 13 files changed, 61 insertions(+), 38 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index 704b8293..9eac9ce0 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -63,7 +63,7 @@ static void set_array_assembly_status(struct context *c,
+ 				   struct assembly_array_info *arr)
+ {
+ 	int raid_disks = arr->preexist_cnt + arr->new_cnt;
+-	char *status_msg = map_num(assemble_statuses, status);
++	char *status_msg = map_num_s(assemble_statuses, status);
+ 
+ 	if (c->export && result)
+ 		*result |= status;
+@@ -77,9 +77,7 @@ static void set_array_assembly_status(struct context *c,
+ 		fprintf(stderr, " (%d new)", arr->new_cnt);
+ 	if (arr->exp_cnt)
+ 		fprintf(stderr, " ( + %d for expansion)", arr->exp_cnt);
+-	if (status_msg)
+-		fprintf(stderr, " %s", status_msg);
+-	fprintf(stderr, ".\n");
++	fprintf(stderr, " %s.\n", status_msg);
+ }
+ 
+ static int name_matches(char *found, char *required, char *homehost, int require_homehost)
+diff --git a/Create.c b/Create.c
+index 9ea19de0..c84c1ac8 100644
+--- a/Create.c
++++ b/Create.c
+@@ -83,7 +83,7 @@ int default_layout(struct supertype *st, int level, int verbose)
+ 
+ 	if (layout_map) {
+ 		layout = map_name(layout_map, "default");
+-		layout_name = map_num(layout_map, layout);
++		layout_name = map_num_s(layout_map, layout);
+ 	}
+ 	if (layout_name && verbose > 0)
+ 		pr_err("layout defaults to %s\n", layout_name);
+diff --git a/Detail.c b/Detail.c
+index 95d4cc70..ce7a8445 100644
+--- a/Detail.c
++++ b/Detail.c
+@@ -495,8 +495,8 @@ int Detail(char *dev, struct context *c)
+ 			if (array.state & (1 << MD_SB_CLEAN)) {
+ 				if ((array.level == 0) ||
+ 				    (array.level == LEVEL_LINEAR))
+-					arrayst = map_num(sysfs_array_states,
+-							  sra->array_state);
++					arrayst = map_num_s(sysfs_array_states,
++							       sra->array_state);
+ 				else
+ 					arrayst = "clean";
+ 			} else {
+diff --git a/Grow.c b/Grow.c
+index 18c5719b..8a242b0f 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -547,7 +547,7 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
+ 	if (s->consistency_policy != CONSISTENCY_POLICY_RESYNC &&
+ 	    s->consistency_policy != CONSISTENCY_POLICY_PPL) {
+ 		pr_err("Operation not supported for consistency policy %s\n",
+-		       map_num(consistency_policies, s->consistency_policy));
++		       map_num_s(consistency_policies, s->consistency_policy));
+ 		return 1;
+ 	}
+ 
+@@ -578,14 +578,14 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
+ 
+ 	if (sra->consistency_policy == (unsigned)s->consistency_policy) {
+ 		pr_err("Consistency policy is already %s\n",
+-		       map_num(consistency_policies, s->consistency_policy));
++		       map_num_s(consistency_policies, s->consistency_policy));
+ 		ret = 1;
+ 		goto free_info;
+ 	} else if (sra->consistency_policy != CONSISTENCY_POLICY_RESYNC &&
+ 		   sra->consistency_policy != CONSISTENCY_POLICY_PPL) {
+ 		pr_err("Current consistency policy is %s, cannot change to %s\n",
+-		       map_num(consistency_policies, sra->consistency_policy),
+-		       map_num(consistency_policies, s->consistency_policy));
++		       map_num_s(consistency_policies, sra->consistency_policy),
++		       map_num_s(consistency_policies, s->consistency_policy));
+ 		ret = 1;
+ 		goto free_info;
+ 	}
+@@ -704,8 +704,8 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
+ 	}
+ 
+ 	ret = sysfs_set_str(sra, NULL, "consistency_policy",
+-			    map_num(consistency_policies,
+-				    s->consistency_policy));
++			    map_num_s(consistency_policies,
++					 s->consistency_policy));
+ 	if (ret)
+ 		pr_err("Failed to change array consistency policy\n");
+ 
+@@ -2241,7 +2241,7 @@ size_change_error:
+ 		info.new_layout = UnSet;
+ 		if (info.array.level == 6 && info.new_level == UnSet) {
+ 			char l[40], *h;
+-			strcpy(l, map_num(r6layout, info.array.layout));
++			strcpy(l, map_num_s(r6layout, info.array.layout));
+ 			h = strrchr(l, '-');
+ 			if (h && strcmp(h, "-6") == 0) {
+ 				*h = 0;
+@@ -2266,7 +2266,7 @@ size_change_error:
+ 			info.new_layout = info.array.layout;
+ 		else if (info.array.level == 5 && info.new_level == 6) {
+ 			char l[40];
+-			strcpy(l, map_num(r5layout, info.array.layout));
++			strcpy(l, map_num_s(r5layout, info.array.layout));
+ 			strcat(l, "-6");
+ 			info.new_layout = map_name(r6layout, l);
+ 		} else {
+diff --git a/Query.c b/Query.c
+index 23fbf8aa..adcd231e 100644
+--- a/Query.c
++++ b/Query.c
+@@ -93,7 +93,7 @@ int Query(char *dev)
+ 	else {
+ 		printf("%s: %s %s %d devices, %d spare%s. Use mdadm --detail for more detail.\n",
+ 		       dev, human_size_brief(larray_size,IEC),
+-		       map_num(pers, level), raid_disks,
++		       map_num_s(pers, level), raid_disks,
+ 		       spare_disks, spare_disks == 1 ? "" : "s");
+ 	}
+ 	st = guess_super(fd);
+@@ -131,7 +131,7 @@ int Query(char *dev)
+ 		       dev,
+ 		       info.disk.number, info.array.raid_disks,
+ 		       activity,
+-		       map_num(pers, info.array.level),
++		       map_num_s(pers, info.array.level),
+ 		       mddev);
+ 		if (st->ss == &super0)
+ 			put_md_name(mddev);
+diff --git a/maps.c b/maps.c
+index a4fd2797..20fcf719 100644
+--- a/maps.c
++++ b/maps.c
+@@ -166,6 +166,30 @@ mapping_t sysfs_array_states[] = {
+ 	{ NULL, ARRAY_UNKNOWN_STATE }
+ };
+ 
++/**
++ * map_num_s() - Safer alternative of map_num() function.
++ * @map: map to search.
++ * @num: key to match.
++ *
++ * Shall be used only if key existence is quaranted.
++ *
++ * Return: Pointer to name of the element.
++ */
++char *map_num_s(mapping_t *map, int num)
++{
++	char *ret = map_num(map, num);
++
++	assert(ret);
++	return ret;
++}
++
++/**
++ * map_num() - get element name by key.
++ * @map: map to search.
++ * @num: key to match.
++ *
++ * Return: Pointer to name of the element or NULL.
++ */
+ char *map_num(mapping_t *map, int num)
+ {
+ 	while (map->name) {
+diff --git a/mdadm.c b/mdadm.c
+index 26299b2e..be40686c 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -280,8 +280,8 @@ int main(int argc, char *argv[])
+ 			else
+ 				fprintf(stderr, "-%c", opt);
+ 			fprintf(stderr, " would set mdadm mode to \"%s\", but it is already set to \"%s\".\n",
+-				map_num(modes, newmode),
+-				map_num(modes, mode));
++				map_num_s(modes, newmode),
++				map_num_s(modes, mode));
+ 			exit(2);
+ 		} else if (!mode && newmode) {
+ 			mode = newmode;
+@@ -544,7 +544,7 @@ int main(int argc, char *argv[])
+ 			switch(s.level) {
+ 			default:
+ 				pr_err("layout not meaningful for %s arrays.\n",
+-					map_num(pers, s.level));
++					map_num_s(pers, s.level));
+ 				exit(2);
+ 			case UnSet:
+ 				pr_err("raid level must be given before layout.\n");
+@@ -1248,10 +1248,10 @@ int main(int argc, char *argv[])
+ 		if (option_index > 0)
+ 			pr_err(":option --%s not valid in %s mode\n",
+ 				long_options[option_index].name,
+-				map_num(modes, mode));
++				map_num_s(modes, mode));
+ 		else
+ 			pr_err("option -%c not valid in %s mode\n",
+-				opt, map_num(modes, mode));
++				opt, map_num_s(modes, mode));
+ 		exit(2);
+ 
+ 	}
+@@ -1276,7 +1276,7 @@ int main(int argc, char *argv[])
+ 		if (s.consistency_policy != CONSISTENCY_POLICY_UNKNOWN &&
+ 		    s.consistency_policy != CONSISTENCY_POLICY_JOURNAL) {
+ 			pr_err("--write-journal is not supported with consistency policy: %s\n",
+-			       map_num(consistency_policies, s.consistency_policy));
++			       map_num_s(consistency_policies, s.consistency_policy));
+ 			exit(2);
+ 		}
+ 	}
+@@ -1285,12 +1285,12 @@ int main(int argc, char *argv[])
+ 	    s.consistency_policy != CONSISTENCY_POLICY_UNKNOWN) {
+ 		if (s.level <= 0) {
+ 			pr_err("--consistency-policy not meaningful with level %s.\n",
+-			       map_num(pers, s.level));
++			       map_num_s(pers, s.level));
+ 			exit(2);
+ 		} else if (s.consistency_policy == CONSISTENCY_POLICY_JOURNAL &&
+ 			   !s.journaldisks) {
+ 			pr_err("--write-journal is required for consistency policy: %s\n",
+-			       map_num(consistency_policies, s.consistency_policy));
++			       map_num_s(consistency_policies, s.consistency_policy));
+ 			exit(2);
+ 		} else if (s.consistency_policy == CONSISTENCY_POLICY_PPL &&
+ 			   s.level != 5) {
+@@ -1300,14 +1300,14 @@ int main(int argc, char *argv[])
+ 			   (!s.bitmap_file ||
+ 			    strcmp(s.bitmap_file, "none") == 0)) {
+ 			pr_err("--bitmap is required for consistency policy: %s\n",
+-			       map_num(consistency_policies, s.consistency_policy));
++			       map_num_s(consistency_policies, s.consistency_policy));
+ 			exit(2);
+ 		} else if (s.bitmap_file &&
+ 			   strcmp(s.bitmap_file, "none") != 0 &&
+ 			   s.consistency_policy != CONSISTENCY_POLICY_BITMAP &&
+ 			   s.consistency_policy != CONSISTENCY_POLICY_JOURNAL) {
+ 			pr_err("--bitmap is not compatible with consistency policy: %s\n",
+-			       map_num(consistency_policies, s.consistency_policy));
++			       map_num_s(consistency_policies, s.consistency_policy));
+ 			exit(2);
+ 		}
+ 	}
+diff --git a/mdadm.h b/mdadm.h
+index cd72e711..09915a00 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -770,7 +770,7 @@ extern int restore_stripes(int *dest, unsigned long long *offsets,
+ #endif
+ 
+ #define SYSLOG_FACILITY LOG_DAEMON
+-
++extern char *map_num_s(mapping_t *map, int num);
+ extern char *map_num(mapping_t *map, int num);
+ extern int map_name(mapping_t *map, char *name);
+ extern mapping_t r0layout[], r5layout[], r6layout[],
+diff --git a/super-ddf.c b/super-ddf.c
+index 3f304cdc..8cda23a7 100644
+--- a/super-ddf.c
++++ b/super-ddf.c
+@@ -1477,13 +1477,13 @@ static void examine_vds(struct ddf_super *sb)
+ 		printf("\n");
+ 		printf("         unit[%d] : %d\n", i, be16_to_cpu(ve->unit));
+ 		printf("        state[%d] : %s, %s%s\n", i,
+-		       map_num(ddf_state, ve->state & 7),
++		       map_num_s(ddf_state, ve->state & 7),
+ 		       (ve->state & DDF_state_morphing) ? "Morphing, ": "",
+ 		       (ve->state & DDF_state_inconsistent)? "Not Consistent" : "Consistent");
+ 		printf("   init state[%d] : %s\n", i,
+-		       map_num(ddf_init_state, ve->init_state&DDF_initstate_mask));
++		       map_num_s(ddf_init_state, ve->init_state & DDF_initstate_mask));
+ 		printf("       access[%d] : %s\n", i,
+-		       map_num(ddf_access, (ve->init_state & DDF_access_mask) >> 6));
++		       map_num_s(ddf_access, (ve->init_state & DDF_access_mask) >> 6));
+ 		printf("         Name[%d] : %.16s\n", i, ve->name);
+ 		examine_vd(i, sb, ve->guid);
+ 	}
+diff --git a/super-intel.c b/super-intel.c
+index 6ff336ee..ba3bd41f 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -5625,7 +5625,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
+ 		free(dev);
+ 		free(dv);
+ 		pr_err("imsm does not support consistency policy %s\n",
+-		       map_num(consistency_policies, s->consistency_policy));
++		       map_num_s(consistency_policies, s->consistency_policy));
+ 		return 0;
+ 	}
+ 
+diff --git a/super0.c b/super0.c
+index b79b97a9..61c9ec1d 100644
+--- a/super0.c
++++ b/super0.c
+@@ -288,7 +288,7 @@ static void export_examine_super0(struct supertype *st)
+ {
+ 	mdp_super_t *sb = st->sb;
+ 
+-	printf("MD_LEVEL=%s\n", map_num(pers, sb->level));
++	printf("MD_LEVEL=%s\n", map_num_s(pers, sb->level));
+ 	printf("MD_DEVICES=%d\n", sb->raid_disks);
+ 	if (sb->minor_version >= 90)
+ 		printf("MD_UUID=%08x:%08x:%08x:%08x\n",
+diff --git a/super1.c b/super1.c
+index a12a5bc8..e3e2f954 100644
+--- a/super1.c
++++ b/super1.c
+@@ -671,7 +671,7 @@ static void export_examine_super1(struct supertype *st)
+ 	int len = 32;
+ 	int layout;
+ 
+-	printf("MD_LEVEL=%s\n", map_num(pers, __le32_to_cpu(sb->level)));
++	printf("MD_LEVEL=%s\n", map_num_s(pers, __le32_to_cpu(sb->level)));
+ 	printf("MD_DEVICES=%d\n", __le32_to_cpu(sb->raid_disks));
+ 	for (i = 0; i < 32; i++)
+ 		if (sb->set_name[i] == '\n' || sb->set_name[i] == '\0') {
+diff --git a/sysfs.c b/sysfs.c
+index 2995713d..0d98a65f 100644
+--- a/sysfs.c
++++ b/sysfs.c
+@@ -689,7 +689,7 @@ int sysfs_set_array(struct mdinfo *info, int vers)
+ 	if (info->array.level < 0)
+ 		return 0; /* FIXME */
+ 	rv |= sysfs_set_str(info, NULL, "level",
+-			    map_num(pers, info->array.level));
++			    map_num_s(pers, info->array.level));
+ 	if (info->reshape_active && info->delta_disks != UnSet)
+ 		raid_disks -= info->delta_disks;
+ 	rv |= sysfs_set_num(info, NULL, "raid_disks", raid_disks);
+@@ -724,9 +724,10 @@ int sysfs_set_array(struct mdinfo *info, int vers)
+ 	}
+ 
+ 	if (info->consistency_policy == CONSISTENCY_POLICY_PPL) {
+-		if (sysfs_set_str(info, NULL, "consistency_policy",
+-				  map_num(consistency_policies,
+-					  info->consistency_policy))) {
++		char *policy = map_num_s(consistency_policies,
++					    info->consistency_policy);
++
++		if (sysfs_set_str(info, NULL, "consistency_policy", policy)) {
+ 			pr_err("This kernel does not support PPL. Falling back to consistency-policy=resync.\n");
+ 			info->consistency_policy = CONSISTENCY_POLICY_RESYNC;
+ 		}
+-- 
+2.31.1
+
diff --git a/SOURCES/0013-mdmon-Stop-parsing-duplicate-options.patch b/SOURCES/0013-mdmon-Stop-parsing-duplicate-options.patch
new file mode 100644
index 0000000..fed1740
--- /dev/null
+++ b/SOURCES/0013-mdmon-Stop-parsing-duplicate-options.patch
@@ -0,0 +1,122 @@
+From 1066ab83dbe9a4cc20f7db44a40aa2cbb9d5eed6 Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Fri, 13 May 2022 09:19:42 +0200
+Subject: [PATCH 13/52] mdmon: Stop parsing duplicate options
+
+Introduce new function is_duplicate_opt() to check if given option
+was already used and prevent setting it again along with an error
+message.
+
+Move parsing above in_initrd() check to be able to detect --offroot
+option duplicates.
+
+Now help option is executed after parsing to prevent executing commands
+like: 'mdmon --help --ndlksnlksajndfjksndafasj'.
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ mdmon.c | 44 +++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 35 insertions(+), 9 deletions(-)
+
+diff --git a/mdmon.c b/mdmon.c
+index 5570574b..c057da63 100644
+--- a/mdmon.c
++++ b/mdmon.c
+@@ -288,6 +288,15 @@ void usage(void)
+ 	exit(2);
+ }
+ 
++static bool is_duplicate_opt(const int opt, const int set_val, const char *long_name)
++{
++	if (opt == set_val) {
++		pr_err("--%s option duplicated!\n", long_name);
++		return true;
++	}
++	return false;
++}
++
+ static int mdmon(char *devnm, int must_fork, int takeover);
+ 
+ int main(int argc, char *argv[])
+@@ -299,6 +308,7 @@ int main(int argc, char *argv[])
+ 	int all = 0;
+ 	int takeover = 0;
+ 	int dofork = 1;
++	bool help = false;
+ 	static struct option options[] = {
+ 		{"all", 0, NULL, 'a'},
+ 		{"takeover", 0, NULL, 't'},
+@@ -308,37 +318,50 @@ int main(int argc, char *argv[])
+ 		{NULL, 0, NULL, 0}
+ 	};
+ 
+-	if (in_initrd()) {
+-		/*
+-		 * set first char of argv[0] to @. This is used by
+-		 * systemd to signal that the task was launched from
+-		 * initrd/initramfs and should be preserved during shutdown
+-		 */
+-		argv[0][0] = '@';
+-	}
+-
+ 	while ((opt = getopt_long(argc, argv, "thaF", options, NULL)) != -1) {
+ 		switch (opt) {
+ 		case 'a':
++			if (is_duplicate_opt(all, 1, "all"))
++				exit(1);
+ 			container_name = argv[optind-1];
+ 			all = 1;
+ 			break;
+ 		case 't':
++			if (is_duplicate_opt(takeover, 1, "takeover"))
++				exit(1);
+ 			takeover = 1;
+ 			break;
+ 		case 'F':
++			if (is_duplicate_opt(dofork, 0, "foreground"))
++				exit(1);
+ 			dofork = 0;
+ 			break;
+ 		case OffRootOpt:
++			if (is_duplicate_opt(argv[0][0], '@', "offroot"))
++				exit(1);
+ 			argv[0][0] = '@';
+ 			break;
+ 		case 'h':
++			if (is_duplicate_opt(help, true, "help"))
++				exit(1);
++			help = true;
++			break;
+ 		default:
+ 			usage();
+ 			break;
+ 		}
+ 	}
+ 
++
++	if (in_initrd()) {
++		/*
++		 * set first char of argv[0] to @. This is used by
++		 * systemd to signal that the task was launched from
++		 * initrd/initramfs and should be preserved during shutdown
++		 */
++		argv[0][0] = '@';
++	}
++
+ 	if (all == 0 && container_name == NULL) {
+ 		if (argv[optind])
+ 			container_name = argv[optind];
+@@ -353,6 +376,9 @@ int main(int argc, char *argv[])
+ 	if (strcmp(container_name, "/proc/mdstat") == 0)
+ 		all = 1;
+ 
++	if (help)
++		usage();
++
+ 	if (all) {
+ 		struct mdstat_ent *mdstat, *e;
+ 		int container_len = strlen(container_name);
+-- 
+2.31.1
+
diff --git a/SOURCES/0014-Grow-block-n-on-external-volumes.patch b/SOURCES/0014-Grow-block-n-on-external-volumes.patch
new file mode 100644
index 0000000..25ffac1
--- /dev/null
+++ b/SOURCES/0014-Grow-block-n-on-external-volumes.patch
@@ -0,0 +1,41 @@
+From 20e114e334ed6ed3280c37a9a08fb95578393d1a Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Thu, 19 May 2022 09:16:08 +0200
+Subject: [PATCH 14/52] Grow: block -n on external volumes.
+
+Performing --raid-devices on external metadata volume should be blocked
+as it causes unwanted behaviour.
+
+Eg. Performing
+mdadm -G /dev/md/volume -l10 -n4
+on r0_d2 inside 4 disk container, returns
+mdadm: Need 2 spares to avoid degraded array, only have 0.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Grow.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/Grow.c b/Grow.c
+index 8a242b0f..f6efbc48 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1892,6 +1892,14 @@ int Grow_reshape(char *devname, int fd,
+ 
+ 		if (retval) {
+ 			pr_err("Cannot read superblock for %s\n", devname);
++			close(cfd);
++			free(subarray);
++			return 1;
++		}
++
++		if (s->raiddisks && subarray) {
++			pr_err("--raid-devices operation can be performed on a container only\n");
++			close(cfd);
+ 			free(subarray);
+ 			return 1;
+ 		}
+-- 
+2.31.1
+
diff --git a/SOURCES/0015-Incremental-Fix-possible-memory-and-resource-leaks.patch b/SOURCES/0015-Incremental-Fix-possible-memory-and-resource-leaks.patch
new file mode 100644
index 0000000..42fa773
--- /dev/null
+++ b/SOURCES/0015-Incremental-Fix-possible-memory-and-resource-leaks.patch
@@ -0,0 +1,90 @@
+From de064c93e3819d72720e4fba6575265ba10e1553 Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Mon, 13 Jun 2022 12:11:25 +0200
+Subject: [PATCH 15/52] Incremental: Fix possible memory and resource leaks
+
+map allocated through map_by_uuid() is not freed if mdfd is invalid.
+In addition mdfd is not closed, and mdinfo list is not freed too.
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Change-Id: I25e726f0e2502cf7e8ce80c2bd7944b3b1e2b9dc
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Incremental.c | 32 +++++++++++++++++++++++---------
+ 1 file changed, 23 insertions(+), 9 deletions(-)
+
+diff --git a/Incremental.c b/Incremental.c
+index a57fc323..4d0cd9d6 100644
+--- a/Incremental.c
++++ b/Incremental.c
+@@ -1499,7 +1499,7 @@ static int Incremental_container(struct supertype *st, char *devname,
+ 		return 0;
+ 	}
+ 	for (ra = list ; ra ; ra = ra->next) {
+-		int mdfd;
++		int mdfd = -1;
+ 		char chosen_name[1024];
+ 		struct map_ent *mp;
+ 		struct mddev_ident *match = NULL;
+@@ -1514,6 +1514,12 @@ static int Incremental_container(struct supertype *st, char *devname,
+ 
+ 		if (mp) {
+ 			mdfd = open_dev(mp->devnm);
++			if (!is_fd_valid(mdfd)) {
++				pr_err("failed to open %s: %s.\n",
++				       mp->devnm, strerror(errno));
++				rv = 2;
++				goto release;
++			}
+ 			if (mp->path)
+ 				strcpy(chosen_name, mp->path);
+ 			else
+@@ -1573,21 +1579,25 @@ static int Incremental_container(struct supertype *st, char *devname,
+ 					    c->autof,
+ 					    trustworthy,
+ 					    chosen_name, 0);
++
++			if (!is_fd_valid(mdfd)) {
++				pr_err("create_mddev failed with chosen name %s: %s.\n",
++				       chosen_name, strerror(errno));
++				rv = 2;
++				goto release;
++			}
+ 		}
+-		if (only && (!mp || strcmp(mp->devnm, only) != 0))
+-			continue;
+ 
+-		if (mdfd < 0) {
+-			pr_err("failed to open %s: %s.\n",
+-				chosen_name, strerror(errno));
+-			return 2;
++		if (only && (!mp || strcmp(mp->devnm, only) != 0)) {
++			close_fd(&mdfd);
++			continue;
+ 		}
+ 
+ 		assemble_container_content(st, mdfd, ra, c,
+ 					   chosen_name, &result);
+ 		map_free(map);
+ 		map = NULL;
+-		close(mdfd);
++		close_fd(&mdfd);
+ 	}
+ 	if (c->export && result) {
+ 		char sep = '=';
+@@ -1610,7 +1620,11 @@ static int Incremental_container(struct supertype *st, char *devname,
+ 		}
+ 		printf("\n");
+ 	}
+-	return 0;
++
++release:
++	map_free(map);
++	sysfs_free(list);
++	return rv;
+ }
+ 
+ static void run_udisks(char *arg1, char *arg2)
+-- 
+2.31.1
+
diff --git a/SOURCES/0016-Mdmonitor-Fix-segfault.patch b/SOURCES/0016-Mdmonitor-Fix-segfault.patch
new file mode 100644
index 0000000..05c7fb4
--- /dev/null
+++ b/SOURCES/0016-Mdmonitor-Fix-segfault.patch
@@ -0,0 +1,98 @@
+From e702f392959d1c2ad2089e595b52235ed97b4e18 Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Mon, 6 Jun 2022 12:32:12 +0200
+Subject: [PATCH 16/52] Mdmonitor: Fix segfault
+
+Mdadm with "--monitor" parameter requires md device
+as an argument to be monitored. If given argument is
+not a md device, error shall be returned. Previously
+it was not checked and invalid argument caused
+segmentation fault. This commit adds checking
+that devices passed to mdmonitor are md devices.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Monitor.c | 10 +++++++++-
+ mdadm.h   |  1 +
+ mdopen.c  | 17 +++++++++++++++++
+ 3 files changed, 27 insertions(+), 1 deletion(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index c0ab5412..4e5802b5 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -182,6 +182,7 @@ int Monitor(struct mddev_dev *devlist,
+ 				continue;
+ 			if (strcasecmp(mdlist->devname, "<ignore>") == 0)
+ 				continue;
++
+ 			st = xcalloc(1, sizeof *st);
+ 			if (mdlist->devname[0] == '/')
+ 				st->devname = xstrdup(mdlist->devname);
+@@ -190,6 +191,8 @@ int Monitor(struct mddev_dev *devlist,
+ 				strcpy(strcpy(st->devname, "/dev/md/"),
+ 				       mdlist->devname);
+ 			}
++			if (!is_mddev(mdlist->devname))
++				return 1;
+ 			st->next = statelist;
+ 			st->devnm[0] = 0;
+ 			st->percent = RESYNC_UNKNOWN;
+@@ -203,7 +206,12 @@ int Monitor(struct mddev_dev *devlist,
+ 		struct mddev_dev *dv;
+ 
+ 		for (dv = devlist; dv; dv = dv->next) {
+-			struct state *st = xcalloc(1, sizeof *st);
++			struct state *st;
++
++			if (!is_mddev(dv->devname))
++				return 1;
++
++			st = xcalloc(1, sizeof *st);
+ 			mdlist = conf_get_ident(dv->devname);
+ 			st->devname = xstrdup(dv->devname);
+ 			st->next = statelist;
+diff --git a/mdadm.h b/mdadm.h
+index 09915a00..d53df169 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1636,6 +1636,7 @@ extern int create_mddev(char *dev, char *name, int autof, int trustworthy,
+ #define	FOREIGN	2
+ #define	METADATA 3
+ extern int open_mddev(char *dev, int report_errors);
++extern int is_mddev(char *dev);
+ extern int open_container(int fd);
+ extern int metadata_container_matches(char *metadata, char *devnm);
+ extern int metadata_subdev_matches(char *metadata, char *devnm);
+diff --git a/mdopen.c b/mdopen.c
+index 245be537..d18c9319 100644
+--- a/mdopen.c
++++ b/mdopen.c
+@@ -475,6 +475,23 @@ int open_mddev(char *dev, int report_errors)
+ 	return mdfd;
+ }
+ 
++/**
++ * is_mddev() - check that file name passed is an md device.
++ * @dev: file name that has to be checked.
++ * Return: 1 if file passed is an md device, 0 if not.
++ */
++int is_mddev(char *dev)
++{
++	int fd = open_mddev(dev, 1);
++
++	if (fd >= 0) {
++		close(fd);
++		return 1;
++	}
++
++	return 0;
++}
++
+ char *find_free_devnm(int use_partitions)
+ {
+ 	static char devnm[32];
+-- 
+2.31.1
+
diff --git a/SOURCES/0017-Mdmonitor-Improve-logging-method.patch b/SOURCES/0017-Mdmonitor-Improve-logging-method.patch
new file mode 100644
index 0000000..f00b8b3
--- /dev/null
+++ b/SOURCES/0017-Mdmonitor-Improve-logging-method.patch
@@ -0,0 +1,61 @@
+From f5ff2988761625b43eb15555993f2797af29f166 Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Mon, 6 Jun 2022 12:32:13 +0200
+Subject: [PATCH 17/52] Mdmonitor: Improve logging method
+
+Change logging, and as a result, mdmonitor in verbose
+mode will report its configuration.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Signed-off-by: Oleksandr Shchirskyi <oleksandr.shchirskyi@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Monitor.c | 25 ++++++++++++++-----------
+ 1 file changed, 14 insertions(+), 11 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 4e5802b5..6ca1ebe5 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -136,24 +136,27 @@ int Monitor(struct mddev_dev *devlist,
+ 	struct mddev_ident *mdlist;
+ 	int delay_for_event = c->delay;
+ 
+-	if (!mailaddr) {
++	if (!mailaddr)
+ 		mailaddr = conf_get_mailaddr();
+-		if (mailaddr && ! c->scan)
+-			pr_err("Monitor using email address \"%s\" from config file\n",
+-			       mailaddr);
+-	}
+-	mailfrom = conf_get_mailfrom();
+ 
+-	if (!alert_cmd) {
++	if (!alert_cmd)
+ 		alert_cmd = conf_get_program();
+-		if (alert_cmd && !c->scan)
+-			pr_err("Monitor using program \"%s\" from config file\n",
+-			       alert_cmd);
+-	}
++
++	mailfrom = conf_get_mailfrom();
++
+ 	if (c->scan && !mailaddr && !alert_cmd && !dosyslog) {
+ 		pr_err("No mail address or alert command - not monitoring.\n");
+ 		return 1;
+ 	}
++
++	if (c->verbose) {
++		pr_err("Monitor is started with delay %ds\n", c->delay);
++		if (mailaddr)
++			pr_err("Monitor using email address %s\n", mailaddr);
++		if (alert_cmd)
++			pr_err("Monitor using program %s\n", alert_cmd);
++	}
++
+ 	info.alert_cmd = alert_cmd;
+ 	info.mailaddr = mailaddr;
+ 	info.mailfrom = mailfrom;
+-- 
+2.31.1
+
diff --git a/SOURCES/0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch b/SOURCES/0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch
new file mode 100644
index 0000000..a5e9351
--- /dev/null
+++ b/SOURCES/0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch
@@ -0,0 +1,73 @@
+From 626bc45396c4959f2c4685c2faa7c4f553f4efdf Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Mon, 13 Jun 2022 11:59:34 +0200
+Subject: [PATCH 18/52] Fix possible NULL ptr dereferences and memory leaks
+
+In Assemble there was a NULL check for sra variable,
+which effectively didn't stop the execution in every case.
+That might have resulted in a NULL pointer dereference.
+
+Also in super-ddf, mu variable was set to NULL for some condition,
+and then immidiately dereferenced.
+Additionally some memory wasn't freed as well.
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c  | 7 ++++++-
+ super-ddf.c | 9 +++++++--
+ 2 files changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index 9eac9ce0..4b213560 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -1982,7 +1982,12 @@ int assemble_container_content(struct supertype *st, int mdfd,
+ 	}
+ 
+ 	sra = sysfs_read(mdfd, NULL, GET_VERSION|GET_DEVS);
+-	if (sra == NULL || strcmp(sra->text_version, content->text_version) != 0) {
++	if (sra == NULL) {
++		pr_err("Failed to read sysfs parameters\n");
++		return 1;
++	}
++
++	if (strcmp(sra->text_version, content->text_version) != 0) {
+ 		if (content->array.major_version == -1 &&
+ 		    content->array.minor_version == -2 &&
+ 		    c->readonly &&
+diff --git a/super-ddf.c b/super-ddf.c
+index 8cda23a7..abbc8b09 100644
+--- a/super-ddf.c
++++ b/super-ddf.c
+@@ -5125,13 +5125,16 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a,
+ 	 */
+ 	vc = find_vdcr(ddf, a->info.container_member, rv->disk.raid_disk,
+ 		       &n_bvd, &vcl);
+-	if (vc == NULL)
++	if (vc == NULL) {
++		free(rv);
+ 		return NULL;
++	}
+ 
+ 	mu = xmalloc(sizeof(*mu));
+ 	if (posix_memalign(&mu->space, 512, sizeof(struct vcl)) != 0) {
+ 		free(mu);
+-		mu = NULL;
++		free(rv);
++		return NULL;
+ 	}
+ 
+ 	mu->len = ddf->conf_rec_len * 512 * vcl->conf.sec_elmnt_count;
+@@ -5161,6 +5164,8 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a,
+ 			pr_err("BUG: can't find disk %d (%d/%d)\n",
+ 			       di->disk.raid_disk,
+ 			       di->disk.major, di->disk.minor);
++			free(mu);
++			free(rv);
+ 			return NULL;
+ 		}
+ 		vc->phys_refnum[i_prim] = ddf->phys->entries[dl->pdnum].refnum;
+-- 
+2.31.1
+
diff --git a/SOURCES/0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch b/SOURCES/0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch
new file mode 100644
index 0000000..87b6db6
--- /dev/null
+++ b/SOURCES/0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch
@@ -0,0 +1,301 @@
+From 756a15f32338fdf0c562678694bc8991ad6afb90 Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Mon, 13 Jun 2022 12:00:09 +0200
+Subject: [PATCH 19/52] imsm: Remove possibility for get_imsm_dev to return
+ NULL
+
+Returning NULL from get_imsm_dev or __get_imsm_dev will cause segfault.
+Guarantee that it never happens.
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 153 +++++++++++++++++++++++++-------------------------
+ 1 file changed, 78 insertions(+), 75 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index ba3bd41f..3788feb9 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -851,6 +851,21 @@ static struct disk_info *get_disk_info(struct imsm_update_create_array *update)
+ 	return inf;
+ }
+ 
++/**
++ * __get_imsm_dev() - Get device with index from imsm_super.
++ * @mpb: &imsm_super pointer, not NULL.
++ * @index: Device index.
++ *
++ * Function works as non-NULL, aborting in such a case,
++ * when NULL would be returned.
++ *
++ * Device index should be in range 0 up to num_raid_devs.
++ * Function assumes the index was already verified.
++ * Index must be valid, otherwise abort() is called.
++ *
++ * Return: Pointer to corresponding imsm_dev.
++ *
++ */
+ static struct imsm_dev *__get_imsm_dev(struct imsm_super *mpb, __u8 index)
+ {
+ 	int offset;
+@@ -858,30 +873,47 @@ static struct imsm_dev *__get_imsm_dev(struct imsm_super *mpb, __u8 index)
+ 	void *_mpb = mpb;
+ 
+ 	if (index >= mpb->num_raid_devs)
+-		return NULL;
++		goto error;
+ 
+ 	/* devices start after all disks */
+ 	offset = ((void *) &mpb->disk[mpb->num_disks]) - _mpb;
+ 
+-	for (i = 0; i <= index; i++)
++	for (i = 0; i <= index; i++, offset += sizeof_imsm_dev(_mpb + offset, 0))
+ 		if (i == index)
+ 			return _mpb + offset;
+-		else
+-			offset += sizeof_imsm_dev(_mpb + offset, 0);
+-
+-	return NULL;
++error:
++	pr_err("cannot find imsm_dev with index %u in imsm_super\n", index);
++	abort();
+ }
+ 
++/**
++ * get_imsm_dev() - Get device with index from intel_super.
++ * @super: &intel_super pointer, not NULL.
++ * @index: Device index.
++ *
++ * Function works as non-NULL, aborting in such a case,
++ * when NULL would be returned.
++ *
++ * Device index should be in range 0 up to num_raid_devs.
++ * Function assumes the index was already verified.
++ * Index must be valid, otherwise abort() is called.
++ *
++ * Return: Pointer to corresponding imsm_dev.
++ *
++ */
+ static struct imsm_dev *get_imsm_dev(struct intel_super *super, __u8 index)
+ {
+ 	struct intel_dev *dv;
+ 
+ 	if (index >= super->anchor->num_raid_devs)
+-		return NULL;
++		goto error;
++
+ 	for (dv = super->devlist; dv; dv = dv->next)
+ 		if (dv->index == index)
+ 			return dv->dev;
+-	return NULL;
++error:
++	pr_err("cannot find imsm_dev with index %u in intel_super\n", index);
++	abort();
+ }
+ 
+ static inline unsigned long long __le48_to_cpu(const struct bbm_log_block_addr
+@@ -4364,8 +4396,7 @@ int check_mpb_migr_compatibility(struct intel_super *super)
+ 	for (i = 0; i < super->anchor->num_raid_devs; i++) {
+ 		struct imsm_dev *dev_iter = __get_imsm_dev(super->anchor, i);
+ 
+-		if (dev_iter &&
+-		    dev_iter->vol.migr_state == 1 &&
++		if (dev_iter->vol.migr_state == 1 &&
+ 		    dev_iter->vol.migr_type == MIGR_GEN_MIGR) {
+ 			/* This device is migrating */
+ 			map0 = get_imsm_map(dev_iter, MAP_0);
+@@ -4514,8 +4545,6 @@ static void clear_hi(struct intel_super *super)
+ 	}
+ 	for (i = 0; i < mpb->num_raid_devs; ++i) {
+ 		struct imsm_dev *dev = get_imsm_dev(super, i);
+-		if (!dev)
+-			return;
+ 		for (n = 0; n < 2; ++n) {
+ 			struct imsm_map *map = get_imsm_map(dev, n);
+ 			if (!map)
+@@ -5836,7 +5865,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
+ 		struct imsm_dev *_dev = __get_imsm_dev(mpb, 0);
+ 
+ 		_disk = __get_imsm_disk(mpb, dl->index);
+-		if (!_dev || !_disk) {
++		if (!_disk) {
+ 			pr_err("BUG mpb setup error\n");
+ 			return 1;
+ 		}
+@@ -6171,10 +6200,10 @@ static int write_super_imsm(struct supertype *st, int doclose)
+ 	for (i = 0; i < mpb->num_raid_devs; i++) {
+ 		struct imsm_dev *dev = __get_imsm_dev(mpb, i);
+ 		struct imsm_dev *dev2 = get_imsm_dev(super, i);
+-		if (dev && dev2) {
+-			imsm_copy_dev(dev, dev2);
+-			mpb_size += sizeof_imsm_dev(dev, 0);
+-		}
++
++		imsm_copy_dev(dev, dev2);
++		mpb_size += sizeof_imsm_dev(dev, 0);
++
+ 		if (is_gen_migration(dev2))
+ 			clear_migration_record = 0;
+ 	}
+@@ -9033,29 +9062,26 @@ static int imsm_rebuild_allowed(struct supertype *cont, int dev_idx, int failed)
+ 	__u8 state;
+ 
+ 	dev2 = get_imsm_dev(cont->sb, dev_idx);
+-	if (dev2) {
+-		state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0);
+-		if (state == IMSM_T_STATE_FAILED) {
+-			map = get_imsm_map(dev2, MAP_0);
+-			if (!map)
+-				return 1;
+-			for (slot = 0; slot < map->num_members; slot++) {
+-				/*
+-				 * Check if failed disks are deleted from intel
+-				 * disk list or are marked to be deleted
+-				 */
+-				idx = get_imsm_disk_idx(dev2, slot, MAP_X);
+-				idisk = get_imsm_dl_disk(cont->sb, idx);
+-				/*
+-				 * Do not rebuild the array if failed disks
+-				 * from failed sub-array are not removed from
+-				 * container.
+-				 */
+-				if (idisk &&
+-				    is_failed(&idisk->disk) &&
+-				    (idisk->action != DISK_REMOVE))
+-					return 0;
+-			}
++
++	state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0);
++	if (state == IMSM_T_STATE_FAILED) {
++		map = get_imsm_map(dev2, MAP_0);
++		for (slot = 0; slot < map->num_members; slot++) {
++			/*
++			 * Check if failed disks are deleted from intel
++			 * disk list or are marked to be deleted
++			 */
++			idx = get_imsm_disk_idx(dev2, slot, MAP_X);
++			idisk = get_imsm_dl_disk(cont->sb, idx);
++			/*
++			 * Do not rebuild the array if failed disks
++			 * from failed sub-array are not removed from
++			 * container.
++			 */
++			if (idisk &&
++			    is_failed(&idisk->disk) &&
++			    (idisk->action != DISK_REMOVE))
++				return 0;
+ 		}
+ 	}
+ 	return 1;
+@@ -10089,7 +10115,6 @@ static void imsm_process_update(struct supertype *st,
+ 		int victim = u->dev_idx;
+ 		struct active_array *a;
+ 		struct intel_dev **dp;
+-		struct imsm_dev *dev;
+ 
+ 		/* sanity check that we are not affecting the uuid of
+ 		 * active arrays, or deleting an active array
+@@ -10105,8 +10130,7 @@ static void imsm_process_update(struct supertype *st,
+ 		 * is active in the container, so checking
+ 		 * mpb->num_raid_devs is just extra paranoia
+ 		 */
+-		dev = get_imsm_dev(super, victim);
+-		if (a || !dev || mpb->num_raid_devs == 1) {
++		if (a || mpb->num_raid_devs == 1 || victim >= super->anchor->num_raid_devs) {
+ 			dprintf("failed to delete subarray-%d\n", victim);
+ 			break;
+ 		}
+@@ -10140,7 +10164,7 @@ static void imsm_process_update(struct supertype *st,
+ 			if (a->info.container_member == target)
+ 				break;
+ 		dev = get_imsm_dev(super, u->dev_idx);
+-		if (a || !dev || !check_name(super, name, 1)) {
++		if (a || !check_name(super, name, 1)) {
+ 			dprintf("failed to rename subarray-%d\n", target);
+ 			break;
+ 		}
+@@ -10169,10 +10193,6 @@ static void imsm_process_update(struct supertype *st,
+ 		struct imsm_update_rwh_policy *u = (void *)update->buf;
+ 		int target = u->dev_idx;
+ 		struct imsm_dev *dev = get_imsm_dev(super, target);
+-		if (!dev) {
+-			dprintf("could not find subarray-%d\n", target);
+-			break;
+-		}
+ 
+ 		if (dev->rwh_policy != u->new_policy) {
+ 			dev->rwh_policy = u->new_policy;
+@@ -11397,8 +11417,10 @@ static int imsm_create_metadata_update_for_migration(
+ {
+ 	struct intel_super *super = st->sb;
+ 	int update_memory_size;
++	int current_chunk_size;
+ 	struct imsm_update_reshape_migration *u;
+-	struct imsm_dev *dev;
++	struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
++	struct imsm_map *map = get_imsm_map(dev, MAP_0);
+ 	int previous_level = -1;
+ 
+ 	dprintf("(enter) New Level = %i\n", geo->level);
+@@ -11415,23 +11437,15 @@ static int imsm_create_metadata_update_for_migration(
+ 	u->new_disks[0] = -1;
+ 	u->new_chunksize = -1;
+ 
+-	dev = get_imsm_dev(super, u->subdev);
+-	if (dev) {
+-		struct imsm_map *map;
++	current_chunk_size = __le16_to_cpu(map->blocks_per_strip) / 2;
+ 
+-		map = get_imsm_map(dev, MAP_0);
+-		if (map) {
+-			int current_chunk_size =
+-				__le16_to_cpu(map->blocks_per_strip) / 2;
+-
+-			if (geo->chunksize != current_chunk_size) {
+-				u->new_chunksize = geo->chunksize / 1024;
+-				dprintf("imsm: chunk size change from %i to %i\n",
+-					current_chunk_size, u->new_chunksize);
+-			}
+-			previous_level = map->raid_level;
+-		}
++	if (geo->chunksize != current_chunk_size) {
++		u->new_chunksize = geo->chunksize / 1024;
++		dprintf("imsm: chunk size change from %i to %i\n",
++			current_chunk_size, u->new_chunksize);
+ 	}
++	previous_level = map->raid_level;
++
+ 	if (geo->level == 5 && previous_level == 0) {
+ 		struct mdinfo *spares = NULL;
+ 
+@@ -12519,9 +12533,6 @@ static int validate_internal_bitmap_imsm(struct supertype *st)
+ 	unsigned long long offset;
+ 	struct dl *d;
+ 
+-	if (!dev)
+-		return -1;
+-
+ 	if (dev->rwh_policy != RWH_BITMAP)
+ 		return 0;
+ 
+@@ -12567,16 +12578,8 @@ static int add_internal_bitmap_imsm(struct supertype *st, int *chunkp,
+ 		return -1;
+ 
+ 	dev = get_imsm_dev(super, vol_idx);
+-
+-	if (!dev) {
+-		dprintf("cannot find the device for volume index %d\n",
+-			vol_idx);
+-		return -1;
+-	}
+ 	dev->rwh_policy = RWH_BITMAP;
+-
+ 	*chunkp = calculate_bitmap_chunksize(st, dev);
+-
+ 	return 0;
+ }
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch b/SOURCES/0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch
new file mode 100644
index 0000000..107ac28
--- /dev/null
+++ b/SOURCES/0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch
@@ -0,0 +1,85 @@
+From 190dc029b141c423e724566cbed5d5afbb10b05a Mon Sep 17 00:00:00 2001
+From: Nigel Croxon <ncroxon@redhat.com>
+Date: Mon, 18 Apr 2022 13:44:23 -0400
+Subject: [PATCH 20/52] Revert "mdadm: fix coredump of mdadm --monitor -r"
+
+This reverts commit 546047688e1c64638f462147c755b58119cabdc8.
+
+The change from commit mdadm: fix coredump of mdadm
+--monitor -r broke the printing of the return message when
+passing -r to mdadm --manage, the removal of a device from
+an array.
+
+If the current code reverts this commit, both issues are
+still fixed.
+
+The original problem reported that the fix tried to address
+was:  The --monitor -r option requires a parameter,
+otherwise a null pointer will be manipulated when
+converting to integer data, and a core dump will appear.
+
+The original problem was really fixed with:
+60815698c0a Refactor parse_num and use it to parse optarg.
+Which added a check for NULL in 'optarg' before moving it
+to the 'increments' variable.
+
+New issue: When trying to remove a device using the short
+argument -r, instead of the long argument --remove, the
+output is empty. The problem started when commit
+546047688e1c was added.
+
+Steps to Reproduce:
+1. create/assemble /dev/md0 device
+2. mdadm --manage /dev/md0 -r /dev/vdxx
+
+Actual results:
+Nothing, empty output, nothing happens, the device is still
+connected to the array.
+
+The output should have stated "mdadm: hot remove failed
+for /dev/vdxx: Device or resource busy", if the device was
+still active. Or it should remove the device and print
+a message:
+
+mdadm: set /dev/vdd faulty in /dev/md0
+mdadm: hot removed /dev/vdd from /dev/md0
+
+The following commit should be reverted as it breaks
+mdadm --manage -r.
+
+commit 546047688e1c64638f462147c755b58119cabdc8
+Author: Wu Guanghao <wuguanghao3@huawei.com>
+Date:   Mon Aug 16 15:24:51 2021 +0800
+mdadm: fix coredump of mdadm --monitor -r
+
+-Nigel
+
+Signed-off-by: Nigel Croxon <ncroxon@redhat.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ ReadMe.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/ReadMe.c b/ReadMe.c
+index 8f873c48..bec1be9a 100644
+--- a/ReadMe.c
++++ b/ReadMe.c
+@@ -81,11 +81,11 @@ char Version[] = "mdadm - v" VERSION " - " VERS_DATE EXTRAVERSION "\n";
+  *     found, it is started.
+  */
+ 
+-char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:r:n:x:u:c:d:z:U:N:safRSow1tye:k";
++char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
+ char short_bitmap_options[]=
+-		"-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:r:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
++		"-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
+ char short_bitmap_auto_options[]=
+-		"-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:r:n:x:u:c:d:z:U:N:sa:rfRSow1tye:k:";
++		"-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sa:rfRSow1tye:k:";
+ 
+ struct option long_options[] = {
+     {"manage",    0, 0, ManageOpt},
+-- 
+2.31.1
+
diff --git a/SOURCES/0021-util-replace-ioctl-use-with-function.patch b/SOURCES/0021-util-replace-ioctl-use-with-function.patch
new file mode 100644
index 0000000..3833674
--- /dev/null
+++ b/SOURCES/0021-util-replace-ioctl-use-with-function.patch
@@ -0,0 +1,31 @@
+From 953cc7e5a485a91ddec7312c7a5d7779749fad5f Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Tue, 21 Jun 2022 00:10:39 +0800
+Subject: [PATCH 21/52] util: replace ioctl use with function
+
+Replace using of ioctl calling to get md array info with
+special function prepared to it.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ util.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util.c b/util.c
+index cc94f96e..38f0420e 100644
+--- a/util.c
++++ b/util.c
+@@ -267,7 +267,7 @@ int md_array_active(int fd)
+ 		 * GET_ARRAY_INFO doesn't provide access to the proper state
+ 		 * information, so fallback to a basic check for raid_disks != 0
+ 		 */
+-		ret = ioctl(fd, GET_ARRAY_INFO, &array);
++		ret = md_get_array_info(fd, &array);
+ 	}
+ 
+ 	return !ret;
+-- 
+2.31.1
+
diff --git a/SOURCES/0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch b/SOURCES/0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch
new file mode 100644
index 0000000..360ec6e
--- /dev/null
+++ b/SOURCES/0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch
@@ -0,0 +1,110 @@
+From 63902857b98c37c8ac4b837bb01d006b327a4532 Mon Sep 17 00:00:00 2001
+From: Heming Zhao <heming.zhao@suse.com>
+Date: Tue, 21 Jun 2022 00:10:40 +0800
+Subject: [PATCH 22/52] mdadm/super1: restore commit 45a87c2f31335 to fix
+ clustered slot issue
+
+Commit 9d67f6496c71 ("mdadm:check the nodes when operate clustered
+array") modified assignment logic for st->nodes in write_bitmap1(),
+which introduced bitmap slot issue:
+
+load_super1 didn't set up supertype.nodes, which made spare disk only
+have one slot info. Then it triggered kernel md_bitmap_load_sb to get
+wrong bitmap slot data.
+
+For fixing this issue, there are two methods:
+
+1> revert the related code of commit 9d67f6496c71. and restore the code
+   from former commit 45a87c2f31335 ("super1: add more checks for
+   NodeNumUpdate option").
+   st->nodes value would be 0 & 1 under current code logic. i.e.
+   When adding a spare disk, there is no place to init st->nodes, and
+   the value is ZERO.
+
+2> keep 9d67f6496c71, add additional ->nodes handling in load_super1(),
+   let load_super1 to set st->nodes when bitmap is BITMAP_MAJOR_CLUSTERED.
+   Under current mdadm code logic, load_super1 will be called many
+   times, any new code in load_super1 will cost mdadm running more time.
+   And more reason is I prefer as much as possible to limit clustered
+   code spreading in every corner.
+
+So I used method <1> to fix this issue.
+
+How to trigger:
+
+dd if=/dev/zero bs=1M count=1 oflag=direct of=/dev/sda
+dd if=/dev/zero bs=1M count=1 oflag=direct of=/dev/sdb
+dd if=/dev/zero bs=1M count=1 oflag=direct of=/dev/sdc
+mdadm -C /dev/md0 -b clustered -e 1.2 -n 2 -l mirror /dev/sda /dev/sdb
+mdadm -a /dev/md0 /dev/sdc
+mdadm /dev/md0 --fail /dev/sda
+mdadm /dev/md0 --remove /dev/sda
+mdadm -Ss
+mdadm -A /dev/md0 /dev/sdb /dev/sdc
+
+the output of current "mdadm -X /dev/sdc":
+(there should be (by default) 4 slot info for correct output)
+```
+        Filename : /dev/sdc
+           Magic : 6d746962
+         Version : 5
+            UUID : a74642f8:a6b1fba8:58e1f8db:cfe7b082
+          Events : 29
+  Events Cleared : 0
+           State : OK
+       Chunksize : 64 MB
+          Daemon : 5s flush period
+      Write Mode : Normal
+       Sync Size : 306176 (299.00 MiB 313.52 MB)
+          Bitmap : 5 bits (chunks), 5 dirty (100.0%)
+```
+
+And mdadm later operations will trigger kernel output error message:
+(triggered by "mdadm -A /dev/md0 /dev/sdb /dev/sdc")
+```
+kernel: md0: invalid bitmap file superblock: bad magic
+kernel: md_bitmap_copy_from_slot can't get bitmap from slot 1
+kernel: md-cluster: Could not gather bitmaps from slot 1
+kernel: md0: invalid bitmap file superblock: bad magic
+kernel: md_bitmap_copy_from_slot can't get bitmap from slot 2
+kernel: md-cluster: Could not gather bitmaps from slot 2
+kernel: md0: invalid bitmap file superblock: bad magic
+kernel: md_bitmap_copy_from_slot can't get bitmap from slot 3
+kernel: md-cluster: Could not gather bitmaps from slot 3
+kernel: md-cluster: failed to gather all resyn infos
+kernel: md0: detected capacity change from 0 to 612352
+```
+
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Heming Zhao <heming.zhao@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super1.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/super1.c b/super1.c
+index e3e2f954..3a0c69fd 100644
+--- a/super1.c
++++ b/super1.c
+@@ -2674,7 +2674,17 @@ static int write_bitmap1(struct supertype *st, int fd, enum bitmap_update update
+ 		}
+ 
+ 		if (bms->version == BITMAP_MAJOR_CLUSTERED) {
+-			if (__cpu_to_le32(st->nodes) < bms->nodes) {
++			if (st->nodes == 1) {
++				/* the parameter for nodes is not valid */
++				pr_err("Warning: cluster-md at least needs two nodes\n");
++				return -EINVAL;
++			} else if (st->nodes == 0) {
++				/*
++				 * parameter "--nodes" is not specified, (eg, add a disk to
++				 * clustered raid)
++				 */
++				break;
++			} else if (__cpu_to_le32(st->nodes) < bms->nodes) {
+ 				/*
+ 				 * Since the nodes num is not increased, no
+ 				 * need to check the space enough or not,
+-- 
+2.31.1
+
diff --git a/SOURCES/0023-imsm-introduce-get_disk_slot_in_dev.patch b/SOURCES/0023-imsm-introduce-get_disk_slot_in_dev.patch
new file mode 100644
index 0000000..d979cc5
--- /dev/null
+++ b/SOURCES/0023-imsm-introduce-get_disk_slot_in_dev.patch
@@ -0,0 +1,122 @@
+From 76c152ca9851e9fcdf52e8f6e7e6c09b936bdd14 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Tue, 21 Jun 2022 00:10:41 +0800
+Subject: [PATCH 23/52] imsm: introduce get_disk_slot_in_dev()
+
+The routine was added to remove unnecessary get_imsm_dev() and
+get_imsm_map() calls, used only to determine disk slot.
+
+Additionally, enum for IMSM return statues was added for further usage.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 47 ++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 36 insertions(+), 11 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 3788feb9..cd1f1e3d 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -366,6 +366,18 @@ struct migr_record {
+ };
+ ASSERT_SIZE(migr_record, 128)
+ 
++/**
++ * enum imsm_status - internal IMSM return values representation.
++ * @STATUS_OK: function succeeded.
++ * @STATUS_ERROR: General error ocurred (not specified).
++ *
++ * Typedefed to imsm_status_t.
++ */
++typedef enum imsm_status {
++	IMSM_STATUS_ERROR = -1,
++	IMSM_STATUS_OK = 0,
++} imsm_status_t;
++
+ struct md_list {
+ 	/* usage marker:
+ 	 *  1: load metadata
+@@ -1183,7 +1195,7 @@ static void set_imsm_ord_tbl_ent(struct imsm_map *map, int slot, __u32 ord)
+ 	map->disk_ord_tbl[slot] = __cpu_to_le32(ord);
+ }
+ 
+-static int get_imsm_disk_slot(struct imsm_map *map, unsigned idx)
++static int get_imsm_disk_slot(struct imsm_map *map, const unsigned int idx)
+ {
+ 	int slot;
+ 	__u32 ord;
+@@ -1194,7 +1206,7 @@ static int get_imsm_disk_slot(struct imsm_map *map, unsigned idx)
+ 			return slot;
+ 	}
+ 
+-	return -1;
++	return IMSM_STATUS_ERROR;
+ }
+ 
+ static int get_imsm_raid_level(struct imsm_map *map)
+@@ -1209,6 +1221,23 @@ static int get_imsm_raid_level(struct imsm_map *map)
+ 	return map->raid_level;
+ }
+ 
++/**
++ * get_disk_slot_in_dev() - retrieve disk slot from &imsm_dev.
++ * @super: &intel_super pointer, not NULL.
++ * @dev_idx: imsm device index.
++ * @idx: disk index.
++ *
++ * Return: Slot on success, IMSM_STATUS_ERROR otherwise.
++ */
++static int get_disk_slot_in_dev(struct intel_super *super, const __u8 dev_idx,
++				const unsigned int idx)
++{
++	struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
++	struct imsm_map *map = get_imsm_map(dev, MAP_0);
++
++	return get_imsm_disk_slot(map, idx);
++}
++
+ static int cmp_extent(const void *av, const void *bv)
+ {
+ 	const struct extent *a = av;
+@@ -1225,13 +1254,9 @@ static int count_memberships(struct dl *dl, struct intel_super *super)
+ 	int memberships = 0;
+ 	int i;
+ 
+-	for (i = 0; i < super->anchor->num_raid_devs; i++) {
+-		struct imsm_dev *dev = get_imsm_dev(super, i);
+-		struct imsm_map *map = get_imsm_map(dev, MAP_0);
+-
+-		if (get_imsm_disk_slot(map, dl->index) >= 0)
++	for (i = 0; i < super->anchor->num_raid_devs; i++)
++		if (get_disk_slot_in_dev(super, i, dl->index) >= 0)
+ 			memberships++;
+-	}
+ 
+ 	return memberships;
+ }
+@@ -1941,6 +1966,7 @@ void examine_migr_rec_imsm(struct intel_super *super)
+ 
+ 		/* first map under migration */
+ 		map = get_imsm_map(dev, MAP_0);
++
+ 		if (map)
+ 			slot = get_imsm_disk_slot(map, super->disks->index);
+ 		if (map == NULL || slot > 1 || slot < 0) {
+@@ -9655,10 +9681,9 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
+ 		/* count arrays using the victim in the metadata */
+ 		found = 0;
+ 		for (a = active_array; a ; a = a->next) {
+-			dev = get_imsm_dev(super, a->info.container_member);
+-			map = get_imsm_map(dev, MAP_0);
++			int dev_idx = a->info.container_member;
+ 
+-			if (get_imsm_disk_slot(map, victim) >= 0)
++			if (get_disk_slot_in_dev(super, dev_idx, victim) >= 0)
+ 				found++;
+ 		}
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0024-imsm-use-same-slot-across-container.patch b/SOURCES/0024-imsm-use-same-slot-across-container.patch
new file mode 100644
index 0000000..31348e4
--- /dev/null
+++ b/SOURCES/0024-imsm-use-same-slot-across-container.patch
@@ -0,0 +1,252 @@
+From 6d4d9ab295de165e57b5c30e044028dbffb8f297 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Tue, 21 Jun 2022 00:10:42 +0800
+Subject: [PATCH 24/52] imsm: use same slot across container
+
+Autolayout relies on drives order on super->disks list, but
+it is not quaranted by readdir() in sysfs_read(). As a result
+drive could be put in different slot in second volume.
+
+Make it consistent by reffering to first volume, if exists.
+
+Use enum imsm_status to unify error handling.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 169 ++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 108 insertions(+), 61 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index cd1f1e3d..deef7c87 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -7522,11 +7522,27 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
+ 	return 1;
+ }
+ 
+-static int imsm_get_free_size(struct supertype *st, int raiddisks,
+-			 unsigned long long size, int chunk,
+-			 unsigned long long *freesize)
++/**
++ * imsm_get_free_size() - get the biggest, common free space from members.
++ * @super: &intel_super pointer, not NULL.
++ * @raiddisks: number of raid disks.
++ * @size: requested size, could be 0 (means max size).
++ * @chunk: requested chunk.
++ * @freesize: pointer for returned size value.
++ *
++ * Return: &IMSM_STATUS_OK or &IMSM_STATUS_ERROR.
++ *
++ * @freesize is set to meaningful value, this can be @size, or calculated
++ * max free size.
++ * super->create_offset value is modified and set appropriately in
++ * merge_extends() for further creation.
++ */
++static imsm_status_t imsm_get_free_size(struct intel_super *super,
++					const int raiddisks,
++					unsigned long long size,
++					const int chunk,
++					unsigned long long *freesize)
+ {
+-	struct intel_super *super = st->sb;
+ 	struct imsm_super *mpb = super->anchor;
+ 	struct dl *dl;
+ 	int i;
+@@ -7570,12 +7586,10 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks,
+ 		/* chunk is in K */
+ 		minsize = chunk * 2;
+ 
+-	if (cnt < raiddisks ||
+-	    (super->orom && used && used != raiddisks) ||
+-	    maxsize < minsize ||
+-	    maxsize == 0) {
++	if (cnt < raiddisks || (super->orom && used && used != raiddisks) ||
++	    maxsize < minsize || maxsize == 0) {
+ 		pr_err("not enough devices with space to create array.\n");
+-		return 0; /* No enough free spaces large enough */
++		return IMSM_STATUS_ERROR;
+ 	}
+ 
+ 	if (size == 0) {
+@@ -7588,37 +7602,69 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks,
+ 	}
+ 	if (mpb->num_raid_devs > 0 && size && size != maxsize)
+ 		pr_err("attempting to create a second volume with size less then remaining space.\n");
+-	cnt = 0;
+-	for (dl = super->disks; dl; dl = dl->next)
+-		if (dl->e)
+-			dl->raiddisk = cnt++;
+-
+ 	*freesize = size;
+ 
+ 	dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
+ 
+-	return 1;
++	return IMSM_STATUS_OK;
+ }
+ 
+-static int reserve_space(struct supertype *st, int raiddisks,
+-			 unsigned long long size, int chunk,
+-			 unsigned long long *freesize)
++/**
++ * autolayout_imsm() - automatically layout a new volume.
++ * @super: &intel_super pointer, not NULL.
++ * @raiddisks: number of raid disks.
++ * @size: requested size, could be 0 (means max size).
++ * @chunk: requested chunk.
++ * @freesize: pointer for returned size value.
++ *
++ * We are being asked to automatically layout a new volume based on the current
++ * contents of the container. If the parameters can be satisfied autolayout_imsm
++ * will record the disks, start offset, and will return size of the volume to
++ * be created. See imsm_get_free_size() for details.
++ * add_to_super() and getinfo_super() detect when autolayout is in progress.
++ * If first volume exists, slots are set consistently to it.
++ *
++ * Return: &IMSM_STATUS_OK on success, &IMSM_STATUS_ERROR otherwise.
++ *
++ * Disks are marked for creation via dl->raiddisk.
++ */
++static imsm_status_t autolayout_imsm(struct intel_super *super,
++				     const int raiddisks,
++				     unsigned long long size, const int chunk,
++				     unsigned long long *freesize)
+ {
+-	struct intel_super *super = st->sb;
+-	struct dl *dl;
+-	int cnt;
+-	int rv = 0;
++	int curr_slot = 0;
++	struct dl *disk;
++	int vol_cnt = super->anchor->num_raid_devs;
++	imsm_status_t rv;
+ 
+-	rv = imsm_get_free_size(st, raiddisks, size, chunk, freesize);
+-	if (rv) {
+-		cnt = 0;
+-		for (dl = super->disks; dl; dl = dl->next)
+-			if (dl->e)
+-				dl->raiddisk = cnt++;
+-		rv = 1;
++	rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize);
++	if (rv != IMSM_STATUS_OK)
++		return IMSM_STATUS_ERROR;
++
++	for (disk = super->disks; disk; disk = disk->next) {
++		if (!disk->e)
++			continue;
++
++		if (curr_slot == raiddisks)
++			break;
++
++		if (vol_cnt == 0) {
++			disk->raiddisk = curr_slot;
++		} else {
++			int _slot = get_disk_slot_in_dev(super, 0, disk->index);
++
++			if (_slot == -1) {
++				pr_err("Disk %s is not used in first volume, aborting\n",
++				       disk->devname);
++				return IMSM_STATUS_ERROR;
++			}
++			disk->raiddisk = _slot;
++		}
++		curr_slot++;
+ 	}
+ 
+-	return rv;
++	return IMSM_STATUS_OK;
+ }
+ 
+ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+@@ -7654,35 +7700,35 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+ 	}
+ 
+ 	if (!dev) {
+-		if (st->sb) {
+-			struct intel_super *super = st->sb;
+-			if (!validate_geometry_imsm_orom(st->sb, level, layout,
+-							 raiddisks, chunk, size,
+-							 verbose))
++		struct intel_super *super = st->sb;
++
++		/*
++		 * Autolayout mode, st->sb and freesize must be set.
++		 */
++		if (!super || !freesize) {
++			pr_vrb("freesize and superblock must be set for autolayout, aborting\n");
++			return 1;
++		}
++
++		if (!validate_geometry_imsm_orom(st->sb, level, layout,
++						 raiddisks, chunk, size,
++						 verbose))
++			return 0;
++
++		if (super->orom) {
++			imsm_status_t rv;
++			int count = count_volumes(super->hba, super->orom->dpa,
++					      verbose);
++			if (super->orom->vphba <= count) {
++				pr_vrb("platform does not support more than %d raid volumes.\n",
++				       super->orom->vphba);
+ 				return 0;
+-			/* we are being asked to automatically layout a
+-			 * new volume based on the current contents of
+-			 * the container.  If the the parameters can be
+-			 * satisfied reserve_space will record the disks,
+-			 * start offset, and size of the volume to be
+-			 * created.  add_to_super and getinfo_super
+-			 * detect when autolayout is in progress.
+-			 */
+-			/* assuming that freesize is always given when array is
+-			   created */
+-			if (super->orom && freesize) {
+-				int count;
+-				count = count_volumes(super->hba,
+-						      super->orom->dpa, verbose);
+-				if (super->orom->vphba <= count) {
+-					pr_vrb("platform does not support more than %d raid volumes.\n",
+-					       super->orom->vphba);
+-					return 0;
+-				}
+ 			}
+-			if (freesize)
+-				return reserve_space(st, raiddisks, size,
+-						     *chunk, freesize);
++
++			rv = autolayout_imsm(super, raiddisks, size, *chunk,
++					     freesize);
++			if (rv != IMSM_STATUS_OK)
++				return 0;
+ 		}
+ 		return 1;
+ 	}
+@@ -11538,7 +11584,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 	unsigned long long current_size;
+ 	unsigned long long free_size;
+ 	unsigned long long max_size;
+-	int rv;
++	imsm_status_t rv;
+ 
+ 	getinfo_super_imsm_volume(st, &info, NULL);
+ 	if (geo->level != info.array.level && geo->level >= 0 &&
+@@ -11657,9 +11703,10 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 		}
+ 		/* check the maximum available size
+ 		 */
+-		rv =  imsm_get_free_size(st, dev->vol.map->num_members,
+-					 0, chunk, &free_size);
+-		if (rv == 0)
++		rv = imsm_get_free_size(super, dev->vol.map->num_members,
++					0, chunk, &free_size);
++
++		if (rv != IMSM_STATUS_OK)
+ 			/* Cannot find maximum available space
+ 			 */
+ 			max_size = 0;
+-- 
+2.31.1
+
diff --git a/SOURCES/0025-imsm-block-changing-slots-during-creation.patch b/SOURCES/0025-imsm-block-changing-slots-during-creation.patch
new file mode 100644
index 0000000..6de11e1
--- /dev/null
+++ b/SOURCES/0025-imsm-block-changing-slots-during-creation.patch
@@ -0,0 +1,122 @@
+From 9a7df595bbe360132cb37c8b39aa1fd9ac24b43f Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Tue, 21 Jun 2022 00:10:43 +0800
+Subject: [PATCH 25/52] imsm: block changing slots during creation
+
+If user specifies drives for array creation, then slot order across
+volumes is not preserved.
+Ideally, it should be checked in validate_geometry() but it is not
+possible in current implementation (order is determined later).
+Add verification in add_to_super_imsm_volume() and throw error if
+mismatch is detected.
+IMSM allows to use only same members within container.
+This is not hardware dependency but metadata limitation.
+Therefore, 09-imsm-overlap test is removed. Testing it is pointless.
+After this patch, creation in this scenario is blocked. Offset
+verification is covered in other tests.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c        | 33 ++++++++++++++++++++++-----------
+ tests/09imsm-overlap | 28 ----------------------------
+ 2 files changed, 22 insertions(+), 39 deletions(-)
+ delete mode 100644 tests/09imsm-overlap
+
+diff --git a/super-intel.c b/super-intel.c
+index deef7c87..8ffe485c 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -5789,6 +5789,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
+ 	struct imsm_map *map;
+ 	struct dl *dl, *df;
+ 	int slot;
++	int autolayout = 0;
++
++	if (!is_fd_valid(fd))
++		autolayout = 1;
+ 
+ 	dev = get_imsm_dev(super, super->current_vol);
+ 	map = get_imsm_map(dev, MAP_0);
+@@ -5799,25 +5803,32 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
+ 		return 1;
+ 	}
+ 
+-	if (!is_fd_valid(fd)) {
+-		/* we're doing autolayout so grab the pre-marked (in
+-		 * validate_geometry) raid_disk
+-		 */
+-		for (dl = super->disks; dl; dl = dl->next)
++	for (dl = super->disks; dl ; dl = dl->next) {
++		if (autolayout) {
+ 			if (dl->raiddisk == dk->raid_disk)
+ 				break;
+-	} else {
+-		for (dl = super->disks; dl ; dl = dl->next)
+-			if (dl->major == dk->major &&
+-			    dl->minor == dk->minor)
+-				break;
++		} else if (dl->major == dk->major && dl->minor == dk->minor)
++			break;
+ 	}
+ 
+ 	if (!dl) {
+-		pr_err("%s is not a member of the same container\n", devname);
++		if (!autolayout)
++			pr_err("%s is not a member of the same container.\n",
++			       devname);
+ 		return 1;
+ 	}
+ 
++	if (!autolayout && super->current_vol > 0) {
++		int _slot = get_disk_slot_in_dev(super, 0, dl->index);
++
++		if (_slot != dk->raid_disk) {
++			pr_err("Member %s is in %d slot for the first volume, but is in %d slot for a new volume.\n",
++			       dl->devname, _slot, dk->raid_disk);
++			pr_err("Raid members are in different order than for the first volume, aborting.\n");
++			return 1;
++		}
++	}
++
+ 	if (mpb->num_disks == 0)
+ 		if (!get_dev_sector_size(dl->fd, dl->devname,
+ 					 &super->sector_size))
+diff --git a/tests/09imsm-overlap b/tests/09imsm-overlap
+deleted file mode 100644
+index ff5d2093..00000000
+--- a/tests/09imsm-overlap
++++ /dev/null
+@@ -1,28 +0,0 @@
+-
+-. tests/env-imsm-template
+-
+-# create raid arrays with varying degress of overlap
+-mdadm -CR $container -e imsm -n 6 $dev0 $dev1 $dev2 $dev3 $dev4 $dev5
+-imsm_check container 6
+-
+-size=1024
+-level=1
+-num_disks=2
+-mdadm -CR $member0 $dev0 $dev1 -n $num_disks -l $level -z $size
+-mdadm -CR $member1 $dev1 $dev2 -n $num_disks -l $level -z $size
+-mdadm -CR $member2 $dev2 $dev3 -n $num_disks -l $level -z $size
+-mdadm -CR $member3 $dev3 $dev4 -n $num_disks -l $level -z $size
+-mdadm -CR $member4 $dev4 $dev5 -n $num_disks -l $level -z $size
+-
+-udevadm settle
+-
+-offset=0
+-imsm_check member $member0 $num_disks $level $size 1024 $offset
+-offset=$((offset+size+4096))
+-imsm_check member $member1 $num_disks $level $size 1024 $offset
+-offset=$((offset+size+4096))
+-imsm_check member $member2 $num_disks $level $size 1024 $offset
+-offset=$((offset+size+4096))
+-imsm_check member $member3 $num_disks $level $size 1024 $offset
+-offset=$((offset+size+4096))
+-imsm_check member $member4 $num_disks $level $size 1024 $offset
+-- 
+2.31.1
+
diff --git a/SOURCES/0026-mdadm-block-update-ppl-for-non-raid456-levels.patch b/SOURCES/0026-mdadm-block-update-ppl-for-non-raid456-levels.patch
new file mode 100644
index 0000000..5e9e87f
--- /dev/null
+++ b/SOURCES/0026-mdadm-block-update-ppl-for-non-raid456-levels.patch
@@ -0,0 +1,177 @@
+From 70f1ff4291b0388adca1f4c91918ce1175e8b360 Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Wed, 15 Jun 2022 14:28:39 +0200
+Subject: [PATCH 26/52] mdadm: block update=ppl for non raid456 levels
+
+Option ppl should be used only for raid levels 4, 5 and 6. Cancel update
+for other levels.
+
+Applied globally for imsm and ddf format.
+
+Additionally introduce is_level456() helper function.
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c | 11 +++++------
+ Grow.c     |  2 +-
+ Manage.c   | 14 ++++++++++++--
+ mdadm.h    | 11 +++++++++++
+ super0.c   |  2 +-
+ super1.c   |  3 +--
+ 6 files changed, 31 insertions(+), 12 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index 4b213560..6df6bfbc 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -906,8 +906,7 @@ static int force_array(struct mdinfo *content,
+ 				 * devices in RAID4 or last devices in RAID4/5/6.
+ 				 */
+ 				delta = devices[j].i.delta_disks;
+-				if (devices[j].i.array.level >= 4 &&
+-				    devices[j].i.array.level <= 6 &&
++				if (is_level456(devices[j].i.array.level) &&
+ 				    i/2 >= content->array.raid_disks - delta)
+ 					/* OK */;
+ 				else if (devices[j].i.array.level == 4 &&
+@@ -1226,8 +1225,7 @@ static int start_array(int mdfd,
+ 				fprintf(stderr, ".\n");
+ 			}
+ 			if (content->reshape_active &&
+-			    content->array.level >= 4 &&
+-			    content->array.level <= 6) {
++			    is_level456(content->array.level)) {
+ 				/* might need to increase the size
+ 				 * of the stripe cache - default is 256
+ 				 */
+@@ -1974,7 +1972,8 @@ int assemble_container_content(struct supertype *st, int mdfd,
+ 	int start_reshape;
+ 	char *avail;
+ 	int err;
+-	int is_raid456, is_clean, all_disks;
++	int is_clean, all_disks;
++	bool is_raid456;
+ 
+ 	if (sysfs_init(content, mdfd, NULL)) {
+ 		pr_err("Unable to initialize sysfs\n");
+@@ -2107,7 +2106,7 @@ int assemble_container_content(struct supertype *st, int mdfd,
+ 		content->array.state |= 1;
+ 	}
+ 
+-	is_raid456 = (content->array.level >= 4 && content->array.level <= 6);
++	is_raid456 = is_level456(content->array.level);
+ 	is_clean = content->array.state & 1;
+ 
+ 	if (enough(content->array.level, content->array.raid_disks,
+diff --git a/Grow.c b/Grow.c
+index f6efbc48..8c520d42 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -2944,7 +2944,7 @@ static int impose_level(int fd, int level, char *devname, int verbose)
+ 	}
+ 
+ 	md_get_array_info(fd, &array);
+-	if (level == 0 && (array.level >= 4 && array.level <= 6)) {
++	if (level == 0 && is_level456(array.level)) {
+ 		/* To convert to RAID0 we need to fail and
+ 		 * remove any non-data devices. */
+ 		int found = 0;
+diff --git a/Manage.c b/Manage.c
+index f789e0c1..e5e6abe4 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -307,7 +307,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
+ 	 *  - unfreeze reshape
+ 	 *  - wait on 'sync_completed' for that point to be reached.
+ 	 */
+-	if (mdi && (mdi->array.level >= 4 && mdi->array.level <= 6) &&
++	if (mdi && is_level456(mdi->array.level) &&
+ 	    sysfs_attribute_available(mdi, NULL, "sync_action") &&
+ 	    sysfs_attribute_available(mdi, NULL, "reshape_direction") &&
+ 	    sysfs_get_str(mdi, NULL, "sync_action", buf, 20) > 0 &&
+@@ -1679,6 +1679,7 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident
+ {
+ 	struct supertype supertype, *st = &supertype;
+ 	int fd, rv = 2;
++	struct mdinfo *info = NULL;
+ 
+ 	memset(st, 0, sizeof(*st));
+ 
+@@ -1696,6 +1697,13 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident
+ 	if (mdmon_running(st->devnm))
+ 		st->update_tail = &st->updates;
+ 
++	info = st->ss->container_content(st, subarray);
++
++	if (strncmp(update, "ppl", 3) == 0 && !is_level456(info->array.level)) {
++		pr_err("RWH policy ppl is supported only for raid4, raid5 and raid6.\n");
++		goto free_super;
++	}
++
+ 	rv = st->ss->update_subarray(st, subarray, update, ident);
+ 
+ 	if (rv) {
+@@ -1711,7 +1719,9 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident
+ 		pr_err("Updated subarray-%s name from %s, UUIDs may have changed\n",
+ 		       subarray, dev);
+ 
+- free_super:
++free_super:
++	if (info)
++		free(info);
+ 	st->ss->free_super(st);
+ 	close(fd);
+ 
+diff --git a/mdadm.h b/mdadm.h
+index d53df169..974415b9 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -796,6 +796,17 @@ static inline int is_fd_valid(int fd)
+ 	return (fd > -1);
+ }
+ 
++/**
++ * is_level456() - check whether given level is between inclusive 4 and 6.
++ * @level: level to check.
++ *
++ * Return: true if condition is met, false otherwise
++ */
++static inline bool is_level456(int level)
++{
++	return (level >= 4 && level <= 6);
++}
++
+ /**
+  * close_fd() - verify, close and unset file descriptor.
+  * @fd: pointer to file descriptor.
+diff --git a/super0.c b/super0.c
+index 61c9ec1d..37f595ed 100644
+--- a/super0.c
++++ b/super0.c
+@@ -683,7 +683,7 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+ 			int parity = sb->level == 6 ? 2 : 1;
+ 			rv = 0;
+ 
+-			if (sb->level >= 4 && sb->level <= 6 &&
++			if (is_level456(sb->level) &&
+ 			    sb->reshape_position % (
+ 				    sb->new_chunk/512 *
+ 				    (sb->raid_disks - sb->delta_disks - parity))) {
+diff --git a/super1.c b/super1.c
+index 3a0c69fd..71af860c 100644
+--- a/super1.c
++++ b/super1.c
+@@ -1530,8 +1530,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+ 			 * So we reject a revert-reshape unless the
+ 			 * alignment is good.
+ 			 */
+-			if (__le32_to_cpu(sb->level) >= 4 &&
+-			    __le32_to_cpu(sb->level) <= 6) {
++			if (is_level456(__le32_to_cpu(sb->level))) {
+ 				reshape_sectors =
+ 					__le64_to_cpu(sb->reshape_position);
+ 				reshape_chunk = __le32_to_cpu(sb->new_chunk);
+-- 
+2.31.1
+
diff --git a/SOURCES/0027-mdadm-Fix-array-size-mismatch-after-grow.patch b/SOURCES/0027-mdadm-Fix-array-size-mismatch-after-grow.patch
new file mode 100644
index 0000000..cd3e93a
--- /dev/null
+++ b/SOURCES/0027-mdadm-Fix-array-size-mismatch-after-grow.patch
@@ -0,0 +1,30 @@
+From 42e02e613fb0b4a2c0c0d984b9e6e2933875bb44 Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Fri, 22 Jul 2022 08:43:47 +0200
+Subject: [PATCH 27/52] mdadm: Fix array size mismatch after grow
+
+imsm_fix_size_mismatch() is invoked to fix the problem, but it couldn't
+proceed due to migration check. This patch allows for intended behavior.
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 8ffe485c..76b947f5 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -11854,7 +11854,7 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
+ 		unsigned long long d_size = imsm_dev_size(dev);
+ 		int u_size;
+ 
+-		if (calc_size == d_size || dev->vol.migr_type == MIGR_GEN_MIGR)
++		if (calc_size == d_size)
+ 			continue;
+ 
+ 		/* There is a difference, confirm that imsm_dev_size is
+-- 
+2.31.1
+
diff --git a/SOURCES/0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch b/SOURCES/0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch
new file mode 100644
index 0000000..4fde0c9
--- /dev/null
+++ b/SOURCES/0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch
@@ -0,0 +1,34 @@
+From 751757620afb25a4c02746bf8368a7b5f22352ec Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Fri, 22 Jul 2022 08:43:48 +0200
+Subject: [PATCH 28/52] mdadm: Remove dead code in imsm_fix_size_mismatch
+
+imsm_create_metadata_update_for_size_change() that returns u_size value
+could return 0 in the past. As its behavior changed, and returned value
+is always the size of imsm_update_size_change structure, check for
+u_size is no longer needed.
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 76b947f5..4ddfcf94 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -11869,10 +11869,6 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
+ 		geo.size = d_size;
+ 		u_size = imsm_create_metadata_update_for_size_change(st, &geo,
+ 								     &update);
+-		if (u_size < 1) {
+-			dprintf("imsm: Cannot prepare size change update\n");
+-			goto exit;
+-		}
+ 		imsm_update_metadata_locally(st, update, u_size);
+ 		if (st->update_tail) {
+ 			append_metadata_update(st, update, u_size);
+-- 
+2.31.1
+
diff --git a/SOURCES/0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch b/SOURCES/0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch
new file mode 100644
index 0000000..c7d871d
--- /dev/null
+++ b/SOURCES/0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch
@@ -0,0 +1,40 @@
+From c8d1c398505b62d9129a4e711f17e4469f4327ff Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Thu, 14 Jul 2022 09:02:10 +0200
+Subject: [PATCH 29/52] Monitor: use devname as char array instead of pointer
+
+Device name wasn't filled properly due to incorrect use of strcpy.
+Strcpy was used twice. Firstly to fill devname with "/dev/md/"
+and then to add chosen name. First strcpy result was overwritten by
+second one (as a result <device_name> instead of "/dev/md/<device_name>"
+was assigned). This commit changes this implementation to use snprintf
+and devname with fixed size.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Monitor.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 6ca1ebe5..a5b11ae2 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -190,9 +190,11 @@ int Monitor(struct mddev_dev *devlist,
+ 			if (mdlist->devname[0] == '/')
+ 				st->devname = xstrdup(mdlist->devname);
+ 			else {
+-				st->devname = xmalloc(8+strlen(mdlist->devname)+1);
+-				strcpy(strcpy(st->devname, "/dev/md/"),
+-				       mdlist->devname);
++				/* length of "/dev/md/" + device name + terminating byte */
++				size_t _len = sizeof("/dev/md/") + strnlen(mdlist->devname, PATH_MAX);
++
++				st->devname = xcalloc(_len, sizeof(char));
++				snprintf(st->devname, _len, "/dev/md/%s", mdlist->devname);
+ 			}
+ 			if (!is_mddev(mdlist->devname))
+ 				return 1;
+-- 
+2.31.1
+
diff --git a/SOURCES/0030-Monitor-use-snprintf-to-fill-device-name.patch b/SOURCES/0030-Monitor-use-snprintf-to-fill-device-name.patch
new file mode 100644
index 0000000..83543cb
--- /dev/null
+++ b/SOURCES/0030-Monitor-use-snprintf-to-fill-device-name.patch
@@ -0,0 +1,133 @@
+From 84d969be8f6d8a345b75f558fad26e4f62a558f6 Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Thu, 14 Jul 2022 09:02:11 +0200
+Subject: [PATCH 30/52] Monitor: use snprintf to fill device name
+
+Safe string functions are propagated in Monitor.c.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Monitor.c | 37 ++++++++++++++-----------------------
+ 1 file changed, 14 insertions(+), 23 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index a5b11ae2..93f36ac0 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -33,8 +33,8 @@
+ #endif
+ 
+ struct state {
+-	char *devname;
+-	char devnm[32];	/* to sync with mdstat info */
++	char devname[MD_NAME_MAX + sizeof("/dev/md/")];	/* length of "/dev/md/" + device name + terminating byte*/
++	char devnm[MD_NAME_MAX];	/* to sync with mdstat info */
+ 	unsigned int utime;
+ 	int err;
+ 	char *spare_group;
+@@ -45,9 +45,9 @@ struct state {
+ 	int devstate[MAX_DISKS];
+ 	dev_t devid[MAX_DISKS];
+ 	int percent;
+-	char parent_devnm[32]; /* For subarray, devnm of parent.
+-				* For others, ""
+-				*/
++	char parent_devnm[MD_NAME_MAX]; /* For subarray, devnm of parent.
++					* For others, ""
++					*/
+ 	struct supertype *metadata;
+ 	struct state *subarray;/* for a container it is a link to first subarray
+ 				* for a subarray it is a link to next subarray
+@@ -187,15 +187,8 @@ int Monitor(struct mddev_dev *devlist,
+ 				continue;
+ 
+ 			st = xcalloc(1, sizeof *st);
+-			if (mdlist->devname[0] == '/')
+-				st->devname = xstrdup(mdlist->devname);
+-			else {
+-				/* length of "/dev/md/" + device name + terminating byte */
+-				size_t _len = sizeof("/dev/md/") + strnlen(mdlist->devname, PATH_MAX);
+-
+-				st->devname = xcalloc(_len, sizeof(char));
+-				snprintf(st->devname, _len, "/dev/md/%s", mdlist->devname);
+-			}
++			snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"),
++				 "/dev/md/%s", basename(mdlist->devname));
+ 			if (!is_mddev(mdlist->devname))
+ 				return 1;
+ 			st->next = statelist;
+@@ -218,7 +211,7 @@ int Monitor(struct mddev_dev *devlist,
+ 
+ 			st = xcalloc(1, sizeof *st);
+ 			mdlist = conf_get_ident(dv->devname);
+-			st->devname = xstrdup(dv->devname);
++			snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), "%s", dv->devname);
+ 			st->next = statelist;
+ 			st->devnm[0] = 0;
+ 			st->percent = RESYNC_UNKNOWN;
+@@ -301,7 +294,6 @@ int Monitor(struct mddev_dev *devlist,
+ 		for (stp = &statelist; (st = *stp) != NULL; ) {
+ 			if (st->from_auto && st->err > 5) {
+ 				*stp = st->next;
+-				free(st->devname);
+ 				free(st->spare_group);
+ 				free(st);
+ 			} else
+@@ -554,7 +546,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+ 		goto disappeared;
+ 
+ 	if (st->devnm[0] == 0)
+-		strcpy(st->devnm, fd2devnm(fd));
++		snprintf(st->devnm, MD_NAME_MAX, "%s", fd2devnm(fd));
+ 
+ 	for (mse2 = mdstat; mse2; mse2 = mse2->next)
+ 		if (strcmp(mse2->devnm, st->devnm) == 0) {
+@@ -684,7 +676,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+ 	    strncmp(mse->metadata_version, "external:", 9) == 0 &&
+ 	    is_subarray(mse->metadata_version+9)) {
+ 		char *sl;
+-		strcpy(st->parent_devnm, mse->metadata_version + 10);
++		snprintf(st->parent_devnm, MD_NAME_MAX, "%s", mse->metadata_version + 10);
+ 		sl = strchr(st->parent_devnm, '/');
+ 		if (sl)
+ 			*sl = 0;
+@@ -772,14 +764,13 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
+ 				continue;
+ 			}
+ 
+-			st->devname = xstrdup(name);
++			snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), "%s", name);
+ 			if ((fd = open(st->devname, O_RDONLY)) < 0 ||
+ 			    md_get_array_info(fd, &array) < 0) {
+ 				/* no such array */
+ 				if (fd >= 0)
+ 					close(fd);
+ 				put_md_name(st->devname);
+-				free(st->devname);
+ 				if (st->metadata) {
+ 					st->metadata->ss->free_super(st->metadata);
+ 					free(st->metadata);
+@@ -791,7 +782,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
+ 			st->next = *statelist;
+ 			st->err = 1;
+ 			st->from_auto = 1;
+-			strcpy(st->devnm, mse->devnm);
++			snprintf(st->devnm, MD_NAME_MAX, "%s", mse->devnm);
+ 			st->percent = RESYNC_UNKNOWN;
+ 			st->expected_spares = -1;
+ 			if (mse->metadata_version &&
+@@ -799,8 +790,8 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
+ 				    "external:", 9) == 0 &&
+ 			    is_subarray(mse->metadata_version+9)) {
+ 				char *sl;
+-				strcpy(st->parent_devnm,
+-					mse->metadata_version+10);
++				snprintf(st->parent_devnm, MD_NAME_MAX,
++					 "%s", mse->metadata_version + 10);
+ 				sl = strchr(st->parent_devnm, '/');
+ 				*sl = 0;
+ 			} else
+-- 
+2.31.1
+
diff --git a/SOURCES/0031-Makefile-Don-t-build-static-build-with-everything-an.patch b/SOURCES/0031-Makefile-Don-t-build-static-build-with-everything-an.patch
new file mode 100644
index 0000000..8922281
--- /dev/null
+++ b/SOURCES/0031-Makefile-Don-t-build-static-build-with-everything-an.patch
@@ -0,0 +1,42 @@
+From 14ae4c37bce9a53da08d59d6c2d7e0946e9c9f47 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 22 Jun 2022 14:25:06 -0600
+Subject: [PATCH 31/52] Makefile: Don't build static build with everything and
+ everything-test
+
+Running the test suite requires building everything, but it seems to be
+difficult to build the static version of mdadm now seeing there
+is no readily available static udev library.
+
+The test suite doesn't need the static binary so just don't build it
+with the everything or everything-test targets.
+
+Leave the mdadm.static and install-static targets in place in case
+someone still has a use case for the static binary.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Makefile | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index bf126033..ec1f99ed 100644
+--- a/Makefile
++++ b/Makefile
+@@ -182,9 +182,9 @@ check_rundir:
+ 		echo "***** or set CHECK_RUN_DIR=0"; exit 1; \
+ 	fi
+ 
+-everything: all mdadm.static swap_super test_stripe raid6check \
++everything: all swap_super test_stripe raid6check \
+ 	mdadm.Os mdadm.O2 man
+-everything-test: all mdadm.static swap_super test_stripe \
++everything-test: all swap_super test_stripe \
+ 	mdadm.Os mdadm.O2 man
+ # mdadm.uclibc doesn't work on x86-64
+ # mdadm.tcc doesn't work..
+-- 
+2.31.1
+
diff --git a/SOURCES/0032-DDF-Cleanup-validate_geometry_ddf_container.patch b/SOURCES/0032-DDF-Cleanup-validate_geometry_ddf_container.patch
new file mode 100644
index 0000000..99e2e6b
--- /dev/null
+++ b/SOURCES/0032-DDF-Cleanup-validate_geometry_ddf_container.patch
@@ -0,0 +1,141 @@
+From 679bd9508a30b2a0a1baecc9a21dd6c7d8d8d7dc Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 22 Jun 2022 14:25:07 -0600
+Subject: [PATCH 32/52] DDF: Cleanup validate_geometry_ddf_container()
+
+Move the function up so that the function declaration is not necessary
+and remove the unused arguments to the function.
+
+No functional changes are intended but will help with a bug fix in the
+next patch.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super-ddf.c | 88 ++++++++++++++++++++++++-----------------------------
+ 1 file changed, 39 insertions(+), 49 deletions(-)
+
+diff --git a/super-ddf.c b/super-ddf.c
+index abbc8b09..9d867f69 100644
+--- a/super-ddf.c
++++ b/super-ddf.c
+@@ -503,13 +503,6 @@ struct ddf_super {
+ static int load_super_ddf_all(struct supertype *st, int fd,
+ 			      void **sbp, char *devname);
+ static int get_svd_state(const struct ddf_super *, const struct vcl *);
+-static int
+-validate_geometry_ddf_container(struct supertype *st,
+-				int level, int layout, int raiddisks,
+-				int chunk, unsigned long long size,
+-				unsigned long long data_offset,
+-				char *dev, unsigned long long *freesize,
+-				int verbose);
+ 
+ static int validate_geometry_ddf_bvd(struct supertype *st,
+ 				     int level, int layout, int raiddisks,
+@@ -3322,6 +3315,42 @@ static int reserve_space(struct supertype *st, int raiddisks,
+ 	return 1;
+ }
+ 
++static int
++validate_geometry_ddf_container(struct supertype *st,
++				int level, int raiddisks,
++				unsigned long long data_offset,
++				char *dev, unsigned long long *freesize,
++				int verbose)
++{
++	int fd;
++	unsigned long long ldsize;
++
++	if (level != LEVEL_CONTAINER)
++		return 0;
++	if (!dev)
++		return 1;
++
++	fd = dev_open(dev, O_RDONLY|O_EXCL);
++	if (fd < 0) {
++		if (verbose)
++			pr_err("ddf: Cannot open %s: %s\n",
++			       dev, strerror(errno));
++		return 0;
++	}
++	if (!get_dev_size(fd, dev, &ldsize)) {
++		close(fd);
++		return 0;
++	}
++	close(fd);
++	if (freesize) {
++		*freesize = avail_size_ddf(st, ldsize >> 9, INVALID_SECTORS);
++		if (*freesize == 0)
++			return 0;
++	}
++
++	return 1;
++}
++
+ static int validate_geometry_ddf(struct supertype *st,
+ 				 int level, int layout, int raiddisks,
+ 				 int *chunk, unsigned long long size,
+@@ -3347,11 +3376,9 @@ static int validate_geometry_ddf(struct supertype *st,
+ 		level = LEVEL_CONTAINER;
+ 	if (level == LEVEL_CONTAINER) {
+ 		/* Must be a fresh device to add to a container */
+-		return validate_geometry_ddf_container(st, level, layout,
+-						       raiddisks, *chunk,
+-						       size, data_offset, dev,
+-						       freesize,
+-						       verbose);
++		return validate_geometry_ddf_container(st, level, raiddisks,
++						       data_offset, dev,
++						       freesize, verbose);
+ 	}
+ 
+ 	if (!dev) {
+@@ -3449,43 +3476,6 @@ static int validate_geometry_ddf(struct supertype *st,
+ 	return 1;
+ }
+ 
+-static int
+-validate_geometry_ddf_container(struct supertype *st,
+-				int level, int layout, int raiddisks,
+-				int chunk, unsigned long long size,
+-				unsigned long long data_offset,
+-				char *dev, unsigned long long *freesize,
+-				int verbose)
+-{
+-	int fd;
+-	unsigned long long ldsize;
+-
+-	if (level != LEVEL_CONTAINER)
+-		return 0;
+-	if (!dev)
+-		return 1;
+-
+-	fd = dev_open(dev, O_RDONLY|O_EXCL);
+-	if (fd < 0) {
+-		if (verbose)
+-			pr_err("ddf: Cannot open %s: %s\n",
+-			       dev, strerror(errno));
+-		return 0;
+-	}
+-	if (!get_dev_size(fd, dev, &ldsize)) {
+-		close(fd);
+-		return 0;
+-	}
+-	close(fd);
+-	if (freesize) {
+-		*freesize = avail_size_ddf(st, ldsize >> 9, INVALID_SECTORS);
+-		if (*freesize == 0)
+-			return 0;
+-	}
+-
+-	return 1;
+-}
+-
+ static int validate_geometry_ddf_bvd(struct supertype *st,
+ 				     int level, int layout, int raiddisks,
+ 				     int *chunk, unsigned long long size,
+-- 
+2.31.1
+
diff --git a/SOURCES/0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch b/SOURCES/0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch
new file mode 100644
index 0000000..3be71e7
--- /dev/null
+++ b/SOURCES/0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch
@@ -0,0 +1,49 @@
+From 2b93288a5650bb811932836f67f30d63c5ddcfbd Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 22 Jun 2022 14:25:08 -0600
+Subject: [PATCH 33/52] DDF: Fix NULL pointer dereference in
+ validate_geometry_ddf()
+
+A relatively recent patch added a call to validate_geometry() in
+Manage_add() that has level=LEVEL_CONTAINER and chunk=NULL.
+
+This causes some ddf tests to segfault which aborts the test suite.
+
+To fix this, avoid dereferencing chunk when the level is
+LEVEL_CONTAINER or LEVEL_NONE.
+
+Fixes: 1f5d54a06df0 ("Manage: Call validate_geometry when adding drive to external container")
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super-ddf.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/super-ddf.c b/super-ddf.c
+index 9d867f69..949e7d15 100644
+--- a/super-ddf.c
++++ b/super-ddf.c
+@@ -3369,9 +3369,6 @@ static int validate_geometry_ddf(struct supertype *st,
+ 	 * If given BVDs, we make an SVD, changing all the GUIDs in the process.
+ 	 */
+ 
+-	if (*chunk == UnSet)
+-		*chunk = DEFAULT_CHUNK;
+-
+ 	if (level == LEVEL_NONE)
+ 		level = LEVEL_CONTAINER;
+ 	if (level == LEVEL_CONTAINER) {
+@@ -3381,6 +3378,9 @@ static int validate_geometry_ddf(struct supertype *st,
+ 						       freesize, verbose);
+ 	}
+ 
++	if (*chunk == UnSet)
++		*chunk = DEFAULT_CHUNK;
++
+ 	if (!dev) {
+ 		mdu_array_info_t array = {
+ 			.level = level,
+-- 
+2.31.1
+
diff --git a/SOURCES/0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch b/SOURCES/0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch
new file mode 100644
index 0000000..849a475
--- /dev/null
+++ b/SOURCES/0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch
@@ -0,0 +1,85 @@
+From 548e9b916f86c06e2cdb50d8f49633f9bec66c7e Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 22 Jun 2022 14:25:09 -0600
+Subject: [PATCH 34/52] mdadm/Grow: Fix use after close bug by closing after
+ fork
+
+The test 07reshape-grow fails most of the time. But it succeeds around
+1 in 5 times. When it does succeed, it causes the tests to die because
+mdadm has segfaulted.
+
+The segfault was caused by mdadm attempting to repoen a file
+descriptor that was already closed. The backtrace of the segfault
+was:
+
+  #0  __strncmp_avx2 () at ../sysdeps/x86_64/multiarch/strcmp-avx2.S:101
+  #1  0x000056146e31d44b in devnm2devid (devnm=0x0) at util.c:956
+  #2  0x000056146e31dab4 in open_dev_flags (devnm=0x0, flags=0)
+                         at util.c:1072
+  #3  0x000056146e31db22 in open_dev (devnm=0x0) at util.c:1079
+  #4  0x000056146e3202e8 in reopen_mddev (mdfd=4) at util.c:2244
+  #5  0x000056146e329f36 in start_array (mdfd=4,
+              mddev=0x7ffc55342450 "/dev/md0", content=0x7ffc55342860,
+              st=0x56146fc78660, ident=0x7ffc55342f70, best=0x56146fc6f5d0,
+              bestcnt=10, chosen_drive=0, devices=0x56146fc706b0, okcnt=5,
+	      sparecnt=0,  rebuilding_cnt=0, journalcnt=0, c=0x7ffc55342e90,
+	      clean=1,  avail=0x56146fc78720 "\001\001\001\001\001",
+	      start_partial_ok=0, err_ok=0, was_forced=0)
+	                  at Assemble.c:1206
+  #6  0x000056146e32c36e in Assemble (st=0x56146fc78660,
+               mddev=0x7ffc55342450 "/dev/md0", ident=0x7ffc55342f70,
+	       devlist=0x56146fc6e2d0, c=0x7ffc55342e90)
+	                 at Assemble.c:1914
+  #7  0x000056146e312ac9 in main (argc=11, argv=0x7ffc55343238)
+                         at mdadm.c:1510
+
+The file descriptor was closed early in Grow_continue(). The noted commit
+moved the close() call to close the fd above the fork which caused the
+parent process to return with a closed fd.
+
+This meant reshape_array() and Grow_continue() would return in the parent
+with the fd forked. The fd would eventually be passed to reopen_mddev()
+which returned an unhandled NULL from fd2devnm() which would then be
+dereferenced in devnm2devid.
+
+Fix this by moving the close() call below the fork. This appears to
+fix the 07revert-grow test. While we're at it, switch to using
+close_fd() to invalidate the file descriptor.
+
+Fixes: 77b72fa82813 ("mdadm/Grow: prevent md's fd from being occupied during delayed time")
+Cc: Alex Wu <alexwu@synology.com>
+Cc: BingJing Chang <bingjingc@synology.com>
+Cc: Danny Shih <dannyshih@synology.com>
+Cc: ChangSyun Peng <allenpeng@synology.com>
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Grow.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/Grow.c b/Grow.c
+index 8c520d42..97f22c75 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -3514,7 +3514,6 @@ started:
+ 			return 0;
+ 		}
+ 
+-	close(fd);
+ 	/* Now we just need to kick off the reshape and watch, while
+ 	 * handling backups of the data...
+ 	 * This is all done by a forked background process.
+@@ -3535,6 +3534,9 @@ started:
+ 		break;
+ 	}
+ 
++	/* Close unused file descriptor in the forked process */
++	close_fd(&fd);
++
+ 	/* If another array on the same devices is busy, the
+ 	 * reshape will wait for them.  This would mean that
+ 	 * the first section that we suspend will stay suspended
+-- 
+2.31.1
+
diff --git a/SOURCES/0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch b/SOURCES/0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch
new file mode 100644
index 0000000..c19c1e4
--- /dev/null
+++ b/SOURCES/0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch
@@ -0,0 +1,36 @@
+From 9ae62977b51dab0f4bb46b1c8ea5ebd1705b2f4d Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 22 Jun 2022 14:25:10 -0600
+Subject: [PATCH 35/52] monitor: Avoid segfault when calling NULL
+ get_bad_blocks
+
+Not all struct superswitch implement a get_bad_blocks() function,
+yet mdmon seems to call it without checking for NULL and thus
+occasionally segfaults in the test 10ddf-geometry.
+
+Fix this by checking for NULL before calling it.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ monitor.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/monitor.c b/monitor.c
+index b877e595..820a93d0 100644
+--- a/monitor.c
++++ b/monitor.c
+@@ -311,6 +311,9 @@ static int check_for_cleared_bb(struct active_array *a, struct mdinfo *mdi)
+ 	struct md_bb *bb;
+ 	int i;
+ 
++	if (!ss->get_bad_blocks)
++		return -1;
++
+ 	/*
+ 	 * Get a list of bad blocks for an array, then read list of
+ 	 * acknowledged bad blocks from kernel and compare it against metadata
+-- 
+2.31.1
+
diff --git a/SOURCES/0036-mdadm-Fix-mdadm-r-remove-option-regression.patch b/SOURCES/0036-mdadm-Fix-mdadm-r-remove-option-regression.patch
new file mode 100644
index 0000000..8bcf0c9
--- /dev/null
+++ b/SOURCES/0036-mdadm-Fix-mdadm-r-remove-option-regression.patch
@@ -0,0 +1,78 @@
+From 6c9d9260633f2c8491985b0782cf0fbd7e51651b Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 22 Jun 2022 14:25:11 -0600
+Subject: [PATCH 36/52] mdadm: Fix mdadm -r remove option regression
+
+The commit noted below globally adds a parameter to the -r option but missed
+the fact that -r is used for another purpose: --remove.
+
+After that commit, a command such as:
+
+  mdadm /dev/md0 -r /dev/loop0
+
+will do nothing seeing the device parameter will be consumed as a
+argument to the -r option; thus, there will only be one device
+seen one the command line, devs_found will only be 1 and nothing will
+happen.
+
+This caused the 01r5integ and 01raid6integ tests to hang indefinitely
+as mdadm did not remove the failed device. With the device not removed,
+it would not be readded. Then the loop waiting for the array status to
+change would loop forever.
+
+This commit was recently reverted, but the legitimate fix for the
+monitor operations was still not fixed. So add specific monitor
+short ops to re-fix the --monitor -r option.
+
+Fixes: 546047688e1c ("mdadm: fix coredump of mdadm --monitor -r")
+Fixes: 190dc029b141 ("Revert "mdadm: fix coredump of mdadm --monitor -r"")
+Cc: Wu Guanghao <wuguanghao3@huawei.com>
+Cc: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ ReadMe.c | 1 +
+ mdadm.c  | 1 +
+ mdadm.h  | 1 +
+ 3 files changed, 3 insertions(+)
+
+diff --git a/ReadMe.c b/ReadMe.c
+index bec1be9a..7518a32a 100644
+--- a/ReadMe.c
++++ b/ReadMe.c
+@@ -82,6 +82,7 @@ char Version[] = "mdadm - v" VERSION " - " VERS_DATE EXTRAVERSION "\n";
+  */
+ 
+ char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
++char short_monitor_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:r:n:x:u:c:d:z:U:N:safRSow1tye:k:";
+ char short_bitmap_options[]=
+ 		"-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
+ char short_bitmap_auto_options[]=
+diff --git a/mdadm.c b/mdadm.c
+index be40686c..d0c5e6de 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -227,6 +227,7 @@ int main(int argc, char *argv[])
+ 			shortopt = short_bitmap_auto_options;
+ 			break;
+ 		case 'F': newmode = MONITOR;
++			shortopt = short_monitor_options;
+ 			break;
+ 		case 'G': newmode = GROW;
+ 			shortopt = short_bitmap_options;
+diff --git a/mdadm.h b/mdadm.h
+index 974415b9..163f4a49 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -419,6 +419,7 @@ enum mode {
+ };
+ 
+ extern char short_options[];
++extern char short_monitor_options[];
+ extern char short_bitmap_options[];
+ extern char short_bitmap_auto_options[];
+ extern struct option long_options[];
+-- 
+2.31.1
+
diff --git a/SOURCES/0037-mdadm-Fix-optional-write-behind-parameter.patch b/SOURCES/0037-mdadm-Fix-optional-write-behind-parameter.patch
new file mode 100644
index 0000000..c10712a
--- /dev/null
+++ b/SOURCES/0037-mdadm-Fix-optional-write-behind-parameter.patch
@@ -0,0 +1,42 @@
+From 41edf6f45895193f4a523cb0a08d639c9ff9ccc9 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 22 Jun 2022 14:25:12 -0600
+Subject: [PATCH 37/52] mdadm: Fix optional --write-behind parameter
+
+The commit noted below changed the behaviour of --write-behind to
+require an argument. This broke the 06wrmostly test with the error:
+
+  mdadm: Invalid value for maximum outstanding write-behind writes: (null).
+         Must be between 0 and 16383.
+
+To fix this, check if optarg is NULL before parising it, as the origial
+code did.
+
+Fixes: 60815698c0ac ("Refactor parse_num and use it to parse optarg.")
+Cc: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ mdadm.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/mdadm.c b/mdadm.c
+index d0c5e6de..56722ed9 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -1201,8 +1201,9 @@ int main(int argc, char *argv[])
+ 		case O(BUILD, WriteBehind):
+ 		case O(CREATE, WriteBehind):
+ 			s.write_behind = DEFAULT_MAX_WRITE_BEHIND;
+-			if (parse_num(&s.write_behind, optarg) != 0 ||
+-			s.write_behind < 0 || s.write_behind > 16383) {
++			if (optarg &&
++			    (parse_num(&s.write_behind, optarg) != 0 ||
++			     s.write_behind < 0 || s.write_behind > 16383)) {
+ 				pr_err("Invalid value for maximum outstanding write-behind writes: %s.\n\tMust be between 0 and 16383.\n",
+ 						optarg);
+ 				exit(2);
+-- 
+2.31.1
+
diff --git a/SOURCES/0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch b/SOURCES/0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch
new file mode 100644
index 0000000..e934bed
--- /dev/null
+++ b/SOURCES/0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch
@@ -0,0 +1,38 @@
+From 7539254342bc591717b0051734cc6c09c1b88640 Mon Sep 17 00:00:00 2001
+From: Sudhakar Panneerselvam <sudhakar.panneerselvam@oracle.com>
+Date: Wed, 22 Jun 2022 14:25:13 -0600
+Subject: [PATCH 38/52] tests/00raid0: add a test that validates raid0 with
+ layout fails for 0.9
+
+329dfc28debb disallows the creation of raid0 with layouts for 0.9
+metadata. This test confirms the new behavior.
+
+Signed-off-by: Sudhakar Panneerselvam <sudhakar.panneerselvam@oracle.com>
+Signed-off-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ tests/00raid0 | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/tests/00raid0 b/tests/00raid0
+index 8bc18985..e6b21cc4 100644
+--- a/tests/00raid0
++++ b/tests/00raid0
+@@ -6,11 +6,9 @@ check raid0
+ testdev $md0 3 $mdsize2_l 512
+ mdadm -S $md0
+ 
+-# now with version-0.90 superblock
++# verify raid0 with layouts fail for 0.90
+ mdadm -CR $md0 -e0.90 -l0 -n4 $dev0 $dev1 $dev2 $dev3
+-check raid0
+-testdev $md0 4 $mdsize0 512
+-mdadm -S $md0
++check opposite_result
+ 
+ # now with no superblock
+ mdadm -B $md0 -l0 -n5 $dev0 $dev1 $dev2 $dev3 $dev4
+-- 
+2.31.1
+
diff --git a/SOURCES/0039-tests-fix-raid0-tests-for-0.90-metadata.patch b/SOURCES/0039-tests-fix-raid0-tests-for-0.90-metadata.patch
new file mode 100644
index 0000000..ace5fbe
--- /dev/null
+++ b/SOURCES/0039-tests-fix-raid0-tests-for-0.90-metadata.patch
@@ -0,0 +1,99 @@
+From 14c2161edb77d7294199e8aa7daa9f9d1d0ad5d7 Mon Sep 17 00:00:00 2001
+From: Sudhakar Panneerselvam <sudhakar.panneerselvam@oracle.com>
+Date: Wed, 22 Jun 2022 14:25:14 -0600
+Subject: [PATCH 39/52] tests: fix raid0 tests for 0.90 metadata
+
+Some of the test cases fail because raid0 creation fails with the error,
+"0.90 metadata does not support layouts for RAID0" added by commit,
+329dfc28debb. Fix some of the test cases by switching from raid0 to
+linear level for 0.9 metadata where possible.
+
+Signed-off-by: Sudhakar Panneerselvam <sudhakar.panneerselvam@oracle.com>
+Signed-off-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ tests/00raid0           | 4 ++--
+ tests/00readonly        | 4 ++++
+ tests/03r0assem         | 6 +++---
+ tests/04r0update        | 4 ++--
+ tests/04update-metadata | 2 +-
+ 5 files changed, 12 insertions(+), 8 deletions(-)
+
+diff --git a/tests/00raid0 b/tests/00raid0
+index e6b21cc4..9b8896cb 100644
+--- a/tests/00raid0
++++ b/tests/00raid0
+@@ -20,8 +20,8 @@ mdadm -S $md0
+ # now same again with different chunk size
+ for chunk in 4 32 256
+ do
+-  mdadm -CR $md0 -e0.90 -l raid0 --chunk $chunk -n3 $dev0 $dev1 $dev2
+-  check raid0
++  mdadm -CR $md0 -e0.90 -l linear --chunk $chunk -n3 $dev0 $dev1 $dev2
++  check linear
+   testdev $md0 3 $mdsize0 $chunk
+   mdadm -S $md0
+ 
+diff --git a/tests/00readonly b/tests/00readonly
+index 28b0fa13..39202487 100644
+--- a/tests/00readonly
++++ b/tests/00readonly
+@@ -4,6 +4,10 @@ for metadata in 0.9 1.0 1.1 1.2
+ do
+ 	for level in linear raid0 raid1 raid4 raid5 raid6 raid10
+ 	do
++		if [[ $metadata == "0.9" && $level == "raid0" ]];
++		then
++			continue
++		fi
+ 		mdadm -CR $md0 -l $level -n 4 --metadata=$metadata \
+ 			$dev1 $dev2 $dev3 $dev4 --assume-clean
+ 		check nosync
+diff --git a/tests/03r0assem b/tests/03r0assem
+index 6744e322..44df0645 100644
+--- a/tests/03r0assem
++++ b/tests/03r0assem
+@@ -68,9 +68,9 @@ mdadm -S $md2
+ ### Now for version 0...
+ 
+ mdadm --zero-superblock $dev0 $dev1 $dev2
+-mdadm -CR $md2 -l0 --metadata=0.90 -n3 $dev0 $dev1 $dev2
+-check raid0
+-tst="testdev $md2 3 $mdsize0 512"
++mdadm -CR $md2 -llinear --metadata=0.90 -n3 $dev0 $dev1 $dev2
++check linear
++tst="testdev $md2 3 $mdsize0 1"
+ $tst
+ 
+ uuid=`mdadm -Db $md2 | sed 's/.*UUID=//'`
+diff --git a/tests/04r0update b/tests/04r0update
+index 73ee3b9f..b95efb06 100644
+--- a/tests/04r0update
++++ b/tests/04r0update
+@@ -1,7 +1,7 @@
+ 
+ # create a raid0, re-assemble with a different super-minor
+-mdadm -CR -e 0.90 $md0 -l0 -n3 $dev0 $dev1 $dev2
+-testdev $md0 3 $mdsize0 512
++mdadm -CR -e 0.90 $md0 -llinear -n3 $dev0 $dev1 $dev2
++testdev $md0 3 $mdsize0 1
+ minor1=`mdadm -E $dev0 | sed -n -e 's/.*Preferred Minor : //p'`
+ mdadm -S /dev/md0
+ 
+diff --git a/tests/04update-metadata b/tests/04update-metadata
+index 232fc1ff..08c14af7 100644
+--- a/tests/04update-metadata
++++ b/tests/04update-metadata
+@@ -8,7 +8,7 @@ set -xe
+ 
+ dlist="$dev0 $dev1 $dev2 $dev3"
+ 
+-for ls in raid0/4 linear/4 raid1/1 raid5/3 raid6/2
++for ls in linear/4 raid1/1 raid5/3 raid6/2
+ do
+   s=${ls#*/} l=${ls%/*}
+   mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 -c 64 $dlist
+-- 
+2.31.1
+
diff --git a/SOURCES/0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch b/SOURCES/0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch
new file mode 100644
index 0000000..76a7586
--- /dev/null
+++ b/SOURCES/0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch
@@ -0,0 +1,39 @@
+From de045db607b1ac4b70fc2a8878463e029c2ab1dc Mon Sep 17 00:00:00 2001
+From: Sudhakar Panneerselvam <sudhakar.panneerselvam@oracle.com>
+Date: Wed, 22 Jun 2022 14:25:15 -0600
+Subject: [PATCH 40/52] tests/04update-metadata: avoid passing chunk size to
+ raid1
+
+'04update-metadata' test fails with error, "specifying chunk size is
+forbidden for this level" added by commit, 5b30a34aa4b5e. Hence,
+correcting the test to ignore passing chunk size to raid1.
+
+Signed-off-by: Sudhakar Panneerselvam <sudhakar.panneerselvam@oracle.com>
+Signed-off-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+[logang@deltatee.com: fix if/then style and dropped unrelated hunk]
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ tests/04update-metadata | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/tests/04update-metadata b/tests/04update-metadata
+index 08c14af7..2b72a303 100644
+--- a/tests/04update-metadata
++++ b/tests/04update-metadata
+@@ -11,7 +11,11 @@ dlist="$dev0 $dev1 $dev2 $dev3"
+ for ls in linear/4 raid1/1 raid5/3 raid6/2
+ do
+   s=${ls#*/} l=${ls%/*}
+-  mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 -c 64 $dlist
++  if [[ $l == 'raid1' ]]; then
++	mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 $dlist
++  else
++	mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 -c 64 $dlist
++  fi
+   testdev $md0 $s 19904 64
+   mdadm -S $md0
+   mdadm -A $md0 --update=metadata $dlist
+-- 
+2.31.1
+
diff --git a/SOURCES/0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch b/SOURCES/0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch
new file mode 100644
index 0000000..00c9367
--- /dev/null
+++ b/SOURCES/0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch
@@ -0,0 +1,31 @@
+From a2c832465fc75202e244327b2081231dfa974617 Mon Sep 17 00:00:00 2001
+From: Sudhakar Panneerselvam <sudhakar.panneerselvam@oracle.com>
+Date: Wed, 22 Jun 2022 14:25:16 -0600
+Subject: [PATCH 41/52] tests/02lineargrow: clear the superblock at every
+ iteration
+
+This fixes 02lineargrow test as prior metadata causes --add operation
+to misbehave.
+
+Signed-off-by: Sudhakar Panneerselvam <sudhakar.panneerselvam@oracle.com>
+Signed-off-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ tests/02lineargrow | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/tests/02lineargrow b/tests/02lineargrow
+index e05c219d..595bf9f2 100644
+--- a/tests/02lineargrow
++++ b/tests/02lineargrow
+@@ -20,4 +20,6 @@ do
+   testdev $md0 3 $sz 1
+ 
+   mdadm -S $md0
++  mdadm --zero /dev/loop2
++  mdadm --zero /dev/loop3
+ done
+-- 
+2.31.1
+
diff --git a/SOURCES/0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch b/SOURCES/0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch
new file mode 100644
index 0000000..288ca2c
--- /dev/null
+++ b/SOURCES/0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch
@@ -0,0 +1,88 @@
+From a7bfcc716e235664dfb3b6c5a9590273e611ac72 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 22 Jun 2022 14:25:17 -0600
+Subject: [PATCH 42/52] mdadm/test: Add a mode to repeat specified tests
+
+Many tests fail infrequently or rarely. To help find these, add
+an option to run the tests multiple times by specifying --loop=N.
+
+If --loop=0 is specified, the test will be looped forever.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ test | 36 ++++++++++++++++++++++++------------
+ 1 file changed, 24 insertions(+), 12 deletions(-)
+
+diff --git a/test b/test
+index 711a3c7a..da6db5e0 100755
+--- a/test
++++ b/test
+@@ -10,6 +10,7 @@ devlist=
+ 
+ savelogs=0
+ exitonerror=1
++loop=1
+ prefix='[0-9][0-9]'
+ 
+ # use loop devices by default if doesn't specify --dev
+@@ -117,6 +118,7 @@ do_help() {
+ 		--logdir=directory          Directory to save all logfiles in
+ 		--save-logs                 Usually use with --logdir together
+ 		--keep-going | --no-error   Don't stop on error, ie. run all tests
++		--loop=N                    Run tests N times (0 to run forever)
+ 		--dev=loop|lvm|ram|disk     Use loop devices (default), LVM, RAM or disk
+ 		--disks=                    Provide a bunch of physical devices for test
+ 		--volgroup=name             LVM volume group for LVM test
+@@ -211,6 +213,9 @@ parse_args() {
+ 		--keep-going | --no-error )
+ 			exitonerror=0
+ 			;;
++		--loop=* )
++			loop="${i##*=}"
++			;;
+ 		--disable-multipath )
+ 			unset MULTIPATH
+ 			;;
+@@ -263,19 +268,26 @@ main() {
+ 	echo "Testing on linux-$(uname -r) kernel"
+ 	[ "$savelogs" == "1" ] &&
+ 		echo "Saving logs to $logdir"
+-	if [ "x$TESTLIST" != "x" ]
+-	then
+-		for script in ${TESTLIST[@]}
+-		do
+-			do_test $testdir/$script
+-		done
+-	else
+-		for script in $testdir/$prefix $testdir/$prefix*[^~]
+-		do
+-			do_test $script
+-		done
+-	fi
+ 
++	while true; do
++		if [ "x$TESTLIST" != "x" ]
++		then
++			for script in ${TESTLIST[@]}
++			do
++				do_test $testdir/$script
++			done
++		else
++			for script in $testdir/$prefix $testdir/$prefix*[^~]
++			do
++				do_test $script
++			done
++		fi
++
++		let loop=$loop-1
++		if [ "$loop" == "0" ]; then
++			break
++		fi
++	done
+ 	exit 0
+ }
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch b/SOURCES/0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch
new file mode 100644
index 0000000..5585173
--- /dev/null
+++ b/SOURCES/0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch
@@ -0,0 +1,120 @@
+From 28520bf114b3b0515a48ff44fff4ecbe9ed6dfad Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 22 Jun 2022 14:25:18 -0600
+Subject: [PATCH 43/52] mdadm/test: Mark and ignore broken test failures
+
+Add functionality to continue if a test marked as broken fails.
+
+To mark a test as broken, a file with the same name but with the suffix
+'.broken' should exist. The first line in the file will be printed with
+a KNOWN BROKEN message; the rest of the file can describe the how the
+test is broken.
+
+Also adds --skip-broken and --skip-always-broken to skip all the tests
+that have a .broken file or to skip all tests whose .broken file's first
+line contains the keyword always.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ test | 37 +++++++++++++++++++++++++++++++++++--
+ 1 file changed, 35 insertions(+), 2 deletions(-)
+
+diff --git a/test b/test
+index da6db5e0..61d9ee83 100755
+--- a/test
++++ b/test
+@@ -10,6 +10,8 @@ devlist=
+ 
+ savelogs=0
+ exitonerror=1
++ctrl_c_error=0
++skipbroken=0
+ loop=1
+ prefix='[0-9][0-9]'
+ 
+@@ -36,6 +38,7 @@ die() {
+ 
+ ctrl_c() {
+ 	exitonerror=1
++	ctrl_c_error=1
+ }
+ 
+ # mdadm always adds --quiet, and we want to see any unexpected messages
+@@ -80,8 +83,21 @@ mdadm() {
+ do_test() {
+ 	_script=$1
+ 	_basename=`basename $_script`
++	_broken=0
++
+ 	if [ -f "$_script" ]
+ 	then
++		if [ -f "${_script}.broken" ]; then
++			_broken=1
++			_broken_msg=$(head -n1 "${_script}.broken" | tr -d '\n')
++			if [ "$skipbroken" == "all" ]; then
++				return
++			elif [ "$skipbroken" == "always" ] &&
++			     [[ "$_broken_msg" == *always* ]]; then
++				return
++			fi
++		fi
++
+ 		rm -f $targetdir/stderr
+ 		# this might have been reset: restore the default.
+ 		echo 2000 > /proc/sys/dev/raid/speed_limit_max
+@@ -98,10 +114,15 @@ do_test() {
+ 		else
+ 			save_log fail
+ 			_fail=1
++			if [ "$_broken" == "1" ]; then
++				echo "  (KNOWN BROKEN TEST: $_broken_msg)"
++			fi
+ 		fi
+ 		[ "$savelogs" == "1" ] &&
+ 			mv -f $targetdir/log $logdir/$_basename.log
+-		[ "$_fail" == "1" -a "$exitonerror" == "1" ] && exit 1
++		[ "$ctrl_c_error" == "1" ] && exit 1
++		[ "$_fail" == "1" -a "$exitonerror" == "1" \
++		  -a "$_broken" == "0" ] && exit 1
+ 	fi
+ }
+ 
+@@ -119,6 +140,8 @@ do_help() {
+ 		--save-logs                 Usually use with --logdir together
+ 		--keep-going | --no-error   Don't stop on error, ie. run all tests
+ 		--loop=N                    Run tests N times (0 to run forever)
++		--skip-broken               Skip tests that are known to be broken
++		--skip-always-broken        Skip tests that are known to always fail
+ 		--dev=loop|lvm|ram|disk     Use loop devices (default), LVM, RAM or disk
+ 		--disks=                    Provide a bunch of physical devices for test
+ 		--volgroup=name             LVM volume group for LVM test
+@@ -216,6 +239,12 @@ parse_args() {
+ 		--loop=* )
+ 			loop="${i##*=}"
+ 			;;
++		--skip-broken )
++			skipbroken=all
++			;;
++		--skip-always-broken )
++			skipbroken=always
++			;;
+ 		--disable-multipath )
+ 			unset MULTIPATH
+ 			;;
+@@ -279,7 +308,11 @@ main() {
+ 		else
+ 			for script in $testdir/$prefix $testdir/$prefix*[^~]
+ 			do
+-				do_test $script
++				case $script in
++				 *.broken) ;;
++				 *)
++				     do_test $script
++				 esac
+ 			done
+ 		fi
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0044-tests-Add-broken-files-for-all-broken-tests.patch b/SOURCES/0044-tests-Add-broken-files-for-all-broken-tests.patch
new file mode 100644
index 0000000..643bf3f
--- /dev/null
+++ b/SOURCES/0044-tests-Add-broken-files-for-all-broken-tests.patch
@@ -0,0 +1,447 @@
+From daa86d6634761796ada1f535c13e47fdd3cc95eb Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 22 Jun 2022 14:25:19 -0600
+Subject: [PATCH 44/52] tests: Add broken files for all broken tests
+
+Each broken file contains the rough frequency of brokeness as well
+as a brief explanation of what happens when it breaks. Estimates
+of failure rates are not statistically significant and can vary
+run to run.
+
+This is really just a view from my window. Tests were done on a
+small VM with the default loop devices, not real hardware. We've
+seen different kernel configurations can cause bugs to appear as well
+(ie. different block schedulers). It may also be that different race
+conditions will be seen on machines with different performance
+characteristics.
+
+These annotations were done with the kernel currently in md/md-next:
+
+ facef3b96c5b ("md: Notify sysfs sync_completed in md_reap_sync_thread()")
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ tests/01r5integ.broken                     |  7 ++++
+ tests/01raid6integ.broken                  |  7 ++++
+ tests/04r5swap.broken                      |  7 ++++
+ tests/07autoassemble.broken                |  8 ++++
+ tests/07autodetect.broken                  |  5 +++
+ tests/07changelevelintr.broken             |  9 +++++
+ tests/07changelevels.broken                |  9 +++++
+ tests/07reshape5intr.broken                | 45 ++++++++++++++++++++++
+ tests/07revert-grow.broken                 | 31 +++++++++++++++
+ tests/07revert-shrink.broken               |  9 +++++
+ tests/07testreshape5.broken                | 12 ++++++
+ tests/09imsm-assemble.broken               |  6 +++
+ tests/09imsm-create-fail-rebuild.broken    |  5 +++
+ tests/09imsm-overlap.broken                |  7 ++++
+ tests/10ddf-assemble-missing.broken        |  6 +++
+ tests/10ddf-fail-create-race.broken        |  7 ++++
+ tests/10ddf-fail-two-spares.broken         |  5 +++
+ tests/10ddf-incremental-wrong-order.broken |  9 +++++
+ tests/14imsm-r1_2d-grow-r1_3d.broken       |  5 +++
+ tests/14imsm-r1_2d-takeover-r0_2d.broken   |  6 +++
+ tests/18imsm-r10_4d-takeover-r0_2d.broken  |  5 +++
+ tests/18imsm-r1_2d-takeover-r0_1d.broken   |  6 +++
+ tests/19raid6auto-repair.broken            |  5 +++
+ tests/19raid6repair.broken                 |  5 +++
+ 24 files changed, 226 insertions(+)
+ create mode 100644 tests/01r5integ.broken
+ create mode 100644 tests/01raid6integ.broken
+ create mode 100644 tests/04r5swap.broken
+ create mode 100644 tests/07autoassemble.broken
+ create mode 100644 tests/07autodetect.broken
+ create mode 100644 tests/07changelevelintr.broken
+ create mode 100644 tests/07changelevels.broken
+ create mode 100644 tests/07reshape5intr.broken
+ create mode 100644 tests/07revert-grow.broken
+ create mode 100644 tests/07revert-shrink.broken
+ create mode 100644 tests/07testreshape5.broken
+ create mode 100644 tests/09imsm-assemble.broken
+ create mode 100644 tests/09imsm-create-fail-rebuild.broken
+ create mode 100644 tests/09imsm-overlap.broken
+ create mode 100644 tests/10ddf-assemble-missing.broken
+ create mode 100644 tests/10ddf-fail-create-race.broken
+ create mode 100644 tests/10ddf-fail-two-spares.broken
+ create mode 100644 tests/10ddf-incremental-wrong-order.broken
+ create mode 100644 tests/14imsm-r1_2d-grow-r1_3d.broken
+ create mode 100644 tests/14imsm-r1_2d-takeover-r0_2d.broken
+ create mode 100644 tests/18imsm-r10_4d-takeover-r0_2d.broken
+ create mode 100644 tests/18imsm-r1_2d-takeover-r0_1d.broken
+ create mode 100644 tests/19raid6auto-repair.broken
+ create mode 100644 tests/19raid6repair.broken
+
+diff --git a/tests/01r5integ.broken b/tests/01r5integ.broken
+new file mode 100644
+index 00000000..20737637
+--- /dev/null
++++ b/tests/01r5integ.broken
+@@ -0,0 +1,7 @@
++fails rarely
++
++Fails about 1 in every 30 runs with a sha mismatch error:
++
++    c49ab26e1b01def7874af9b8a6d6d0c29fdfafe6 /dev/md0 does not match
++    15dc2f73262f811ada53c65e505ceec9cf025cb9 /dev/md0 with /dev/loop3
++    missing
+diff --git a/tests/01raid6integ.broken b/tests/01raid6integ.broken
+new file mode 100644
+index 00000000..1df735f0
+--- /dev/null
++++ b/tests/01raid6integ.broken
+@@ -0,0 +1,7 @@
++fails infrequently
++
++Fails about 1 in 5 with a sha mismatch:
++
++    8286c2bc045ae2cfe9f8b7ae3a898fa25db6926f /dev/md0 does not match
++    a083a0738b58caab37fd568b91b177035ded37df /dev/md0 with /dev/loop2 and
++    /dev/loop3 missing
+diff --git a/tests/04r5swap.broken b/tests/04r5swap.broken
+new file mode 100644
+index 00000000..e38987db
+--- /dev/null
++++ b/tests/04r5swap.broken
+@@ -0,0 +1,7 @@
++always fails
++
++Fails with errors:
++
++  mdadm: /dev/loop0 has no superblock - assembly aborted
++
++   ERROR: no recovery happening
+diff --git a/tests/07autoassemble.broken b/tests/07autoassemble.broken
+new file mode 100644
+index 00000000..8be09407
+--- /dev/null
++++ b/tests/07autoassemble.broken
+@@ -0,0 +1,8 @@
++always fails
++
++Prints lots of messages, but the array doesn't assemble. Error
++possibly related to:
++
++  mdadm: /dev/md/1 is busy - skipping
++  mdadm: no recogniseable superblock on /dev/md/testing:0
++  mdadm: /dev/md/2 is busy - skipping
+diff --git a/tests/07autodetect.broken b/tests/07autodetect.broken
+new file mode 100644
+index 00000000..294954a1
+--- /dev/null
++++ b/tests/07autodetect.broken
+@@ -0,0 +1,5 @@
++always fails
++
++Fails with error:
++
++    ERROR: no resync happening
+diff --git a/tests/07changelevelintr.broken b/tests/07changelevelintr.broken
+new file mode 100644
+index 00000000..284b4906
+--- /dev/null
++++ b/tests/07changelevelintr.broken
+@@ -0,0 +1,9 @@
++always fails
++
++Fails with errors:
++
++  mdadm: this change will reduce the size of the array.
++         use --grow --array-size first to truncate array.
++         e.g. mdadm --grow /dev/md0 --array-size 56832
++
++  ERROR: no reshape happening
+diff --git a/tests/07changelevels.broken b/tests/07changelevels.broken
+new file mode 100644
+index 00000000..9b930d93
+--- /dev/null
++++ b/tests/07changelevels.broken
+@@ -0,0 +1,9 @@
++always fails
++
++Fails with errors:
++
++    mdadm: /dev/loop0 is smaller than given size. 18976K < 19968K + metadata
++    mdadm: /dev/loop1 is smaller than given size. 18976K < 19968K + metadata
++    mdadm: /dev/loop2 is smaller than given size. 18976K < 19968K + metadata
++
++    ERROR: /dev/md0 isn't a block device.
+diff --git a/tests/07reshape5intr.broken b/tests/07reshape5intr.broken
+new file mode 100644
+index 00000000..efe52a66
+--- /dev/null
++++ b/tests/07reshape5intr.broken
+@@ -0,0 +1,45 @@
++always fails
++
++This patch, recently added to md-next causes the test to always fail:
++
++7e6ba434cc60 ("md: don't unregister sync_thread with reconfig_mutex
++held")
++
++The new error is simply:
++
++   ERROR: no reshape happening
++
++Before the patch, the error seen is below.
++
++--
++
++fails infrequently
++
++Fails roughly 1 in 4 runs with errors:
++
++    mdadm: Merging with already-assembled /dev/md/0
++    mdadm: cannot re-read metadata from /dev/loop6 - aborting
++
++    ERROR: no reshape happening
++
++Also have seen a random deadlock:
++
++     INFO: task mdadm:109702 blocked for more than 30 seconds.
++           Not tainted 5.18.0-rc3-eid-vmlocalyes-dbg-00095-g3c2b5427979d #2040
++     "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
++     task:mdadm           state:D stack:    0 pid:109702 ppid:     1 flags:0x00004000
++     Call Trace:
++      <TASK>
++      __schedule+0x67e/0x13b0
++      schedule+0x82/0x110
++      mddev_suspend+0x2e1/0x330
++      suspend_lo_store+0xbd/0x140
++      md_attr_store+0xcb/0x130
++      sysfs_kf_write+0x89/0xb0
++      kernfs_fop_write_iter+0x202/0x2c0
++      new_sync_write+0x222/0x330
++      vfs_write+0x3bc/0x4d0
++      ksys_write+0xd9/0x180
++      __x64_sys_write+0x43/0x50
++      do_syscall_64+0x3b/0x90
++      entry_SYSCALL_64_after_hwframe+0x44/0xae
+diff --git a/tests/07revert-grow.broken b/tests/07revert-grow.broken
+new file mode 100644
+index 00000000..9b6db86f
+--- /dev/null
++++ b/tests/07revert-grow.broken
+@@ -0,0 +1,31 @@
++always fails
++
++This patch, recently added to md-next causes the test to always fail:
++
++7e6ba434cc60 ("md: don't unregister sync_thread with reconfig_mutex held")
++
++The errors are:
++
++    mdadm: No active reshape to revert on /dev/loop0
++    ERROR: active raid5 not found
++
++Before the patch, the error seen is below.
++
++--
++
++fails rarely
++
++Fails about 1 in every 30 runs with errors:
++
++    mdadm: Merging with already-assembled /dev/md/0
++    mdadm: backup file /tmp/md-backup inaccessible: No such file or directory
++    mdadm: failed to add /dev/loop1 to /dev/md/0: Invalid argument
++    mdadm: failed to add /dev/loop2 to /dev/md/0: Invalid argument
++    mdadm: failed to add /dev/loop3 to /dev/md/0: Invalid argument
++    mdadm: failed to add /dev/loop0 to /dev/md/0: Invalid argument
++    mdadm: /dev/md/0 assembled from 1 drive - need all 5 to start it
++            (use --run to insist).
++
++    grep: /sys/block/md*/md/sync_action: No such file or directory
++
++    ERROR: active raid5 not found
+diff --git a/tests/07revert-shrink.broken b/tests/07revert-shrink.broken
+new file mode 100644
+index 00000000..c33c39ec
+--- /dev/null
++++ b/tests/07revert-shrink.broken
+@@ -0,0 +1,9 @@
++always fails
++
++Fails with errors:
++
++    mdadm: this change will reduce the size of the array.
++           use --grow --array-size first to truncate array.
++           e.g. mdadm --grow /dev/md0 --array-size 53760
++
++    ERROR: active raid5 not found
+diff --git a/tests/07testreshape5.broken b/tests/07testreshape5.broken
+new file mode 100644
+index 00000000..a8ce03e4
+--- /dev/null
++++ b/tests/07testreshape5.broken
+@@ -0,0 +1,12 @@
++always fails
++
++Test seems to run 'test_stripe' at $dir directory, but $dir is never
++set. If $dir is adjusted to $PWD, the test still fails with:
++
++    mdadm: /dev/loop2 is not suitable for this array.
++    mdadm: create aborted
++    ++ return 1
++    ++ cmp -s -n 8192 /dev/md0 /tmp/RandFile
++    ++ echo cmp failed
++    cmp failed
++    ++ exit 2
+diff --git a/tests/09imsm-assemble.broken b/tests/09imsm-assemble.broken
+new file mode 100644
+index 00000000..a6d4d5cf
+--- /dev/null
++++ b/tests/09imsm-assemble.broken
+@@ -0,0 +1,6 @@
++fails infrequently
++
++Fails roughly 1 in 10 runs with errors:
++
++    mdadm: /dev/loop2 is still in use, cannot remove.
++    /dev/loop2 removal from /dev/md/container should have succeeded
+diff --git a/tests/09imsm-create-fail-rebuild.broken b/tests/09imsm-create-fail-rebuild.broken
+new file mode 100644
+index 00000000..40c4b294
+--- /dev/null
++++ b/tests/09imsm-create-fail-rebuild.broken
+@@ -0,0 +1,5 @@
++always fails
++
++Fails with error:
++
++    **Error**: Array size mismatch - expected 3072, actual 16384
+diff --git a/tests/09imsm-overlap.broken b/tests/09imsm-overlap.broken
+new file mode 100644
+index 00000000..e7ccab76
+--- /dev/null
++++ b/tests/09imsm-overlap.broken
+@@ -0,0 +1,7 @@
++always fails
++
++Fails with errors:
++
++    **Error**: Offset mismatch - expected 15360, actual 0
++    **Error**: Offset mismatch - expected 15360, actual 0
++    /dev/md/vol3 failed check
+diff --git a/tests/10ddf-assemble-missing.broken b/tests/10ddf-assemble-missing.broken
+new file mode 100644
+index 00000000..bfd8d103
+--- /dev/null
++++ b/tests/10ddf-assemble-missing.broken
+@@ -0,0 +1,6 @@
++always fails
++
++Fails with errors:
++
++    ERROR: /dev/md/vol0 has unexpected state on /dev/loop10
++    ERROR: unexpected number of online disks on /dev/loop10
+diff --git a/tests/10ddf-fail-create-race.broken b/tests/10ddf-fail-create-race.broken
+new file mode 100644
+index 00000000..6c0df023
+--- /dev/null
++++ b/tests/10ddf-fail-create-race.broken
+@@ -0,0 +1,7 @@
++usually fails
++
++Fails about 9 out of 10 times with many errors:
++
++    mdadm: cannot open MISSING: No such file or directory
++    ERROR: non-degraded array found
++    ERROR: disk 0 not marked as failed in meta data
+diff --git a/tests/10ddf-fail-two-spares.broken b/tests/10ddf-fail-two-spares.broken
+new file mode 100644
+index 00000000..eeea56d9
+--- /dev/null
++++ b/tests/10ddf-fail-two-spares.broken
+@@ -0,0 +1,5 @@
++fails infrequently
++
++Fails roughly 1 in 3 with error:
++
++   ERROR: /dev/md/vol1 should be optimal in meta data
+diff --git a/tests/10ddf-incremental-wrong-order.broken b/tests/10ddf-incremental-wrong-order.broken
+new file mode 100644
+index 00000000..a5af3bab
+--- /dev/null
++++ b/tests/10ddf-incremental-wrong-order.broken
+@@ -0,0 +1,9 @@
++always fails
++
++Fails with errors:
++    ERROR: sha1sum of /dev/md/vol0 has changed
++    ERROR: /dev/md/vol0 has unexpected state on /dev/loop10
++    ERROR: unexpected number of online disks on /dev/loop10
++    ERROR: /dev/md/vol0 has unexpected state on /dev/loop8
++    ERROR: unexpected number of online disks on /dev/loop8
++    ERROR: sha1sum of /dev/md/vol0 has changed
+diff --git a/tests/14imsm-r1_2d-grow-r1_3d.broken b/tests/14imsm-r1_2d-grow-r1_3d.broken
+new file mode 100644
+index 00000000..4ef1d406
+--- /dev/null
++++ b/tests/14imsm-r1_2d-grow-r1_3d.broken
+@@ -0,0 +1,5 @@
++always fails
++
++Fails with error:
++
++    mdadm/tests/func.sh: line 325: dvsize/chunk: division by 0 (error token is "chunk")
+diff --git a/tests/14imsm-r1_2d-takeover-r0_2d.broken b/tests/14imsm-r1_2d-takeover-r0_2d.broken
+new file mode 100644
+index 00000000..89cd4e57
+--- /dev/null
++++ b/tests/14imsm-r1_2d-takeover-r0_2d.broken
+@@ -0,0 +1,6 @@
++always fails
++
++Fails with error:
++
++    tests/func.sh: line 325: dvsize/chunk: division by 0 (error token
++		is "chunk")
+diff --git a/tests/18imsm-r10_4d-takeover-r0_2d.broken b/tests/18imsm-r10_4d-takeover-r0_2d.broken
+new file mode 100644
+index 00000000..a27399f5
+--- /dev/null
++++ b/tests/18imsm-r10_4d-takeover-r0_2d.broken
+@@ -0,0 +1,5 @@
++fails rarely
++
++Fails about 1 run in 100 with message:
++
++   ERROR:  size is wrong for /dev/md/vol0: 2 * 5120 (chunk=128) = 20480, not 0
+diff --git a/tests/18imsm-r1_2d-takeover-r0_1d.broken b/tests/18imsm-r1_2d-takeover-r0_1d.broken
+new file mode 100644
+index 00000000..aa1982e6
+--- /dev/null
++++ b/tests/18imsm-r1_2d-takeover-r0_1d.broken
+@@ -0,0 +1,6 @@
++always fails
++
++Fails with error:
++
++    tests/func.sh: line 325: dvsize/chunk: division by 0 (error token
++			is "chunk")
+diff --git a/tests/19raid6auto-repair.broken b/tests/19raid6auto-repair.broken
+new file mode 100644
+index 00000000..e91a1425
+--- /dev/null
++++ b/tests/19raid6auto-repair.broken
+@@ -0,0 +1,5 @@
++always fails
++
++Fails with:
++
++    "should detect errors"
+diff --git a/tests/19raid6repair.broken b/tests/19raid6repair.broken
+new file mode 100644
+index 00000000..e91a1425
+--- /dev/null
++++ b/tests/19raid6repair.broken
+@@ -0,0 +1,5 @@
++always fails
++
++Fails with:
++
++    "should detect errors"
+-- 
+2.31.1
+
diff --git a/SOURCES/0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch b/SOURCES/0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch
new file mode 100644
index 0000000..44b6d7c
--- /dev/null
+++ b/SOURCES/0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch
@@ -0,0 +1,316 @@
+From 239b3cc0b5da87e966746533b1873c439db54b16 Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Fri, 12 Aug 2022 16:36:02 +0200
+Subject: [PATCH 45/52] mdadm: Replace obsolete usleep with nanosleep
+
+According to POSIX.1-2001, usleep is considered obsolete.
+Replace it with a wrapper that uses nanosleep, as recommended in man.
+Add handy macros for conversions between msec, usec and nsec.
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c    |  2 +-
+ Grow.c        |  4 ++--
+ Manage.c      | 10 +++++-----
+ managemon.c   |  8 ++++----
+ mdadm.h       |  4 ++++
+ mdmon.c       |  4 ++--
+ super-intel.c |  6 +++---
+ util.c        | 42 +++++++++++++++++++++++++++++++++---------
+ 8 files changed, 54 insertions(+), 26 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index 6df6bfbc..be2160b4 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -1947,7 +1947,7 @@ out:
+ 						break;
+ 					close(mdfd);
+ 				}
+-				usleep(usecs);
++				sleep_for(0, USEC_TO_NSEC(usecs), true);
+ 				usecs <<= 1;
+ 			}
+ 		}
+diff --git a/Grow.c b/Grow.c
+index 97f22c75..5780635a 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -954,7 +954,7 @@ int start_reshape(struct mdinfo *sra, int already_running,
+ 			err = sysfs_set_str(sra, NULL, "sync_action",
+ 					    "reshape");
+ 			if (err)
+-				sleep(1);
++				sleep_for(1, 0, true);
+ 		} while (err && errno == EBUSY && cnt-- > 0);
+ 	}
+ 	return err;
+@@ -5058,7 +5058,7 @@ int Grow_continue_command(char *devname, int fd,
+ 			}
+ 			st->ss->getinfo_super(st, content, NULL);
+ 			if (!content->reshape_active)
+-				sleep(3);
++				sleep_for(3, 0, true);
+ 			else
+ 				break;
+ 		} while (cnt-- > 0);
+diff --git a/Manage.c b/Manage.c
+index e5e6abe4..a142f8bd 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -244,7 +244,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
+ 					    "array_state",
+ 					    "inactive")) < 0 &&
+ 		       errno == EBUSY) {
+-			usleep(200000);
++			sleep_for(0, MSEC_TO_NSEC(200), true);
+ 			count--;
+ 		}
+ 		if (err) {
+@@ -328,7 +328,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
+ 		       sysfs_get_ll(mdi, NULL, "sync_max", &old_sync_max) == 0) {
+ 			/* must be in the critical section - wait a bit */
+ 			delay -= 1;
+-			usleep(100000);
++			sleep_for(0, MSEC_TO_NSEC(100), true);
+ 		}
+ 
+ 		if (sysfs_set_str(mdi, NULL, "sync_action", "frozen") != 0)
+@@ -405,7 +405,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
+ 				 * quite started yet.  Wait a bit and
+ 				 * check  'sync_action' to see.
+ 				 */
+-				usleep(10000);
++				sleep_for(0, MSEC_TO_NSEC(10), true);
+ 				sysfs_get_str(mdi, NULL, "sync_action", buf, sizeof(buf));
+ 				if (strncmp(buf, "reshape", 7) != 0)
+ 					break;
+@@ -447,7 +447,7 @@ done:
+ 	count = 25; err = 0;
+ 	while (count && fd >= 0 &&
+ 	       (err = ioctl(fd, STOP_ARRAY, NULL)) < 0 && errno == EBUSY) {
+-		usleep(200000);
++		sleep_for(0, MSEC_TO_NSEC(200), true);
+ 		count --;
+ 	}
+ 	if (fd >= 0 && err) {
+@@ -1105,7 +1105,7 @@ int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv,
+ 				ret = sysfs_unique_holder(devnm, rdev);
+ 				if (ret < 2)
+ 					break;
+-				usleep(100 * 1000);	/* 100ms */
++				sleep_for(0, MSEC_TO_NSEC(100), true);
+ 			} while (--count > 0);
+ 
+ 			if (ret == 0) {
+diff --git a/managemon.c b/managemon.c
+index 0e9bdf00..a7bfa8f6 100644
+--- a/managemon.c
++++ b/managemon.c
+@@ -207,7 +207,7 @@ static void replace_array(struct supertype *container,
+ 	remove_old();
+ 	while (pending_discard) {
+ 		while (discard_this == NULL)
+-			sleep(1);
++			sleep_for(1, 0, true);
+ 		remove_old();
+ 	}
+ 	pending_discard = old;
+@@ -568,7 +568,7 @@ static void manage_member(struct mdstat_ent *mdstat,
+ 		updates = NULL;
+ 		while (update_queue_pending || update_queue) {
+ 			check_update_queue(container);
+-			usleep(15*1000);
++			sleep_for(0, MSEC_TO_NSEC(15), true);
+ 		}
+ 		replace_array(container, a, newa);
+ 		if (sysfs_set_str(&a->info, NULL,
+@@ -822,7 +822,7 @@ static void handle_message(struct supertype *container, struct metadata_update *
+ 	if (msg->len <= 0)
+ 		while (update_queue_pending || update_queue) {
+ 			check_update_queue(container);
+-			usleep(15*1000);
++			sleep_for(0, MSEC_TO_NSEC(15), true);
+ 		}
+ 
+ 	if (msg->len == 0) { /* ping_monitor */
+@@ -836,7 +836,7 @@ static void handle_message(struct supertype *container, struct metadata_update *
+ 		wakeup_monitor();
+ 
+ 		while (monitor_loop_cnt - cnt < 0)
+-			usleep(10 * 1000);
++			sleep_for(0, MSEC_TO_NSEC(10), true);
+ 	} else if (msg->len == -1) { /* ping_manager */
+ 		struct mdstat_ent *mdstat = mdstat_read(1, 0);
+ 
+diff --git a/mdadm.h b/mdadm.h
+index 163f4a49..add9c0b6 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1720,6 +1720,10 @@ extern int cluster_get_dlmlock(void);
+ extern int cluster_release_dlmlock(void);
+ extern void set_dlm_hooks(void);
+ 
++#define MSEC_TO_NSEC(msec) ((msec) * 1000000)
++#define USEC_TO_NSEC(usec) ((usec) * 1000)
++extern void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt);
++
+ #define _ROUND_UP(val, base)	(((val) + (base) - 1) & ~(base - 1))
+ #define ROUND_UP(val, base)	_ROUND_UP(val, (typeof(val))(base))
+ #define ROUND_UP_PTR(ptr, base)	((typeof(ptr)) \
+diff --git a/mdmon.c b/mdmon.c
+index c057da63..e9d035eb 100644
+--- a/mdmon.c
++++ b/mdmon.c
+@@ -99,7 +99,7 @@ static int clone_monitor(struct supertype *container)
+ 	if (rc)
+ 		return rc;
+ 	while (mon_tid == -1)
+-		usleep(10);
++		sleep_for(0, USEC_TO_NSEC(10), true);
+ 	pthread_attr_destroy(&attr);
+ 
+ 	mgr_tid = syscall(SYS_gettid);
+@@ -209,7 +209,7 @@ static void try_kill_monitor(pid_t pid, char *devname, int sock)
+ 		rv = kill(pid, SIGUSR1);
+ 		if (rv < 0)
+ 			break;
+-		usleep(200000);
++		sleep_for(0, MSEC_TO_NSEC(200), true);
+ 	}
+ }
+ 
+diff --git a/super-intel.c b/super-intel.c
+index 4ddfcf94..4d82af3d 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -5275,7 +5275,7 @@ static int get_super_block(struct intel_super **super_list, char *devnm, char *d
+ 	/* retry the load if we might have raced against mdmon */
+ 	if (err == 3 && devnm && mdmon_running(devnm))
+ 		for (retry = 0; retry < 3; retry++) {
+-			usleep(3000);
++			sleep_for(0, MSEC_TO_NSEC(3), true);
+ 			err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
+ 			if (err != 3)
+ 				break;
+@@ -5377,7 +5377,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
+ 
+ 		if (mdstat && mdmon_running(mdstat->devnm) && getpid() != mdmon_pid(mdstat->devnm)) {
+ 			for (retry = 0; retry < 3; retry++) {
+-				usleep(3000);
++				sleep_for(0, MSEC_TO_NSEC(3), true);
+ 				rv = load_and_parse_mpb(fd, super, devname, 0);
+ 				if (rv != 3)
+ 					break;
+@@ -12084,7 +12084,7 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
+ 				close(fd);
+ 				return 1;
+ 			}
+-			usleep(30000);
++			sleep_for(0, MSEC_TO_NSEC(30), true);
+ 		} else
+ 			break;
+ 	} while (retry--);
+diff --git a/util.c b/util.c
+index 38f0420e..ca48d976 100644
+--- a/util.c
++++ b/util.c
+@@ -166,7 +166,7 @@ retry:
+ 		pr_err("error %d when get PW mode on lock %s\n", errno, str);
+ 		/* let's try several times if EAGAIN happened */
+ 		if (dlm_lock_res->lksb.sb_status == EAGAIN && retry_count < 10) {
+-			sleep(10);
++			sleep_for(10, 0, true);
+ 			retry_count++;
+ 			goto retry;
+ 		}
+@@ -1085,7 +1085,7 @@ int open_dev_excl(char *devnm)
+ 	int i;
+ 	int flags = O_RDWR;
+ 	dev_t devid = devnm2devid(devnm);
+-	long delay = 1000;
++	unsigned int delay = 1; // miliseconds
+ 
+ 	sprintf(buf, "%d:%d", major(devid), minor(devid));
+ 	for (i = 0; i < 25; i++) {
+@@ -1098,8 +1098,8 @@ int open_dev_excl(char *devnm)
+ 		}
+ 		if (errno != EBUSY)
+ 			return fd;
+-		usleep(delay);
+-		if (delay < 200000)
++		sleep_for(0, MSEC_TO_NSEC(delay), true);
++		if (delay < 200)
+ 			delay *= 2;
+ 	}
+ 	return -1;
+@@ -1123,7 +1123,7 @@ void wait_for(char *dev, int fd)
+ {
+ 	int i;
+ 	struct stat stb_want;
+-	long delay = 1000;
++	unsigned int delay = 1; // miliseconds
+ 
+ 	if (fstat(fd, &stb_want) != 0 ||
+ 	    (stb_want.st_mode & S_IFMT) != S_IFBLK)
+@@ -1135,8 +1135,8 @@ void wait_for(char *dev, int fd)
+ 		    (stb.st_mode & S_IFMT) == S_IFBLK &&
+ 		    (stb.st_rdev == stb_want.st_rdev))
+ 			return;
+-		usleep(delay);
+-		if (delay < 200000)
++		sleep_for(0, MSEC_TO_NSEC(delay), true);
++		if (delay < 200)
+ 			delay *= 2;
+ 	}
+ 	if (i == 25)
+@@ -1821,7 +1821,7 @@ int hot_remove_disk(int mdfd, unsigned long dev, int force)
+ 	while ((ret = ioctl(mdfd, HOT_REMOVE_DISK, dev)) == -1 &&
+ 	       errno == EBUSY &&
+ 	       cnt-- > 0)
+-		usleep(10000);
++		sleep_for(0, MSEC_TO_NSEC(10), true);
+ 
+ 	return ret;
+ }
+@@ -1834,7 +1834,7 @@ int sys_hot_remove_disk(int statefd, int force)
+ 	while ((ret = write(statefd, "remove", 6)) == -1 &&
+ 	       errno == EBUSY &&
+ 	       cnt-- > 0)
+-		usleep(10000);
++		sleep_for(0, MSEC_TO_NSEC(10), true);
+ 	return ret == 6 ? 0 : -1;
+ }
+ 
+@@ -2375,3 +2375,27 @@ out:
+ 	close(fd_zero);
+ 	return ret;
+ }
++
++/**
++ * sleep_for() - Sleeps for specified time.
++ * @sec: Seconds to sleep for.
++ * @nsec: Nanoseconds to sleep for, has to be less than one second.
++ * @wake_after_interrupt: If set, wake up if interrupted.
++ *
++ * Function immediately returns if error different than EINTR occurs.
++ */
++void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt)
++{
++	struct timespec delay = {.tv_sec = sec, .tv_nsec = nsec};
++
++	assert(nsec < MSEC_TO_NSEC(1000));
++
++	do {
++		errno = 0;
++		nanosleep(&delay, &delay);
++		if (errno != 0 && errno != EINTR) {
++			pr_err("Error sleeping for %us %ldns: %s\n", sec, nsec, strerror(errno));
++			return;
++		}
++	} while (!wake_after_interrupt && errno == EINTR);
++}
+-- 
+2.31.1
+
diff --git a/SOURCES/0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch b/SOURCES/0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch
new file mode 100644
index 0000000..34f81dd
--- /dev/null
+++ b/SOURCES/0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch
@@ -0,0 +1,36 @@
+From 39b381252c32275079344d30de18b76fda4bba26 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 27 Jul 2022 15:52:45 -0600
+Subject: [PATCH 46/52] tests/00readonly: Run udevadm settle before setting ro
+
+In some recent kernel versions, 00readonly fails with:
+
+  mdadm: failed to set readonly for /dev/md0: Device or resource busy
+  ERROR: array is not read-only!
+
+This was traced down to a race condition with udev holding a reference
+to the block device at the same time as trying to set it read only.
+
+To fix this, call udevadm settle before setting the array read only.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ tests/00readonly | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/tests/00readonly b/tests/00readonly
+index 39202487..afe243b3 100644
+--- a/tests/00readonly
++++ b/tests/00readonly
+@@ -12,6 +12,7 @@ do
+ 			$dev1 $dev2 $dev3 $dev4 --assume-clean
+ 		check nosync
+ 		check $level
++		udevadm settle
+ 		mdadm -ro $md0
+ 		check readonly
+ 		state=$(cat /sys/block/md0/md/array_state)
+-- 
+2.31.1
+
diff --git a/SOURCES/0047-tests-add-test-for-names.patch b/SOURCES/0047-tests-add-test-for-names.patch
new file mode 100644
index 0000000..b1dee23
--- /dev/null
+++ b/SOURCES/0047-tests-add-test-for-names.patch
@@ -0,0 +1,119 @@
+From b7671c82010ffc04dfaecff2dd19ef8b2283e2b6 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Tue, 19 Jul 2022 14:48:21 +0200
+Subject: [PATCH 47/52] tests: add test for names
+
+Current behavior is not documented and tested. This test is a base for
+future improvements. It is enough to test it only with native metadata,
+because it is generic code. Generated properties are passed to metadata
+handler.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ tests/00createnames | 93 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 93 insertions(+)
+ create mode 100644 tests/00createnames
+
+diff --git a/tests/00createnames b/tests/00createnames
+new file mode 100644
+index 00000000..64b81b92
+--- /dev/null
++++ b/tests/00createnames
+@@ -0,0 +1,93 @@
++set -x -e
++
++# Test how <devname> and --name= are handled for create mode.
++# We need to check three properties, generated from those parameters:
++# - devnode name
++# - link in /dev/md/ (MD_DEVNAME property from --detail --export)
++# - name in metadata (MD_NAME property from --examine --export)
++
++function _verify() {
++  local DEVNODE_NAME="$1"
++  local WANTED_LINK="$2"
++  local WANTED_NAME="$3"
++
++  local RES="$(mdadm -D --export $DEVNODE_NAME | grep MD_DEVNAME)"
++  if [[ "$?" != "0" ]]; then
++    echo "Cannot get details for $DEVNODE_NAME - unexpected devnode."
++    exit 1
++  fi
++
++  if [[ "$WANTED_LINK" != "empty" ]]; then
++    local EXPECTED="MD_DEVNAME=$WANTED_LINK"
++      if [[ "$RES" != "$EXPECTED" ]]; then
++        echo "$RES doesn't match $EXPECTED."
++        exit 1
++      fi
++  fi
++
++
++  local RES="$(mdadm -E --export $dev0 | grep MD_NAME)"
++  if [[ "$?" != "0" ]]; then
++    echo "Cannot get metadata from $dev0."
++    exit 1
++  fi
++
++  local EXPECTED="MD_NAME=$(hostname):$WANTED_NAME"
++  if [[ "$RES" != "$EXPECTED" ]]; then
++    echo "$RES doesn't match $EXPECTED."
++    exit 1
++  fi
++}
++
++function _create() {
++  local DEVNAME=$1
++  local NAME=$2
++
++  if [[ -z "$NAME" ]]; then
++    mdadm -CR "$DEVNAME" -l0 -n 1 $dev0 --force
++  else
++    mdadm -CR "$DEVNAME" --name="$NAME" -l0 -n 1 $dev0 --force
++  fi
++
++  if [[ "$?" != "0" ]]; then
++    echo "Cannot create device."
++    exit 1
++  fi
++}
++
++# The most trivial case.
++_create "/dev/md/name"
++_verify "/dev/md127" "name" "name"
++mdadm -S "/dev/md127"
++
++_create "name"
++_verify "/dev/md127" "name" "name"
++mdadm -S "/dev/md127"
++
++# Use 'mdX' as name.
++_create "/dev/md/md0"
++_verify "/dev/md127" "md0" "md0"
++mdadm -S "/dev/md127"
++
++_create "md0"
++_verify "/dev/md127" "md0" "md0"
++mdadm -S "/dev/md127"
++
++# <devnode> is used to create MD_DEVNAME but, name is used to create MD_NAME.
++_create "/dev/md/devnode" "name"
++_verify "/dev/md127" "devnode" "name"
++mdadm -S "/dev/md127"
++
++_create "devnode" "name"
++_verify "/dev/md127" "devnode" "name"
++mdadm -S "/dev/md127"
++
++# Devnode points to /dev/ directory. MD_DEVNAME doesn't exist.
++_create "/dev/md0"
++_verify "/dev/md0" "empty" "0"
++mdadm -S "/dev/md0"
++
++# Devnode points to /dev/ directory and name is set.
++_create "/dev/md0" "name"
++_verify "/dev/md0" "empty" "name"
++mdadm -S "/dev/md0"
+-- 
+2.31.1
+
diff --git a/SOURCES/0048-mdadm-remove-symlink-option.patch b/SOURCES/0048-mdadm-remove-symlink-option.patch
new file mode 100644
index 0000000..13f67ad
--- /dev/null
+++ b/SOURCES/0048-mdadm-remove-symlink-option.patch
@@ -0,0 +1,176 @@
+From e4a030a0d3a953b8e74c118200e58dc83c2fc608 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Tue, 19 Jul 2022 14:48:22 +0200
+Subject: [PATCH 48/52] mdadm: remove symlink option
+
+The option is not used. Remove it from code.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ ReadMe.c        |  1 -
+ config.c        |  7 +------
+ mdadm.8.in      |  9 ---------
+ mdadm.c         | 20 --------------------
+ mdadm.conf.5.in | 15 ---------------
+ mdadm.h         |  2 --
+ 6 files changed, 1 insertion(+), 53 deletions(-)
+
+diff --git a/ReadMe.c b/ReadMe.c
+index 7518a32a..7f94847e 100644
+--- a/ReadMe.c
++++ b/ReadMe.c
+@@ -147,7 +147,6 @@ struct option long_options[] = {
+     {"nofailfast",0, 0,  NoFailFast},
+     {"re-add",    0, 0,  ReAdd},
+     {"homehost",  1, 0,  HomeHost},
+-    {"symlinks",  1, 0,  Symlinks},
+     {"data-offset",1, 0, DataOffset},
+     {"nodes",1, 0, Nodes}, /* also for --assemble */
+     {"home-cluster",1, 0, ClusterName},
+diff --git a/config.c b/config.c
+index 9c725457..dc1620c1 100644
+--- a/config.c
++++ b/config.c
+@@ -194,7 +194,6 @@ struct mddev_dev *load_containers(void)
+ 
+ struct createinfo createinfo = {
+ 	.autof = 2, /* by default, create devices with standard names */
+-	.symlinks = 1,
+ 	.names = 0, /* By default, stick with numbered md devices. */
+ 	.bblist = 1, /* Use a bad block list by default */
+ #ifdef DEBIAN
+@@ -310,11 +309,7 @@ static void createline(char *line)
+ 			if (!createinfo.supertype)
+ 				pr_err("metadata format %s unknown, ignoring\n",
+ 					w+9);
+-		} else if (strncasecmp(w, "symlinks=yes", 12) == 0)
+-			createinfo.symlinks = 1;
+-		else if  (strncasecmp(w, "symlinks=no", 11) == 0)
+-			createinfo.symlinks = 0;
+-		else if (strncasecmp(w, "names=yes", 12) == 0)
++		} else if (strncasecmp(w, "names=yes", 12) == 0)
+ 			createinfo.names = 1;
+ 		else if  (strncasecmp(w, "names=no", 11) == 0)
+ 			createinfo.names = 0;
+diff --git a/mdadm.8.in b/mdadm.8.in
+index 0be02e4a..f2736226 100644
+--- a/mdadm.8.in
++++ b/mdadm.8.in
+@@ -1048,11 +1048,6 @@ simultaneously. If not specified, this defaults to 4.
+ Specify journal device for the RAID-4/5/6 array. The journal device
+ should be a SSD with reasonable lifetime.
+ 
+-.TP
+-.BR \-\-symlinks
+-Auto creation of symlinks in /dev to /dev/md, option --symlinks must
+-be 'no' or 'yes' and work with --create and --build.
+-
+ .TP
+ .BR \-k ", " \-\-consistency\-policy=
+ Specify how the array maintains consistency in case of unexpected shutdown.
+@@ -1405,10 +1400,6 @@ Reshape can be continued later using the
+ .B \-\-continue
+ option for the grow command.
+ 
+-.TP
+-.BR \-\-symlinks
+-See this option under Create and Build options.
+-
+ .SH For Manage mode:
+ 
+ .TP
+diff --git a/mdadm.c b/mdadm.c
+index 56722ed9..180f7a9c 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -59,7 +59,6 @@ int main(int argc, char *argv[])
+ 	struct mddev_dev *dv;
+ 	mdu_array_info_t array;
+ 	int devs_found = 0;
+-	char *symlinks = NULL;
+ 	int grow_continue = 0;
+ 	/* autof indicates whether and how to create device node.
+ 	 * bottom 3 bits are style.  Rest (when shifted) are number of parts
+@@ -663,13 +662,6 @@ int main(int argc, char *argv[])
+ 		case O(ASSEMBLE,Auto): /* auto-creation of device node */
+ 			c.autof = parse_auto(optarg, "--auto flag", 0);
+ 			continue;
+-
+-		case O(CREATE,Symlinks):
+-		case O(BUILD,Symlinks):
+-		case O(ASSEMBLE,Symlinks): /* auto creation of symlinks in /dev to /dev/md */
+-			symlinks = optarg;
+-			continue;
+-
+ 		case O(BUILD,'f'): /* force honouring '-n 1' */
+ 		case O(BUILD,Force): /* force honouring '-n 1' */
+ 		case O(GROW,'f'): /* ditto */
+@@ -1325,18 +1317,6 @@ int main(int argc, char *argv[])
+ 		exit(2);
+ 	}
+ 
+-	if (symlinks) {
+-		struct createinfo *ci = conf_get_create_info();
+-
+-		if (strcasecmp(symlinks, "yes") == 0)
+-			ci->symlinks = 1;
+-		else if (strcasecmp(symlinks, "no") == 0)
+-			ci->symlinks = 0;
+-		else {
+-			pr_err("option --symlinks must be 'no' or 'yes'\n");
+-			exit(2);
+-		}
+-	}
+ 	/* Ok, got the option parsing out of the way
+ 	 * hopefully it's mostly right but there might be some stuff
+ 	 * missing
+diff --git a/mdadm.conf.5.in b/mdadm.conf.5.in
+index cd4e6a9d..bc2295c2 100644
+--- a/mdadm.conf.5.in
++++ b/mdadm.conf.5.in
+@@ -338,21 +338,6 @@ missing device entries should be created.
+ The name of the metadata format to use if none is explicitly given.
+ This can be useful to impose a system-wide default of version-1 superblocks.
+ 
+-.TP
+-.B symlinks=no
+-Normally when creating devices in
+-.B /dev/md/
+-.I mdadm
+-will create a matching symlink from
+-.B /dev/
+-with a name starting
+-.B md
+-or
+-.BR md_ .
+-Give
+-.B symlinks=no
+-to suppress this symlink creation.
+-
+ .TP
+ .B names=yes
+ Since Linux 2.6.29 it has been possible to create
+diff --git a/mdadm.h b/mdadm.h
+index add9c0b6..93e72786 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -394,7 +394,6 @@ struct createinfo {
+ 	int	gid;
+ 	int	autof;
+ 	int	mode;
+-	int	symlinks;
+ 	int	names;
+ 	int	bblist;
+ 	struct supertype *supertype;
+@@ -442,7 +441,6 @@ enum special_options {
+ 	BackupFile,
+ 	HomeHost,
+ 	AutoHomeHost,
+-	Symlinks,
+ 	AutoDetect,
+ 	Waitclean,
+ 	DetailPlatform,
+-- 
+2.31.1
+
diff --git a/SOURCES/0049-mdadm-move-data_offset-to-struct-shape.patch b/SOURCES/0049-mdadm-move-data_offset-to-struct-shape.patch
new file mode 100644
index 0000000..9613654
--- /dev/null
+++ b/SOURCES/0049-mdadm-move-data_offset-to-struct-shape.patch
@@ -0,0 +1,232 @@
+From ae5dfc56b7a96805d5a0b50eaf93b9fec8604298 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Tue, 19 Jul 2022 14:48:23 +0200
+Subject: [PATCH 49/52] mdadm: move data_offset to struct shape
+
+Data offset is a shape property so move it there to remove additional
+parameter from some functions.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Create.c | 16 ++++++++--------
+ Grow.c   |  7 +++----
+ mdadm.c  | 20 +++++++++-----------
+ mdadm.h  |  5 ++---
+ 4 files changed, 22 insertions(+), 26 deletions(-)
+
+diff --git a/Create.c b/Create.c
+index c84c1ac8..e06ec2ae 100644
+--- a/Create.c
++++ b/Create.c
+@@ -95,7 +95,7 @@ int Create(struct supertype *st, char *mddev,
+ 	   char *name, int *uuid,
+ 	   int subdevs, struct mddev_dev *devlist,
+ 	   struct shape *s,
+-	   struct context *c, unsigned long long data_offset)
++	   struct context *c)
+ {
+ 	/*
+ 	 * Create a new raid array.
+@@ -288,7 +288,7 @@ int Create(struct supertype *st, char *mddev,
+ 	newsize = s->size * 2;
+ 	if (st && ! st->ss->validate_geometry(st, s->level, s->layout, s->raiddisks,
+ 					      &s->chunk, s->size*2,
+-					      data_offset, NULL,
++					      s->data_offset, NULL,
+ 					      &newsize, s->consistency_policy,
+ 					      c->verbose >= 0))
+ 		return 1;
+@@ -323,10 +323,10 @@ int Create(struct supertype *st, char *mddev,
+ 	info.array.working_disks = 0;
+ 	dnum = 0;
+ 	for (dv = devlist; dv; dv = dv->next)
+-		if (data_offset == VARIABLE_OFFSET)
++		if (s->data_offset == VARIABLE_OFFSET)
+ 			dv->data_offset = INVALID_SECTORS;
+ 		else
+-			dv->data_offset = data_offset;
++			dv->data_offset = s->data_offset;
+ 
+ 	for (dv=devlist; dv && !have_container; dv=dv->next, dnum++) {
+ 		char *dname = dv->devname;
+@@ -342,7 +342,7 @@ int Create(struct supertype *st, char *mddev,
+ 			missing_disks ++;
+ 			continue;
+ 		}
+-		if (data_offset == VARIABLE_OFFSET) {
++		if (s->data_offset == VARIABLE_OFFSET) {
+ 			doff = strchr(dname, ':');
+ 			if (doff) {
+ 				*doff++ = 0;
+@@ -350,7 +350,7 @@ int Create(struct supertype *st, char *mddev,
+ 			} else
+ 				dv->data_offset = INVALID_SECTORS;
+ 		} else
+-			dv->data_offset = data_offset;
++			dv->data_offset = s->data_offset;
+ 
+ 		dfd = open(dname, O_RDONLY);
+ 		if (dfd < 0) {
+@@ -535,7 +535,7 @@ int Create(struct supertype *st, char *mddev,
+ 			if (!st->ss->validate_geometry(st, s->level, s->layout,
+ 						       s->raiddisks,
+ 						       &s->chunk, minsize*2,
+-						       data_offset,
++						       s->data_offset,
+ 						       NULL, NULL,
+ 						       s->consistency_policy, 0)) {
+ 				pr_err("devices too large for RAID level %d\n", s->level);
+@@ -754,7 +754,7 @@ int Create(struct supertype *st, char *mddev,
+ 		}
+ 	}
+ 	if (!st->ss->init_super(st, &info.array, s, name, c->homehost, uuid,
+-				data_offset))
++				s->data_offset))
+ 		goto abort_locked;
+ 
+ 	total_slots = info.array.nr_disks;
+diff --git a/Grow.c b/Grow.c
+index 5780635a..868bdc3a 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1775,7 +1775,6 @@ static int reshape_container(char *container, char *devname,
+ 
+ int Grow_reshape(char *devname, int fd,
+ 		 struct mddev_dev *devlist,
+-		 unsigned long long data_offset,
+ 		 struct context *c, struct shape *s)
+ {
+ 	/* Make some changes in the shape of an array.
+@@ -1821,7 +1820,7 @@ int Grow_reshape(char *devname, int fd,
+ 		return 1;
+ 	}
+ 
+-	if (data_offset != INVALID_SECTORS && array.level != 10 &&
++	if (s->data_offset != INVALID_SECTORS && array.level != 10 &&
+ 	    (array.level < 4 || array.level > 6)) {
+ 		pr_err("--grow --data-offset not yet supported\n");
+ 		return 1;
+@@ -2179,7 +2178,7 @@ size_change_error:
+ 	if ((s->level == UnSet || s->level == array.level) &&
+ 	    (s->layout_str == NULL) &&
+ 	    (s->chunk == 0 || s->chunk == array.chunk_size) &&
+-	    data_offset == INVALID_SECTORS &&
++	    s->data_offset == INVALID_SECTORS &&
+ 	    (s->raiddisks == 0 || s->raiddisks == array.raid_disks)) {
+ 		/* Nothing more to do */
+ 		if (!changed && c->verbose >= 0)
+@@ -2379,7 +2378,7 @@ size_change_error:
+ 		}
+ 		sync_metadata(st);
+ 		rv = reshape_array(container, fd, devname, st, &info, c->force,
+-				   devlist, data_offset, c->backup_file,
++				   devlist, s->data_offset, c->backup_file,
+ 				   c->verbose, 0, 0, 0);
+ 		frozen = 0;
+ 	}
+diff --git a/mdadm.c b/mdadm.c
+index 180f7a9c..845e4466 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -49,7 +49,6 @@ int main(int argc, char *argv[])
+ 	int i;
+ 
+ 	unsigned long long array_size = 0;
+-	unsigned long long data_offset = INVALID_SECTORS;
+ 	struct mddev_ident ident;
+ 	char *configfile = NULL;
+ 	int devmode = 0;
+@@ -79,6 +78,7 @@ int main(int argc, char *argv[])
+ 		.layout		= UnSet,
+ 		.bitmap_chunk	= UnSet,
+ 		.consistency_policy	= CONSISTENCY_POLICY_UNKNOWN,
++		.data_offset = INVALID_SECTORS,
+ 	};
+ 
+ 	char sys_hostname[256];
+@@ -479,15 +479,15 @@ int main(int argc, char *argv[])
+ 
+ 		case O(CREATE,DataOffset):
+ 		case O(GROW,DataOffset):
+-			if (data_offset != INVALID_SECTORS) {
++			if (s.data_offset != INVALID_SECTORS) {
+ 				pr_err("data-offset may only be specified one. Second value is %s.\n", optarg);
+ 				exit(2);
+ 			}
+ 			if (mode == CREATE && strcmp(optarg, "variable") == 0)
+-				data_offset = VARIABLE_OFFSET;
++				s.data_offset = VARIABLE_OFFSET;
+ 			else
+-				data_offset = parse_size(optarg);
+-			if (data_offset == INVALID_SECTORS) {
++				s.data_offset = parse_size(optarg);
++			if (s.data_offset == INVALID_SECTORS) {
+ 				pr_err("invalid data-offset: %s\n",
+ 					optarg);
+ 				exit(2);
+@@ -1416,7 +1416,7 @@ int main(int argc, char *argv[])
+ 		exit(1);
+ 	}
+ 
+-	if (c.backup_file && data_offset != INVALID_SECTORS) {
++	if (c.backup_file && s.data_offset != INVALID_SECTORS) {
+ 		pr_err("--backup-file and --data-offset are incompatible\n");
+ 		exit(2);
+ 	}
+@@ -1587,8 +1587,7 @@ int main(int argc, char *argv[])
+ 
+ 		rv = Create(ss, devlist->devname,
+ 			    ident.name, ident.uuid_set ? ident.uuid : NULL,
+-			    devs_found-1, devlist->next,
+-			    &s, &c, data_offset);
++			    devs_found - 1, devlist->next, &s, &c);
+ 		break;
+ 	case MISC:
+ 		if (devmode == 'E') {
+@@ -1706,10 +1705,9 @@ int main(int argc, char *argv[])
+ 						   c.verbose);
+ 		else if (s.size > 0 || s.raiddisks || s.layout_str ||
+ 			 s.chunk != 0 || s.level != UnSet ||
+-			 data_offset != INVALID_SECTORS) {
++			 s.data_offset != INVALID_SECTORS) {
+ 			rv = Grow_reshape(devlist->devname, mdfd,
+-					  devlist->next,
+-					  data_offset, &c, &s);
++					  devlist->next, &c, &s);
+ 		} else if (s.consistency_policy != CONSISTENCY_POLICY_UNKNOWN) {
+ 			rv = Grow_consistency_policy(devlist->devname, mdfd, &c, &s);
+ 		} else if (array_size == 0)
+diff --git a/mdadm.h b/mdadm.h
+index 93e72786..adb7cdaa 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -595,6 +595,7 @@ struct shape {
+ 	int	assume_clean;
+ 	int	write_behind;
+ 	unsigned long long size;
++	unsigned long long data_offset;
+ 	int	consistency_policy;
+ };
+ 
+@@ -1431,7 +1432,6 @@ extern int Grow_addbitmap(char *devname, int fd,
+ 			  struct context *c, struct shape *s);
+ extern int Grow_reshape(char *devname, int fd,
+ 			struct mddev_dev *devlist,
+-			unsigned long long data_offset,
+ 			struct context *c, struct shape *s);
+ extern int Grow_restart(struct supertype *st, struct mdinfo *info,
+ 			int *fdlist, int cnt, char *backup_file, int verbose);
+@@ -1462,8 +1462,7 @@ extern int Create(struct supertype *st, char *mddev,
+ 		  char *name, int *uuid,
+ 		  int subdevs, struct mddev_dev *devlist,
+ 		  struct shape *s,
+-		  struct context *c,
+-		  unsigned long long data_offset);
++		  struct context *c);
+ 
+ extern int Detail(char *dev, struct context *c);
+ extern int Detail_Platform(struct superswitch *ss, int scan, int verbose, int export, char *controller_path);
+-- 
+2.31.1
+
diff --git a/SOURCES/0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch b/SOURCES/0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch
new file mode 100644
index 0000000..a28efa4
--- /dev/null
+++ b/SOURCES/0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch
@@ -0,0 +1,162 @@
+From 27ad4900501c615b7c6b266bf23948e5606dba53 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 27 Jul 2022 15:52:46 -0600
+Subject: [PATCH 50/52] mdadm: Don't open md device for CREATE and ASSEMBLE
+
+The mdadm command tries to open the md device for most modes, first
+thing, no matter what. When running to create or assemble an array,
+in most cases, the md device will not exist, the open call will fail
+and everything will proceed correctly.
+
+However, when running tests, a create or assembly command may be run
+shortly after stopping an array and the old md device file may still
+be around. Then, if create_on_open is set in the kernel, a new md
+device will be created when mdadm does its initial open.
+
+When mdadm gets around to creating the new device with the new_array
+parameter it issues this error:
+
+   mdadm: Fail to create md0 when using
+   /sys/module/md_mod/parameters/new_array, fallback to creation via node
+
+This is because an mddev was already created by the kernel with the
+earlier open() call and thus the new one being created will fail with
+EEXIST. The mdadm command will still successfully be created due to
+falling back to the node creation method. However, the error message
+itself will fail any test that's running it.
+
+This issue is a race condition that is very rare, but a recent change
+in the kernel caused this to happen more frequently: about 1 in 50
+times.
+
+To fix this, don't bother trying to open the md device for CREATE,
+ASSEMBLE and BUILD commands, as the file descriptor will never be used
+anyway even if it is successfully openned. The mdfd has not been used
+for these commands since:
+
+   7f91af49ad09 ("Delay creation of array devices for assemble/build/create")
+
+The checks that were done on the open device can be changed to being
+done with stat.
+
+Side note: it would be nice to disable create_on_open as well to help
+solve this, but it seems the work for this was never finished. By default,
+mdadm will create using the old node interface when a name is specified
+unless the user specifically puts names=yes in a config file, which
+doesn't seem to be common or desirable to require this..
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ lib.c   | 12 ++++++++++++
+ mdadm.c | 40 ++++++++++++++++++++--------------------
+ mdadm.h |  1 +
+ 3 files changed, 33 insertions(+), 20 deletions(-)
+
+diff --git a/lib.c b/lib.c
+index 7e3e3d47..e395b28d 100644
+--- a/lib.c
++++ b/lib.c
+@@ -164,6 +164,18 @@ char *stat2devnm(struct stat *st)
+ 	return devid2devnm(st->st_rdev);
+ }
+ 
++bool stat_is_md_dev(struct stat *st)
++{
++	if ((S_IFMT & st->st_mode) != S_IFBLK)
++		return false;
++	if (major(st->st_rdev) == MD_MAJOR)
++		return true;
++	if (major(st->st_rdev) == (unsigned)get_mdp_major())
++		return true;
++
++	return false;
++}
++
+ char *fd2devnm(int fd)
+ {
+ 	struct stat stb;
+diff --git a/mdadm.c b/mdadm.c
+index 845e4466..972adb52 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -1329,6 +1329,9 @@ int main(int argc, char *argv[])
+ 
+ 	if (mode == MANAGE || mode == BUILD || mode == CREATE ||
+ 	    mode == GROW || (mode == ASSEMBLE && ! c.scan)) {
++		struct stat stb;
++		int ret;
++
+ 		if (devs_found < 1) {
+ 			pr_err("an md device must be given in this mode\n");
+ 			exit(2);
+@@ -1341,6 +1344,12 @@ int main(int argc, char *argv[])
+ 			mdfd = open_mddev(devlist->devname, 1);
+ 			if (mdfd < 0)
+ 				exit(1);
++
++			ret = fstat(mdfd, &stb);
++			if (ret) {
++				pr_err("fstat failed on %s.\n", devlist->devname);
++				exit(1);
++			}
+ 		} else {
+ 			char *bname = basename(devlist->devname);
+ 
+@@ -1348,30 +1357,21 @@ int main(int argc, char *argv[])
+ 				pr_err("Name %s is too long.\n", devlist->devname);
+ 				exit(1);
+ 			}
+-			/* non-existent device is OK */
+-			mdfd = open_mddev(devlist->devname, 0);
+-		}
+-		if (mdfd == -2) {
+-			pr_err("device %s exists but is not an md array.\n", devlist->devname);
+-			exit(1);
+-		}
+-		if ((int)ident.super_minor == -2) {
+-			struct stat stb;
+-			if (mdfd < 0) {
++
++			ret = stat(devlist->devname, &stb);
++			if (ident.super_minor == -2 && ret != 0) {
+ 				pr_err("--super-minor=dev given, and listed device %s doesn't exist.\n",
+-					devlist->devname);
++				       devlist->devname);
++				exit(1);
++			}
++
++			if (!ret && !stat_is_md_dev(&stb)) {
++				pr_err("device %s exists but is not an md array.\n", devlist->devname);
+ 				exit(1);
+ 			}
+-			fstat(mdfd, &stb);
+-			ident.super_minor = minor(stb.st_rdev);
+-		}
+-		if (mdfd >= 0 && mode != MANAGE && mode != GROW) {
+-			/* We don't really want this open yet, we just might
+-			 * have wanted to check some things
+-			 */
+-			close(mdfd);
+-			mdfd = -1;
+ 		}
++		if (ident.super_minor == -2)
++			ident.super_minor = minor(stb.st_rdev);
+ 	}
+ 
+ 	if (s.raiddisks) {
+diff --git a/mdadm.h b/mdadm.h
+index adb7cdaa..8208b81e 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1672,6 +1672,7 @@ void *super1_make_v0(struct supertype *st, struct mdinfo *info, mdp_super_t *sb0
+ extern char *stat2kname(struct stat *st);
+ extern char *fd2kname(int fd);
+ extern char *stat2devnm(struct stat *st);
++bool stat_is_md_dev(struct stat *st);
+ extern char *fd2devnm(int fd);
+ extern void udev_block(char *devnm);
+ extern void udev_unblock(void);
+-- 
+2.31.1
+
diff --git a/SOURCES/0051-Grow-Split-Grow_reshape-into-helper-function.patch b/SOURCES/0051-Grow-Split-Grow_reshape-into-helper-function.patch
new file mode 100644
index 0000000..2b5aaaf
--- /dev/null
+++ b/SOURCES/0051-Grow-Split-Grow_reshape-into-helper-function.patch
@@ -0,0 +1,231 @@
+From 7211116c295ba1f9e1fcbdc2dd2d3762855062e1 Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Thu, 28 Jul 2022 20:20:53 +0800
+Subject: [PATCH 51/52] Grow: Split Grow_reshape into helper function
+
+Grow_reshape should be split into helper functions given its size.
+- Add helper function for preparing reshape on external metadata.
+- Close cfd file descriptor.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Grow.c  | 125 ++++++++++++++++++++++++++++++--------------------------
+ mdadm.h |   1 +
+ util.c  |  14 +++++++
+ 3 files changed, 81 insertions(+), 59 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index 868bdc3a..0f07a894 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1773,6 +1773,65 @@ static int reshape_container(char *container, char *devname,
+ 			     char *backup_file, int verbose,
+ 			     int forked, int restart, int freeze_reshape);
+ 
++/**
++ * prepare_external_reshape() - prepares update on external metadata if supported.
++ * @devname: Device name.
++ * @subarray: Subarray.
++ * @st: Supertype.
++ * @container: Container.
++ * @cfd: Container file descriptor.
++ *
++ * Function checks that the requested reshape is supported on external metadata,
++ * and performs an initial check that the container holds the pre-requisite
++ * spare devices (mdmon owns final validation).
++ *
++ * Return: 0 on success, else 1
++ */
++static int prepare_external_reshape(char *devname, char *subarray,
++				    struct supertype *st, char *container,
++				    const int cfd)
++{
++	struct mdinfo *cc = NULL;
++	struct mdinfo *content = NULL;
++
++	if (st->ss->load_container(st, cfd, NULL)) {
++		pr_err("Cannot read superblock for %s\n", devname);
++		return 1;
++	}
++
++	if (!st->ss->container_content)
++		return 1;
++
++	cc = st->ss->container_content(st, subarray);
++	for (content = cc; content ; content = content->next) {
++		/*
++		 * check if reshape is allowed based on metadata
++		 * indications stored in content.array.status
++		 */
++		if (is_bit_set(&content->array.state, MD_SB_BLOCK_VOLUME) ||
++		    is_bit_set(&content->array.state, MD_SB_BLOCK_CONTAINER_RESHAPE)) {
++			pr_err("Cannot reshape arrays in container with unsupported metadata: %s(%s)\n",
++			       devname, container);
++			goto error;
++		}
++		if (content->consistency_policy == CONSISTENCY_POLICY_PPL) {
++			pr_err("Operation not supported when ppl consistency policy is enabled\n");
++			goto error;
++		}
++		if (content->consistency_policy == CONSISTENCY_POLICY_BITMAP) {
++			pr_err("Operation not supported when write-intent bitmap consistency policy is enabled\n");
++			goto error;
++		}
++	}
++	sysfs_free(cc);
++	if (mdmon_running(container))
++		st->update_tail = &st->updates;
++	return 0;
++error:
++	sysfs_free(cc);
++	return 1;
++}
++
+ int Grow_reshape(char *devname, int fd,
+ 		 struct mddev_dev *devlist,
+ 		 struct context *c, struct shape *s)
+@@ -1799,7 +1858,7 @@ int Grow_reshape(char *devname, int fd,
+ 	struct supertype *st;
+ 	char *subarray = NULL;
+ 
+-	int frozen;
++	int frozen = 0;
+ 	int changed = 0;
+ 	char *container = NULL;
+ 	int cfd = -1;
+@@ -1808,7 +1867,7 @@ int Grow_reshape(char *devname, int fd,
+ 	int added_disks;
+ 
+ 	struct mdinfo info;
+-	struct mdinfo *sra;
++	struct mdinfo *sra = NULL;
+ 
+ 	if (md_get_array_info(fd, &array) < 0) {
+ 		pr_err("%s is not an active md array - aborting\n",
+@@ -1865,13 +1924,7 @@ int Grow_reshape(char *devname, int fd,
+ 		}
+ 	}
+ 
+-	/* in the external case we need to check that the requested reshape is
+-	 * supported, and perform an initial check that the container holds the
+-	 * pre-requisite spare devices (mdmon owns final validation)
+-	 */
+ 	if (st->ss->external) {
+-		int retval;
+-
+ 		if (subarray) {
+ 			container = st->container_devnm;
+ 			cfd = open_dev_excl(st->container_devnm);
+@@ -1887,13 +1940,12 @@ int Grow_reshape(char *devname, int fd,
+ 			return 1;
+ 		}
+ 
+-		retval = st->ss->load_container(st, cfd, NULL);
+-
+-		if (retval) {
+-			pr_err("Cannot read superblock for %s\n", devname);
+-			close(cfd);
++		rv = prepare_external_reshape(devname, subarray, st,
++					      container, cfd);
++		if (rv > 0) {
+ 			free(subarray);
+-			return 1;
++			close(cfd);
++			goto release;
+ 		}
+ 
+ 		if (s->raiddisks && subarray) {
+@@ -1902,51 +1954,6 @@ int Grow_reshape(char *devname, int fd,
+ 			free(subarray);
+ 			return 1;
+ 		}
+-
+-		/* check if operation is supported for metadata handler */
+-		if (st->ss->container_content) {
+-			struct mdinfo *cc = NULL;
+-			struct mdinfo *content = NULL;
+-
+-			cc = st->ss->container_content(st, subarray);
+-			for (content = cc; content ; content = content->next) {
+-				int allow_reshape = 1;
+-
+-				/* check if reshape is allowed based on metadata
+-				 * indications stored in content.array.status
+-				 */
+-				if (content->array.state &
+-				    (1 << MD_SB_BLOCK_VOLUME))
+-					allow_reshape = 0;
+-				if (content->array.state &
+-				    (1 << MD_SB_BLOCK_CONTAINER_RESHAPE))
+-					allow_reshape = 0;
+-				if (!allow_reshape) {
+-					pr_err("cannot reshape arrays in container with unsupported metadata: %s(%s)\n",
+-					       devname, container);
+-					sysfs_free(cc);
+-					free(subarray);
+-					return 1;
+-				}
+-				if (content->consistency_policy ==
+-				    CONSISTENCY_POLICY_PPL) {
+-					pr_err("Operation not supported when ppl consistency policy is enabled\n");
+-					sysfs_free(cc);
+-					free(subarray);
+-					return 1;
+-				}
+-				if (content->consistency_policy ==
+-				    CONSISTENCY_POLICY_BITMAP) {
+-					pr_err("Operation not supported when write-intent bitmap is enabled\n");
+-					sysfs_free(cc);
+-					free(subarray);
+-					return 1;
+-				}
+-			}
+-			sysfs_free(cc);
+-		}
+-		if (mdmon_running(container))
+-			st->update_tail = &st->updates;
+ 	}
+ 
+ 	added_disks = 0;
+diff --git a/mdadm.h b/mdadm.h
+index 8208b81e..941a5f38 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1539,6 +1539,7 @@ extern int stat_is_blkdev(char *devname, dev_t *rdev);
+ extern bool is_dev_alive(char *path);
+ extern int get_mdp_major(void);
+ extern int get_maj_min(char *dev, int *major, int *minor);
++extern bool is_bit_set(int *val, unsigned char index);
+ extern int dev_open(char *dev, int flags);
+ extern int open_dev(char *devnm);
+ extern void reopen_mddev(int mdfd);
+diff --git a/util.c b/util.c
+index ca48d976..26ffdcea 100644
+--- a/util.c
++++ b/util.c
+@@ -1027,6 +1027,20 @@ int get_maj_min(char *dev, int *major, int *minor)
+ 		*e == 0);
+ }
+ 
++/**
++ * is_bit_set() - get bit value by index.
++ * @val: value.
++ * @index: index of the bit (LSB numbering).
++ *
++ * Return: bit value.
++ */
++bool is_bit_set(int *val, unsigned char index)
++{
++	if ((*val) & (1 << index))
++		return true;
++	return false;
++}
++
+ int dev_open(char *dev, int flags)
+ {
+ 	/* like 'open', but if 'dev' matches %d:%d, create a temp
+-- 
+2.31.1
+
diff --git a/SOURCES/0052-Assemble-check-if-device-is-container-before-schedul.patch b/SOURCES/0052-Assemble-check-if-device-is-container-before-schedul.patch
new file mode 100644
index 0000000..4c4c323
--- /dev/null
+++ b/SOURCES/0052-Assemble-check-if-device-is-container-before-schedul.patch
@@ -0,0 +1,36 @@
+From 5c3c3df646dd3b7e8df81152f08e9ac4ddccc671 Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Fri, 19 Aug 2022 02:55:46 +0200
+Subject: [PATCH 52/52] Assemble: check if device is container before
+ scheduling force-clean update
+
+Up to now using assemble with force flag making each array as clean.
+Force-clean should not be done for the container. This commit add
+check if device is different than container before cleaning.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index be2160b4..1dd82a8c 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -1809,10 +1809,9 @@ try_again:
+ 		}
+ #endif
+ 	}
+-	if (c->force && !clean &&
++	if (c->force && !clean && content->array.level != LEVEL_CONTAINER &&
+ 	    !enough(content->array.level, content->array.raid_disks,
+-		    content->array.layout, clean,
+-		    avail)) {
++		    content->array.layout, clean, avail)) {
+ 		change += st->ss->update_super(st, content, "force-array",
+ 					       devices[chosen_drive].devname, c->verbose,
+ 					       0, NULL);
+-- 
+2.31.1
+
diff --git a/SPECS/mdadm.spec b/SPECS/mdadm.spec
index cf23fc5..543e1a2 100644
--- a/SPECS/mdadm.spec
+++ b/SPECS/mdadm.spec
@@ -2,7 +2,7 @@ Summary:     The mdadm program controls Linux md devices (software RAID arrays)
 Name:        mdadm
 Version:     4.2
 # extraversion is used to define rhel internal version
-%define extraversion 2
+%define extraversion 5
 Release:     %{extraversion}%{?dist}
 Source:      http://www.kernel.org/pub/linux/utils/raid/mdadm/mdadm-%{version}%{?subversion:-%{subversion}}.tar.xz
 Source1:     mdmonitor.init
@@ -17,7 +17,57 @@ Source9:     mdcheck
 Source10:    mdadm_env.sh
 
 Patch000:    disable-Werror.patch
-Patch001:    0001-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch
+Patch001:    0001-Unify-error-message.patch
+Patch002:    0002-mdadm-Fix-double-free.patch
+Patch003:    0003-Grow_reshape-Add-r0-grow-size-error-message-and-upda.patch
+Patch004:    0004-udev-adapt-rules-to-systemd-v247.patch
+Patch005:    0005-Replace-error-prone-signal-with-sigaction.patch
+Patch006:    0006-mdadm-Respect-config-file-location-in-man.patch
+Patch007:    0007-mdadm-Update-ReadMe.patch
+Patch008:    0008-mdadm-Update-config-man-regarding-default-files-and-.patch
+Patch009:    0009-mdadm-Update-config-manual.patch
+Patch010:    0010-Create-Build-use-default_layout.patch
+Patch011:    0011-mdadm-add-map_num_s.patch
+Patch012:    0013-mdmon-Stop-parsing-duplicate-options.patch
+Patch013:    0014-Grow-block-n-on-external-volumes.patch
+Patch014:    0015-Incremental-Fix-possible-memory-and-resource-leaks.patch
+Patch015:    0016-Mdmonitor-Fix-segfault.patch
+Patch016:    0017-Mdmonitor-Improve-logging-method.patch
+Patch017:    0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch
+Patch018:    0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch
+Patch019:    0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch
+Patch020:    0021-util-replace-ioctl-use-with-function.patch
+Patch021:    0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch
+Patch022:    0023-imsm-introduce-get_disk_slot_in_dev.patch
+Patch023:    0024-imsm-use-same-slot-across-container.patch
+Patch024:    0025-imsm-block-changing-slots-during-creation.patch
+Patch025:    0026-mdadm-block-update-ppl-for-non-raid456-levels.patch
+Patch026:    0027-mdadm-Fix-array-size-mismatch-after-grow.patch
+Patch027:    0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch
+Patch028:    0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch
+Patch029:    0030-Monitor-use-snprintf-to-fill-device-name.patch
+Patch030:    0031-Makefile-Don-t-build-static-build-with-everything-an.patch
+Patch031:    0032-DDF-Cleanup-validate_geometry_ddf_container.patch
+Patch032:    0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch
+Patch033:    0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch
+Patch034:    0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch
+Patch035:    0036-mdadm-Fix-mdadm-r-remove-option-regression.patch
+Patch036:    0037-mdadm-Fix-optional-write-behind-parameter.patch
+Patch037:    0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch
+Patch038:    0039-tests-fix-raid0-tests-for-0.90-metadata.patch
+Patch039:    0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch
+Patch040:    0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch
+Patch041:    0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch
+Patch042:    0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch
+Patch043:    0044-tests-Add-broken-files-for-all-broken-tests.patch
+Patch044:    0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch
+Patch045:    0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch
+Patch046:    0047-tests-add-test-for-names.patch
+Patch047:    0048-mdadm-remove-symlink-option.patch
+Patch048:    0049-mdadm-move-data_offset-to-struct-shape.patch
+Patch049:    0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch
+Patch050:    0051-Grow-Split-Grow_reshape-into-helper-function.patch
+Patch051:    0052-Assemble-check-if-device-is-container-before-schedul.patch
 
 # RHEL customization patches
 Patch200:    mdadm-3.3-udev.patch
@@ -50,6 +100,56 @@ file can be used to help with some common tasks.
 
 %patch000 -p1 -b .disable
 %patch001 -p1 -b .0001
+%patch002 -p1 -b .0002
+%patch003 -p1 -b .0003
+%patch004 -p1 -b .0004
+%patch005 -p1 -b .0005
+%patch006 -p1 -b .0006
+%patch007 -p1 -b .0007
+%patch008 -p1 -b .0008
+%patch009 -p1 -b .0009
+%patch010 -p1 -b .0010
+%patch011 -p1 -b .0011
+%patch012 -p1 -b .0013
+%patch013 -p1 -b .0014
+%patch014 -p1 -b .0015
+%patch015 -p1 -b .0016
+%patch016 -p1 -b .0017
+%patch017 -p1 -b .0018
+%patch018 -p1 -b .0019
+%patch019 -p1 -b .0020
+%patch020 -p1 -b .0021
+%patch021 -p1 -b .0022
+%patch022 -p1 -b .0023
+%patch023 -p1 -b .0024
+%patch024 -p1 -b .0025
+%patch025 -p1 -b .0026
+%patch026 -p1 -b .0027
+%patch027 -p1 -b .0028
+%patch028 -p1 -b .0029
+%patch029 -p1 -b .0030
+%patch030 -p1 -b .0031
+%patch031 -p1 -b .0032
+%patch032 -p1 -b .0033
+%patch033 -p1 -b .0034
+%patch034 -p1 -b .0035
+%patch035 -p1 -b .0036
+%patch036 -p1 -b .0037
+%patch037 -p1 -b .0038
+%patch038 -p1 -b .0039
+%patch039 -p1 -b .0040
+%patch040 -p1 -b .0041
+%patch041 -p1 -b .0042
+%patch042 -p1 -b .0043
+%patch043 -p1 -b .0044
+%patch044 -p1 -b .0045
+%patch045 -p1 -b .0046
+%patch046 -p1 -b .0047
+%patch047 -p1 -b .0048
+%patch048 -p1 -b .0049
+%patch049 -p1 -b .0050
+%patch050 -p1 -b .0051
+%patch051 -p1 -b .0052
 
 # RHEL customization patches
 %patch200 -p1 -b .udev
@@ -121,6 +221,18 @@ rm -rf %{buildroot}
 /usr/lib/mdadm/mdadm_env.sh
 
 %changelog
+* Thu Aug 25 2022 Xiao Ni <xni@redhat.com> - 4.2-5
+- Update mdadm to latest upstream
+- Resolves rhbz#2092326
+
+* Sun Aug 07 2022 Xiao Ni <xni@redhat.com> - 4.2-4
+- Add KillMode=none to mdmon systemd service again
+- Resolves rhbz#2109397
+
+* Mon May 30 2022 Xiao Ni <xni@redhat.com> - 4.2-3
+- Update mdadm to latest upstream
+- Resolves rhbz#2052563, rhbz#1991596
+
 * Thu Feb 24 2022 Xiao Ni <xni@redhat.com> - 4.2-2
 - mdadm re-add fault/removed disk failed
 - Resolves rhbz#2046323