]> git.pld-linux.org Git - packages/mdadm.git/commitdiff
- added upstream patches (from Fedora)
authorKrzysztof Mrozowicz <mrozowik@pld-linux.org>
Sun, 23 Jul 2023 09:34:29 +0000 (09:34 +0000)
committerKrzysztof Mrozowicz <mrozowik@pld-linux.org>
Sun, 23 Jul 2023 09:34:29 +0000 (09:34 +0000)
121 files changed:
0001-Unify-error-message.patch [new file with mode: 0644]
0002-mdadm-Fix-double-free.patch [new file with mode: 0644]
0003-Grow_reshape-Add-r0-grow-size-error-message-and-upda.patch [new file with mode: 0644]
0004-udev-adapt-rules-to-systemd-v247.patch [new file with mode: 0644]
0005-Replace-error-prone-signal-with-sigaction.patch [new file with mode: 0644]
0006-mdadm-Respect-config-file-location-in-man.patch [new file with mode: 0644]
0007-mdadm-Update-ReadMe.patch [new file with mode: 0644]
0008-mdadm-Update-config-man-regarding-default-files-and-.patch [new file with mode: 0644]
0009-mdadm-Update-config-manual.patch [new file with mode: 0644]
0010-Create-Build-use-default_layout.patch [new file with mode: 0644]
0011-mdadm-add-map_num_s.patch [new file with mode: 0644]
0012-mdadm-systemd-remove-KillMode-none-from-service-file.patch [new file with mode: 0644]
0013-mdmon-Stop-parsing-duplicate-options.patch [new file with mode: 0644]
0014-Grow-block-n-on-external-volumes.patch [new file with mode: 0644]
0015-Incremental-Fix-possible-memory-and-resource-leaks.patch [new file with mode: 0644]
0016-Mdmonitor-Fix-segfault.patch [new file with mode: 0644]
0017-Mdmonitor-Improve-logging-method.patch [new file with mode: 0644]
0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch [new file with mode: 0644]
0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch [new file with mode: 0644]
0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch [new file with mode: 0644]
0021-util-replace-ioctl-use-with-function.patch [new file with mode: 0644]
0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch [new file with mode: 0644]
0023-imsm-introduce-get_disk_slot_in_dev.patch [new file with mode: 0644]
0024-imsm-use-same-slot-across-container.patch [new file with mode: 0644]
0025-imsm-block-changing-slots-during-creation.patch [new file with mode: 0644]
0026-mdadm-block-update-ppl-for-non-raid456-levels.patch [new file with mode: 0644]
0027-mdadm-Fix-array-size-mismatch-after-grow.patch [new file with mode: 0644]
0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch [new file with mode: 0644]
0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch [new file with mode: 0644]
0030-Monitor-use-snprintf-to-fill-device-name.patch [new file with mode: 0644]
0031-Makefile-Don-t-build-static-build-with-everything-an.patch [new file with mode: 0644]
0032-DDF-Cleanup-validate_geometry_ddf_container.patch [new file with mode: 0644]
0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch [new file with mode: 0644]
0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch [new file with mode: 0644]
0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch [new file with mode: 0644]
0036-mdadm-Fix-mdadm-r-remove-option-regression.patch [new file with mode: 0644]
0037-mdadm-Fix-optional-write-behind-parameter.patch [new file with mode: 0644]
0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch [new file with mode: 0644]
0039-tests-fix-raid0-tests-for-0.90-metadata.patch [new file with mode: 0644]
0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch [new file with mode: 0644]
0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch [new file with mode: 0644]
0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch [new file with mode: 0644]
0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch [new file with mode: 0644]
0044-tests-Add-broken-files-for-all-broken-tests.patch [new file with mode: 0644]
0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch [new file with mode: 0644]
0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch [new file with mode: 0644]
0047-tests-add-test-for-names.patch [new file with mode: 0644]
0048-mdadm-remove-symlink-option.patch [new file with mode: 0644]
0049-mdadm-move-data_offset-to-struct-shape.patch [new file with mode: 0644]
0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch [new file with mode: 0644]
0051-Grow-Split-Grow_reshape-into-helper-function.patch [new file with mode: 0644]
0052-Assemble-check-if-device-is-container-before-schedul.patch [new file with mode: 0644]
0053-super1-report-truncated-device.patch [new file with mode: 0644]
0054-mdadm-Correct-typos-punctuation-and-grammar-in-man.patch [new file with mode: 0644]
0055-Manage-Block-unsafe-member-failing.patch [new file with mode: 0644]
0056-Monitor-Fix-statelist-memory-leaks.patch [new file with mode: 0644]
0057-mdadm-added-support-for-Intel-Alderlake-RST-on-VMD-p.patch [new file with mode: 0644]
0058-mdadm-Add-Documentation-entries-to-systemd-services.patch [new file with mode: 0644]
0059-ReadMe-fix-command-line-help.patch [new file with mode: 0644]
0060-mdadm-replace-container-level-checking-with-inline.patch [new file with mode: 0644]
0061-Mdmonitor-Omit-non-md-devices.patch [new file with mode: 0644]
0062-Mdmonitor-Split-alert-into-separate-functions.patch [new file with mode: 0644]
0063-Monitor-block-if-monitor-modes-are-combined.patch [new file with mode: 0644]
0064-Update-mdadm-Monitor-manual.patch [new file with mode: 0644]
0065-Grow-fix-possible-memory-leak.patch [new file with mode: 0644]
0066-mdadm-create-ident_init.patch [new file with mode: 0644]
0067-mdadm-Add-option-validation-for-update-subarray.patch [new file with mode: 0644]
0068-Fix-update-subarray-on-active-volume.patch [new file with mode: 0644]
0069-Add-code-specific-update-options-to-enum.patch [new file with mode: 0644]
0070-super-ddf-Remove-update_super_ddf.patch [new file with mode: 0644]
0071-super0-refactor-the-code-for-enum.patch [new file with mode: 0644]
0072-super1-refactor-the-code-for-enum.patch [new file with mode: 0644]
0073-super-intel-refactor-the-code-for-enum.patch [new file with mode: 0644]
0074-Change-update-to-enum-in-update_super-and-update_sub.patch [new file with mode: 0644]
0075-Manage-Incremental-code-refactor-string-to-enum.patch [new file with mode: 0644]
0076-Change-char-to-enum-in-context-update-refactor-code.patch [new file with mode: 0644]
0077-mdmon-fix-segfault.patch [new file with mode: 0644]
0078-util-remove-obsolete-code-from-get_md_name.patch [new file with mode: 0644]
0079-mdadm-udev-Don-t-handle-change-event-on-raw-devices.patch [new file with mode: 0644]
0080-Manage-do-not-check-array-state-when-drive-is-remove.patch [new file with mode: 0644]
0081-incremental-manage-do-not-verify-if-remove-is-safe.patch [new file with mode: 0644]
0082-super-intel-make-freesize-not-required-for-chunk-siz.patch [new file with mode: 0644]
0083-manage-move-comment-with-function-description.patch [new file with mode: 0644]
0084-Revert-mdadm-systemd-remove-KillMode-none-from-servi.patch [new file with mode: 0644]
0085-Grow-fix-can-t-change-bitmap-type-from-none-to-clust.patch [new file with mode: 0644]
0086-Fix-NULL-dereference-in-super_by_fd.patch [new file with mode: 0644]
0087-Mdmonitor-Make-alert_info-global.patch [new file with mode: 0644]
0088-Mdmonitor-Pass-events-to-alert-using-enums-instead-o.patch [new file with mode: 0644]
0089-Mdmonitor-Add-helper-functions.patch [new file with mode: 0644]
0090-Add-helpers-to-determine-whether-directories-or-file.patch [new file with mode: 0644]
0091-Mdmonitor-Refactor-write_autorebuild_pid.patch [new file with mode: 0644]
0092-Mdmonitor-Refactor-check_one_sharer-for-better-error.patch [new file with mode: 0644]
0093-util.c-reorder-code-lines-in-parse_layout_faulty.patch [new file with mode: 0644]
0094-util.c-fix-memleak-in-parse_layout_faulty.patch [new file with mode: 0644]
0095-Detail.c-fix-memleak-in-Detail.patch [new file with mode: 0644]
0096-isuper-intel.c-fix-double-free-in-load_imsm_mpb.patch [new file with mode: 0644]
0097-super-intel.c-fix-memleak-in-find_disk_attached_hba.patch [new file with mode: 0644]
0098-super-ddf.c-fix-memleak-in-get_vd_num_of_subarray.patch [new file with mode: 0644]
0099-Create-goto-abort_locked-instead-of-return-1-in-erro.patch [new file with mode: 0644]
0100-Create-remove-safe_mode_delay-local-variable.patch [new file with mode: 0644]
0101-Create-Factor-out-add_disks-helpers.patch [new file with mode: 0644]
0102-mdadm-Introduce-pr_info.patch [new file with mode: 0644]
0103-mdadm-Add-write-zeros-option-for-Create.patch [new file with mode: 0644]
0104-tests-00raid5-zero-Introduce-test-to-exercise-write-.patch [new file with mode: 0644]
0105-manpage-Add-write-zeroes-option-to-manpage.patch [new file with mode: 0644]
0106-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch [new file with mode: 0644]
0107-Use-existence-of-etc-initrd-release-to-detect-initrd.patch [new file with mode: 0644]
0108-mdmon-don-t-test-both-all-and-container_name.patch [new file with mode: 0644]
0109-mdmon-change-systemd-unit-file-to-use-foreground.patch [new file with mode: 0644]
0110-mdmon-Remove-need-for-KillMode-none.patch [new file with mode: 0644]
0111-mdmon-Improve-switchroot-interactions.patch [new file with mode: 0644]
0112-mdopen-always-try-create_named_array.patch [new file with mode: 0644]
0113-Improvements-for-IMSM_NO_PLATFORM-testing.patch [new file with mode: 0644]
0114-Revert-Revert-mdadm-systemd-remove-KillMode-none-fro.patch [new file with mode: 0644]
0115-Create-Fix-checking-for-container-in-update_metadata.patch [new file with mode: 0644]
0116-Fix-null-pointer-for-incremental-in-mdadm.patch [new file with mode: 0644]
0117-super1-fix-truncation-check-for-journal-device.patch [new file with mode: 0644]
0118-Fix-some-cases-eyesore-formatting.patch [new file with mode: 0644]
0119-Bump-minimum-kernel-version-to-2.6.32.patch [new file with mode: 0644]
0120-Remove-the-config-files-in-mdcheck_start-continue-se.patch [new file with mode: 0644]
mdadm.spec

diff --git a/0001-Unify-error-message.patch b/0001-Unify-error-message.patch
new file mode 100644 (file)
index 0000000..14dc69c
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0002-mdadm-Fix-double-free.patch b/0002-mdadm-Fix-double-free.patch
new file mode 100644 (file)
index 0000000..e6b7d37
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0003-Grow_reshape-Add-r0-grow-size-error-message-and-upda.patch b/0003-Grow_reshape-Add-r0-grow-size-error-message-and-upda.patch
new file mode 100644 (file)
index 0000000..e43cdaa
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0004-udev-adapt-rules-to-systemd-v247.patch b/0004-udev-adapt-rules-to-systemd-v247.patch
new file mode 100644 (file)
index 0000000..a755c53
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0005-Replace-error-prone-signal-with-sigaction.patch b/0005-Replace-error-prone-signal-with-sigaction.patch
new file mode 100644 (file)
index 0000000..dd04b8c
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0006-mdadm-Respect-config-file-location-in-man.patch b/0006-mdadm-Respect-config-file-location-in-man.patch
new file mode 100644 (file)
index 0000000..bee28ac
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0007-mdadm-Update-ReadMe.patch b/0007-mdadm-Update-ReadMe.patch
new file mode 100644 (file)
index 0000000..a143a22
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0008-mdadm-Update-config-man-regarding-default-files-and-.patch b/0008-mdadm-Update-config-man-regarding-default-files-and-.patch
new file mode 100644 (file)
index 0000000..0109e9a
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0009-mdadm-Update-config-manual.patch b/0009-mdadm-Update-config-manual.patch
new file mode 100644 (file)
index 0000000..08599d5
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0010-Create-Build-use-default_layout.patch b/0010-Create-Build-use-default_layout.patch
new file mode 100644 (file)
index 0000000..7f9791b
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0011-mdadm-add-map_num_s.patch b/0011-mdadm-add-map_num_s.patch
new file mode 100644 (file)
index 0000000..ee2c755
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0012-mdadm-systemd-remove-KillMode-none-from-service-file.patch b/0012-mdadm-systemd-remove-KillMode-none-from-service-file.patch
new file mode 100644 (file)
index 0000000..ae67325
--- /dev/null
@@ -0,0 +1,69 @@
+From 52c67fcdd6dadc4138ecad73e65599551804d445 Mon Sep 17 00:00:00 2001
+From: Coly Li <colyli@suse.de>
+Date: Tue, 15 Feb 2022 21:34:15 +0800
+Subject: [PATCH 012/120] mdadm/systemd: remove KillMode=none from service file
+
+For mdadm's systemd configuration, current systemd KillMode is "none" in
+following service files,
+- mdadm-grow-continue@.service
+- mdmon@.service
+
+This "none" mode is strongly againsted by systemd developers (see man 5
+systemd.kill for "KillMode=" section), and is considering to remove in
+future systemd version.
+
+As systemd developer explained in disuccsion, the systemd kill process
+is,
+1. send the signal specified by KillSignal= to the list of processes (if
+   any), TERM is the default
+2. wait until either the target of process(es) exit or a timeout expires
+3. if the timeout expires send the signal specified by FinalKillSignal=,
+   KILL is the default
+
+For "control-group", all remaining processes will receive the SIGTERM
+signal (by default) and if there are still processes after a period f
+time, they will get the SIGKILL signal.
+
+For "mixed", only the main process will receive the SIGTERM signal, and
+if there are still processes after a period of time, all remaining
+processes (including the main one) will receive the SIGKILL signal.
+
+From the above comment, currently KillMode=control-group is a proper
+kill mode. Since control-gropu is the default kill mode, the fix can be
+simply removing KillMode=none line from the service file, then the
+default mode will take effect.
+
+Signed-off-by: Coly Li <colyli@suse.de>
+Cc: Benjamin Brunner <bbrunner@suse.com>
+Cc: Franck Bui <fbui@suse.de>
+Cc: Jes Sorensen <jes@trained-monkey.org>
+Cc: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Cc: Neil Brown <neilb@suse.de>
+Cc: Xiao Ni <xni@redhat.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ systemd/mdadm-grow-continue@.service | 1 -
+ systemd/mdmon@.service               | 1 -
+ 2 files changed, 2 deletions(-)
+
+diff --git a/systemd/mdadm-grow-continue@.service b/systemd/mdadm-grow-continue@.service
+index 5c667d2a..9fdc8ec7 100644
+--- a/systemd/mdadm-grow-continue@.service
++++ b/systemd/mdadm-grow-continue@.service
+@@ -14,4 +14,3 @@ ExecStart=BINDIR/mdadm --grow --continue /dev/%I
+ StandardInput=null
+ StandardOutput=null
+ StandardError=null
+-KillMode=none
+diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service
+index 85a3a7c5..77533958 100644
+--- a/systemd/mdmon@.service
++++ b/systemd/mdmon@.service
+@@ -25,4 +25,3 @@ Type=forking
+ # it out) and systemd will remove it when transitioning from
+ # initramfs to rootfs.
+ #PIDFile=/run/mdadm/%I.pid
+-KillMode=none
+-- 
+2.38.1
+
diff --git a/0013-mdmon-Stop-parsing-duplicate-options.patch b/0013-mdmon-Stop-parsing-duplicate-options.patch
new file mode 100644 (file)
index 0000000..77324cf
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0014-Grow-block-n-on-external-volumes.patch b/0014-Grow-block-n-on-external-volumes.patch
new file mode 100644 (file)
index 0000000..4e6a874
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0015-Incremental-Fix-possible-memory-and-resource-leaks.patch b/0015-Incremental-Fix-possible-memory-and-resource-leaks.patch
new file mode 100644 (file)
index 0000000..51a9e0f
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0016-Mdmonitor-Fix-segfault.patch b/0016-Mdmonitor-Fix-segfault.patch
new file mode 100644 (file)
index 0000000..61c64ab
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0017-Mdmonitor-Improve-logging-method.patch b/0017-Mdmonitor-Improve-logging-method.patch
new file mode 100644 (file)
index 0000000..3c7eed2
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch b/0018-Fix-possible-NULL-ptr-dereferences-and-memory-leaks.patch
new file mode 100644 (file)
index 0000000..24db49f
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch b/0019-imsm-Remove-possibility-for-get_imsm_dev-to-return-N.patch
new file mode 100644 (file)
index 0000000..12dd070
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch b/0020-Revert-mdadm-fix-coredump-of-mdadm-monitor-r.patch
new file mode 100644 (file)
index 0000000..f51c730
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0021-util-replace-ioctl-use-with-function.patch b/0021-util-replace-ioctl-use-with-function.patch
new file mode 100644 (file)
index 0000000..56ee5e8
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch b/0022-mdadm-super1-restore-commit-45a87c2f31335-to-fix-clu.patch
new file mode 100644 (file)
index 0000000..88bba83
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0023-imsm-introduce-get_disk_slot_in_dev.patch b/0023-imsm-introduce-get_disk_slot_in_dev.patch
new file mode 100644 (file)
index 0000000..ca1d015
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0024-imsm-use-same-slot-across-container.patch b/0024-imsm-use-same-slot-across-container.patch
new file mode 100644 (file)
index 0000000..dc23b3c
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0025-imsm-block-changing-slots-during-creation.patch b/0025-imsm-block-changing-slots-during-creation.patch
new file mode 100644 (file)
index 0000000..4c3b918
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0026-mdadm-block-update-ppl-for-non-raid456-levels.patch b/0026-mdadm-block-update-ppl-for-non-raid456-levels.patch
new file mode 100644 (file)
index 0000000..d593669
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0027-mdadm-Fix-array-size-mismatch-after-grow.patch b/0027-mdadm-Fix-array-size-mismatch-after-grow.patch
new file mode 100644 (file)
index 0000000..02bdf9c
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch b/0028-mdadm-Remove-dead-code-in-imsm_fix_size_mismatch.patch
new file mode 100644 (file)
index 0000000..08688dd
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch b/0029-Monitor-use-devname-as-char-array-instead-of-pointer.patch
new file mode 100644 (file)
index 0000000..f337ff0
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0030-Monitor-use-snprintf-to-fill-device-name.patch b/0030-Monitor-use-snprintf-to-fill-device-name.patch
new file mode 100644 (file)
index 0000000..7d3b4bc
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0031-Makefile-Don-t-build-static-build-with-everything-an.patch b/0031-Makefile-Don-t-build-static-build-with-everything-an.patch
new file mode 100644 (file)
index 0000000..de5e49e
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0032-DDF-Cleanup-validate_geometry_ddf_container.patch b/0032-DDF-Cleanup-validate_geometry_ddf_container.patch
new file mode 100644 (file)
index 0000000..ec2954d
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch b/0033-DDF-Fix-NULL-pointer-dereference-in-validate_geometr.patch
new file mode 100644 (file)
index 0000000..3a53577
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch b/0034-mdadm-Grow-Fix-use-after-close-bug-by-closing-after-.patch
new file mode 100644 (file)
index 0000000..2695f67
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch b/0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch
new file mode 100644 (file)
index 0000000..ed09288
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0036-mdadm-Fix-mdadm-r-remove-option-regression.patch b/0036-mdadm-Fix-mdadm-r-remove-option-regression.patch
new file mode 100644 (file)
index 0000000..f091c64
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0037-mdadm-Fix-optional-write-behind-parameter.patch b/0037-mdadm-Fix-optional-write-behind-parameter.patch
new file mode 100644 (file)
index 0000000..60cafdb
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch b/0038-tests-00raid0-add-a-test-that-validates-raid0-with-l.patch
new file mode 100644 (file)
index 0000000..7794e18
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0039-tests-fix-raid0-tests-for-0.90-metadata.patch b/0039-tests-fix-raid0-tests-for-0.90-metadata.patch
new file mode 100644 (file)
index 0000000..d897fb1
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch b/0040-tests-04update-metadata-avoid-passing-chunk-size-to-.patch
new file mode 100644 (file)
index 0000000..12b291b
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch b/0041-tests-02lineargrow-clear-the-superblock-at-every-ite.patch
new file mode 100644 (file)
index 0000000..e6b9bba
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch b/0042-mdadm-test-Add-a-mode-to-repeat-specified-tests.patch
new file mode 100644 (file)
index 0000000..63f72dc
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch b/0043-mdadm-test-Mark-and-ignore-broken-test-failures.patch
new file mode 100644 (file)
index 0000000..52fd3e9
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0044-tests-Add-broken-files-for-all-broken-tests.patch b/0044-tests-Add-broken-files-for-all-broken-tests.patch
new file mode 100644 (file)
index 0000000..2484e1b
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch b/0045-mdadm-Replace-obsolete-usleep-with-nanosleep.patch
new file mode 100644 (file)
index 0000000..74bf834
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch b/0046-tests-00readonly-Run-udevadm-settle-before-setting-r.patch
new file mode 100644 (file)
index 0000000..5872416
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0047-tests-add-test-for-names.patch b/0047-tests-add-test-for-names.patch
new file mode 100644 (file)
index 0000000..03aee00
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0048-mdadm-remove-symlink-option.patch b/0048-mdadm-remove-symlink-option.patch
new file mode 100644 (file)
index 0000000..1956e2b
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0049-mdadm-move-data_offset-to-struct-shape.patch b/0049-mdadm-move-data_offset-to-struct-shape.patch
new file mode 100644 (file)
index 0000000..5dca508
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch b/0050-mdadm-Don-t-open-md-device-for-CREATE-and-ASSEMBLE.patch
new file mode 100644 (file)
index 0000000..c319da2
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0051-Grow-Split-Grow_reshape-into-helper-function.patch b/0051-Grow-Split-Grow_reshape-into-helper-function.patch
new file mode 100644 (file)
index 0000000..8fe5894
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0052-Assemble-check-if-device-is-container-before-schedul.patch b/0052-Assemble-check-if-device-is-container-before-schedul.patch
new file mode 100644 (file)
index 0000000..52d08b8
--- /dev/null
@@ -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/83] 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.38.1
+
diff --git a/0053-super1-report-truncated-device.patch b/0053-super1-report-truncated-device.patch
new file mode 100644 (file)
index 0000000..35cbd4b
--- /dev/null
@@ -0,0 +1,112 @@
+From 171e9743881edf2dfb163ddff483566fbf913ccd Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Fri, 26 Aug 2022 08:55:56 +1000
+Subject: [PATCH 53/83] super1: report truncated device
+
+When the metadata is at the start of the device, it is possible that it
+describes a device large than the one it is actually stored on.  When
+this happens, report it loudly in --examine.
+
+....
+   Unused Space : before=1968 sectors, after=-2047 sectors DEVICE TOO SMALL
+          State : clean TRUNCATED DEVICE
+....
+
+Also report in --assemble so that the failure which the kernel will
+report will be explained.
+
+mdadm: Device /dev/sdb is not large enough for data described in superblock
+mdadm: no RAID superblock on /dev/sdb
+mdadm: /dev/sdb has no superblock - assembly aborted
+
+Scenario can be demonstrated as follows:
+
+mdadm: Note: this array has metadata at the start and
+    may not be suitable as a boot device.  If you plan to
+    store '/boot' on this device please ensure that
+    your boot-loader understands md/v1.x metadata, or use
+    --metadata=0.90
+mdadm: Defaulting to version 1.2 metadata
+mdadm: array /dev/md/test started.
+mdadm: stopped /dev/md/test
+   Unused Space : before=1968 sectors, after=-2047 sectors DEVICE TOO SMALL
+          State : clean TRUNCATED DEVICE
+   Unused Space : before=1968 sectors, after=-2047 sectors DEVICE TOO SMALL
+          State : clean TRUNCATED DEVICE
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super1.c | 35 ++++++++++++++++++++++++++++-------
+ 1 file changed, 28 insertions(+), 7 deletions(-)
+
+diff --git a/super1.c b/super1.c
+index 71af860c..58345e68 100644
+--- a/super1.c
++++ b/super1.c
+@@ -406,12 +406,18 @@ static void examine_super1(struct supertype *st, char *homehost)
+       st->ss->getinfo_super(st, &info, NULL);
+       if (info.space_after != 1 &&
+-          !(__le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET))
+-              printf("   Unused Space : before=%llu sectors, after=%llu sectors\n",
+-                     info.space_before, info.space_after);
+-
+-      printf("          State : %s\n",
+-             (__le64_to_cpu(sb->resync_offset)+1)? "active":"clean");
++          !(__le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET)) {
++              printf("   Unused Space : before=%llu sectors, ",
++                     info.space_before);
++              if (info.space_after < INT64_MAX)
++                      printf("after=%llu sectors\n", info.space_after);
++              else
++                      printf("after=-%llu sectors DEVICE TOO SMALL\n",
++                             UINT64_MAX - info.space_after);
++      }
++      printf("          State : %s%s\n",
++             (__le64_to_cpu(sb->resync_offset)+1) ? "active":"clean",
++             (info.space_after > INT64_MAX)       ? " TRUNCATED DEVICE" : "");
+       printf("    Device UUID : ");
+       for (i=0; i<16; i++) {
+               if ((i&3)==0 && i != 0)
+@@ -2206,6 +2212,7 @@ static int load_super1(struct supertype *st, int fd, char *devname)
+               tst.ss = &super1;
+               for (tst.minor_version = 0; tst.minor_version <= 2;
+                    tst.minor_version++) {
++                      tst.ignore_hw_compat = st->ignore_hw_compat;
+                       switch(load_super1(&tst, fd, devname)) {
+                       case 0: super = tst.sb;
+                               if (bestvers == -1 ||
+@@ -2312,7 +2319,6 @@ static int load_super1(struct supertype *st, int fd, char *devname)
+               free(super);
+               return 2;
+       }
+-      st->sb = super;
+       bsb = (struct bitmap_super_s *)(((char*)super)+MAX_SB_SIZE);
+@@ -2322,6 +2328,21 @@ static int load_super1(struct supertype *st, int fd, char *devname)
+       if (st->data_offset == INVALID_SECTORS)
+               st->data_offset = __le64_to_cpu(super->data_offset);
++      if (st->minor_version >= 1 &&
++          st->ignore_hw_compat == 0 &&
++          (dsize < (__le64_to_cpu(super->data_offset) +
++                    __le64_to_cpu(super->size))
++           ||
++           dsize < (__le64_to_cpu(super->data_offset) +
++                    __le64_to_cpu(super->data_size)))) {
++              if (devname)
++                      pr_err("Device %s is not large enough for data described in superblock\n",
++                             devname);
++              free(super);
++              return 2;
++      }
++      st->sb = super;
++
+       /* Now check on the bitmap superblock */
+       if ((__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) == 0)
+               return 0;
+-- 
+2.38.1
+
diff --git a/0054-mdadm-Correct-typos-punctuation-and-grammar-in-man.patch b/0054-mdadm-Correct-typos-punctuation-and-grammar-in-man.patch
new file mode 100644 (file)
index 0000000..c37276f
--- /dev/null
@@ -0,0 +1,616 @@
+From 1a386f804d8392b849b3362da6b0157b0db83091 Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Fri, 12 Aug 2022 16:52:12 +0200
+Subject: [PATCH 54/83] mdadm: Correct typos, punctuation and grammar in man
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Reviewed-by: Wol <anthony@youngman.org.uk>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ mdadm.8.in | 178 ++++++++++++++++++++++++++---------------------------
+ 1 file changed, 88 insertions(+), 90 deletions(-)
+
+diff --git a/mdadm.8.in b/mdadm.8.in
+index f2736226..70c79d1e 100644
+--- a/mdadm.8.in
++++ b/mdadm.8.in
+@@ -158,7 +158,7 @@ adding new spares and removing faulty devices.
+ .B Misc
+ This is an 'everything else' mode that supports operations on active
+ arrays, operations on component devices such as erasing old superblocks, and
+-information gathering operations.
++information-gathering operations.
+ .\"This mode allows operations on independent devices such as examine MD
+ .\"superblocks, erasing old superblocks and stopping active arrays.
+@@ -231,12 +231,12 @@ mode to be assumed.
+ .TP
+ .BR \-h ", " \-\-help
+-Display general help message or, after one of the above options, a
++Display a general help message or, after one of the above options, a
+ mode-specific help message.
+ .TP
+ .B \-\-help\-options
+-Display more detailed help about command line parsing and some commonly
++Display more detailed help about command-line parsing and some commonly
+ used options.
+ .TP
+@@ -266,7 +266,7 @@ the exact meaning of this option in different contexts.
+ .TP
+ .BR \-c ", " \-\-config=
+-Specify the config file or directory.  If not specified, default config file
++Specify the config file or directory.  If not specified, the default config file
+ and default conf.d directory will be used.  See
+ .BR mdadm.conf (5)
+ for more details.
+@@ -379,7 +379,7 @@ When creating an array, the
+ .B homehost
+ will be recorded in the metadata.  For version-1 superblocks, it will
+ be prefixed to the array name.  For version-0.90 superblocks, part of
+-the SHA1 hash of the hostname will be stored in the later half of the
++the SHA1 hash of the hostname will be stored in the latter half of the
+ UUID.
+ When reporting information about an array, any array which is tagged
+@@ -388,7 +388,7 @@ for the given homehost will be reported as such.
+ When using Auto-Assemble, only arrays tagged for the given homehost
+ will be allowed to use 'local' names (i.e. not ending in '_' followed
+ by a digit string).  See below under
+-.BR "Auto Assembly" .
++.BR "Auto-Assembly" .
+ The special name "\fBany\fP" can be used as a wild card.  If an array
+ is created with
+@@ -403,7 +403,7 @@ When
+ .I mdadm
+ needs to print the name for a device it normally finds the name in
+ .B /dev
+-which refers to the device and is shortest.  When a path component is
++which refers to the device and is the shortest.  When a path component is
+ given with
+ .B \-\-prefer
+ .I mdadm
+@@ -478,9 +478,9 @@ still be larger than any replacement.
+ This option can be used with
+ .B \-\-create
+-for determining initial size of an array. For external metadata,
++for determining the 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
++Setting the initial size of
+ .B RAID 0
+ array is only valid for external metadata.
+@@ -545,20 +545,20 @@ Clustered arrays do not support this parameter yet.
+ .TP
+ .BR \-c ", " \-\-chunk=
+-Specify chunk size of kilobytes.  The default when creating an
++Specify chunk size in kilobytes.  The default when creating an
+ array is 512KB.  To ensure compatibility with earlier versions, the
+ default when building an array with no persistent metadata is 64KB.
+ This is only meaningful for RAID0, RAID4, RAID5, RAID6, and RAID10.
+ RAID4, RAID5, RAID6, and RAID10 require the chunk size to be a power
+-of 2.  In any case it must be a multiple of 4KB.
++of 2, with minimal chunk size being 4KB.
+ A suffix of 'K', 'M', 'G' or 'T' can be given to indicate Kilobytes,
+ Megabytes, Gigabytes or Terabytes respectively.
+ .TP
+ .BR \-\-rounding=
+-Specify rounding factor for a Linear array.  The size of each
++Specify the rounding factor for a Linear array.  The size of each
+ component will be rounded down to a multiple of this size.
+ This is a synonym for
+ .B \-\-chunk
+@@ -655,7 +655,8 @@ option to set subsequent failure modes.
+ and "flush" will clear any persistent faults.
+ The layout options for RAID10 are one of 'n', 'o' or 'f' followed
+-by a small number.  The default is 'n2'.  The supported options are:
++by a small number signifying the number of copies of each datablock.
++The default is 'n2'.  The supported options are:
+ .I 'n'
+ signals 'near' copies.  Multiple copies of one data block are at
+@@ -673,7 +674,7 @@ signals 'far' copies
+ (multiple copies have very different offsets).
+ See md(4) for more detail about 'near', 'offset', and 'far'.
+-The number is the number of copies of each datablock.  2 is normal, 3
++As for the number of copies of each data block, 2 is normal, 3
+ can be useful.  This number can be at most equal to the number of
+ devices in the array.  It does not need to divide evenly into that
+ number (e.g. it is perfectly legal to have an 'n2' layout for an array
+@@ -684,7 +685,7 @@ A bug introduced in Linux 3.14 means that RAID0 arrays
+ started using a different layout.  This could lead to
+ data corruption.  Since Linux 5.4 (and various stable releases that received
+ backports), the kernel will not accept such an array unless
+-a layout is explictly set.  It can be set to
++a layout is explicitly set.  It can be set to
+ .RB ' original '
+ or
+ .RB ' alternate '.
+@@ -760,13 +761,13 @@ or by selecting a different consistency policy with
+ .TP
+ .BR \-\-bitmap\-chunk=
+-Set the chunksize of the bitmap.  Each bit corresponds to that many
++Set the chunk size of the bitmap.  Each bit corresponds to that many
+ Kilobytes of storage.
+-When using a file based bitmap, the default is to use the smallest
+-size that is at-least 4 and requires no more than 2^21 chunks.
++When using a file-based bitmap, the default is to use the smallest
++size that is at least 4 and requires no more than 2^21 chunks.
+ When using an
+ .B internal
+-bitmap, the chunksize defaults to 64Meg, or larger if necessary to
++bitmap, the chunk size defaults to 64Meg, or larger if necessary to
+ fit the bitmap into the available space.
+ A suffix of 'K', 'M', 'G' or 'T' can be given to indicate Kilobytes,
+@@ -840,7 +841,7 @@ can be used with that command to avoid the automatic resync.
+ .BR \-\-backup\-file=
+ This is needed when
+ .B \-\-grow
+-is used to increase the number of raid-devices in a RAID5 or RAID6 if
++is used to increase the number of raid devices in a RAID5 or RAID6 if
+ there are no spare devices available, or to shrink, change RAID level
+ or layout.  See the GROW MODE section below on RAID\-DEVICES CHANGES.
+ The file must be stored on a separate device, not on the RAID array
+@@ -879,7 +880,7 @@ When creating an array,
+ .B \-\-data\-offset
+ can be specified as
+ .BR variable .
+-In the case each member device is expected to have a offset appended
++In the case each member device is expected to have an offset appended
+ to the name, separated by a colon.  This makes it possible to recreate
+ exactly an array which has varying data offsets (as can happen when
+ different versions of
+@@ -943,7 +944,7 @@ Insist that
+ .I mdadm
+ accept the geometry and layout specified without question.  Normally
+ .I mdadm
+-will not allow creation of an array with only one device, and will try
++will not allow the creation of an array with only one device, and will try
+ to create a RAID5 array with one missing drive (as this makes the
+ initial resync work faster).  With
+ .BR \-\-force ,
+@@ -1004,7 +1005,7 @@ number added, e.g.
+ If the md device name is in a 'standard' format as described in DEVICE
+ NAMES, then it will be created, if necessary, with the appropriate
+ device number based on that name.  If the device name is not in one of these
+-formats, then a unused device number will be allocated.  The device
++formats, then an unused device number will be allocated.  The device
+ number will be considered unused if there is no active array for that
+ number, and there is no entry in /dev for that number and with a
+ non-standard name.  Names that are not in 'standard' format are only
+@@ -1032,25 +1033,25 @@ then
+ .B \-\-add
+ can be used to add some extra devices to be included in the array.
+ In most cases this is not needed as the extra devices can be added as
+-spares first, and then the number of raid-disks can be changed.
+-However for RAID0, it is not possible to add spares.  So to increase
++spares first, and then the number of raid disks can be changed.
++However, for RAID0 it is not possible to add spares.  So to increase
+ the number of devices in a RAID0, it is necessary to set the new
+ number of devices, and to add the new devices, in the same command.
+ .TP
+ .BR \-\-nodes
+-Only works when the array is for clustered environment. It specifies
++Only works when the array is created for a clustered environment. It specifies
+ the maximum number of nodes in the cluster that will use this device
+ simultaneously. If not specified, this defaults to 4.
+ .TP
+ .BR \-\-write-journal
+ Specify journal device for the RAID-4/5/6 array. The journal device
+-should be a SSD with reasonable lifetime.
++should be an SSD with a reasonable lifetime.
+ .TP
+ .BR \-k ", " \-\-consistency\-policy=
+-Specify how the array maintains consistency in case of unexpected shutdown.
++Specify how the array maintains consistency in the case of an unexpected shutdown.
+ Only relevant for RAID levels with redundancy.
+ Currently supported options are:
+ .RS
+@@ -1058,7 +1059,7 @@ Currently supported options are:
+ .TP
+ .B resync
+ Full resync is performed and all redundancy is regenerated when the array is
+-started after unclean shutdown.
++started after an unclean shutdown.
+ .TP
+ .B bitmap
+@@ -1067,8 +1068,8 @@ Resync assisted by a write-intent bitmap. Implicitly selected when using
+ .TP
+ .B journal
+-For RAID levels 4/5/6, journal device is used to log transactions and replay
+-after unclean shutdown. Implicitly selected when using
++For RAID levels 4/5/6, the journal device is used to log transactions and replay
++after an unclean shutdown. Implicitly selected when using
+ .BR \-\-write\-journal .
+ .TP
+@@ -1237,7 +1238,7 @@ This can be useful if
+ reports a different "Preferred Minor" to
+ .BR \-\-detail .
+ In some cases this update will be performed automatically
+-by the kernel driver.  In particular the update happens automatically
++by the kernel driver.  In particular, the update happens automatically
+ at the first write to an array with redundancy (RAID level 1 or
+ greater) on a 2.6 (or later) kernel.
+@@ -1277,7 +1278,7 @@ For version-1 superblocks, this involves updating the name.
+ The
+ .B home\-cluster
+ option will change the cluster name as recorded in the superblock and
+-bitmap. This option only works for clustered environment.
++bitmap. This option only works for a clustered environment.
+ The
+ .B resync
+@@ -1390,10 +1391,10 @@ This option should be used with great caution.
+ .TP
+ .BR \-\-freeze\-reshape
+-Option is intended to be used in start-up scripts during initrd boot phase.
+-When array under reshape is assembled during initrd phase, this option
+-stops reshape after reshape critical section is being restored. This happens
+-before file system pivot operation and avoids loss of file system context.
++This option is intended to be used in start-up scripts during the initrd boot phase.
++When the array under reshape is assembled during the initrd phase, this option
++stops the reshape after the reshape-critical section has been restored. This happens
++before the file system pivot operation and avoids loss of filesystem context.
+ Losing file system context would cause reshape to be broken.
+ Reshape can be continued later using the
+@@ -1437,9 +1438,9 @@ re\-add a device that was previously removed from an array.
+ If the metadata on the device reports that it is a member of the
+ array, and the slot that it used is still vacant, then the device will
+ be added back to the array in the same position.  This will normally
+-cause the data for that device to be recovered.  However based on the
++cause the data for that device to be recovered.  However, based on the
+ event count on the device, the recovery may only require sections that
+-are flagged a write-intent bitmap to be recovered or may not require
++are flagged by a write-intent bitmap to be recovered or may not require
+ any recovery at all.
+ When used on an array that has no metadata (i.e. it was built with
+@@ -1447,13 +1448,12 @@ When used on an array that has no metadata (i.e. it was built with
+ it will be assumed that bitmap-based recovery is enough to make the
+ device fully consistent with the array.
+-When used with v1.x metadata,
+ .B \-\-re\-add
+-can be accompanied by
++can also be accompanied by
+ .BR \-\-update=devicesize ,
+ .BR \-\-update=bbl ", or"
+ .BR \-\-update=no\-bbl .
+-See the description of these option when used in Assemble mode for an
++See descriptions of these options when used in Assemble mode for an
+ explanation of their use.
+ If the device name given is
+@@ -1480,7 +1480,7 @@ Add a device as a spare.  This is similar to
+ except that it does not attempt
+ .B \-\-re\-add
+ first.  The device will be added as a spare even if it looks like it
+-could be an recent member of the array.
++could be a recent member of the array.
+ .TP
+ .BR \-r ", " \-\-remove
+@@ -1497,12 +1497,12 @@ and names like
+ .B set-A
+ can be given to
+ .BR \-\-remove .
+-The first causes all failed device to be removed.  The second causes
++The first causes all failed devices to be removed.  The second causes
+ any device which is no longer connected to the system (i.e an 'open'
+ returns
+ .BR ENXIO )
+ to be removed.
+-The third will remove a set as describe below under
++The third will remove a set as described below under
+ .BR \-\-fail .
+ .TP
+@@ -1519,7 +1519,7 @@ For RAID10 arrays where the number of copies evenly divides the number
+ of devices, the devices can be conceptually divided into sets where
+ each set contains a single complete copy of the data on the array.
+ Sometimes a RAID10 array will be configured so that these sets are on
+-separate controllers.  In this case all the devices in one set can be
++separate controllers.  In this case, all the devices in one set can be
+ failed by giving a name like
+ .B set\-A
+ or
+@@ -1549,9 +1549,9 @@ This can follow a list of
+ .B \-\-replace
+ devices.  The devices listed after
+ .B \-\-with
+-will be preferentially used to replace the devices listed after
++will preferentially be used to replace the devices listed after
+ .BR \-\-replace .
+-These device must already be spare devices in the array.
++These devices must already be spare devices in the array.
+ .TP
+ .BR \-\-write\-mostly
+@@ -1574,8 +1574,8 @@ the device is found or <slot>:missing in case the device is not found.
+ .TP
+ .BR \-\-add-journal
+-Add journal to an existing array, or recreate journal for RAID-4/5/6 array
+-that lost a journal device. To avoid interrupting on-going write opertions,
++Add a journal to an existing array, or recreate journal for a RAID-4/5/6 array
++that lost a journal device. To avoid interrupting ongoing write operations,
+ .B \-\-add-journal
+ only works for array in Read-Only state.
+@@ -1631,9 +1631,9 @@ Print details of one or more md devices.
+ .TP
+ .BR \-\-detail\-platform
+ Print details of the platform's RAID capabilities (firmware / hardware
+-topology) for a given metadata format. If used without argument, mdadm
++topology) for a given metadata format. If used without an argument, mdadm
+ will scan all controllers looking for their capabilities. Otherwise, mdadm
+-will only look at the controller specified by the argument in form of an
++will only look at the controller specified by the argument in the form of an
+ absolute filepath or a link, e.g.
+ .IR /sys/devices/pci0000:00/0000:00:1f.2 .
+@@ -1742,8 +1742,8 @@ the block where the superblock would be is overwritten even if it
+ doesn't appear to be valid.
+ .B Note:
+-Be careful to call \-\-zero\-superblock with clustered raid, make sure
+-array isn't used or assembled in other cluster node before execute it.
++Be careful when calling \-\-zero\-superblock with clustered raid. Make sure
++the array isn't used or assembled in another cluster node before executing it.
+ .TP
+ .B \-\-kill\-subarray=
+@@ -1790,7 +1790,7 @@ For each md device given, or each device in /proc/mdstat if
+ is given, arrange for the array to be marked clean as soon as possible.
+ .I mdadm
+ will return with success if the array uses external metadata and we
+-successfully waited.  For native arrays this returns immediately as the
++successfully waited.  For native arrays, this returns immediately as the
+ kernel handles dirty-clean transitions at shutdown.  No action is taken
+ if safe-mode handling is disabled.
+@@ -1830,7 +1830,7 @@ uses to help track which arrays are currently being assembled.
+ .TP
+ .BR \-\-run ", " \-R
+-Run any array assembled as soon as a minimal number of devices are
++Run any array assembled as soon as a minimal number of devices is
+ available, rather than waiting until all expected devices are present.
+ .TP
+@@ -1860,7 +1860,7 @@ Only used with \-\-fail.  The 'path' given will be recorded so that if
+ a new device appears at the same location it can be automatically
+ added to the same array.  This allows the failed device to be
+ automatically replaced by a new device without metadata if it appears
+-at specified path.   This option is normally only set by a
++at specified path.   This option is normally only set by an
+ .I udev
+ script.
+@@ -1961,7 +1961,7 @@ Usage:
+ .PP
+ This usage assembles one or more RAID arrays from pre-existing components.
+ For each array, mdadm needs to know the md device, the identity of the
+-array, and a number of component-devices.  These can be found in a number of ways.
++array, and the number of component devices.  These can be found in a number of ways.
+ In the first usage example (without the
+ .BR \-\-scan )
+@@ -2001,7 +2001,7 @@ The config file is only used if explicitly named with
+ .B \-\-config
+ or requested with (a possibly implicit)
+ .BR \-\-scan .
+-In the later case, default config file is used.  See
++In the latter case, the default config file is used.  See
+ .BR mdadm.conf (5)
+ for more details.
+@@ -2039,14 +2039,14 @@ detects that udev is not configured, it will create the devices in
+ .B /dev
+ itself.
+-In Linux kernels prior to version 2.6.28 there were two distinctly
+-different types of md devices that could be created: one that could be
++In Linux kernels prior to version 2.6.28 there were two distinct
++types of md devices that could be created: one that could be
+ partitioned using standard partitioning tools and one that could not.
+-Since 2.6.28 that distinction is no longer relevant as both type of
++Since 2.6.28 that distinction is no longer relevant as both types of
+ devices can be partitioned.
+ .I mdadm
+ will normally create the type that originally could not be partitioned
+-as it has a well defined major number (9).
++as it has a well-defined major number (9).
+ Prior to 2.6.28, it is important that mdadm chooses the correct type
+ of array device to use.  This can be controlled with the
+@@ -2066,7 +2066,7 @@ can also be given in the configuration file as a word starting
+ .B auto=
+ on the ARRAY line for the relevant array.
+-.SS Auto Assembly
++.SS Auto-Assembly
+ When
+ .B \-\-assemble
+ is used with
+@@ -2122,11 +2122,11 @@ See
+ .IR mdadm.conf (5)
+ for further details.
+-Note: Auto assembly cannot be used for assembling and activating some
++Note: Auto-assembly cannot be used for assembling and activating some
+ arrays which are undergoing reshape.  In particular as the
+ .B backup\-file
+-cannot be given, any reshape which requires a backup-file to continue
+-cannot be started by auto assembly.  An array which is growing to more
++cannot be given, any reshape which requires a backup file to continue
++cannot be started by auto-assembly.  An array which is growing to more
+ devices and has passed the critical section can be assembled using
+ auto-assembly.
+@@ -2233,7 +2233,7 @@ When creating a partition based array, using
+ .I mdadm
+ with version-1.x metadata, the partition type should be set to
+ .B 0xDA
+-(non fs-data).  This type selection allows for greater precision since
++(non fs-data).  This type of selection allows for greater precision since
+ using any other [RAID auto-detect (0xFD) or a GNU/Linux partition (0x83)],
+ might create problems in the event of array recovery through a live cdrom.
+@@ -2249,7 +2249,7 @@ when creating a v0.90 array will silently override any
+ setting.
+ .\"If the
+ .\".B \-\-size
+-.\"option is given, it is not necessary to list any component-devices in this command.
++.\"option is given, it is not necessary to list any component devices in this command.
+ .\"They can be added later, before a
+ .\".B \-\-run.
+ .\"If no
+@@ -2263,7 +2263,7 @@ requested with the
+ .B \-\-bitmap
+ option or a different consistency policy is selected with the
+ .B \-\-consistency\-policy
+-option. In any case space for a bitmap will be reserved so that one
++option. In any case, space for a bitmap will be reserved so that one
+ can be added later with
+ .BR "\-\-grow \-\-bitmap=internal" .
+@@ -2313,7 +2313,7 @@ will firstly mark
+ as faulty in
+ .B /dev/md0
+ and will then remove it from the array and finally add it back
+-in as a spare.  However only one md array can be affected by a single
++in as a spare.  However, only one md array can be affected by a single
+ command.
+ When a device is added to an active array, mdadm checks to see if it
+@@ -2458,14 +2458,14 @@ config file to be examined.
+ If the device contains RAID metadata, a file will be created in the
+ .I directory
+ and the metadata will be written to it.  The file will be the same
+-size as the device and have the metadata written in the file at the
+-same locate that it exists in the device.  However the file will be "sparse" so
++size as the device and will have the metadata written at the
++same location as it exists in the device.  However, the file will be "sparse" so
+ that only those blocks containing metadata will be allocated. The
+ total space used will be small.
+-The file name used in the
++The filename used in the
+ .I directory
+-will be the base name of the device.   Further if any links appear in
++will be the base name of the device.   Further, if any links appear in
+ .I /dev/disk/by-id
+ which point to the device, then hard links to the file will be created
+ in
+@@ -2567,7 +2567,7 @@ and if the destination array has a failed drive but no spares.
+ If any devices are listed on the command line,
+ .I mdadm
+-will only monitor those devices.  Otherwise all arrays listed in the
++will only monitor those devices, otherwise, all arrays listed in the
+ configuration file will be monitored.  Further, if
+ .B \-\-scan
+ is given, then any other md devices that appear in
+@@ -2624,10 +2624,10 @@ check, repair). (syslog priority: Warning)
+ .BI Rebuild NN
+ Where
+ .I NN
+-is a two-digit number (ie. 05, 48). This indicates that rebuild
+-has passed that many percent of the total. The events are generated
+-with fixed increment since 0. Increment size may be specified with
+-a commandline option (default is 20). (syslog priority: Warning)
++is a two-digit number (eg. 05, 48). This indicates that the rebuild
++has reached that percentage of the total. The events are generated
++at a fixed increment from 0. The increment size may be specified with
++a command-line option (the default is 20). (syslog priority: Warning)
+ .TP
+ .B RebuildFinished
+@@ -2735,8 +2735,8 @@ When
+ detects that an array in a spare group has fewer active
+ devices than necessary for the complete array, and has no spare
+ devices, it will look for another array in the same spare group that
+-has a full complement of working drive and a spare.  It will then
+-attempt to remove the spare from the second drive and add it to the
++has a full complement of working drives and a spare.  It will then
++attempt to remove the spare from the second array and add it to the
+ first.
+ If the removal succeeds but the adding fails, then it is added back to
+ the original array.
+@@ -2750,10 +2750,8 @@ and then follow similar steps as above if a matching spare is found.
+ .SH GROW MODE
+ The GROW mode is used for changing the size or shape of an active
+ array.
+-For this to work, the kernel must support the necessary change.
+-Various types of growth are being added during 2.6 development.
+-Currently the supported changes include
++During the kernel 2.6 era the following changes were added:
+ .IP \(bu 4
+ change the "size" attribute for RAID1, RAID4, RAID5 and RAID6.
+ .IP \(bu 4
+@@ -2796,8 +2794,8 @@ use more than half of a spare device for backup space.
+ .SS SIZE CHANGES
+ Normally when an array is built the "size" is taken from the smallest
+-of the drives.  If all the small drives in an arrays are, one at a
+-time, removed and replaced with larger drives, then you could have an
++of the drives.  If all the small drives in an arrays are, over time,
++removed and replaced with larger drives, then you could have an
+ array of large drives with only a small amount used.  In this
+ situation, changing the "size" with "GROW" mode will allow the extra
+ space to start being used.  If the size is increased in this way, a
+@@ -2812,7 +2810,7 @@ after growing, or to reduce its size
+ .B prior
+ to shrinking the array.
+-Also the size of an array cannot be changed while it has an active
++Also, the size of an array cannot be changed while it has an active
+ bitmap.  If an array has a bitmap, it must be removed before the size
+ can be changed. Once the change is complete a new bitmap can be created.
+@@ -2892,7 +2890,7 @@ long time.  A
+ is required.  If the array is not simultaneously being grown or
+ shrunk, so that the array size will remain the same - for example,
+ reshaping a 3-drive RAID5 into a 4-drive RAID6 - the backup file will
+-be used not just for a "cricital section" but throughout the reshape
++be used not just for a "critical section" but throughout the reshape
+ operation, as described below under LAYOUT CHANGES.
+ .SS CHUNK-SIZE AND LAYOUT CHANGES
+@@ -2910,7 +2908,7 @@ slowly.
+ If the reshape is interrupted for any reason, this backup file must be
+ made available to
+ .B "mdadm --assemble"
+-so the array can be reassembled.  Consequently the file cannot be
++so the array can be reassembled.  Consequently, the file cannot be
+ stored on the device being reshaped.
+-- 
+2.38.1
+
diff --git a/0055-Manage-Block-unsafe-member-failing.patch b/0055-Manage-Block-unsafe-member-failing.patch
new file mode 100644 (file)
index 0000000..290c56f
--- /dev/null
@@ -0,0 +1,91 @@
+From fc6fd4063769f4194c3fb8f77b32b2819e140fb9 Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Thu, 18 Aug 2022 11:47:21 +0200
+Subject: [PATCH 55/83] Manage: Block unsafe member failing
+
+Kernel may or may not block mdadm from removing member device if it
+will cause arrays failed state. It depends on raid personality
+implementation in kernel.
+Add verification on requested removal path (#mdadm --set-faulty
+command).
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Manage.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 52 insertions(+), 1 deletion(-)
+
+diff --git a/Manage.c b/Manage.c
+index a142f8bd..b1d0e630 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -1285,6 +1285,50 @@ int Manage_with(struct supertype *tst, int fd, struct mddev_dev *dv,
+       return -1;
+ }
++/**
++ * is_remove_safe() - Check if remove is safe.
++ * @array: Array info.
++ * @fd: Array file descriptor.
++ * @devname: Name of device to remove.
++ * @verbose: Verbose.
++ *
++ * The function determines if array will be operational
++ * after removing &devname.
++ *
++ * Return: True if array will be operational, false otherwise.
++ */
++bool is_remove_safe(mdu_array_info_t *array, const int fd, char *devname, const int verbose)
++{
++      dev_t devid = devnm2devid(devname + 5);
++      struct mdinfo *mdi = sysfs_read(fd, NULL, GET_DEVS | GET_DISKS | GET_STATE);
++
++      if (!mdi) {
++              if (verbose)
++                      pr_err("Failed to read sysfs attributes for %s\n", devname);
++              return false;
++      }
++
++      char *avail = xcalloc(array->raid_disks, sizeof(char));
++
++      for (mdi = mdi->devs; mdi; mdi = mdi->next) {
++              if (mdi->disk.raid_disk < 0)
++                      continue;
++              if (!(mdi->disk.state & (1 << MD_DISK_SYNC)))
++                      continue;
++              if (makedev(mdi->disk.major, mdi->disk.minor) == devid)
++                      continue;
++              avail[mdi->disk.raid_disk] = 1;
++      }
++      sysfs_free(mdi);
++
++      bool is_enough = enough(array->level, array->raid_disks,
++                              array->layout, (array->state & 1),
++                              avail);
++
++      free(avail);
++      return is_enough;
++}
++
+ int Manage_subdevs(char *devname, int fd,
+                  struct mddev_dev *devlist, int verbose, int test,
+                  char *update, int force)
+@@ -1598,7 +1642,14 @@ int Manage_subdevs(char *devname, int fd,
+                       break;
+               case 'f': /* set faulty */
+-                      /* FIXME check current member */
++                      if (!is_remove_safe(&array, fd, dv->devname, verbose)) {
++                              pr_err("Cannot remove %s from %s, array will be failed.\n",
++                                     dv->devname, devname);
++                              if (sysfd >= 0)
++                                      close(sysfd);
++                              goto abort;
++                      }
++
+                       if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) ||
+                           (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY,
+                                               rdev))) {
+-- 
+2.38.1
+
diff --git a/0056-Monitor-Fix-statelist-memory-leaks.patch b/0056-Monitor-Fix-statelist-memory-leaks.patch
new file mode 100644 (file)
index 0000000..ad36a25
--- /dev/null
@@ -0,0 +1,112 @@
+From 55c10e4de13abe3e6934895e1fff7d2d20d0b2c2 Mon Sep 17 00:00:00 2001
+From: Pawel Baldysiak <pawel.baldysiak@intel.com>
+Date: Thu, 1 Sep 2022 11:20:31 +0200
+Subject: [PATCH 56/83] Monitor: Fix statelist memory leaks
+
+Free statelist in error path in Monitor initialization.
+
+Signed-off-by: Pawel Baldysiak <pawel.baldysiak@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Monitor.c | 40 +++++++++++++++++++++++++++++++---------
+ 1 file changed, 31 insertions(+), 9 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 93f36ac0..b4e954c6 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -74,6 +74,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
+                         int test, struct alert_info *info);
+ static void try_spare_migration(struct state *statelist, struct alert_info *info);
+ static void link_containers_with_subarrays(struct state *list);
++static void free_statelist(struct state *statelist);
+ #ifndef NO_LIBUDEV
+ static int check_udev_activity(void);
+ #endif
+@@ -128,7 +129,6 @@ int Monitor(struct mddev_dev *devlist,
+        */
+       struct state *statelist = NULL;
+-      struct state *st2;
+       int finished = 0;
+       struct mdstat_ent *mdstat = NULL;
+       char *mailfrom;
+@@ -185,12 +185,14 @@ int Monitor(struct mddev_dev *devlist,
+                               continue;
+                       if (strcasecmp(mdlist->devname, "<ignore>") == 0)
+                               continue;
++                      if (!is_mddev(mdlist->devname)) {
++                              free_statelist(statelist);
++                              return 1;
++                      }
+                       st = xcalloc(1, sizeof *st);
+                       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;
+                       st->devnm[0] = 0;
+                       st->percent = RESYNC_UNKNOWN;
+@@ -206,8 +208,10 @@ int Monitor(struct mddev_dev *devlist,
+               for (dv = devlist; dv; dv = dv->next) {
+                       struct state *st;
+-                      if (!is_mddev(dv->devname))
++                      if (!is_mddev(dv->devname)) {
++                              free_statelist(statelist);
+                               return 1;
++                      }
+                       st = xcalloc(1, sizeof *st);
+                       mdlist = conf_get_ident(dv->devname);
+@@ -294,16 +298,16 @@ int Monitor(struct mddev_dev *devlist,
+               for (stp = &statelist; (st = *stp) != NULL; ) {
+                       if (st->from_auto && st->err > 5) {
+                               *stp = st->next;
+-                              free(st->spare_group);
++                              if (st->spare_group)
++                                      free(st->spare_group);
++
+                               free(st);
+                       } else
+                               stp = &st->next;
+               }
+       }
+-      for (st2 = statelist; st2; st2 = statelist) {
+-              statelist = st2->next;
+-              free(st2);
+-      }
++
++      free_statelist(statelist);
+       if (pidfile)
+               unlink(pidfile);
+@@ -1056,6 +1060,24 @@ static void link_containers_with_subarrays(struct state *list)
+                               }
+ }
++/**
++ * free_statelist() - Frees statelist.
++ * @statelist: statelist to free
++ */
++static void free_statelist(struct state *statelist)
++{
++      struct state *tmp = NULL;
++
++      while (statelist) {
++              if (statelist->spare_group)
++                      free(statelist->spare_group);
++
++              tmp = statelist;
++              statelist = statelist->next;
++              free(tmp);
++      }
++}
++
+ #ifndef NO_LIBUDEV
+ /* function: check_udev_activity
+  * Description: Function waits for udev to finish
+-- 
+2.38.1
+
diff --git a/0057-mdadm-added-support-for-Intel-Alderlake-RST-on-VMD-p.patch b/0057-mdadm-added-support-for-Intel-Alderlake-RST-on-VMD-p.patch
new file mode 100644 (file)
index 0000000..79a3262
--- /dev/null
@@ -0,0 +1,64 @@
+From ea7a02a3294aae223e1329aed5da7f4aa3ac05c5 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Old=C5=99ich=20Jedli=C4=8Dka?= <oldium.pro@gmail.com>
+Date: Wed, 31 Aug 2022 19:57:29 +0200
+Subject: [PATCH 57/83] mdadm: added support for Intel Alderlake RST on VMD
+ platform
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Alderlake RST on VMD uses RstVmdV UEFI variable name, so detect it.
+
+Signed-off-by: Oldřich Jedlička <oldium.pro@gmail.com>
+Reviewed-by: Kinga Tanska <kinga.tanska@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ platform-intel.c | 18 +++++++++++++-----
+ 1 file changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/platform-intel.c b/platform-intel.c
+index 5a8729e7..757f0b1b 100644
+--- a/platform-intel.c
++++ b/platform-intel.c
+@@ -512,7 +512,8 @@ static const struct imsm_orom *find_imsm_hba_orom(struct sys_dev *hba)
+ #define AHCI_PROP "RstSataV"
+ #define AHCI_SSATA_PROP "RstsSatV"
+ #define AHCI_TSATA_PROP "RsttSatV"
+-#define VMD_PROP "RstUefiV"
++#define VROC_VMD_PROP "RstUefiV"
++#define RST_VMD_PROP "RstVmdV"
+ #define VENDOR_GUID \
+       EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6)
+@@ -605,6 +606,7 @@ const struct imsm_orom *find_imsm_efi(struct sys_dev *hba)
+       struct orom_entry *ret;
+       static const char * const sata_efivars[] = {AHCI_PROP, AHCI_SSATA_PROP,
+                                                   AHCI_TSATA_PROP};
++      static const char * const vmd_efivars[] = {VROC_VMD_PROP, RST_VMD_PROP};
+       unsigned long i;
+       if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
+@@ -636,10 +638,16 @@ const struct imsm_orom *find_imsm_efi(struct sys_dev *hba)
+               break;
+       case SYS_DEV_VMD:
+-              if (!read_efi_variable(&orom, sizeof(orom), VMD_PROP,
+-                                     VENDOR_GUID))
+-                      break;
+-              return NULL;
++              for (i = 0; i < ARRAY_SIZE(vmd_efivars); i++) {
++                      if (!read_efi_variable(&orom, sizeof(orom),
++                                              vmd_efivars[i], VENDOR_GUID))
++                              break;
++              }
++
++              if (i == ARRAY_SIZE(vmd_efivars))
++                      return NULL;
++
++              break;
+       default:
+               return NULL;
+       }
+-- 
+2.38.1
+
diff --git a/0058-mdadm-Add-Documentation-entries-to-systemd-services.patch b/0058-mdadm-Add-Documentation-entries-to-systemd-services.patch
new file mode 100644 (file)
index 0000000..6e1a179
--- /dev/null
@@ -0,0 +1,111 @@
+From ea109700563d93704ebdc540c7770d874369f667 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Fri, 9 Sep 2022 15:50:33 +0200
+Subject: [PATCH 58/83] mdadm: Add Documentation entries to systemd services
+
+Add documentation section.
+Copied from Debian.
+
+Cc: Felix Lechner <felix.lechner@lease-up.com>
+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>
+---
+ systemd/mdadm-grow-continue@.service | 1 +
+ systemd/mdadm-last-resort@.service   | 1 +
+ systemd/mdcheck_continue.service     | 3 ++-
+ systemd/mdcheck_start.service        | 1 +
+ systemd/mdmon@.service               | 1 +
+ systemd/mdmonitor-oneshot.service    | 1 +
+ systemd/mdmonitor.service            | 1 +
+ 7 files changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/systemd/mdadm-grow-continue@.service b/systemd/mdadm-grow-continue@.service
+index 9fdc8ec7..64b8254a 100644
+--- a/systemd/mdadm-grow-continue@.service
++++ b/systemd/mdadm-grow-continue@.service
+@@ -8,6 +8,7 @@
+ [Unit]
+ Description=Manage MD Reshape on /dev/%I
+ DefaultDependencies=no
++Documentation=man:mdadm(8)
+ [Service]
+ ExecStart=BINDIR/mdadm --grow --continue /dev/%I
+diff --git a/systemd/mdadm-last-resort@.service b/systemd/mdadm-last-resort@.service
+index efeb3f63..e9381125 100644
+--- a/systemd/mdadm-last-resort@.service
++++ b/systemd/mdadm-last-resort@.service
+@@ -2,6 +2,7 @@
+ Description=Activate md array %I even though degraded
+ DefaultDependencies=no
+ ConditionPathExists=!/sys/devices/virtual/block/%i/md/sync_action
++Documentation=man:mdadm(8)
+ [Service]
+ Type=oneshot
+diff --git a/systemd/mdcheck_continue.service b/systemd/mdcheck_continue.service
+index 854317f1..f5324905 100644
+--- a/systemd/mdcheck_continue.service
++++ b/systemd/mdcheck_continue.service
+@@ -7,7 +7,8 @@
+ [Unit]
+ Description=MD array scrubbing - continuation
+-ConditionPathExistsGlob = /var/lib/mdcheck/MD_UUID_*
++ConditionPathExistsGlob=/var/lib/mdcheck/MD_UUID_*
++Documentation=man:mdadm(8)
+ [Service]
+ Type=oneshot
+diff --git a/systemd/mdcheck_start.service b/systemd/mdcheck_start.service
+index 3bb3d130..703a6583 100644
+--- a/systemd/mdcheck_start.service
++++ b/systemd/mdcheck_start.service
+@@ -8,6 +8,7 @@
+ [Unit]
+ Description=MD array scrubbing
+ Wants=mdcheck_continue.timer
++Documentation=man:mdadm(8)
+ [Service]
+ Type=oneshot
+diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service
+index 77533958..97a1acd9 100644
+--- a/systemd/mdmon@.service
++++ b/systemd/mdmon@.service
+@@ -9,6 +9,7 @@
+ Description=MD Metadata Monitor on /dev/%I
+ DefaultDependencies=no
+ Before=initrd-switch-root.target
++Documentation=man:mdmon(8)
+ [Service]
+ # mdmon should never complain due to lack of a platform,
+diff --git a/systemd/mdmonitor-oneshot.service b/systemd/mdmonitor-oneshot.service
+index 373955a2..ba86b44e 100644
+--- a/systemd/mdmonitor-oneshot.service
++++ b/systemd/mdmonitor-oneshot.service
+@@ -7,6 +7,7 @@
+ [Unit]
+ Description=Reminder for degraded MD arrays
++Documentation=man:mdadm(8)
+ [Service]
+ Environment=MDADM_MONITOR_ARGS=--scan
+diff --git a/systemd/mdmonitor.service b/systemd/mdmonitor.service
+index 46f7b880..9c364785 100644
+--- a/systemd/mdmonitor.service
++++ b/systemd/mdmonitor.service
+@@ -8,6 +8,7 @@
+ [Unit]
+ Description=MD array monitor
+ DefaultDependencies=no
++Documentation=man:mdadm(8)
+ [Service]
+ Environment=  MDADM_MONITOR_ARGS=--scan
+-- 
+2.38.1
+
diff --git a/0059-ReadMe-fix-command-line-help.patch b/0059-ReadMe-fix-command-line-help.patch
new file mode 100644 (file)
index 0000000..837a339
--- /dev/null
@@ -0,0 +1,32 @@
+From f7cbd810b639eb946ba1b3bddb1faefb9696de42 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Fri, 9 Sep 2022 15:50:34 +0200
+Subject: [PATCH 59/83] ReadMe: fix command-line help
+
+Make command-line help consistent with manual page.
+Copied from Debian.
+
+Cc: Felix Lechner <felix.lechner@lease-up.com>
+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>
+---
+ ReadMe.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ReadMe.c b/ReadMe.c
+index 7f94847e..50a5e36d 100644
+--- a/ReadMe.c
++++ b/ReadMe.c
+@@ -477,7 +477,7 @@ char Help_assemble[] =
+ ;
+ char Help_manage[] =
+-"Usage: mdadm arraydevice options component devices...\n"
++"Usage: mdadm [mode] arraydevice [options] <component devices...>\n"
+ "\n"
+ "This usage is for managing the component devices within an array.\n"
+ "The --manage option is not needed and is assumed if the first argument\n"
+-- 
+2.38.1
+
diff --git a/0060-mdadm-replace-container-level-checking-with-inline.patch b/0060-mdadm-replace-container-level-checking-with-inline.patch
new file mode 100644 (file)
index 0000000..7b2b6b2
--- /dev/null
@@ -0,0 +1,257 @@
+From 6f2af6a48c541f207cb727a31fb86de2cd04fc21 Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Fri, 2 Sep 2022 08:49:23 +0200
+Subject: [PATCH 60/83] mdadm: replace container level checking with inline
+
+To unify all containers checks in code, is_container() function is
+added and propagated.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c    |  7 +++----
+ Create.c      |  6 +++---
+ Grow.c        |  6 +++---
+ Incremental.c |  4 ++--
+ mdadm.h       | 14 ++++++++++++++
+ super-ddf.c   |  6 +++---
+ super-intel.c |  4 ++--
+ super0.c      |  2 +-
+ super1.c      |  2 +-
+ sysfs.c       |  2 +-
+ 10 files changed, 33 insertions(+), 20 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index 1dd82a8c..8b0af0c9 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -1120,7 +1120,7 @@ static int start_array(int mdfd,
+                              i/2, mddev);
+       }
+-      if (content->array.level == LEVEL_CONTAINER) {
++      if (is_container(content->array.level)) {
+               sysfs_rules_apply(mddev, content);
+               if (c->verbose >= 0) {
+                       pr_err("Container %s has been assembled with %d drive%s",
+@@ -1549,8 +1549,7 @@ try_again:
+                        */
+                       trustworthy = LOCAL;
+-              if (name[0] == 0 &&
+-                  content->array.level == LEVEL_CONTAINER) {
++              if (!name[0] && is_container(content->array.level)) {
+                       name = content->text_version;
+                       trustworthy = METADATA;
+               }
+@@ -1809,7 +1808,7 @@ try_again:
+               }
+ #endif
+       }
+-      if (c->force && !clean && content->array.level != LEVEL_CONTAINER &&
++      if (c->force && !clean && !is_container(content->array.level) &&
+           !enough(content->array.level, content->array.raid_disks,
+                   content->array.layout, clean, avail)) {
+               change += st->ss->update_super(st, content, "force-array",
+diff --git a/Create.c b/Create.c
+index e06ec2ae..953e7372 100644
+--- a/Create.c
++++ b/Create.c
+@@ -487,7 +487,7 @@ int Create(struct supertype *st, char *mddev,
+                           st->minor_version >= 1)
+                               /* metadata at front */
+                               warn |= check_partitions(fd, dname, 0, 0);
+-                      else if (s->level == 1 || s->level == LEVEL_CONTAINER ||
++                      else if (s->level == 1 || is_container(s->level) ||
+                                (s->level == 0 && s->raiddisks == 1))
+                               /* partitions could be meaningful */
+                               warn |= check_partitions(fd, dname, freesize*2, s->size*2);
+@@ -997,7 +997,7 @@ int Create(struct supertype *st, char *mddev,
+                        * again returns container info.
+                        */
+                       st->ss->getinfo_super(st, &info_new, NULL);
+-                      if (st->ss->external && s->level != LEVEL_CONTAINER &&
++                      if (st->ss->external && !is_container(s->level) &&
+                           !same_uuid(info_new.uuid, info.uuid, 0)) {
+                               map_update(&map, fd2devnm(mdfd),
+                                          info_new.text_version,
+@@ -1040,7 +1040,7 @@ int Create(struct supertype *st, char *mddev,
+       map_unlock(&map);
+       free(infos);
+-      if (s->level == LEVEL_CONTAINER) {
++      if (is_container(s->level)) {
+               /* No need to start.  But we should signal udev to
+                * create links */
+               sysfs_uevent(&info, "change");
+diff --git a/Grow.c b/Grow.c
+index 0f07a894..e362403a 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -2175,7 +2175,7 @@ size_change_error:
+                                       devname, s->size);
+               }
+               changed = 1;
+-      } else if (array.level != LEVEL_CONTAINER) {
++      } else if (!is_container(array.level)) {
+               s->size = get_component_size(fd)/2;
+               if (s->size == 0)
+                       s->size = array.size;
+@@ -2231,7 +2231,7 @@ size_change_error:
+       info.component_size = s->size*2;
+       info.new_level = s->level;
+       info.new_chunk = s->chunk * 1024;
+-      if (info.array.level == LEVEL_CONTAINER) {
++      if (is_container(info.array.level)) {
+               info.delta_disks = UnSet;
+               info.array.raid_disks = s->raiddisks;
+       } else if (s->raiddisks)
+@@ -2344,7 +2344,7 @@ size_change_error:
+                               printf("layout for %s set to %d\n",
+                                      devname, array.layout);
+               }
+-      } else if (array.level == LEVEL_CONTAINER) {
++      } else if (is_container(array.level)) {
+               /* This change is to be applied to every array in the
+                * container.  This is only needed when the metadata imposes
+                * restraints of the various arrays in the container.
+diff --git a/Incremental.c b/Incremental.c
+index 4d0cd9d6..5a5f4c4c 100644
+--- a/Incremental.c
++++ b/Incremental.c
+@@ -244,7 +244,7 @@ int Incremental(struct mddev_dev *devlist, struct context *c,
+               c->autof = ci->autof;
+       name_to_use = info.name;
+-      if (name_to_use[0] == 0 && info.array.level == LEVEL_CONTAINER) {
++      if (name_to_use[0] == 0 && is_container(info.array.level)) {
+               name_to_use = info.text_version;
+               trustworthy = METADATA;
+       }
+@@ -472,7 +472,7 @@ int Incremental(struct mddev_dev *devlist, struct context *c,
+       /* 7/ Is there enough devices to possibly start the array? */
+       /* 7a/ if not, finish with success. */
+-      if (info.array.level == LEVEL_CONTAINER) {
++      if (is_container(info.array.level)) {
+               char devnm[32];
+               /* Try to assemble within the container */
+               sysfs_uevent(sra, "change");
+diff --git a/mdadm.h b/mdadm.h
+index 941a5f38..3673494e 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1924,3 +1924,17 @@ enum r0layout {
+  * This is true for native and DDF, IMSM allows 16.
+  */
+ #define MD_NAME_MAX 32
++
++/**
++ * is_container() - check if @level is &LEVEL_CONTAINER
++ * @level: level value
++ *
++ * return:
++ * 1 if level is equal to &LEVEL_CONTAINER, 0 otherwise.
++ */
++static inline int is_container(const int level)
++{
++      if (level == LEVEL_CONTAINER)
++              return 1;
++      return 0;
++}
+diff --git a/super-ddf.c b/super-ddf.c
+index 949e7d15..9d1e3b94 100644
+--- a/super-ddf.c
++++ b/super-ddf.c
+@@ -3325,7 +3325,7 @@ validate_geometry_ddf_container(struct supertype *st,
+       int fd;
+       unsigned long long ldsize;
+-      if (level != LEVEL_CONTAINER)
++      if (!is_container(level))
+               return 0;
+       if (!dev)
+               return 1;
+@@ -3371,7 +3371,7 @@ static int validate_geometry_ddf(struct supertype *st,
+       if (level == LEVEL_NONE)
+               level = LEVEL_CONTAINER;
+-      if (level == LEVEL_CONTAINER) {
++      if (is_container(level)) {
+               /* Must be a fresh device to add to a container */
+               return validate_geometry_ddf_container(st, level, raiddisks,
+                                                      data_offset, dev,
+@@ -3488,7 +3488,7 @@ static int validate_geometry_ddf_bvd(struct supertype *st,
+       struct dl *dl;
+       unsigned long long maxsize;
+       /* ddf/bvd supports lots of things, but not containers */
+-      if (level == LEVEL_CONTAINER) {
++      if (is_container(level)) {
+               if (verbose)
+                       pr_err("DDF cannot create a container within an container\n");
+               return 0;
+diff --git a/super-intel.c b/super-intel.c
+index 4d82af3d..b0565610 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -6727,7 +6727,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
+       struct intel_super *super = NULL;
+       int rv = 0;
+-      if (level != LEVEL_CONTAINER)
++      if (!is_container(level))
+               return 0;
+       if (!dev)
+               return 1;
+@@ -7692,7 +7692,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+        * if given unused devices create a container
+        * if given given devices in a container create a member volume
+        */
+-      if (level == LEVEL_CONTAINER)
++      if (is_container(level))
+               /* Must be a fresh device to add to a container */
+               return validate_geometry_imsm_container(st, level, raiddisks,
+                                                       data_offset, dev,
+diff --git a/super0.c b/super0.c
+index 37f595ed..93876e2e 100644
+--- a/super0.c
++++ b/super0.c
+@@ -1273,7 +1273,7 @@ static int validate_geometry0(struct supertype *st, int level,
+       if (get_linux_version() < 3001000)
+               tbmax = 2;
+-      if (level == LEVEL_CONTAINER) {
++      if (is_container(level)) {
+               if (verbose)
+                       pr_err("0.90 metadata does not support containers\n");
+               return 0;
+diff --git a/super1.c b/super1.c
+index 58345e68..0b505a7e 100644
+--- a/super1.c
++++ b/super1.c
+@@ -2830,7 +2830,7 @@ static int validate_geometry1(struct supertype *st, int level,
+       unsigned long long overhead;
+       int fd;
+-      if (level == LEVEL_CONTAINER) {
++      if (is_container(level)) {
+               if (verbose)
+                       pr_err("1.x metadata does not support containers\n");
+               return 0;
+diff --git a/sysfs.c b/sysfs.c
+index 0d98a65f..ca1d888f 100644
+--- a/sysfs.c
++++ b/sysfs.c
+@@ -763,7 +763,7 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
+       rv = sysfs_set_num(sra, sd, "offset", sd->data_offset);
+       rv |= sysfs_set_num(sra, sd, "size", (sd->component_size+1) / 2);
+-      if (sra->array.level != LEVEL_CONTAINER) {
++      if (!is_container(sra->array.level)) {
+               if (sra->consistency_policy == CONSISTENCY_POLICY_PPL) {
+                       rv |= sysfs_set_num(sra, sd, "ppl_sector", sd->ppl_sector);
+                       rv |= sysfs_set_num(sra, sd, "ppl_size", sd->ppl_size);
+-- 
+2.38.1
+
diff --git a/0061-Mdmonitor-Omit-non-md-devices.patch b/0061-Mdmonitor-Omit-non-md-devices.patch
new file mode 100644 (file)
index 0000000..062ecdf
--- /dev/null
@@ -0,0 +1,58 @@
+From 8b668d4aa3305af5963162b7499b128bd71f8f29 Mon Sep 17 00:00:00 2001
+From: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Date: Thu, 22 Sep 2022 08:29:50 +0200
+Subject: [PATCH 61/83] Mdmonitor: Omit non-md devices
+
+Fix segfault commit [1] introduced check whether given device is
+mddevice, but it happend to terminate Mdmonitor if at least one of given
+devices didn't fulfill that condition. In result Mdmonitor service was
+no longer started on boot (with --scan option) when config contained some
+non-existent array entry.
+
+This commit introduces ommiting non-md devices so scan option can still
+be used when config is wrong and allow Mdmonitor service to run on boot.
+
+Giving a list of devices to monitor containing non-existing or
+non-md devices will result in monitoring only confirmed mddevices.
+
+[1] https://git.kernel.org/pub/scm/utils/mdadm/mdadm.git/commit/?id=e702f392959d1c2ad2089e595b52235ed97b4e18
+
+Signed-off-by: Lukasz Florczak <lukasz.florczak@linux.intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Monitor.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index b4e954c6..7d7dc4d2 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -185,10 +185,8 @@ int Monitor(struct mddev_dev *devlist,
+                               continue;
+                       if (strcasecmp(mdlist->devname, "<ignore>") == 0)
+                               continue;
+-                      if (!is_mddev(mdlist->devname)) {
+-                              free_statelist(statelist);
+-                              return 1;
+-                      }
++                      if (!is_mddev(mdlist->devname))
++                              continue;
+                       st = xcalloc(1, sizeof *st);
+                       snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"),
+@@ -208,10 +206,8 @@ int Monitor(struct mddev_dev *devlist,
+               for (dv = devlist; dv; dv = dv->next) {
+                       struct state *st;
+-                      if (!is_mddev(dv->devname)) {
+-                              free_statelist(statelist);
+-                              return 1;
+-                      }
++                      if (!is_mddev(dv->devname))
++                              continue;
+                       st = xcalloc(1, sizeof *st);
+                       mdlist = conf_get_ident(dv->devname);
+-- 
+2.38.1
+
diff --git a/0062-Mdmonitor-Split-alert-into-separate-functions.patch b/0062-Mdmonitor-Split-alert-into-separate-functions.patch
new file mode 100644 (file)
index 0000000..c7562e7
--- /dev/null
@@ -0,0 +1,233 @@
+From 3698867194f27fdd7824b8bdd172d619a2c087cc Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Wed, 7 Sep 2022 14:56:49 +0200
+Subject: [PATCH 62/83] Mdmonitor: Split alert() into separate functions
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Monitor.c | 186 ++++++++++++++++++++++++++++--------------------------
+ 1 file changed, 95 insertions(+), 91 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 7d7dc4d2..0036e8cd 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -66,7 +66,7 @@ struct alert_info {
+ static int make_daemon(char *pidfile);
+ static int check_one_sharer(int scan);
+ static void write_autorebuild_pid(void);
+-static void alert(char *event, char *dev, char *disc, struct alert_info *info);
++static void alert(const char *event, const char *dev, const char *disc, struct alert_info *info);
+ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+                      int test, struct alert_info *info,
+                      int increments, char *prefer);
+@@ -407,111 +407,115 @@ static void write_autorebuild_pid()
+       }
+ }
+-static void alert(char *event, char *dev, char *disc, struct alert_info *info)
++static void execute_alert_cmd(const char *event, const char *dev, const char *disc, struct alert_info *info)
++{
++      int pid = fork();
++
++      switch (pid) {
++      default:
++              waitpid(pid, NULL, 0);
++              break;
++      case -1:
++              pr_err("Cannot fork to execute alert command");
++              break;
++      case 0:
++              execl(info->alert_cmd, info->alert_cmd, event, dev, disc, NULL);
++              exit(2);
++      }
++}
++
++static void send_event_email(const char *event, const char *dev, const char *disc, struct alert_info *info)
++{
++      FILE *mp, *mdstat;
++      char hname[256];
++      char buf[BUFSIZ];
++      int n;
++
++      mp = popen(Sendmail, "w");
++      if (!mp) {
++              pr_err("Cannot open pipe stream for sendmail.\n");
++              return;
++      }
++
++      gethostname(hname, sizeof(hname));
++      signal(SIGPIPE, SIG_IGN);
++      if (info->mailfrom)
++              fprintf(mp, "From: %s\n", info->mailfrom);
++      else
++              fprintf(mp, "From: %s monitoring <root>\n", Name);
++      fprintf(mp, "To: %s\n", info->mailaddr);
++      fprintf(mp, "Subject: %s event on %s:%s\n\n", event, dev, hname);
++      fprintf(mp, "This is an automatically generated mail message. \n");
++      fprintf(mp, "A %s event had been detected on md device %s.\n\n", event, dev);
++
++      if (disc && disc[0] != ' ')
++              fprintf(mp,
++                      "It could be related to component device %s.\n\n", disc);
++      if (disc && disc[0] == ' ')
++              fprintf(mp, "Extra information:%s.\n\n", disc);
++
++      mdstat = fopen("/proc/mdstat", "r");
++      if (!mdstat) {
++              pr_err("Cannot open /proc/mdstat\n");
++              pclose(mp);
++              return;
++      }
++
++      fprintf(mp, "The /proc/mdstat file currently contains the following:\n\n");
++      while ((n = fread(buf, 1, sizeof(buf), mdstat)) > 0)
++              n = fwrite(buf, 1, n, mp);
++      fclose(mdstat);
++      pclose(mp);
++}
++
++static void log_event_to_syslog(const char *event, const char *dev, const char *disc)
+ {
+       int priority;
++      /* Log at a different severity depending on the event.
++       *
++       * These are the critical events:  */
++      if (strncmp(event, "Fail", 4) == 0 ||
++              strncmp(event, "Degrade", 7) == 0 ||
++              strncmp(event, "DeviceDisappeared", 17) == 0)
++              priority = LOG_CRIT;
++      /* Good to know about, but are not failures: */
++      else if (strncmp(event, "Rebuild", 7) == 0 ||
++                      strncmp(event, "MoveSpare", 9) == 0 ||
++                      strncmp(event, "Spares", 6) != 0)
++              priority = LOG_WARNING;
++      /* Everything else: */
++      else
++              priority = LOG_INFO;
++      if (disc && disc[0] != ' ')
++              syslog(priority,
++                      "%s event detected on md device %s, component device %s", event, dev, disc);
++      else if (disc)
++              syslog(priority, "%s event detected on md device %s: %s", event, dev, disc);
++      else
++              syslog(priority, "%s event detected on md device %s", event, dev);
++}
++
++static void alert(const char *event, const char *dev, const char *disc, struct alert_info *info)
++{
+       if (!info->alert_cmd && !info->mailaddr && !info->dosyslog) {
+               time_t now = time(0);
+               printf("%1.15s: %s on %s %s\n", ctime(&now) + 4,
+                      event, dev, disc?disc:"unknown device");
+       }
+-      if (info->alert_cmd) {
+-              int pid = fork();
+-              switch(pid) {
+-              default:
+-                      waitpid(pid, NULL, 0);
+-                      break;
+-              case -1:
+-                      break;
+-              case 0:
+-                      execl(info->alert_cmd, info->alert_cmd,
+-                            event, dev, disc, NULL);
+-                      exit(2);
+-              }
+-      }
++      if (info->alert_cmd)
++              execute_alert_cmd(event, dev, disc, info);
++
+       if (info->mailaddr && (strncmp(event, "Fail", 4) == 0 ||
+                              strncmp(event, "Test", 4) == 0 ||
+                              strncmp(event, "Spares", 6) == 0 ||
+                              strncmp(event, "Degrade", 7) == 0)) {
+-              FILE *mp = popen(Sendmail, "w");
+-              if (mp) {
+-                      FILE *mdstat;
+-                      char hname[256];
+-
+-                      gethostname(hname, sizeof(hname));
+-                      signal_s(SIGPIPE, SIG_IGN);
+-
+-                      if (info->mailfrom)
+-                              fprintf(mp, "From: %s\n", info->mailfrom);
+-                      else
+-                              fprintf(mp, "From: %s monitoring <root>\n",
+-                                      Name);
+-                      fprintf(mp, "To: %s\n", info->mailaddr);
+-                      fprintf(mp, "Subject: %s event on %s:%s\n\n",
+-                              event, dev, hname);
+-
+-                      fprintf(mp,
+-                              "This is an automatically generated mail message from %s\n", Name);
+-                      fprintf(mp, "running on %s\n\n", hname);
+-
+-                      fprintf(mp,
+-                              "A %s event had been detected on md device %s.\n\n", event, dev);
+-
+-                      if (disc && disc[0] != ' ')
+-                              fprintf(mp,
+-                                      "It could be related to component device %s.\n\n", disc);
+-                      if (disc && disc[0] == ' ')
+-                              fprintf(mp, "Extra information:%s.\n\n", disc);
+-
+-                      fprintf(mp, "Faithfully yours, etc.\n");
+-
+-                      mdstat = fopen("/proc/mdstat", "r");
+-                      if (mdstat) {
+-                              char buf[8192];
+-                              int n;
+-                              fprintf(mp,
+-                                      "\nP.S. The /proc/mdstat file currently contains the following:\n\n");
+-                              while ((n = fread(buf, 1, sizeof(buf),
+-                                                mdstat)) > 0)
+-                                      n = fwrite(buf, 1, n, mp);
+-                              fclose(mdstat);
+-                      }
+-                      pclose(mp);
+-              }
++              send_event_email(event, dev, disc, info);
+       }
+-      /* log the event to syslog maybe */
+-      if (info->dosyslog) {
+-              /* Log at a different severity depending on the event.
+-               *
+-               * These are the critical events:  */
+-              if (strncmp(event, "Fail", 4) == 0 ||
+-                  strncmp(event, "Degrade", 7) == 0 ||
+-                  strncmp(event, "DeviceDisappeared", 17) == 0)
+-                      priority = LOG_CRIT;
+-              /* Good to know about, but are not failures: */
+-              else if (strncmp(event, "Rebuild", 7) == 0 ||
+-                       strncmp(event, "MoveSpare", 9) == 0 ||
+-                       strncmp(event, "Spares", 6) != 0)
+-                      priority = LOG_WARNING;
+-              /* Everything else: */
+-              else
+-                      priority = LOG_INFO;
+-
+-              if (disc && disc[0] != ' ')
+-                      syslog(priority,
+-                             "%s event detected on md device %s, component device %s", event, dev, disc);
+-              else if (disc)
+-                      syslog(priority,
+-                             "%s event detected on md device %s: %s",
+-                             event, dev, disc);
+-              else
+-                      syslog(priority,
+-                             "%s event detected on md device %s",
+-                             event, dev);
+-      }
++      if (info->dosyslog)
++              log_event_to_syslog(event, dev, disc);
+ }
+ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+-- 
+2.38.1
+
diff --git a/0063-Monitor-block-if-monitor-modes-are-combined.patch b/0063-Monitor-block-if-monitor-modes-are-combined.patch
new file mode 100644 (file)
index 0000000..d993d9d
--- /dev/null
@@ -0,0 +1,41 @@
+From f40ac0e7e6043361ad12e9db97c07e56c3977cf6 Mon Sep 17 00:00:00 2001
+From: Blazej Kucman <blazej.kucman@intel.com>
+Date: Mon, 19 Dec 2022 11:21:57 +0100
+Subject: [PATCH 63/83] Monitor: block if monitor modes are combined.
+
+Block monitoring start if --scan mode and MD devices list are combined.
+
+Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Monitor.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 0036e8cd..188cb8be 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -123,7 +123,7 @@ int Monitor(struct mddev_dev *devlist,
+        *  and if we can get_disk_info and find a name
+        *  Then we hot-remove and hot-add to the other array
+        *
+-       * If devlist is NULL, then we can monitor everything because --scan
++       * If devlist is NULL, then we can monitor everything if --scan
+        * was given.  We get an initial list from config file and add anything
+        * that appears in /proc/mdstat
+        */
+@@ -136,6 +136,11 @@ int Monitor(struct mddev_dev *devlist,
+       struct mddev_ident *mdlist;
+       int delay_for_event = c->delay;
++      if (devlist && c->scan) {
++              pr_err("Devices list and --scan option cannot be combined - not monitoring.\n");
++              return 1;
++      }
++
+       if (!mailaddr)
+               mailaddr = conf_get_mailaddr();
+-- 
+2.38.1
+
diff --git a/0064-Update-mdadm-Monitor-manual.patch b/0064-Update-mdadm-Monitor-manual.patch
new file mode 100644 (file)
index 0000000..15f52e1
--- /dev/null
@@ -0,0 +1,119 @@
+From 725e37cd14866906ba28c970394b9f7a4cd97413 Mon Sep 17 00:00:00 2001
+From: Blazej Kucman <blazej.kucman@intel.com>
+Date: Mon, 19 Dec 2022 11:21:58 +0100
+Subject: [PATCH 64/83] Update mdadm Monitor manual.
+
+- describe monitor work modes,
+- clarify the turning off condition,
+- describe the mdmonitor.service as a prefered management way.
+
+Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ mdadm.8.in | 71 ++++++++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 50 insertions(+), 21 deletions(-)
+
+diff --git a/mdadm.8.in b/mdadm.8.in
+index 70c79d1e..64f71ed1 100644
+--- a/mdadm.8.in
++++ b/mdadm.8.in
+@@ -2548,13 +2548,33 @@ Usage:
+ .I options... devices...
+ .PP
+-This usage causes
++Monitor option can work in two modes:
++.IP \(bu 4
++system wide mode, follow all md devices based on
++.B /proc/mdstat,
++.IP \(bu 4
++follow only specified MD devices in command line.
++.PP
++
++.B \-\-scan -
++indicates system wide mode. Option causes the
++.I monitor
++to track all md devices that appear in
++.B /proc/mdstat.
++If it is not set, then at least one
++.B device
++must be specified.
++
++Monitor usage causes
+ .I mdadm
+ to periodically poll a number of md arrays and to report on any events
+ noticed.
+-.I mdadm
+-will never exit once it decides that there are arrays to be checked,
+-so it should normally be run in the background.
++
++In both modes,
++.I monitor
++will work as long as there is an active array with redundancy and it is defined to follow (for
++.B \-\-scan
++every array is followed).
+ As well as reporting events,
+ .I mdadm
+@@ -2565,15 +2585,6 @@ or
+ .B domain
+ and if the destination array has a failed drive but no spares.
+-If any devices are listed on the command line,
+-.I mdadm
+-will only monitor those devices, otherwise, all arrays listed in the
+-configuration file will be monitored.  Further, if
+-.B \-\-scan
+-is given, then any other md devices that appear in
+-.B /proc/mdstat
+-will also be monitored.
+-
+ The result of monitoring the arrays is the generation of events.
+ These events are passed to a separate program (if specified) and may
+ be mailed to a given E-mail address.
+@@ -2586,16 +2597,34 @@ device if relevant (such as a component device that has failed).
+ If
+ .B \-\-scan
+-is given, then a program or an E-mail address must be specified on the
+-command line or in the config file.  If neither are available, then
++is given, then a
++.B program
++or an
++.B e-mail
++address must be specified on the
++command line or in the config file. If neither are available, then
+ .I mdadm
+ will not monitor anything.
+-Without
+-.B \-\-scan,
+-.I mdadm
+-will continue monitoring as long as something was found to monitor.  If
+-no program or email is given, then each event is reported to
+-.BR stdout .
++For devices given directly in command line, without
++.B program
++or
++.B email
++specified, each event is reported to
++.BR stdout.
++
++Note: For systems where
++.If mdadm monitor
++is configured via systemd,
++.B mdmonitor(mdmonitor.service)
++should be configured. The service is designed to be primary solution for array monitoring,
++it is configured to work in system wide mode.
++It is automatically started and stopped according to current state and types of MD arrays in system.
++The service may require additional configuration, like
++.B e-mail
++or
++.B delay.
++That should be done in
++.B mdadm.conf.
+ The different events are:
+-- 
+2.38.1
+
diff --git a/0065-Grow-fix-possible-memory-leak.patch b/0065-Grow-fix-possible-memory-leak.patch
new file mode 100644 (file)
index 0000000..07d9fb6
--- /dev/null
@@ -0,0 +1,38 @@
+From 434b3b9bb96a76dc12f693b64cf23b581781e20b Mon Sep 17 00:00:00 2001
+From: Blazej Kucman <blazej.kucman@intel.com>
+Date: Tue, 20 Dec 2022 12:07:51 +0100
+Subject: [PATCH 65/83] Grow: fix possible memory leak.
+
+Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Grow.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/Grow.c b/Grow.c
+index e362403a..b73ec2ae 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -432,6 +432,7 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
+                       if (((disk.state & (1 << MD_DISK_WRITEMOSTLY)) == 0) &&
+                          (strcmp(s->bitmap_file, "clustered") == 0)) {
+                               pr_err("%s disks marked write-mostly are not supported with clustered bitmap\n",devname);
++                              free(mdi);
+                               return 1;
+                       }
+                       fd2 = dev_open(dv, O_RDWR);
+@@ -453,8 +454,10 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
+                               pr_err("failed to load super-block.\n");
+                       }
+                       close(fd2);
+-                      if (rv)
++                      if (rv) {
++                              free(mdi);
+                               return 1;
++                      }
+               }
+               if (offset_setable) {
+                       st->ss->getinfo_super(st, mdi, NULL);
+-- 
+2.38.1
+
diff --git a/0066-mdadm-create-ident_init.patch b/0066-mdadm-create-ident_init.patch
new file mode 100644 (file)
index 0000000..32d374b
--- /dev/null
@@ -0,0 +1,148 @@
+From 7fcbfd7c620e2dcd3b539d18e93cb503ee3a8a62 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Wed, 21 Dec 2022 12:50:17 +0100
+Subject: [PATCH 66/83] mdadm: create ident_init()
+
+Add a wrapper for repeated initializations in mdadm.c and config.c.
+Move includes up.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ config.c | 45 +++++++++++++++++++++++++++++----------------
+ mdadm.c  | 16 ++--------------
+ mdadm.h  |  7 +++++--
+ 3 files changed, 36 insertions(+), 32 deletions(-)
+
+diff --git a/config.c b/config.c
+index dc1620c1..eeedd0c6 100644
+--- a/config.c
++++ b/config.c
+@@ -119,6 +119,34 @@ int match_keyword(char *word)
+       return -1;
+ }
++/**
++ * ident_init() - Set defaults.
++ * @ident: ident pointer, not NULL.
++ */
++inline void ident_init(struct mddev_ident *ident)
++{
++      assert(ident);
++
++      ident->assembled = false;
++      ident->autof = 0;
++      ident->bitmap_fd = -1;
++      ident->bitmap_file = NULL;
++      ident->container = NULL;
++      ident->devices = NULL;
++      ident->devname = NULL;
++      ident->level = UnSet;
++      ident->member = NULL;
++      ident->name[0] = 0;
++      ident->next = NULL;
++      ident->raid_disks = UnSet;
++      ident->spare_group = NULL;
++      ident->spare_disks = 0;
++      ident->st = NULL;
++      ident->super_minor = UnSet;
++      ident->uuid[0] = 0;
++      ident->uuid_set = 0;
++}
++
+ struct conf_dev {
+       struct conf_dev *next;
+       char *name;
+@@ -363,22 +391,7 @@ void arrayline(char *line)
+       struct mddev_ident mis;
+       struct mddev_ident *mi;
+-      mis.uuid_set = 0;
+-      mis.super_minor = UnSet;
+-      mis.level = UnSet;
+-      mis.raid_disks = UnSet;
+-      mis.spare_disks = 0;
+-      mis.devices = NULL;
+-      mis.devname = NULL;
+-      mis.spare_group = NULL;
+-      mis.autof = 0;
+-      mis.next = NULL;
+-      mis.st = NULL;
+-      mis.bitmap_fd = -1;
+-      mis.bitmap_file = NULL;
+-      mis.name[0] = 0;
+-      mis.container = NULL;
+-      mis.member = NULL;
++      ident_init(&mis);
+       for (w = dl_next(line); w != line; w = dl_next(w)) {
+               if (w[0] == '/' || strchr(w, '=') == NULL) {
+diff --git a/mdadm.c b/mdadm.c
+index 972adb52..74fdec31 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -107,25 +107,13 @@ int main(int argc, char *argv[])
+       srandom(time(0) ^ getpid());
+-      ident.uuid_set = 0;
+-      ident.level = UnSet;
+-      ident.raid_disks = UnSet;
+-      ident.super_minor = UnSet;
+-      ident.devices = 0;
+-      ident.spare_group = NULL;
+-      ident.autof = 0;
+-      ident.st = NULL;
+-      ident.bitmap_fd = -1;
+-      ident.bitmap_file = NULL;
+-      ident.name[0] = 0;
+-      ident.container = NULL;
+-      ident.member = NULL;
+-
+       if (get_linux_version() < 2006015) {
+               pr_err("This version of mdadm does not support kernels older than 2.6.15\n");
+               exit(1);
+       }
++      ident_init(&ident);
++
+       while ((option_index = -1),
+              (opt = getopt_long(argc, argv, shortopt, long_options,
+                                 &option_index)) != -1) {
+diff --git a/mdadm.h b/mdadm.h
+index 3673494e..23ffe977 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -33,8 +33,10 @@ extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
+ # endif
+ #endif
++#include      <assert.h>
+ #include      <sys/types.h>
+ #include      <sys/stat.h>
++#include      <stdarg.h>
+ #include      <stdint.h>
+ #include      <stdlib.h>
+ #include      <time.h>
+@@ -1552,6 +1554,8 @@ extern void enable_fds(int devices);
+ extern void manage_fork_fds(int close_all);
+ extern int continue_via_systemd(char *devnm, char *service_name);
++extern void ident_init(struct mddev_ident *ident);
++
+ extern int parse_auto(char *str, char *msg, int config);
+ extern struct mddev_ident *conf_get_ident(char *dev);
+ extern struct mddev_dev *conf_get_devs(void);
+@@ -1779,8 +1783,7 @@ static inline sighandler_t signal_s(int sig, sighandler_t handler)
+ #define dprintf_cont(fmt, arg...) \
+         ({ if (0) fprintf(stderr, fmt, ##arg); 0; })
+ #endif
+-#include <assert.h>
+-#include <stdarg.h>
++
+ static inline int xasprintf(char **strp, const char *fmt, ...) {
+       va_list ap;
+       int ret;
+-- 
+2.38.1
+
diff --git a/0067-mdadm-Add-option-validation-for-update-subarray.patch b/0067-mdadm-Add-option-validation-for-update-subarray.patch
new file mode 100644 (file)
index 0000000..faa7113
--- /dev/null
@@ -0,0 +1,287 @@
+From 2568ce89ea5c26225e8984733adc2ea7559d853a Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:35:15 +0100
+Subject: [PATCH 67/83] mdadm: Add option validation for --update-subarray
+
+Subset of options available for "--update" is not same as for "--update-subarray".
+Define maps and enum for update options and use them instead of direct comparisons.
+Add proper error message.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ ReadMe.c |  31 +++++++++++++++++
+ maps.c   |  31 +++++++++++++++++
+ mdadm.c  | 104 +++++++++++++++++--------------------------------------
+ mdadm.h  |  32 ++++++++++++++++-
+ 4 files changed, 124 insertions(+), 74 deletions(-)
+
+diff --git a/ReadMe.c b/ReadMe.c
+index 50a5e36d..bd8d50d2 100644
+--- a/ReadMe.c
++++ b/ReadMe.c
+@@ -655,3 +655,34 @@ char *mode_help[mode_count] = {
+       [GROW]          = Help_grow,
+       [INCREMENTAL]   = Help_incr,
+ };
++
++/**
++ * fprint_update_options() - Print valid update options depending on the mode.
++ * @outf: File (output stream)
++ * @update_mode: Used to distinguish update and update_subarray
++ */
++void fprint_update_options(FILE *outf, enum update_opt update_mode)
++{
++      int counter = UOPT_NAME, breakpoint = UOPT_HELP;
++      mapping_t *map = update_options;
++
++      if (!outf)
++              return;
++      if (update_mode == UOPT_SUBARRAY_ONLY) {
++              breakpoint = UOPT_SUBARRAY_ONLY;
++              fprintf(outf, "Valid --update options for update-subarray are:\n\t");
++      } else
++              fprintf(outf, "Valid --update options are:\n\t");
++      while (map->num) {
++              if (map->num >= breakpoint)
++                      break;
++              fprintf(outf, "'%s', ", map->name);
++              if (counter % 5 == 0)
++                      fprintf(outf, "\n\t");
++              counter++;
++              map++;
++      }
++      if ((counter - 1) % 5)
++              fprintf(outf, "\n");
++      fprintf(outf, "\r");
++}
+diff --git a/maps.c b/maps.c
+index 20fcf719..b586679a 100644
+--- a/maps.c
++++ b/maps.c
+@@ -165,6 +165,37 @@ mapping_t sysfs_array_states[] = {
+       { "broken", ARRAY_BROKEN },
+       { NULL, ARRAY_UNKNOWN_STATE }
+ };
++/**
++ * mapping_t update_options - stores supported update options.
++ */
++mapping_t update_options[] = {
++      { "name", UOPT_NAME },
++      { "ppl", UOPT_PPL },
++      { "no-ppl", UOPT_NO_PPL },
++      { "bitmap", UOPT_BITMAP },
++      { "no-bitmap", UOPT_NO_BITMAP },
++      { "sparc2.2", UOPT_SPARC22 },
++      { "super-minor", UOPT_SUPER_MINOR },
++      { "summaries", UOPT_SUMMARIES },
++      { "resync", UOPT_RESYNC },
++      { "uuid", UOPT_UUID },
++      { "homehost", UOPT_HOMEHOST },
++      { "home-cluster", UOPT_HOME_CLUSTER },
++      { "nodes", UOPT_NODES },
++      { "devicesize", UOPT_DEVICESIZE },
++      { "bbl", UOPT_BBL },
++      { "no-bbl", UOPT_NO_BBL },
++      { "force-no-bbl", UOPT_FORCE_NO_BBL },
++      { "metadata", UOPT_METADATA },
++      { "revert-reshape", UOPT_REVERT_RESHAPE },
++      { "layout-original", UOPT_LAYOUT_ORIGINAL },
++      { "layout-alternate", UOPT_LAYOUT_ALTERNATE },
++      { "layout-unspecified", UOPT_LAYOUT_UNSPECIFIED },
++      { "byteorder", UOPT_BYTEORDER },
++      { "help", UOPT_HELP },
++      { "?", UOPT_HELP },
++      { NULL, UOPT_UNDEFINED}
++};
+ /**
+  * map_num_s() - Safer alternative of map_num() function.
+diff --git a/mdadm.c b/mdadm.c
+index 74fdec31..f5f505fe 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -100,7 +100,7 @@ int main(int argc, char *argv[])
+       char *dump_directory = NULL;
+       int print_help = 0;
+-      FILE *outf;
++      FILE *outf = NULL;
+       int mdfd = -1;
+       int locked = 0;
+@@ -723,7 +723,11 @@ int main(int argc, char *argv[])
+                       continue;
+               case O(ASSEMBLE,'U'): /* update the superblock */
+-              case O(MISC,'U'):
++              case O(MISC,'U'): {
++                      enum update_opt updateopt = map_name(update_options, c.update);
++                      enum update_opt print_mode = UOPT_HELP;
++                      const char *error_addon = "update option";
++
+                       if (c.update) {
+                               pr_err("Can only update one aspect of superblock, both %s and %s given.\n",
+                                       c.update, optarg);
+@@ -733,83 +737,37 @@ int main(int argc, char *argv[])
+                               pr_err("Only subarrays can be updated in misc mode\n");
+                               exit(2);
+                       }
++
+                       c.update = optarg;
+-                      if (strcmp(c.update, "sparc2.2") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "super-minor") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "summaries") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "resync") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "uuid") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "name") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "homehost") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "home-cluster") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "nodes") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "devicesize") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "bitmap") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "no-bitmap") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "bbl") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "no-bbl") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "force-no-bbl") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "ppl") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "no-ppl") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "metadata") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "revert-reshape") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "layout-original") == 0 ||
+-                          strcmp(c.update, "layout-alternate") == 0 ||
+-                          strcmp(c.update, "layout-unspecified") == 0)
+-                              continue;
+-                      if (strcmp(c.update, "byteorder") == 0) {
++
++                      if (devmode == UpdateSubarray) {
++                              print_mode = UOPT_SUBARRAY_ONLY;
++                              error_addon = "update-subarray option";
++
++                              if (updateopt > UOPT_SUBARRAY_ONLY && updateopt < UOPT_HELP)
++                                      updateopt = UOPT_UNDEFINED;
++                      }
++
++                      switch (updateopt) {
++                      case UOPT_UNDEFINED:
++                              pr_err("'--update=%s' is invalid %s. ",
++                                      c.update, error_addon);
++                              outf = stderr;
++                      case UOPT_HELP:
++                              if (!outf)
++                                      outf = stdout;
++                              fprint_update_options(outf, print_mode);
++                              exit(outf == stdout ? 0 : 2);
++                      case UOPT_BYTEORDER:
+                               if (ss) {
+                                       pr_err("must not set metadata type with --update=byteorder.\n");
+                                       exit(2);
+                               }
+-                              for(i = 0; !ss && superlist[i]; i++)
+-                                      ss = superlist[i]->match_metadata_desc(
+-                                              "0.swap");
+-                              if (!ss) {
+-                                      pr_err("INTERNAL ERROR cannot find 0.swap\n");
+-                                      exit(2);
+-                              }
+-
+-                              continue;
++                      default:
++                              break;
+                       }
+-                      if (strcmp(c.update,"?") == 0 ||
+-                          strcmp(c.update, "help") == 0) {
+-                              outf = stdout;
+-                              fprintf(outf, "%s: ", Name);
+-                      } else {
+-                              outf = stderr;
+-                              fprintf(outf,
+-                                      "%s: '--update=%s' is invalid.  ",
+-                                      Name, c.update);
+-                      }
+-                      fprintf(outf, "Valid --update options are:\n"
+-              "     'sparc2.2', 'super-minor', 'uuid', 'name', 'nodes', 'resync',\n"
+-              "     'summaries', 'homehost', 'home-cluster', 'byteorder', 'devicesize',\n"
+-              "     'bitmap', 'no-bitmap', 'metadata', 'revert-reshape'\n"
+-              "     'bbl', 'no-bbl', 'force-no-bbl', 'ppl', 'no-ppl'\n"
+-              "     'layout-original', 'layout-alternate', 'layout-unspecified'\n"
+-                              );
+-                      exit(outf == stdout ? 0 : 2);
+-
++                      continue;
++              }
+               case O(MANAGE,'U'):
+                       /* update=devicesize is allowed with --re-add */
+                       if (devmode != 'A') {
+diff --git a/mdadm.h b/mdadm.h
+index 23ffe977..51f1db2d 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -497,6 +497,36 @@ enum special_options {
+       ConsistencyPolicy,
+ };
++enum update_opt {
++      UOPT_NAME = 1,
++      UOPT_PPL,
++      UOPT_NO_PPL,
++      UOPT_BITMAP,
++      UOPT_NO_BITMAP,
++      UOPT_SUBARRAY_ONLY,
++      UOPT_SPARC22,
++      UOPT_SUPER_MINOR,
++      UOPT_SUMMARIES,
++      UOPT_RESYNC,
++      UOPT_UUID,
++      UOPT_HOMEHOST,
++      UOPT_HOME_CLUSTER,
++      UOPT_NODES,
++      UOPT_DEVICESIZE,
++      UOPT_BBL,
++      UOPT_NO_BBL,
++      UOPT_FORCE_NO_BBL,
++      UOPT_METADATA,
++      UOPT_REVERT_RESHAPE,
++      UOPT_LAYOUT_ORIGINAL,
++      UOPT_LAYOUT_ALTERNATE,
++      UOPT_LAYOUT_UNSPECIFIED,
++      UOPT_BYTEORDER,
++      UOPT_HELP,
++      UOPT_UNDEFINED
++};
++extern void fprint_update_options(FILE *outf, enum update_opt update_mode);
++
+ enum prefix_standard {
+       JEDEC,
+       IEC
+@@ -777,7 +807,7 @@ extern char *map_num(mapping_t *map, int num);
+ extern int map_name(mapping_t *map, char *name);
+ extern mapping_t r0layout[], r5layout[], r6layout[],
+       pers[], modes[], faultylayout[];
+-extern mapping_t consistency_policies[], sysfs_array_states[];
++extern mapping_t consistency_policies[], sysfs_array_states[], update_options[];
+ extern char *map_dev_preferred(int major, int minor, int create,
+                              char *prefer);
+-- 
+2.38.1
+
diff --git a/0068-Fix-update-subarray-on-active-volume.patch b/0068-Fix-update-subarray-on-active-volume.patch
new file mode 100644 (file)
index 0000000..7c1c4bc
--- /dev/null
@@ -0,0 +1,54 @@
+From db10eab68e652f141169b7240e057d110d626c3d Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:35:16 +0100
+Subject: [PATCH 68/83] Fix --update-subarray on active volume
+
+Options: bitmap, ppl and name should not be updated when array is active.
+Those features are mutually exclusive and share the same data area in IMSM (danger of overwriting by kernel).
+Remove check for active subarrays from super-intel.
+Since ddf is not supported, apply it globally for all options.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Manage.c      | 7 +++++++
+ super-intel.c | 5 -----
+ 2 files changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/Manage.c b/Manage.c
+index b1d0e630..5a9ea316 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -1745,6 +1745,13 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident
+               goto free_super;
+       }
++      if (is_subarray_active(subarray, st->devnm)) {
++              if (verbose >= 0)
++                      pr_err("Subarray %s in %s is active, cannot update %s\n",
++                             subarray, dev, update);
++              goto free_super;
++      }
++
+       if (mdmon_running(st->devnm))
+               st->update_tail = &st->updates;
+diff --git a/super-intel.c b/super-intel.c
+index b0565610..5f93f3d3 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -7914,11 +7914,6 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
+               char *ep;
+               int vol;
+-              if (is_subarray_active(subarray, st->devnm)) {
+-                      pr_err("Unable to update name of active subarray\n");
+-                      return 2;
+-              }
+-
+               if (!check_name(super, name, 0))
+                       return 2;
+-- 
+2.38.1
+
diff --git a/0069-Add-code-specific-update-options-to-enum.patch b/0069-Add-code-specific-update-options-to-enum.patch
new file mode 100644 (file)
index 0000000..57386f5
--- /dev/null
@@ -0,0 +1,77 @@
+From 2257de106cbf17a7f1df33a10cfd2be0d5a064cb Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:35:17 +0100
+Subject: [PATCH 69/83] Add code specific update options to enum.
+
+Some of update options aren't taken from user input, but are hard-coded
+as strings.
+Include those options in enum.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ maps.c  | 21 +++++++++++++++++++++
+ mdadm.h | 15 +++++++++++++++
+ 2 files changed, 36 insertions(+)
+
+diff --git a/maps.c b/maps.c
+index b586679a..c59036f1 100644
+--- a/maps.c
++++ b/maps.c
+@@ -194,6 +194,27 @@ mapping_t update_options[] = {
+       { "byteorder", UOPT_BYTEORDER },
+       { "help", UOPT_HELP },
+       { "?", UOPT_HELP },
++      /*
++       * Those enries are temporary and will be removed in this patchset.
++       *
++       * Before update_super:update can be changed to enum,
++       * all update_super sub-functions must be adapted first.
++       * Update options will be passed as string (as it is for now),
++       * and then mapped, so all options must be handled temporarily.
++       *
++       * Those options code specific and should not be accessible for user.
++       */
++      { "force-one", UOPT_SPEC_FORCE_ONE },
++      { "force-array", UOPT_SPEC_FORCE_ARRAY },
++      { "assemble", UOPT_SPEC_ASSEMBLE },
++      { "linear-grow-new", UOPT_SPEC_LINEAR_GROW_NEW },
++      { "linear-grow-update", UOPT_SPEC_LINEAR_GROW_UPDATE },
++      { "_reshape_progress", UOPT_SPEC__RESHAPE_PROGRESS },
++      { "writemostly", UOPT_SPEC_WRITEMOSTLY },
++      { "readwrite", UOPT_SPEC_READWRITE },
++      { "failfast", UOPT_SPEC_FAILFAST },
++      { "nofailfast", UOPT_SPEC_NOFAILFAST },
++      { "revert-reshape-nobackup", UOPT_SPEC_REVERT_RESHAPE_NOBACKUP },
+       { NULL, UOPT_UNDEFINED}
+ };
+diff --git a/mdadm.h b/mdadm.h
+index 51f1db2d..31db25f5 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -523,6 +523,21 @@ enum update_opt {
+       UOPT_LAYOUT_UNSPECIFIED,
+       UOPT_BYTEORDER,
+       UOPT_HELP,
++      UOPT_USER_ONLY,
++      /*
++       * Code specific options, cannot be set by the user
++       */
++      UOPT_SPEC_FORCE_ONE,
++      UOPT_SPEC_FORCE_ARRAY,
++      UOPT_SPEC_ASSEMBLE,
++      UOPT_SPEC_LINEAR_GROW_NEW,
++      UOPT_SPEC_LINEAR_GROW_UPDATE,
++      UOPT_SPEC__RESHAPE_PROGRESS,
++      UOPT_SPEC_WRITEMOSTLY,
++      UOPT_SPEC_READWRITE,
++      UOPT_SPEC_FAILFAST,
++      UOPT_SPEC_NOFAILFAST,
++      UOPT_SPEC_REVERT_RESHAPE_NOBACKUP,
+       UOPT_UNDEFINED
+ };
+ extern void fprint_update_options(FILE *outf, enum update_opt update_mode);
+-- 
+2.38.1
+
diff --git a/0070-super-ddf-Remove-update_super_ddf.patch b/0070-super-ddf-Remove-update_super_ddf.patch
new file mode 100644 (file)
index 0000000..7a6d213
--- /dev/null
@@ -0,0 +1,106 @@
+From 35aa44c549290e22f285896684c704acb53b7717 Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:35:18 +0100
+Subject: [PATCH 70/83] super-ddf: Remove update_super_ddf.
+
+This is not supported by ddf.
+It hides errors by returning success status for some updates.
+Remove update_super_dff().
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super-ddf.c | 70 -----------------------------------------------------
+ 1 file changed, 70 deletions(-)
+
+diff --git a/super-ddf.c b/super-ddf.c
+index 9d1e3b94..309812df 100644
+--- a/super-ddf.c
++++ b/super-ddf.c
+@@ -2139,75 +2139,6 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info, cha
+               }
+ }
+-static int update_super_ddf(struct supertype *st, struct mdinfo *info,
+-                          char *update,
+-                          char *devname, int verbose,
+-                          int uuid_set, char *homehost)
+-{
+-      /* For 'assemble' and 'force' we need to return non-zero if any
+-       * change was made.  For others, the return value is ignored.
+-       * Update options are:
+-       *  force-one : This device looks a bit old but needs to be included,
+-       *        update age info appropriately.
+-       *  assemble: clear any 'faulty' flag to allow this device to
+-       *              be assembled.
+-       *  force-array: Array is degraded but being forced, mark it clean
+-       *         if that will be needed to assemble it.
+-       *
+-       *  newdev:  not used ????
+-       *  grow:  Array has gained a new device - this is currently for
+-       *              linear only
+-       *  resync: mark as dirty so a resync will happen.
+-       *  uuid:  Change the uuid of the array to match what is given
+-       *  homehost:  update the recorded homehost
+-       *  name:  update the name - preserving the homehost
+-       *  _reshape_progress: record new reshape_progress position.
+-       *
+-       * Following are not relevant for this version:
+-       *  sparc2.2 : update from old dodgey metadata
+-       *  super-minor: change the preferred_minor number
+-       *  summaries:  update redundant counters.
+-       */
+-      int rv = 0;
+-//    struct ddf_super *ddf = st->sb;
+-//    struct vd_config *vd = find_vdcr(ddf, info->container_member);
+-//    struct virtual_entry *ve = find_ve(ddf);
+-
+-      /* we don't need to handle "force-*" or "assemble" as
+-       * there is no need to 'trick' the kernel.  When the metadata is
+-       * first updated to activate the array, all the implied modifications
+-       * will just happen.
+-       */
+-
+-      if (strcmp(update, "grow") == 0) {
+-              /* FIXME */
+-      } else if (strcmp(update, "resync") == 0) {
+-//            info->resync_checkpoint = 0;
+-      } else if (strcmp(update, "homehost") == 0) {
+-              /* homehost is stored in controller->vendor_data,
+-               * or it is when we are the vendor
+-               */
+-//            if (info->vendor_is_local)
+-//                    strcpy(ddf->controller.vendor_data, homehost);
+-              rv = -1;
+-      } else if (strcmp(update, "name") == 0) {
+-              /* name is stored in virtual_entry->name */
+-//            memset(ve->name, ' ', 16);
+-//            strncpy(ve->name, info->name, 16);
+-              rv = -1;
+-      } else if (strcmp(update, "_reshape_progress") == 0) {
+-              /* We don't support reshape yet */
+-      } else if (strcmp(update, "assemble") == 0 ) {
+-              /* Do nothing, just succeed */
+-              rv = 0;
+-      } else
+-              rv = -1;
+-
+-//    update_all_csum(ddf);
+-
+-      return rv;
+-}
+-
+ static void make_header_guid(char *guid)
+ {
+       be32 stamp;
+@@ -5211,7 +5142,6 @@ struct superswitch super_ddf = {
+       .match_home     = match_home_ddf,
+       .uuid_from_super= uuid_from_super_ddf,
+       .getinfo_super  = getinfo_super_ddf,
+-      .update_super   = update_super_ddf,
+       .avail_size     = avail_size_ddf,
+-- 
+2.38.1
+
diff --git a/0071-super0-refactor-the-code-for-enum.patch b/0071-super0-refactor-the-code-for-enum.patch
new file mode 100644 (file)
index 0000000..f01c534
--- /dev/null
@@ -0,0 +1,212 @@
+From 0a9e39383d3bf63e1f5cf10f64200083a1af8091 Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:35:19 +0100
+Subject: [PATCH 71/83] super0: refactor the code for enum
+
+It prepares update_super0 for change context->update to enum.
+Change if else statements to switch.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super0.c | 102 ++++++++++++++++++++++++++++++++++---------------------
+ 1 file changed, 63 insertions(+), 39 deletions(-)
+
+diff --git a/super0.c b/super0.c
+index 93876e2e..d9f5bff4 100644
+--- a/super0.c
++++ b/super0.c
+@@ -502,19 +502,39 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+       int rv = 0;
+       int uuid[4];
+       mdp_super_t *sb = st->sb;
++      enum update_opt update_enum = map_name(update_options, update);
+-      if (strcmp(update, "homehost") == 0 &&
+-          homehost) {
+-              /* note that 'homehost' is special as it is really
++      if (update_enum == UOPT_HOMEHOST && homehost) {
++              /*
++               * note that 'homehost' is special as it is really
+                * a "uuid" update.
+                */
+               uuid_set = 0;
+-              update = "uuid";
++              update_enum = UOPT_UUID;
+               info->uuid[0] = sb->set_uuid0;
+               info->uuid[1] = sb->set_uuid1;
+       }
+-      if (strcmp(update, "sparc2.2")==0 ) {
++      switch (update_enum) {
++      case UOPT_UUID:
++              if (!uuid_set && homehost) {
++                      char buf[20];
++                      memcpy(info->uuid+2,
++                             sha1_buffer(homehost, strlen(homehost), buf),
++                             8);
++              }
++              sb->set_uuid0 = info->uuid[0];
++              sb->set_uuid1 = info->uuid[1];
++              sb->set_uuid2 = info->uuid[2];
++              sb->set_uuid3 = info->uuid[3];
++              if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) {
++                      struct bitmap_super_s *bm;
++                      bm = (struct bitmap_super_s *)(sb+1);
++                      uuid_from_super0(st, uuid);
++                      memcpy(bm->uuid, uuid, 16);
++              }
++              break;
++      case UOPT_SPARC22: {
+               /* 2.2 sparc put the events in the wrong place
+                * So we copy the tail of the superblock
+                * up 4 bytes before continuing
+@@ -527,12 +547,15 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+               if (verbose >= 0)
+                       pr_err("adjusting superblock of %s for 2.2/sparc compatibility.\n",
+                              devname);
+-      } else if (strcmp(update, "super-minor") ==0) {
++              break;
++      }
++      case UOPT_SUPER_MINOR:
+               sb->md_minor = info->array.md_minor;
+               if (verbose > 0)
+                       pr_err("updating superblock of %s with minor number %d\n",
+                               devname, info->array.md_minor);
+-      } else if (strcmp(update, "summaries") == 0) {
++              break;
++      case UOPT_SUMMARIES: {
+               unsigned int i;
+               /* set nr_disks, active_disks, working_disks,
+                * failed_disks, spare_disks based on disks[]
+@@ -559,7 +582,9 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+                                       sb->spare_disks++;
+                       } else if (i >= sb->raid_disks && sb->disks[i].number == 0)
+                               sb->disks[i].state = 0;
+-      } else if (strcmp(update, "force-one")==0) {
++              break;
++      }
++      case UOPT_SPEC_FORCE_ONE: {
+               /* Not enough devices for a working array, so
+                * bring this one up-to-date.
+                */
+@@ -569,7 +594,9 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+               if (sb->events_hi != ehi ||
+                   sb->events_lo != elo)
+                       rv = 1;
+-      } else if (strcmp(update, "force-array")==0) {
++              break;
++      }
++      case UOPT_SPEC_FORCE_ARRAY:
+               /* degraded array and 'force' requested, so
+                * maybe need to mark it 'clean'
+                */
+@@ -579,7 +606,8 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+                       sb->state |= (1 << MD_SB_CLEAN);
+                       rv = 1;
+               }
+-      } else if (strcmp(update, "assemble")==0) {
++              break;
++      case UOPT_SPEC_ASSEMBLE: {
+               int d = info->disk.number;
+               int wonly = sb->disks[d].state & (1<<MD_DISK_WRITEMOSTLY);
+               int failfast = sb->disks[d].state & (1<<MD_DISK_FAILFAST);
+@@ -609,7 +637,9 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+                       sb->reshape_position = info->reshape_progress;
+                       rv = 1;
+               }
+-      } else if (strcmp(update, "linear-grow-new") == 0) {
++              break;
++      }
++      case UOPT_SPEC_LINEAR_GROW_NEW:
+               memset(&sb->disks[info->disk.number], 0, sizeof(sb->disks[0]));
+               sb->disks[info->disk.number].number = info->disk.number;
+               sb->disks[info->disk.number].major = info->disk.major;
+@@ -617,7 +647,8 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+               sb->disks[info->disk.number].raid_disk = info->disk.raid_disk;
+               sb->disks[info->disk.number].state = info->disk.state;
+               sb->this_disk = sb->disks[info->disk.number];
+-      } else if (strcmp(update, "linear-grow-update") == 0) {
++              break;
++      case UOPT_SPEC_LINEAR_GROW_UPDATE:
+               sb->raid_disks = info->array.raid_disks;
+               sb->nr_disks = info->array.nr_disks;
+               sb->active_disks = info->array.active_disks;
+@@ -628,29 +659,15 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+               sb->disks[info->disk.number].minor = info->disk.minor;
+               sb->disks[info->disk.number].raid_disk = info->disk.raid_disk;
+               sb->disks[info->disk.number].state = info->disk.state;
+-      } else if (strcmp(update, "resync") == 0) {
+-              /* make sure resync happens */
++              break;
++      case UOPT_RESYNC:
++              /*
++               * make sure resync happens
++               */
+               sb->state &= ~(1<<MD_SB_CLEAN);
+               sb->recovery_cp = 0;
+-      } else if (strcmp(update, "uuid") == 0) {
+-              if (!uuid_set && homehost) {
+-                      char buf[20];
+-                      char *hash = sha1_buffer(homehost,
+-                                               strlen(homehost),
+-                                               buf);
+-                      memcpy(info->uuid+2, hash, 8);
+-              }
+-              sb->set_uuid0 = info->uuid[0];
+-              sb->set_uuid1 = info->uuid[1];
+-              sb->set_uuid2 = info->uuid[2];
+-              sb->set_uuid3 = info->uuid[3];
+-              if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) {
+-                      struct bitmap_super_s *bm;
+-                      bm = (struct bitmap_super_s*)(sb+1);
+-                      uuid_from_super0(st, uuid);
+-                      memcpy(bm->uuid, uuid, 16);
+-              }
+-      } else if (strcmp(update, "metadata") == 0) {
++              break;
++      case UOPT_METADATA:
+               /* Create some v1.0 metadata to match ours but make the
+                * ctime bigger.  Also update info->array.*_version.
+                * We need to arrange that store_super writes out
+@@ -670,7 +687,8 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+                       uuid_from_super0(st, info->uuid);
+                       st->other = super1_make_v0(st, info, st->sb);
+               }
+-      } else if (strcmp(update, "revert-reshape") == 0) {
++              break;
++      case UOPT_REVERT_RESHAPE:
+               rv = -2;
+               if (sb->minor_version <= 90)
+                       pr_err("No active reshape to revert on %s\n",
+@@ -702,16 +720,22 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+                       sb->new_chunk = sb->chunk_size;
+                       sb->chunk_size = tmp;
+               }
+-      } else if (strcmp(update, "no-bitmap") == 0) {
++              break;
++      case UOPT_NO_BITMAP:
+               sb->state &= ~(1<<MD_SB_BITMAP_PRESENT);
+-      } else if (strcmp(update, "_reshape_progress")==0)
++              break;
++      case UOPT_SPEC__RESHAPE_PROGRESS:
+               sb->reshape_position = info->reshape_progress;
+-      else if (strcmp(update, "writemostly")==0)
++              break;
++      case UOPT_SPEC_WRITEMOSTLY:
+               sb->state |= (1<<MD_DISK_WRITEMOSTLY);
+-      else if (strcmp(update, "readwrite")==0)
++              break;
++      case UOPT_SPEC_READWRITE:
+               sb->state &= ~(1<<MD_DISK_WRITEMOSTLY);
+-      else
++              break;
++      default:
+               rv = -1;
++      }
+       sb->sb_csum = calc_sb0_csum(sb);
+       return rv;
+-- 
+2.38.1
+
diff --git a/0072-super1-refactor-the-code-for-enum.patch b/0072-super1-refactor-the-code-for-enum.patch
new file mode 100644 (file)
index 0000000..bd164b8
--- /dev/null
@@ -0,0 +1,302 @@
+From 7e8daba8b7937716dce8ea28298a4e2e72cb829e Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:35:20 +0100
+Subject: [PATCH 72/83] super1: refactor the code for enum
+
+It prepares update_super1 for change context->update to enum.
+Change if else statements into switch.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super1.c | 152 +++++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 91 insertions(+), 61 deletions(-)
+
+diff --git a/super1.c b/super1.c
+index 0b505a7e..b0a97016 100644
+--- a/super1.c
++++ b/super1.c
+@@ -1218,30 +1218,55 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+       int rv = 0;
+       struct mdp_superblock_1 *sb = st->sb;
+       bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE);
++      enum update_opt update_enum = map_name(update_options, update);
+-      if (strcmp(update, "homehost") == 0 &&
+-          homehost) {
+-              /* Note that 'homehost' is special as it is really
++      if (update_enum == UOPT_HOMEHOST && homehost) {
++              /*
++               * Note that 'homehost' is special as it is really
+                * a "name" update.
+                */
+               char *c;
+-              update = "name";
++              update_enum = UOPT_NAME;
+               c = strchr(sb->set_name, ':');
+               if (c)
+-                      strncpy(info->name, c+1, 31 - (c-sb->set_name));
++                      snprintf(info->name, sizeof(info->name), "%s", c+1);
+               else
+-                      strncpy(info->name, sb->set_name, 32);
+-              info->name[32] = 0;
++                      snprintf(info->name, sizeof(info->name), "%s", sb->set_name);
+       }
+-      if (strcmp(update, "force-one")==0) {
++      switch (update_enum) {
++      case UOPT_NAME: {
++              int namelen;
++
++              if (!info->name[0])
++                      snprintf(info->name, sizeof(info->name), "%d", info->array.md_minor);
++              memset(sb->set_name, 0, sizeof(sb->set_name));
++
++              namelen = strnlen(homehost, MD_NAME_MAX) + 1 + strnlen(info->name, MD_NAME_MAX);
++              if (homehost &&
++                  strchr(info->name, ':') == NULL &&
++                  namelen < MD_NAME_MAX) {
++                      strcpy(sb->set_name, homehost);
++                      strcat(sb->set_name, ":");
++                      strcat(sb->set_name, info->name);
++              } else {
++                      namelen = min((int)strnlen(info->name, MD_NAME_MAX),
++                                    (int)sizeof(sb->set_name) - 1);
++                      memcpy(sb->set_name, info->name, namelen);
++                      memset(&sb->set_name[namelen], '\0',
++                             sizeof(sb->set_name) - namelen);
++              }
++              break;
++      }
++      case UOPT_SPEC_FORCE_ONE:
+               /* Not enough devices for a working array,
+                * so bring this one up-to-date
+                */
+               if (sb->events != __cpu_to_le64(info->events))
+                       rv = 1;
+               sb->events = __cpu_to_le64(info->events);
+-      } else if (strcmp(update, "force-array")==0) {
++              break;
++      case UOPT_SPEC_FORCE_ARRAY:
+               /* Degraded array and 'force' requests to
+                * maybe need to mark it 'clean'.
+                */
+@@ -1254,7 +1279,8 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                               rv = 1;
+                       sb->resync_offset = MaxSector;
+               }
+-      } else if (strcmp(update, "assemble")==0) {
++              break;
++      case UOPT_SPEC_ASSEMBLE: {
+               int d = info->disk.number;
+               int want;
+               if (info->disk.state & (1<<MD_DISK_ACTIVE))
+@@ -1287,7 +1313,9 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                               __cpu_to_le64(info->reshape_progress);
+                       rv = 1;
+               }
+-      } else if (strcmp(update, "linear-grow-new") == 0) {
++              break;
++      }
++      case UOPT_SPEC_LINEAR_GROW_NEW: {
+               int i;
+               int fd;
+               int max = __le32_to_cpu(sb->max_dev);
+@@ -1330,7 +1358,9 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                                       ds - __le64_to_cpu(sb->data_offset));
+                       }
+               }
+-      } else if (strcmp(update, "linear-grow-update") == 0) {
++              break;
++      }
++      case UOPT_SPEC_LINEAR_GROW_UPDATE: {
+               int max = __le32_to_cpu(sb->max_dev);
+               int i = info->disk.number;
+               if (max > MAX_DEVS || i > MAX_DEVS)
+@@ -1342,19 +1372,20 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+               sb->raid_disks = __cpu_to_le32(info->array.raid_disks);
+               sb->dev_roles[info->disk.number] =
+                       __cpu_to_le16(info->disk.raid_disk);
+-      } else if (strcmp(update, "resync") == 0) {
+-              /* make sure resync happens */
+-              sb->resync_offset = 0ULL;
+-      } else if (strcmp(update, "uuid") == 0) {
++              break;
++      }
++      case UOPT_UUID:
+               copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid);
+               if (__le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)
+                       memcpy(bms->uuid, sb->set_uuid, 16);
+-      } else if (strcmp(update, "no-bitmap") == 0) {
++              break;
++      case UOPT_NO_BITMAP:
+               sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
+               if (bms->version == BITMAP_MAJOR_CLUSTERED && !IsBitmapDirty(devname))
+                       sb->resync_offset = MaxSector;
+-      } else if (strcmp(update, "bbl") == 0) {
++              break;
++      case UOPT_BBL: {
+               /* only possible if there is room after the bitmap, or if
+                * there is no bitmap
+                */
+@@ -1383,14 +1414,12 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                               bb_offset = bitmap_offset + bm_sectors;
+                       while (bb_offset < (long)sb_offset + 8 + 32*2 &&
+                              bb_offset + 8+8 <= (long)data_offset)
+-                              /* too close to bitmap, and room to grow */
+                               bb_offset += 8;
+                       if (bb_offset + 8 <= (long)data_offset) {
+                               sb->bblog_size = __cpu_to_le16(8);
+                               sb->bblog_offset = __cpu_to_le32(bb_offset);
+                       }
+               } else {
+-                      /* 1.0 - Put bbl just before super block */
+                       if (bm_sectors && bitmap_offset < 0)
+                               space = -bitmap_offset - bm_sectors;
+                       else
+@@ -1401,7 +1430,9 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                               sb->bblog_offset = __cpu_to_le32((unsigned)-8);
+                       }
+               }
+-      } else if (strcmp(update, "no-bbl") == 0) {
++              break;
++      }
++      case UOPT_NO_BBL:
+               if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BAD_BLOCKS))
+                       pr_err("Cannot remove active bbl from %s\n",devname);
+               else {
+@@ -1409,12 +1440,14 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                       sb->bblog_shift = 0;
+                       sb->bblog_offset = 0;
+               }
+-      } else if (strcmp(update, "force-no-bbl") == 0) {
++              break;
++      case UOPT_FORCE_NO_BBL:
+               sb->feature_map &= ~ __cpu_to_le32(MD_FEATURE_BAD_BLOCKS);
+               sb->bblog_size = 0;
+               sb->bblog_shift = 0;
+               sb->bblog_offset = 0;
+-      } else if (strcmp(update, "ppl") == 0) {
++              break;
++      case UOPT_PPL: {
+               unsigned long long sb_offset = __le64_to_cpu(sb->super_offset);
+               unsigned long long data_offset = __le64_to_cpu(sb->data_offset);
+               unsigned long long data_size = __le64_to_cpu(sb->data_size);
+@@ -1464,37 +1497,26 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+               sb->ppl.offset = __cpu_to_le16(offset);
+               sb->ppl.size = __cpu_to_le16(space);
+               sb->feature_map |= __cpu_to_le32(MD_FEATURE_PPL);
+-      } else if (strcmp(update, "no-ppl") == 0) {
++              break;
++      }
++      case UOPT_NO_PPL:
+               sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_PPL |
+                                                  MD_FEATURE_MUTLIPLE_PPLS);
+-      } else if (strcmp(update, "name") == 0) {
+-              if (info->name[0] == 0)
+-                      sprintf(info->name, "%d", info->array.md_minor);
+-              memset(sb->set_name, 0, sizeof(sb->set_name));
+-              if (homehost &&
+-                  strchr(info->name, ':') == NULL &&
+-                  strlen(homehost)+1+strlen(info->name) < 32) {
+-                      strcpy(sb->set_name, homehost);
+-                      strcat(sb->set_name, ":");
+-                      strcat(sb->set_name, info->name);
+-              } else {
+-                      int namelen;
+-
+-                      namelen = min((int)strlen(info->name),
+-                                    (int)sizeof(sb->set_name) - 1);
+-                      memcpy(sb->set_name, info->name, namelen);
+-                      memset(&sb->set_name[namelen], '\0',
+-                             sizeof(sb->set_name) - namelen);
+-              }
+-      } else if (strcmp(update, "devicesize") == 0 &&
+-                 __le64_to_cpu(sb->super_offset) <
+-                 __le64_to_cpu(sb->data_offset)) {
+-              /* set data_size to device size less data_offset */
++              break;
++      case UOPT_DEVICESIZE:
++              if (__le64_to_cpu(sb->super_offset) >=
++                  __le64_to_cpu(sb->data_offset))
++                      break;
++              /*
++               * set data_size to device size less data_offset
++               */
+               struct misc_dev_info *misc = (struct misc_dev_info*)
+                       (st->sb + MAX_SB_SIZE + BM_SUPER_SIZE);
+               sb->data_size = __cpu_to_le64(
+                       misc->device_size - __le64_to_cpu(sb->data_offset));
+-      } else if (strncmp(update, "revert-reshape", 14) == 0) {
++              break;
++      case UOPT_SPEC_REVERT_RESHAPE_NOBACKUP:
++      case UOPT_REVERT_RESHAPE:
+               rv = -2;
+               if (!(sb->feature_map &
+                     __cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE)))
+@@ -1512,7 +1534,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                        * If that couldn't happen, the "-nobackup" version
+                        * will be used.
+                        */
+-                      if (strcmp(update, "revert-reshape-nobackup") == 0 &&
++                      if (update_enum == UOPT_SPEC_REVERT_RESHAPE_NOBACKUP &&
+                           sb->reshape_position == 0 &&
+                           (__le32_to_cpu(sb->delta_disks) > 0 ||
+                            (__le32_to_cpu(sb->delta_disks) == 0 &&
+@@ -1575,32 +1597,40 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                       }
+               done:;
+               }
+-      } else if (strcmp(update, "_reshape_progress") == 0)
++              break;
++      case UOPT_SPEC__RESHAPE_PROGRESS:
+               sb->reshape_position = __cpu_to_le64(info->reshape_progress);
+-      else if (strcmp(update, "writemostly") == 0)
++              break;
++      case UOPT_SPEC_WRITEMOSTLY:
+               sb->devflags |= WriteMostly1;
+-      else if (strcmp(update, "readwrite") == 0)
++              break;
++      case UOPT_SPEC_READWRITE:
+               sb->devflags &= ~WriteMostly1;
+-      else if (strcmp(update, "failfast") == 0)
++              break;
++      case UOPT_SPEC_FAILFAST:
+               sb->devflags |= FailFast1;
+-      else if (strcmp(update, "nofailfast") == 0)
++              break;
++      case UOPT_SPEC_NOFAILFAST:
+               sb->devflags &= ~FailFast1;
+-      else if (strcmp(update, "layout-original") == 0 ||
+-               strcmp(update, "layout-alternate") == 0 ||
+-               strcmp(update, "layout-unspecified") == 0) {
++              break;
++      case UOPT_LAYOUT_ORIGINAL:
++      case UOPT_LAYOUT_ALTERNATE:
++      case UOPT_LAYOUT_UNSPECIFIED:
+               if (__le32_to_cpu(sb->level) != 0) {
+                       pr_err("%s: %s only supported for RAID0\n",
+-                             devname?:"", update);
++                             devname ?: "", map_num(update_options, update_enum));
+                       rv = -1;
+-              } else if (strcmp(update, "layout-unspecified") == 0) {
++              } else if (update_enum == UOPT_LAYOUT_UNSPECIFIED) {
+                       sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_RAID0_LAYOUT);
+                       sb->layout = 0;
+               } else {
+                       sb->feature_map |= __cpu_to_le32(MD_FEATURE_RAID0_LAYOUT);
+-                      sb->layout = __cpu_to_le32(update[7] == 'o' ? 1 : 2);
++                      sb->layout = __cpu_to_le32(update_enum == UOPT_LAYOUT_ORIGINAL ? 1 : 2);
+               }
+-      } else
++              break;
++      default:
+               rv = -1;
++      }
+       sb->sb_csum = calc_sb_1_csum(sb);
+-- 
+2.38.1
+
diff --git a/0073-super-intel-refactor-the-code-for-enum.patch b/0073-super-intel-refactor-the-code-for-enum.patch
new file mode 100644 (file)
index 0000000..6756297
--- /dev/null
@@ -0,0 +1,106 @@
+From 4345e135c4c7dd04bb15bad140dfc4747f677738 Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:35:21 +0100
+Subject: [PATCH 73/83] super-intel: refactor the code for enum
+
+It prepares super-intel for change context->update to enum.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super-intel.c | 37 +++++++++++++++++++++++++------------
+ 1 file changed, 25 insertions(+), 12 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 5f93f3d3..85fb7f17 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -3930,7 +3930,8 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
+       mpb = super->anchor;
+-      if (strcmp(update, "uuid") == 0) {
++      switch (map_name(update_options, update)) {
++      case UOPT_UUID:
+               /* We take this to mean that the family_num should be updated.
+                * However that is much smaller than the uuid so we cannot really
+                * allow an explicit uuid to be given.  And it is hard to reliably
+@@ -3954,10 +3955,14 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
+               }
+               if (rv == 0)
+                       mpb->orig_family_num = info->uuid[0];
+-      } else if (strcmp(update, "assemble") == 0)
++              break;
++      case UOPT_SPEC_ASSEMBLE:
+               rv = 0;
+-      else
++              break;
++      default:
+               rv = -1;
++              break;
++      }
+       /* successful update? recompute checksum */
+       if (rv == 0)
+@@ -7889,17 +7894,25 @@ static int kill_subarray_imsm(struct supertype *st, char *subarray_id)
+       return 0;
+ }
+-static int get_rwh_policy_from_update(char *update)
++/**
++ * get_rwh_policy_from_update() - Get the rwh policy for update option.
++ * @update: Update option.
++ */
++static int get_rwh_policy_from_update(enum update_opt update)
+ {
+-      if (strcmp(update, "ppl") == 0)
++      switch (update) {
++      case UOPT_PPL:
+               return RWH_MULTIPLE_DISTRIBUTED;
+-      else if (strcmp(update, "no-ppl") == 0)
++      case UOPT_NO_PPL:
+               return RWH_MULTIPLE_OFF;
+-      else if (strcmp(update, "bitmap") == 0)
++      case UOPT_BITMAP:
+               return RWH_BITMAP;
+-      else if (strcmp(update, "no-bitmap") == 0)
++      case UOPT_NO_BITMAP:
+               return RWH_OFF;
+-      return -1;
++      default:
++              break;
++      }
++      return UOPT_UNDEFINED;
+ }
+ static int update_subarray_imsm(struct supertype *st, char *subarray,
+@@ -7909,7 +7922,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
+       struct intel_super *super = st->sb;
+       struct imsm_super *mpb = super->anchor;
+-      if (strcmp(update, "name") == 0) {
++      if (map_name(update_options, update) == UOPT_NAME) {
+               char *name = ident->name;
+               char *ep;
+               int vol;
+@@ -7943,7 +7956,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
+                       }
+                       super->updates_pending++;
+               }
+-      } else if (get_rwh_policy_from_update(update) != -1) {
++      } else if (get_rwh_policy_from_update(map_name(update_options, update)) != UOPT_UNDEFINED) {
+               int new_policy;
+               char *ep;
+               int vol = strtoul(subarray, &ep, 10);
+@@ -7951,7 +7964,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
+               if (*ep != '\0' || vol >= super->anchor->num_raid_devs)
+                       return 2;
+-              new_policy = get_rwh_policy_from_update(update);
++              new_policy = get_rwh_policy_from_update(map_name(update_options, update));
+               if (st->update_tail) {
+                       struct imsm_update_rwh_policy *u = xmalloc(sizeof(*u));
+-- 
+2.38.1
+
diff --git a/0074-Change-update-to-enum-in-update_super-and-update_sub.patch b/0074-Change-update-to-enum-in-update_super-and-update_sub.patch
new file mode 100644 (file)
index 0000000..c9e186e
--- /dev/null
@@ -0,0 +1,424 @@
+From 03312b5240438ffc3b63114bdc87e911222f01e5 Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:35:22 +0100
+Subject: [PATCH 74/83] Change update to enum in update_super and
+ update_subarray
+
+Use already existing enum, change update_super and update_subarray
+update to enum globally.
+Refactor function references also.
+Remove code specific options from update_options.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Assemble.c    | 14 +++++++++-----
+ Examine.c     |  2 +-
+ Grow.c        |  9 +++++----
+ Manage.c      | 14 ++++++++------
+ maps.c        | 21 ---------------------
+ mdadm.h       | 12 +++++++++---
+ super-intel.c | 16 ++++++++--------
+ super0.c      |  9 ++++-----
+ super1.c      | 17 ++++++++---------
+ 9 files changed, 52 insertions(+), 62 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index 8b0af0c9..dba910cd 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -695,12 +695,16 @@ static int load_devices(struct devs *devices, char *devmap,
+                       } else if (strcmp(c->update, "revert-reshape") == 0 &&
+                                  c->invalid_backup)
+                               err = tst->ss->update_super(tst, content,
+-                                                          "revert-reshape-nobackup",
++                                                          UOPT_SPEC_REVERT_RESHAPE_NOBACKUP,
+                                                           devname, c->verbose,
+                                                           ident->uuid_set,
+                                                           c->homehost);
+                       else
+-                              err = tst->ss->update_super(tst, content, c->update,
++                              /*
++                               * Mapping is temporary, will be removed in this patchset
++                               */
++                              err = tst->ss->update_super(tst, content,
++                                                          map_name(update_options, c->update),
+                                                           devname, c->verbose,
+                                                           ident->uuid_set,
+                                                           c->homehost);
+@@ -960,7 +964,7 @@ static int force_array(struct mdinfo *content,
+                       continue;
+               }
+               content->events = devices[most_recent].i.events;
+-              tst->ss->update_super(tst, content, "force-one",
++              tst->ss->update_super(tst, content, UOPT_SPEC_FORCE_ONE,
+                                     devices[chosen_drive].devname, c->verbose,
+                                     0, NULL);
+@@ -1788,7 +1792,7 @@ try_again:
+               if (!(devices[j].i.array.state & 1))
+                       clean = 0;
+-              if (st->ss->update_super(st, &devices[j].i, "assemble", NULL,
++              if (st->ss->update_super(st, &devices[j].i, UOPT_SPEC_ASSEMBLE, NULL,
+                                        c->verbose, 0, NULL)) {
+                       if (c->force) {
+                               if (c->verbose >= 0)
+@@ -1811,7 +1815,7 @@ try_again:
+       if (c->force && !clean && !is_container(content->array.level) &&
+           !enough(content->array.level, content->array.raid_disks,
+                   content->array.layout, clean, avail)) {
+-              change += st->ss->update_super(st, content, "force-array",
++              change += st->ss->update_super(st, content, UOPT_SPEC_FORCE_ARRAY,
+                                              devices[chosen_drive].devname, c->verbose,
+                                              0, NULL);
+               was_forced = 1;
+diff --git a/Examine.c b/Examine.c
+index 9574a3cc..c9605a60 100644
+--- a/Examine.c
++++ b/Examine.c
+@@ -117,7 +117,7 @@ int Examine(struct mddev_dev *devlist,
+               }
+               if (c->SparcAdjust)
+-                      st->ss->update_super(st, NULL, "sparc2.2",
++                      st->ss->update_super(st, NULL, UOPT_SPARC22,
+                                            devlist->devname, 0, 0, NULL);
+               /* Ok, its good enough to try, though the checksum could be wrong */
+diff --git a/Grow.c b/Grow.c
+index b73ec2ae..82d5d2ea 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -196,7 +196,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
+       info.disk.minor = minor(rdev);
+       info.disk.raid_disk = d;
+       info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE);
+-      if (st->ss->update_super(st, &info, "linear-grow-new", newdev,
++      if (st->ss->update_super(st, &info, UOPT_SPEC_LINEAR_GROW_NEW, newdev,
+                                0, 0, NULL) != 0) {
+               pr_err("Preparing new metadata failed on %s\n", newdev);
+               close(nfd);
+@@ -254,7 +254,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
+               info.array.active_disks = nd+1;
+               info.array.working_disks = nd+1;
+-              if (st->ss->update_super(st, &info, "linear-grow-update", dv,
++              if (st->ss->update_super(st, &info, UOPT_SPEC_LINEAR_GROW_UPDATE, dv,
+                                    0, 0, NULL) != 0) {
+                       pr_err("Updating metadata failed on %s\n", dv);
+                       close(fd2);
+@@ -668,7 +668,7 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
+                                       goto free_info;
+                               }
+-                              ret = st->ss->update_super(st, sra, "ppl",
++                              ret = st->ss->update_super(st, sra, UOPT_PPL,
+                                                          devname,
+                                                          c->verbose, 0, NULL);
+                               if (ret) {
+@@ -4950,7 +4950,8 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist,
+                               continue;
+                       st->ss->getinfo_super(st, &dinfo, NULL);
+                       dinfo.reshape_progress = info->reshape_progress;
+-                      st->ss->update_super(st, &dinfo, "_reshape_progress",
++                      st->ss->update_super(st, &dinfo,
++                                           UOPT_SPEC__RESHAPE_PROGRESS,
+                                            NULL,0, 0, NULL);
+                       st->ss->store_super(st, fdlist[j]);
+                       st->ss->free_super(st);
+diff --git a/Manage.c b/Manage.c
+index 5a9ea316..87b8aa0c 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -605,6 +605,7 @@ int attempt_re_add(int fd, int tfd, struct mddev_dev *dv,
+       struct mdinfo mdi;
+       int duuid[4];
+       int ouuid[4];
++      enum update_opt update_enum = map_name(update_options, update);
+       dev_st->ss->getinfo_super(dev_st, &mdi, NULL);
+       dev_st->ss->uuid_from_super(dev_st, ouuid);
+@@ -666,23 +667,23 @@ int attempt_re_add(int fd, int tfd, struct mddev_dev *dv,
+                       if (dv->writemostly == FlagSet)
+                               rv = dev_st->ss->update_super(
+-                                      dev_st, NULL, "writemostly",
++                                      dev_st, NULL, UOPT_SPEC_WRITEMOSTLY,
+                                       devname, verbose, 0, NULL);
+                       if (dv->writemostly == FlagClear)
+                               rv = dev_st->ss->update_super(
+-                                      dev_st, NULL, "readwrite",
++                                      dev_st, NULL, UOPT_SPEC_READWRITE,
+                                       devname, verbose, 0, NULL);
+                       if (dv->failfast == FlagSet)
+                               rv = dev_st->ss->update_super(
+-                                      dev_st, NULL, "failfast",
++                                      dev_st, NULL, UOPT_SPEC_FAILFAST,
+                                       devname, verbose, 0, NULL);
+                       if (dv->failfast == FlagClear)
+                               rv = dev_st->ss->update_super(
+-                                      dev_st, NULL, "nofailfast",
++                                      dev_st, NULL, UOPT_SPEC_NOFAILFAST,
+                                       devname, verbose, 0, NULL);
+                       if (update)
+                               rv = dev_st->ss->update_super(
+-                                      dev_st, NULL, update,
++                                      dev_st, NULL, update_enum,
+                                       devname, verbose, 0, NULL);
+                       if (rv == 0)
+                               rv = dev_st->ss->store_super(dev_st, tfd);
+@@ -1731,6 +1732,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;
++      enum update_opt update_enum = map_name(update_options, update);
+       memset(st, 0, sizeof(*st));
+@@ -1762,7 +1764,7 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident
+               goto free_super;
+       }
+-      rv = st->ss->update_subarray(st, subarray, update, ident);
++      rv = st->ss->update_subarray(st, subarray, update_enum, ident);
+       if (rv) {
+               if (verbose >= 0)
+diff --git a/maps.c b/maps.c
+index c59036f1..b586679a 100644
+--- a/maps.c
++++ b/maps.c
+@@ -194,27 +194,6 @@ mapping_t update_options[] = {
+       { "byteorder", UOPT_BYTEORDER },
+       { "help", UOPT_HELP },
+       { "?", UOPT_HELP },
+-      /*
+-       * Those enries are temporary and will be removed in this patchset.
+-       *
+-       * Before update_super:update can be changed to enum,
+-       * all update_super sub-functions must be adapted first.
+-       * Update options will be passed as string (as it is for now),
+-       * and then mapped, so all options must be handled temporarily.
+-       *
+-       * Those options code specific and should not be accessible for user.
+-       */
+-      { "force-one", UOPT_SPEC_FORCE_ONE },
+-      { "force-array", UOPT_SPEC_FORCE_ARRAY },
+-      { "assemble", UOPT_SPEC_ASSEMBLE },
+-      { "linear-grow-new", UOPT_SPEC_LINEAR_GROW_NEW },
+-      { "linear-grow-update", UOPT_SPEC_LINEAR_GROW_UPDATE },
+-      { "_reshape_progress", UOPT_SPEC__RESHAPE_PROGRESS },
+-      { "writemostly", UOPT_SPEC_WRITEMOSTLY },
+-      { "readwrite", UOPT_SPEC_READWRITE },
+-      { "failfast", UOPT_SPEC_FAILFAST },
+-      { "nofailfast", UOPT_SPEC_NOFAILFAST },
+-      { "revert-reshape-nobackup", UOPT_SPEC_REVERT_RESHAPE_NOBACKUP },
+       { NULL, UOPT_UNDEFINED}
+ };
+diff --git a/mdadm.h b/mdadm.h
+index 31db25f5..5dc94390 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1011,7 +1011,7 @@ extern struct superswitch {
+        *                    it will resume going in the opposite direction.
+        */
+       int (*update_super)(struct supertype *st, struct mdinfo *info,
+-                          char *update,
++                          enum update_opt update,
+                           char *devname, int verbose,
+                           int uuid_set, char *homehost);
+@@ -1137,9 +1137,15 @@ extern struct superswitch {
+       /* Permit subarray's to be deleted from inactive containers */
+       int (*kill_subarray)(struct supertype *st,
+                            char *subarray_id); /* optional */
+-      /* Permit subarray's to be modified */
++      /**
++       * update_subarray() - Permit subarray to be modified.
++       * @st: Supertype.
++       * @subarray: Subarray name.
++       * @update: Update option.
++       * @ident: Optional identifiers.
++       */
+       int (*update_subarray)(struct supertype *st, char *subarray,
+-                             char *update, struct mddev_ident *ident); /* optional */
++                             enum update_opt update, struct mddev_ident *ident);
+       /* Check if reshape is supported for this external format.
+        * st is obtained from super_by_fd() where st->subarray[0] is
+        * initialized to indicate if reshape is being performed at the
+diff --git a/super-intel.c b/super-intel.c
+index 85fb7f17..1f5f6eda 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -3893,8 +3893,8 @@ struct mdinfo *getinfo_super_disks_imsm(struct supertype *st)
+ }
+ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
+-                           char *update, char *devname, int verbose,
+-                           int uuid_set, char *homehost)
++                           enum update_opt update, char *devname,
++                           int verbose, int uuid_set, char *homehost)
+ {
+       /* For 'assemble' and 'force' we need to return non-zero if any
+        * change was made.  For others, the return value is ignored.
+@@ -3930,7 +3930,7 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
+       mpb = super->anchor;
+-      switch (map_name(update_options, update)) {
++      switch (update) {
+       case UOPT_UUID:
+               /* We take this to mean that the family_num should be updated.
+                * However that is much smaller than the uuid so we cannot really
+@@ -6538,7 +6538,7 @@ static int validate_ppl_imsm(struct supertype *st, struct mdinfo *info,
+               if (mdmon_running(st->container_devnm))
+                       st->update_tail = &st->updates;
+-              if (st->ss->update_subarray(st, subarray, "ppl", NULL)) {
++              if (st->ss->update_subarray(st, subarray, UOPT_PPL, NULL)) {
+                       pr_err("Failed to update subarray %s\n",
+                             subarray);
+               } else {
+@@ -7916,13 +7916,13 @@ static int get_rwh_policy_from_update(enum update_opt update)
+ }
+ static int update_subarray_imsm(struct supertype *st, char *subarray,
+-                              char *update, struct mddev_ident *ident)
++                              enum update_opt update, struct mddev_ident *ident)
+ {
+       /* update the subarray currently referenced by ->current_vol */
+       struct intel_super *super = st->sb;
+       struct imsm_super *mpb = super->anchor;
+-      if (map_name(update_options, update) == UOPT_NAME) {
++      if (update == UOPT_NAME) {
+               char *name = ident->name;
+               char *ep;
+               int vol;
+@@ -7956,7 +7956,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
+                       }
+                       super->updates_pending++;
+               }
+-      } else if (get_rwh_policy_from_update(map_name(update_options, update)) != UOPT_UNDEFINED) {
++      } else if (get_rwh_policy_from_update(update) != UOPT_UNDEFINED) {
+               int new_policy;
+               char *ep;
+               int vol = strtoul(subarray, &ep, 10);
+@@ -7964,7 +7964,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
+               if (*ep != '\0' || vol >= super->anchor->num_raid_devs)
+                       return 2;
+-              new_policy = get_rwh_policy_from_update(map_name(update_options, update));
++              new_policy = get_rwh_policy_from_update(update);
+               if (st->update_tail) {
+                       struct imsm_update_rwh_policy *u = xmalloc(sizeof(*u));
+diff --git a/super0.c b/super0.c
+index d9f5bff4..a7c5f813 100644
+--- a/super0.c
++++ b/super0.c
+@@ -491,7 +491,7 @@ static struct mdinfo *container_content0(struct supertype *st, char *subarray)
+ }
+ static int update_super0(struct supertype *st, struct mdinfo *info,
+-                       char *update,
++                       enum update_opt update,
+                        char *devname, int verbose,
+                        int uuid_set, char *homehost)
+ {
+@@ -502,20 +502,19 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
+       int rv = 0;
+       int uuid[4];
+       mdp_super_t *sb = st->sb;
+-      enum update_opt update_enum = map_name(update_options, update);
+-      if (update_enum == UOPT_HOMEHOST && homehost) {
++      if (update == UOPT_HOMEHOST && homehost) {
+               /*
+                * note that 'homehost' is special as it is really
+                * a "uuid" update.
+                */
+               uuid_set = 0;
+-              update_enum = UOPT_UUID;
++              update = UOPT_UUID;
+               info->uuid[0] = sb->set_uuid0;
+               info->uuid[1] = sb->set_uuid1;
+       }
+-      switch (update_enum) {
++      switch (update) {
+       case UOPT_UUID:
+               if (!uuid_set && homehost) {
+                       char buf[20];
+diff --git a/super1.c b/super1.c
+index b0a97016..f7020320 100644
+--- a/super1.c
++++ b/super1.c
+@@ -1208,7 +1208,7 @@ static struct mdinfo *container_content1(struct supertype *st, char *subarray)
+ }
+ static int update_super1(struct supertype *st, struct mdinfo *info,
+-                       char *update, char *devname, int verbose,
++                       enum update_opt update, char *devname, int verbose,
+                        int uuid_set, char *homehost)
+ {
+       /* NOTE: for 'assemble' and 'force' we need to return non-zero
+@@ -1218,15 +1218,14 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+       int rv = 0;
+       struct mdp_superblock_1 *sb = st->sb;
+       bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE);
+-      enum update_opt update_enum = map_name(update_options, update);
+-      if (update_enum == UOPT_HOMEHOST && homehost) {
++      if (update == UOPT_HOMEHOST && homehost) {
+               /*
+                * Note that 'homehost' is special as it is really
+                * a "name" update.
+                */
+               char *c;
+-              update_enum = UOPT_NAME;
++              update = UOPT_NAME;
+               c = strchr(sb->set_name, ':');
+               if (c)
+                       snprintf(info->name, sizeof(info->name), "%s", c+1);
+@@ -1234,7 +1233,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                       snprintf(info->name, sizeof(info->name), "%s", sb->set_name);
+       }
+-      switch (update_enum) {
++      switch (update) {
+       case UOPT_NAME: {
+               int namelen;
+@@ -1534,7 +1533,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                        * If that couldn't happen, the "-nobackup" version
+                        * will be used.
+                        */
+-                      if (update_enum == UOPT_SPEC_REVERT_RESHAPE_NOBACKUP &&
++                      if (update == UOPT_SPEC_REVERT_RESHAPE_NOBACKUP &&
+                           sb->reshape_position == 0 &&
+                           (__le32_to_cpu(sb->delta_disks) > 0 ||
+                            (__le32_to_cpu(sb->delta_disks) == 0 &&
+@@ -1618,14 +1617,14 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+       case UOPT_LAYOUT_UNSPECIFIED:
+               if (__le32_to_cpu(sb->level) != 0) {
+                       pr_err("%s: %s only supported for RAID0\n",
+-                             devname ?: "", map_num(update_options, update_enum));
++                             devname ?: "", map_num(update_options, update));
+                       rv = -1;
+-              } else if (update_enum == UOPT_LAYOUT_UNSPECIFIED) {
++              } else if (update == UOPT_LAYOUT_UNSPECIFIED) {
+                       sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_RAID0_LAYOUT);
+                       sb->layout = 0;
+               } else {
+                       sb->feature_map |= __cpu_to_le32(MD_FEATURE_RAID0_LAYOUT);
+-                      sb->layout = __cpu_to_le32(update_enum == UOPT_LAYOUT_ORIGINAL ? 1 : 2);
++                      sb->layout = __cpu_to_le32(update == UOPT_LAYOUT_ORIGINAL ? 1 : 2);
+               }
+               break;
+       default:
+-- 
+2.38.1
+
diff --git a/0075-Manage-Incremental-code-refactor-string-to-enum.patch b/0075-Manage-Incremental-code-refactor-string-to-enum.patch
new file mode 100644 (file)
index 0000000..d4b20ff
--- /dev/null
@@ -0,0 +1,279 @@
+From f2e8393bd7223c419aaa33c45feeb5c75440b986 Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:35:23 +0100
+Subject: [PATCH 75/83] Manage&Incremental: code refactor, string to enum
+
+Prepare Manage and Incremental for later changing context->update to enum.
+Change update from string to enum in multiple functions and pass enum
+where already possible.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Grow.c        |  8 ++++----
+ Incremental.c |  8 ++++----
+ Manage.c      | 35 +++++++++++++++++------------------
+ mdadm.c       | 23 ++++++++++++++++++-----
+ mdadm.h       |  4 ++--
+ 5 files changed, 45 insertions(+), 33 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index 82d5d2ea..8f5cf07d 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -605,12 +605,12 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
+       }
+       if (subarray) {
+-              char *update;
++              enum update_opt update;
+               if (s->consistency_policy == CONSISTENCY_POLICY_PPL)
+-                      update = "ppl";
++                      update = UOPT_PPL;
+               else
+-                      update = "no-ppl";
++                      update = UOPT_NO_PPL;
+               sprintf(container_dev, "/dev/%s", st->container_devnm);
+@@ -3243,7 +3243,7 @@ static int reshape_array(char *container, int fd, char *devname,
+        * level and frozen, we can safely add them.
+        */
+       if (devlist) {
+-              if (Manage_subdevs(devname, fd, devlist, verbose, 0, NULL, 0))
++              if (Manage_subdevs(devname, fd, devlist, verbose, 0, UOPT_UNDEFINED, 0))
+                       goto release;
+       }
+diff --git a/Incremental.c b/Incremental.c
+index 5a5f4c4c..ff3548c0 100644
+--- a/Incremental.c
++++ b/Incremental.c
+@@ -1025,7 +1025,7 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
+                       close(dfd);
+                       *dfdp = -1;
+                       rv =  Manage_subdevs(chosen->sys_name, mdfd, &devlist,
+-                                           -1, 0, NULL, 0);
++                                           -1, 0, UOPT_UNDEFINED, 0);
+                       close(mdfd);
+               }
+               if (verbose > 0) {
+@@ -1666,7 +1666,7 @@ static void remove_from_member_array(struct mdstat_ent *memb,
+       if (subfd >= 0) {
+               rv = Manage_subdevs(memb->devnm, subfd, devlist, verbose,
+-                                  0, NULL, 0);
++                                  0, UOPT_UNDEFINED, 0);
+               if (rv & 2) {
+                       if (sysfs_init(&mmdi, -1, memb->devnm))
+                               pr_err("unable to initialize sysfs for: %s\n",
+@@ -1758,7 +1758,7 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
+               free_mdstat(mdstat);
+       } else {
+               rv |= Manage_subdevs(ent->devnm, mdfd, &devlist,
+-                                  verbose, 0, NULL, 0);
++                                  verbose, 0, UOPT_UNDEFINED, 0);
+               if (rv & 2) {
+               /* Failed due to EBUSY, try to stop the array.
+                * Give udisks a chance to unmount it first.
+@@ -1770,7 +1770,7 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
+       devlist.disposition = 'r';
+       rv = Manage_subdevs(ent->devnm, mdfd, &devlist,
+-                          verbose, 0, NULL, 0);
++                          verbose, 0, UOPT_UNDEFINED, 0);
+ end:
+       close(mdfd);
+       free_mdstat(ent);
+diff --git a/Manage.c b/Manage.c
+index 87b8aa0c..594e3d2c 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -598,14 +598,12 @@ static void add_set(struct mddev_dev *dv, int fd, char set_char)
+ int attempt_re_add(int fd, int tfd, struct mddev_dev *dv,
+                  struct supertype *dev_st, struct supertype *tst,
+-                 unsigned long rdev,
+-                 char *update, char *devname, int verbose,
+-                 mdu_array_info_t *array)
++                 unsigned long rdev, enum update_opt update,
++                 char *devname, int verbose, mdu_array_info_t *array)
+ {
+       struct mdinfo mdi;
+       int duuid[4];
+       int ouuid[4];
+-      enum update_opt update_enum = map_name(update_options, update);
+       dev_st->ss->getinfo_super(dev_st, &mdi, NULL);
+       dev_st->ss->uuid_from_super(dev_st, ouuid);
+@@ -683,7 +681,7 @@ int attempt_re_add(int fd, int tfd, struct mddev_dev *dv,
+                                       devname, verbose, 0, NULL);
+                       if (update)
+                               rv = dev_st->ss->update_super(
+-                                      dev_st, NULL, update_enum,
++                                      dev_st, NULL, update,
+                                       devname, verbose, 0, NULL);
+                       if (rv == 0)
+                               rv = dev_st->ss->store_super(dev_st, tfd);
+@@ -715,8 +713,8 @@ skip_re_add:
+ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
+              struct supertype *tst, mdu_array_info_t *array,
+              int force, int verbose, char *devname,
+-             char *update, unsigned long rdev, unsigned long long array_size,
+-             int raid_slot)
++             enum update_opt update, unsigned long rdev,
++             unsigned long long array_size, int raid_slot)
+ {
+       unsigned long long ldsize;
+       struct supertype *dev_st;
+@@ -1332,7 +1330,7 @@ bool is_remove_safe(mdu_array_info_t *array, const int fd, char *devname, const
+ int Manage_subdevs(char *devname, int fd,
+                  struct mddev_dev *devlist, int verbose, int test,
+-                 char *update, int force)
++                 enum update_opt update, int force)
+ {
+       /* Do something to each dev.
+        * devmode can be
+@@ -1727,12 +1725,13 @@ int autodetect(void)
+       return rv;
+ }
+-int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident *ident, int verbose)
++int Update_subarray(char *dev, char *subarray, enum update_opt update,
++                  struct mddev_ident *ident, int verbose)
+ {
+       struct supertype supertype, *st = &supertype;
+       int fd, rv = 2;
+       struct mdinfo *info = NULL;
+-      enum update_opt update_enum = map_name(update_options, update);
++      char *update_verb = map_num(update_options, update);
+       memset(st, 0, sizeof(*st));
+@@ -1750,7 +1749,7 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident
+       if (is_subarray_active(subarray, st->devnm)) {
+               if (verbose >= 0)
+                       pr_err("Subarray %s in %s is active, cannot update %s\n",
+-                             subarray, dev, update);
++                              subarray, dev, update_verb);
+               goto free_super;
+       }
+@@ -1759,23 +1758,23 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident
+       info = st->ss->container_content(st, subarray);
+-      if (strncmp(update, "ppl", 3) == 0 && !is_level456(info->array.level)) {
++      if (update == UOPT_PPL && !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_enum, ident);
++      rv = st->ss->update_subarray(st, subarray, update, ident);
+       if (rv) {
+               if (verbose >= 0)
+                       pr_err("Failed to update %s of subarray-%s in %s\n",
+-                              update, subarray, dev);
++                              update_verb, subarray, dev);
+       } else if (st->update_tail)
+               flush_metadata_updates(st);
+       else
+               st->ss->sync_metadata(st);
+-      if (rv == 0 && strcmp(update, "name") == 0 && verbose >= 0)
++      if (rv == 0 && update == UOPT_NAME && verbose >= 0)
+               pr_err("Updated subarray-%s name from %s, UUIDs may have changed\n",
+                      subarray, dev);
+@@ -1816,10 +1815,10 @@ int move_spare(char *from_devname, char *to_devname, dev_t devid)
+       sprintf(devname, "%d:%d", major(devid), minor(devid));
+       devlist.disposition = 'r';
+-      if (Manage_subdevs(from_devname, fd2, &devlist, -1, 0, NULL, 0) == 0) {
++      if (Manage_subdevs(from_devname, fd2, &devlist, -1, 0, UOPT_UNDEFINED, 0) == 0) {
+               devlist.disposition = 'a';
+               if (Manage_subdevs(to_devname, fd1, &devlist, -1, 0,
+-                                 NULL, 0) == 0) {
++                                 UOPT_UNDEFINED, 0) == 0) {
+                       /* make sure manager is aware of changes */
+                       ping_manager(to_devname);
+                       ping_manager(from_devname);
+@@ -1829,7 +1828,7 @@ int move_spare(char *from_devname, char *to_devname, dev_t devid)
+               }
+               else
+                       Manage_subdevs(from_devname, fd2, &devlist,
+-                                     -1, 0, NULL, 0);
++                                     -1, 0, UOPT_UNDEFINED, 0);
+       }
+       close(fd1);
+       close(fd2);
+diff --git a/mdadm.c b/mdadm.c
+index f5f505fe..d06e2820 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -1402,10 +1402,22 @@ int main(int argc, char *argv[])
+               /* readonly, add/remove, readwrite, runstop */
+               if (c.readonly > 0)
+                       rv = Manage_ro(devlist->devname, mdfd, c.readonly);
+-              if (!rv && devs_found>1)
+-                      rv = Manage_subdevs(devlist->devname, mdfd,
+-                                          devlist->next, c.verbose, c.test,
+-                                          c.update, c.force);
++              if (!rv && devs_found > 1) {
++                      /*
++                       * This is temporary and will be removed in next patches
++                       * Null c.update will cause segfault
++                       */
++                      if (c.update)
++                              rv = Manage_subdevs(devlist->devname, mdfd,
++                                              devlist->next, c.verbose, c.test,
++                                              map_name(update_options, c.update),
++                                              c.force);
++                      else
++                              rv = Manage_subdevs(devlist->devname, mdfd,
++                                              devlist->next, c.verbose, c.test,
++                                              UOPT_UNDEFINED,
++                                              c.force);
++              }
+               if (!rv && c.readonly < 0)
+                       rv = Manage_ro(devlist->devname, mdfd, c.readonly);
+               if (!rv && c.runstop > 0)
+@@ -1931,7 +1943,8 @@ static int misc_list(struct mddev_dev *devlist,
+                               continue;
+                       }
+                       rv |= Update_subarray(dv->devname, c->subarray,
+-                                            c->update, ident, c->verbose);
++                                            map_name(update_options, c->update),
++                                            ident, c->verbose);
+                       continue;
+               case Dump:
+                       rv |= Dump_metadata(dv->devname, dump_directory, c, ss);
+diff --git a/mdadm.h b/mdadm.h
+index 5dc94390..924f4b63 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1478,7 +1478,7 @@ extern int Manage_stop(char *devname, int fd, int quiet,
+                      int will_retry);
+ extern int Manage_subdevs(char *devname, int fd,
+                         struct mddev_dev *devlist, int verbose, int test,
+-                        char *update, int force);
++                        enum update_opt update, int force);
+ extern int autodetect(void);
+ extern int Grow_Add_device(char *devname, int fd, char *newdev);
+ extern int Grow_addbitmap(char *devname, int fd,
+@@ -1532,7 +1532,7 @@ extern int Monitor(struct mddev_dev *devlist,
+ extern int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl);
+ extern int Kill_subarray(char *dev, char *subarray, int verbose);
+-extern int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident *ident, int quiet);
++extern int Update_subarray(char *dev, char *subarray, enum update_opt update, struct mddev_ident *ident, int quiet);
+ extern int Wait(char *dev);
+ extern int WaitClean(char *dev, int verbose);
+ extern int SetAction(char *dev, char *action);
+-- 
+2.38.1
+
diff --git a/0076-Change-char-to-enum-in-context-update-refactor-code.patch b/0076-Change-char-to-enum-in-context-update-refactor-code.patch
new file mode 100644 (file)
index 0000000..a18f8d1
--- /dev/null
@@ -0,0 +1,289 @@
+From 3a87fa67112dc2c2c3664aeecd0b49cb4b6ceaa9 Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:35:24 +0100
+Subject: [PATCH 76/83] Change char* to enum in context->update & refactor code
+
+Storing update option in string is bad for frequent comparisons and
+error prone.
+Replace char array with enum so already existing enum is passed around
+instead of string.
+Adapt code to changes.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Assemble.c | 40 +++++++++++++++++-----------------------
+ mdadm.c    | 52 +++++++++++++++++++---------------------------------
+ mdadm.h    |  2 +-
+ 3 files changed, 37 insertions(+), 57 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index dba910cd..49804941 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -135,17 +135,17 @@ static int ident_matches(struct mddev_ident *ident,
+                        struct mdinfo *content,
+                        struct supertype *tst,
+                        char *homehost, int require_homehost,
+-                       char *update, char *devname)
++                       enum update_opt update, char *devname)
+ {
+-      if (ident->uuid_set && (!update || strcmp(update, "uuid")!= 0) &&
++      if (ident->uuid_set && update != UOPT_UUID &&
+           same_uuid(content->uuid, ident->uuid, tst->ss->swapuuid)==0 &&
+           memcmp(content->uuid, uuid_zero, sizeof(int[4])) != 0) {
+               if (devname)
+                       pr_err("%s has wrong uuid.\n", devname);
+               return 0;
+       }
+-      if (ident->name[0] && (!update || strcmp(update, "name")!= 0) &&
++      if (ident->name[0] && update != UOPT_NAME &&
+           name_matches(content->name, ident->name, homehost, require_homehost)==0) {
+               if (devname)
+                       pr_err("%s has wrong name.\n", devname);
+@@ -648,11 +648,10 @@ static int load_devices(struct devs *devices, char *devmap,
+                       int err;
+                       fstat(mdfd, &stb2);
+-                      if (strcmp(c->update, "uuid") == 0 && !ident->uuid_set)
++                      if (c->update == UOPT_UUID && !ident->uuid_set)
+                               random_uuid((__u8 *)ident->uuid);
+-                      if (strcmp(c->update, "ppl") == 0 &&
+-                          ident->bitmap_fd >= 0) {
++                      if (c->update == UOPT_PPL && ident->bitmap_fd >= 0) {
+                               pr_err("PPL is not compatible with bitmap\n");
+                               close(mdfd);
+                               free(devices);
+@@ -684,34 +683,30 @@ static int load_devices(struct devs *devices, char *devmap,
+                       strcpy(content->name, ident->name);
+                       content->array.md_minor = minor(stb2.st_rdev);
+-                      if (strcmp(c->update, "byteorder") == 0)
++                      if (c->update == UOPT_BYTEORDER)
+                               err = 0;
+-                      else if (strcmp(c->update, "home-cluster") == 0) {
++                      else if (c->update == UOPT_HOME_CLUSTER) {
+                               tst->cluster_name = c->homecluster;
+                               err = tst->ss->write_bitmap(tst, dfd, NameUpdate);
+-                      } else if (strcmp(c->update, "nodes") == 0) {
++                      } else if (c->update == UOPT_NODES) {
+                               tst->nodes = c->nodes;
+                               err = tst->ss->write_bitmap(tst, dfd, NodeNumUpdate);
+-                      } else if (strcmp(c->update, "revert-reshape") == 0 &&
+-                                 c->invalid_backup)
++                      } else if (c->update == UOPT_REVERT_RESHAPE && c->invalid_backup)
+                               err = tst->ss->update_super(tst, content,
+                                                           UOPT_SPEC_REVERT_RESHAPE_NOBACKUP,
+                                                           devname, c->verbose,
+                                                           ident->uuid_set,
+                                                           c->homehost);
+                       else
+-                              /*
+-                               * Mapping is temporary, will be removed in this patchset
+-                               */
+                               err = tst->ss->update_super(tst, content,
+-                                                          map_name(update_options, c->update),
++                                                          c->update,
+                                                           devname, c->verbose,
+                                                           ident->uuid_set,
+                                                           c->homehost);
+                       if (err < 0) {
+                               if (err == -1)
+                                       pr_err("--update=%s not understood for %s metadata\n",
+-                                             c->update, tst->ss->name);
++                                             map_num(update_options, c->update), tst->ss->name);
+                               tst->ss->free_super(tst);
+                               free(tst);
+                               close(mdfd);
+@@ -721,7 +716,7 @@ static int load_devices(struct devs *devices, char *devmap,
+                               *stp = st;
+                               return -1;
+                       }
+-                      if (strcmp(c->update, "uuid")==0 &&
++                      if (c->update == UOPT_UUID &&
+                           !ident->uuid_set) {
+                               ident->uuid_set = 1;
+                               memcpy(ident->uuid, content->uuid, 16);
+@@ -730,7 +725,7 @@ static int load_devices(struct devs *devices, char *devmap,
+                               pr_err("Could not re-write superblock on %s.\n",
+                                      devname);
+-                      if (strcmp(c->update, "uuid")==0 &&
++                      if (c->update == UOPT_UUID &&
+                           ident->bitmap_fd >= 0 && !bitmap_done) {
+                               if (bitmap_update_uuid(ident->bitmap_fd,
+                                                      content->uuid,
+@@ -1188,8 +1183,7 @@ static int start_array(int mdfd,
+                               pr_err("%s: Need a backup file to complete reshape of this array.\n",
+                                      mddev);
+                               pr_err("Please provided one with \"--backup-file=...\"\n");
+-                              if (c->update &&
+-                                  strcmp(c->update, "revert-reshape") == 0)
++                              if (c->update == UOPT_REVERT_RESHAPE)
+                                       pr_err("(Don't specify --update=revert-reshape again, that part succeeded.)\n");
+                               return 1;
+                       }
+@@ -1487,7 +1481,7 @@ try_again:
+        */
+       if (map_lock(&map))
+               pr_err("failed to get exclusive lock on mapfile - continue anyway...\n");
+-      if (c->update && strcmp(c->update,"uuid") == 0)
++      if (c->update == UOPT_UUID)
+               mp = NULL;
+       else
+               mp = map_by_uuid(&map, content->uuid);
+@@ -1634,7 +1628,7 @@ try_again:
+               goto out;
+       }
+-      if (c->update && strcmp(c->update, "byteorder")==0)
++      if (c->update == UOPT_BYTEORDER)
+               st->minor_version = 90;
+       st->ss->getinfo_super(st, content, NULL);
+@@ -1902,7 +1896,7 @@ try_again:
+       /* First, fill in the map, so that udev can find our name
+        * as soon as we become active.
+        */
+-      if (c->update && strcmp(c->update, "metadata")==0) {
++      if (c->update == UOPT_METADATA) {
+               content->array.major_version = 1;
+               content->array.minor_version = 0;
+               strcpy(content->text_version, "1.0");
+diff --git a/mdadm.c b/mdadm.c
+index d06e2820..57e8e6fa 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -724,13 +724,12 @@ int main(int argc, char *argv[])
+               case O(ASSEMBLE,'U'): /* update the superblock */
+               case O(MISC,'U'): {
+-                      enum update_opt updateopt = map_name(update_options, c.update);
+                       enum update_opt print_mode = UOPT_HELP;
+                       const char *error_addon = "update option";
+                       if (c.update) {
+                               pr_err("Can only update one aspect of superblock, both %s and %s given.\n",
+-                                      c.update, optarg);
++                                      map_num(update_options, c.update), optarg);
+                               exit(2);
+                       }
+                       if (mode == MISC && !c.subarray) {
+@@ -738,20 +737,20 @@ int main(int argc, char *argv[])
+                               exit(2);
+                       }
+-                      c.update = optarg;
++                      c.update = map_name(update_options, optarg);
+                       if (devmode == UpdateSubarray) {
+                               print_mode = UOPT_SUBARRAY_ONLY;
+                               error_addon = "update-subarray option";
+-                              if (updateopt > UOPT_SUBARRAY_ONLY && updateopt < UOPT_HELP)
+-                                      updateopt = UOPT_UNDEFINED;
++                              if (c.update > UOPT_SUBARRAY_ONLY && c.update < UOPT_HELP)
++                                      c.update = UOPT_UNDEFINED;
+                       }
+-                      switch (updateopt) {
++                      switch (c.update) {
+                       case UOPT_UNDEFINED:
+                               pr_err("'--update=%s' is invalid %s. ",
+-                                      c.update, error_addon);
++                                      optarg, error_addon);
+                               outf = stderr;
+                       case UOPT_HELP:
+                               if (!outf)
+@@ -776,14 +775,14 @@ int main(int argc, char *argv[])
+                       }
+                       if (c.update) {
+                               pr_err("Can only update one aspect of superblock, both %s and %s given.\n",
+-                                      c.update, optarg);
++                                      map_num(update_options, c.update), optarg);
+                               exit(2);
+                       }
+-                      c.update = optarg;
+-                      if (strcmp(c.update, "devicesize") != 0 &&
+-                          strcmp(c.update, "bbl") != 0 &&
+-                          strcmp(c.update, "force-no-bbl") != 0 &&
+-                          strcmp(c.update, "no-bbl") != 0) {
++                      c.update = map_name(update_options, optarg);
++                      if (c.update != UOPT_DEVICESIZE &&
++                          c.update != UOPT_BBL &&
++                          c.update != UOPT_NO_BBL &&
++                          c.update != UOPT_FORCE_NO_BBL) {
+                               pr_err("only 'devicesize', 'bbl', 'no-bbl', and 'force-no-bbl' can be updated with --re-add\n");
+                               exit(2);
+                       }
+@@ -1357,7 +1356,7 @@ int main(int argc, char *argv[])
+               }
+       }
+-      if (c.update && strcmp(c.update, "nodes") == 0 && c.nodes == 0) {
++      if (c.update && c.update == UOPT_NODES && c.nodes == 0) {
+               pr_err("Please specify nodes number with --nodes\n");
+               exit(1);
+       }
+@@ -1402,22 +1401,10 @@ int main(int argc, char *argv[])
+               /* readonly, add/remove, readwrite, runstop */
+               if (c.readonly > 0)
+                       rv = Manage_ro(devlist->devname, mdfd, c.readonly);
+-              if (!rv && devs_found > 1) {
+-                      /*
+-                       * This is temporary and will be removed in next patches
+-                       * Null c.update will cause segfault
+-                       */
+-                      if (c.update)
+-                              rv = Manage_subdevs(devlist->devname, mdfd,
+-                                              devlist->next, c.verbose, c.test,
+-                                              map_name(update_options, c.update),
+-                                              c.force);
+-                      else
+-                              rv = Manage_subdevs(devlist->devname, mdfd,
+-                                              devlist->next, c.verbose, c.test,
+-                                              UOPT_UNDEFINED,
+-                                              c.force);
+-              }
++              if (!rv && devs_found > 1)
++                      rv = Manage_subdevs(devlist->devname, mdfd,
++                                          devlist->next, c.verbose,
++                                          c.test, c.update, c.force);
+               if (!rv && c.readonly < 0)
+                       rv = Manage_ro(devlist->devname, mdfd, c.readonly);
+               if (!rv && c.runstop > 0)
+@@ -1937,14 +1924,13 @@ static int misc_list(struct mddev_dev *devlist,
+                       rv |= Kill_subarray(dv->devname, c->subarray, c->verbose);
+                       continue;
+               case UpdateSubarray:
+-                      if (c->update == NULL) {
++                      if (!c->update) {
+                               pr_err("-U/--update must be specified with --update-subarray\n");
+                               rv |= 1;
+                               continue;
+                       }
+                       rv |= Update_subarray(dv->devname, c->subarray,
+-                                            map_name(update_options, c->update),
+-                                            ident, c->verbose);
++                                            c->update, ident, c->verbose);
+                       continue;
+               case Dump:
+                       rv |= Dump_metadata(dv->devname, dump_directory, c, ss);
+diff --git a/mdadm.h b/mdadm.h
+index 924f4b63..13f8b4cb 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -616,7 +616,7 @@ struct context {
+       int     export;
+       int     test;
+       char    *subarray;
+-      char    *update;
++      enum    update_opt update;
+       int     scan;
+       int     SparcAdjust;
+       int     autof;
+-- 
+2.38.1
+
diff --git a/0077-mdmon-fix-segfault.patch b/0077-mdmon-fix-segfault.patch
new file mode 100644 (file)
index 0000000..980ceda
--- /dev/null
@@ -0,0 +1,86 @@
+From 9b429fc0a4ffd7028b3b336589d38e32fb9045dc Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:46:21 +0100
+Subject: [PATCH 77/83] mdmon: fix segfault
+
+Mdmon crashes if stat2devnm returns null.
+Use open_mddev to check if device is mddevice and get name using
+fd2devnm.
+Refactor container name handling.
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Makefile |  2 +-
+ mdmon.c  | 26 ++++++++++++--------------
+ 2 files changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index ec1f99ed..5eac1a4e 100644
+--- a/Makefile
++++ b/Makefile
+@@ -160,7 +160,7 @@ SRCS =  $(patsubst %.o,%.c,$(OBJS))
+ INCL = mdadm.h part.h bitmap.h
+-MON_OBJS = mdmon.o monitor.o managemon.o uuid.o util.o maps.o mdstat.o sysfs.o \
++MON_OBJS = mdmon.o monitor.o managemon.o uuid.o util.o maps.o mdstat.o sysfs.o config.o mapfile.o mdopen.o\
+       policy.o lib.o \
+       Kill.o sg_io.o dlink.o ReadMe.o super-intel.o \
+       super-mbr.o super-gpt.o \
+diff --git a/mdmon.c b/mdmon.c
+index e9d035eb..ecf52dc8 100644
+--- a/mdmon.c
++++ b/mdmon.c
+@@ -363,14 +363,14 @@ int main(int argc, char *argv[])
+       }
+       if (all == 0 && container_name == NULL) {
+-              if (argv[optind])
+-                      container_name = argv[optind];
++              if (argv[optind]) {
++                      container_name = get_md_name(argv[optind]);
++                      if (!container_name)
++                              container_name = argv[optind];
++              }
+       }
+-      if (container_name == NULL)
+-              usage();
+-
+-      if (argc - optind > 1)
++      if (container_name == NULL || argc - optind > 1)
+               usage();
+       if (strcmp(container_name, "/proc/mdstat") == 0)
+@@ -402,21 +402,19 @@ int main(int argc, char *argv[])
+               free_mdstat(mdstat);
+               return status;
+-      } else if (strncmp(container_name, "md", 2) == 0) {
+-              int id = devnm2devid(container_name);
+-              if (id)
+-                      devnm = container_name;
+       } else {
+-              struct stat st;
++              int mdfd = open_mddev(container_name, 1);
+-              if (stat(container_name, &st) == 0)
+-                      devnm = xstrdup(stat2devnm(&st));
++              if (mdfd < 0)
++                      return 1;
++              devnm = fd2devnm(mdfd);
++              close(mdfd);
+       }
+       if (!devnm) {
+               pr_err("%s is not a valid md device name\n",
+                       container_name);
+-              exit(1);
++              return 1;
+       }
+       return mdmon(devnm, dofork && do_fork(), takeover);
+ }
+-- 
+2.38.1
+
diff --git a/0078-util-remove-obsolete-code-from-get_md_name.patch b/0078-util-remove-obsolete-code-from-get_md_name.patch
new file mode 100644 (file)
index 0000000..b371d39
--- /dev/null
@@ -0,0 +1,116 @@
+From b938519e7719c992dae2d61c796c45fe49e6b71b Mon Sep 17 00:00:00 2001
+From: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Date: Mon, 2 Jan 2023 09:46:22 +0100
+Subject: [PATCH 78/83] util: remove obsolete code from get_md_name
+
+get_md_name() is used only with mdstat entries.
+Remove dead code and simplyfy function.
+
+Remove redundadnt checks from mdmon.c
+
+Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ mdmon.c |  8 +++-----
+ util.c  | 51 +++++++++++++++++----------------------------------
+ 2 files changed, 20 insertions(+), 39 deletions(-)
+
+diff --git a/mdmon.c b/mdmon.c
+index ecf52dc8..60ba3182 100644
+--- a/mdmon.c
++++ b/mdmon.c
+@@ -366,7 +366,7 @@ int main(int argc, char *argv[])
+               if (argv[optind]) {
+                       container_name = get_md_name(argv[optind]);
+                       if (!container_name)
+-                              container_name = argv[optind];
++                              return 1;
+               }
+       }
+@@ -403,11 +403,9 @@ int main(int argc, char *argv[])
+               return status;
+       } else {
+-              int mdfd = open_mddev(container_name, 1);
+-
+-              if (mdfd < 0)
+-                      return 1;
++              int mdfd = open_mddev(container_name, 0);
+               devnm = fd2devnm(mdfd);
++
+               close(mdfd);
+       }
+diff --git a/util.c b/util.c
+index 26ffdcea..9cd89fa4 100644
+--- a/util.c
++++ b/util.c
+@@ -968,47 +968,30 @@ dev_t devnm2devid(char *devnm)
+       return 0;
+ }
++/**
++ * get_md_name() - Get main dev node of the md device.
++ * @devnm: Md device name or path.
++ *
++ * Function checks if the full name was passed and returns md name
++ * if it is the MD device.
++ *
++ * Return: Main dev node of the md device or NULL if not found.
++ */
+ char *get_md_name(char *devnm)
+ {
+-      /* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */
+-      /* if dev < 0, want /dev/md/d%d or find mdp in /proc/devices ... */
+-
+-      static char devname[50];
++      static char devname[NAME_MAX];
+       struct stat stb;
+-      dev_t rdev = devnm2devid(devnm);
+-      char *dn;
+-      if (rdev == 0)
+-              return 0;
+-      if (strncmp(devnm, "md_", 3) == 0) {
+-              snprintf(devname, sizeof(devname), "/dev/md/%s",
+-                      devnm + 3);
+-              if (stat(devname, &stb) == 0 &&
+-                  (S_IFMT&stb.st_mode) == S_IFBLK && (stb.st_rdev == rdev))
+-                      return devname;
+-      }
+-      snprintf(devname, sizeof(devname), "/dev/%s", devnm);
+-      if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
+-          (stb.st_rdev == rdev))
+-              return devname;
++      if (strncmp(devnm, "/dev/", 5) == 0)
++              snprintf(devname, sizeof(devname), "%s", devnm);
++      else
++              snprintf(devname, sizeof(devname), "/dev/%s", devnm);
+-      snprintf(devname, sizeof(devname), "/dev/md/%s", devnm+2);
+-      if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
+-          (stb.st_rdev == rdev))
++      if (!is_mddev(devname))
++              return NULL;
++      if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK)
+               return devname;
+-      dn = map_dev(major(rdev), minor(rdev), 0);
+-      if (dn)
+-              return dn;
+-      snprintf(devname, sizeof(devname), "/dev/.tmp.%s", devnm);
+-      if (mknod(devname, S_IFBLK | 0600, rdev) == -1)
+-              if (errno != EEXIST)
+-                      return NULL;
+-
+-      if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
+-          (stb.st_rdev == rdev))
+-              return devname;
+-      unlink(devname);
+       return NULL;
+ }
+-- 
+2.38.1
+
diff --git a/0079-mdadm-udev-Don-t-handle-change-event-on-raw-devices.patch b/0079-mdadm-udev-Don-t-handle-change-event-on-raw-devices.patch
new file mode 100644 (file)
index 0000000..f888a09
--- /dev/null
@@ -0,0 +1,54 @@
+From 24d329fc97a64ec185ef27e59730f3f058c09029 Mon Sep 17 00:00:00 2001
+From: Xiao Ni <xni@redhat.com>
+Date: Thu, 5 Jan 2023 00:29:20 +0800
+Subject: [PATCH 79/83] mdadm/udev: Don't handle change event on raw devices
+
+The raw devices are ready when add event happpens and the raid
+can be assembled. So there is no need to handle change events.
+And it can cause some inconvenient problems.
+
+For example, the OS is installed on md0(/root) and md1(/home).
+md0 and md1 are created on partitions. When it wants to re-install
+OS, anaconda can't clear the storage configure. It deletes one
+partition and does some jobs. The change event happens. Now
+the raid device is assembled again. It can't delete the other
+partitions.
+
+So in this patch, we don't handle change event on raw devices
+anymore.
+
+Signed-off-by: Xiao Ni <xni@redhat.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ udev-md-raid-assembly.rules | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/udev-md-raid-assembly.rules b/udev-md-raid-assembly.rules
+index 39b4344b..d4a7f0a5 100644
+--- a/udev-md-raid-assembly.rules
++++ b/udev-md-raid-assembly.rules
+@@ -11,6 +11,11 @@ SUBSYSTEM!="block", GOTO="md_inc_end"
+ ENV{SYSTEMD_READY}=="0", GOTO="md_inc_end"
+ # handle potential components of arrays (the ones supported by md)
++# For member devices which are md/dm devices, we don't need to
++# handle add event. Because md/dm devices need to do some init jobs.
++# Then the change event happens.
++# When adding md/dm devices, ID_FS_TYPE can only be linux_raid_member
++# after change event happens.
+ ENV{ID_FS_TYPE}=="linux_raid_member", GOTO="md_inc"
+ # "noiswmd" on kernel command line stops mdadm from handling
+@@ -28,6 +33,9 @@ GOTO="md_inc_end"
+ LABEL="md_inc"
++# Bare disks are ready when add event happens, the raid can be assembled.
++ACTION=="change", KERNEL!="dm-*|md*", GOTO="md_inc_end"
++
+ # remember you can limit what gets auto/incrementally assembled by
+ # mdadm.conf(5)'s 'AUTO' and selectively whitelist using 'ARRAY'
+ ACTION!="remove", IMPORT{program}="BINDIR/mdadm --incremental --export $devnode --offroot $env{DEVLINKS}"
+-- 
+2.38.1
+
diff --git a/0080-Manage-do-not-check-array-state-when-drive-is-remove.patch b/0080-Manage-do-not-check-array-state-when-drive-is-remove.patch
new file mode 100644 (file)
index 0000000..e2c1179
--- /dev/null
@@ -0,0 +1,33 @@
+From b3e7b7eb1dfedd7cbd9a3800e884941f67d94c96 Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Tue, 27 Dec 2022 06:50:42 +0100
+Subject: [PATCH 80/83] Manage: do not check array state when drive is removed
+
+Array state doesn't need to be checked when drive is
+removed, but until now clean state was required. Result
+of the is_remove_safe() function will be independent
+from array state.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Manage.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/Manage.c b/Manage.c
+index 594e3d2c..4d6e54b1 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -1321,8 +1321,7 @@ bool is_remove_safe(mdu_array_info_t *array, const int fd, char *devname, const
+       sysfs_free(mdi);
+       bool is_enough = enough(array->level, array->raid_disks,
+-                              array->layout, (array->state & 1),
+-                              avail);
++                              array->layout, 1, avail);
+       free(avail);
+       return is_enough;
+-- 
+2.38.1
+
diff --git a/0081-incremental-manage-do-not-verify-if-remove-is-safe.patch b/0081-incremental-manage-do-not-verify-if-remove-is-safe.patch
new file mode 100644 (file)
index 0000000..4e0169c
--- /dev/null
@@ -0,0 +1,59 @@
+From 461fae7e7809670d286cc19aac5bfa861c29f93a Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Tue, 27 Dec 2022 06:50:43 +0100
+Subject: [PATCH 81/83] incremental, manage: do not verify if remove is safe
+
+Function is_remove_safe() was introduced to verify if removing
+member device won't cause failed state of the array. This
+verification should be used only with set-faulty command. Add
+special mode indicating that Incremental removal was executed.
+If this mode is used do not execute is_remove_safe() routine.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Incremental.c | 2 +-
+ Manage.c      | 7 ++++---
+ 2 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/Incremental.c b/Incremental.c
+index ff3548c0..09b94b9f 100644
+--- a/Incremental.c
++++ b/Incremental.c
+@@ -1744,7 +1744,7 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
+       memset(&devlist, 0, sizeof(devlist));
+       devlist.devname = devname;
+-      devlist.disposition = 'f';
++      devlist.disposition = 'I';
+       /* for a container, we must fail each member array */
+       if (ent->metadata_version &&
+           strncmp(ent->metadata_version, "external:", 9) == 0) {
+diff --git a/Manage.c b/Manage.c
+index 4d6e54b1..6184d3f7 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -1494,8 +1494,9 @@ int Manage_subdevs(char *devname, int fd,
+                       /* Assume this is a kernel-internal name like 'sda1' */
+                       int found = 0;
+                       char dname[55];
+-                      if (dv->disposition != 'r' && dv->disposition != 'f') {
+-                              pr_err("%s only meaningful with -r or -f, not -%c\n",
++                      if (dv->disposition != 'r' && dv->disposition != 'f' &&
++                          dv->disposition != 'I') {
++                              pr_err("%s only meaningful with -r, -f or -I, not -%c\n",
+                                       dv->devname, dv->disposition);
+                               goto abort;
+                       }
+@@ -1647,7 +1648,7 @@ int Manage_subdevs(char *devname, int fd,
+                                       close(sysfd);
+                               goto abort;
+                       }
+-
++              case 'I': /* incremental fail */
+                       if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) ||
+                           (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY,
+                                               rdev))) {
+-- 
+2.38.1
+
diff --git a/0082-super-intel-make-freesize-not-required-for-chunk-siz.patch b/0082-super-intel-make-freesize-not-required-for-chunk-siz.patch
new file mode 100644 (file)
index 0000000..0035c89
--- /dev/null
@@ -0,0 +1,52 @@
+From 071f839ea549e2a384cd13bba445245cd87e48b1 Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Fri, 28 Oct 2022 04:51:17 +0200
+Subject: [PATCH 82/83] super-intel: make freesize not required for chunk size
+ migration
+
+Freesize is needed to be set for migrations where size of RAID could
+be changed - expand. It tells how many free space is determined for
+members. In chunk size migartion freesize is not needed to be set,
+pointer shouldn't be checked if exists. This commit moves check to
+condition which contains size calculations, instead of checking it
+always at the first step.
+Fix return value when superblock is not set.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super-intel.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 1f5f6eda..89fac626 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -7719,11 +7719,11 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+               struct intel_super *super = st->sb;
+               /*
+-               * Autolayout mode, st->sb and freesize must be set.
++               * Autolayout mode, st->sb must be set.
+                */
+-              if (!super || !freesize) {
+-                      pr_vrb("freesize and superblock must be set for autolayout, aborting\n");
+-                      return 1;
++              if (!super) {
++                      pr_vrb("superblock must be set for autolayout, aborting\n");
++                      return 0;
+               }
+               if (!validate_geometry_imsm_orom(st->sb, level, layout,
+@@ -7731,7 +7731,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+                                                verbose))
+                       return 0;
+-              if (super->orom) {
++              if (super->orom && freesize) {
+                       imsm_status_t rv;
+                       int count = count_volumes(super->hba, super->orom->dpa,
+                                             verbose);
+-- 
+2.38.1
+
diff --git a/0083-manage-move-comment-with-function-description.patch b/0083-manage-move-comment-with-function-description.patch
new file mode 100644 (file)
index 0000000..091854f
--- /dev/null
@@ -0,0 +1,105 @@
+From 36a707824eb1dafbb990f5daf1cbbe0e37dbbefb Mon Sep 17 00:00:00 2001
+From: Kinga Tanska <kinga.tanska@intel.com>
+Date: Thu, 5 Jan 2023 06:31:25 +0100
+Subject: [PATCH 83/83] manage: move comment with function description
+
+Move the function description from the function body to outside
+to obey kernel coding style.
+
+Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Manage.c | 72 ++++++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 44 insertions(+), 28 deletions(-)
+
+diff --git a/Manage.c b/Manage.c
+index 6184d3f7..fde6aba3 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -1327,38 +1327,54 @@ bool is_remove_safe(mdu_array_info_t *array, const int fd, char *devname, const
+       return is_enough;
+ }
++/**
++ * Manage_subdevs() - Execute operation depending on devmode.
++ *
++ * @devname: name of the device.
++ * @fd: file descriptor.
++ * @devlist: list of sub-devices to manage.
++ * @verbose: verbose level.
++ * @test: test flag.
++ * @update: type of update.
++ * @force: force flag.
++ *
++ * This function executes operation defined by devmode
++ * for each dev from devlist.
++ * Devmode can be:
++ * 'a' - add the device
++ * 'S' - add the device as a spare - don't try re-add
++ * 'j' - add the device as a journal device
++ * 'A' - re-add the device
++ * 'r' - remove the device: HOT_REMOVE_DISK
++ *       device can be 'faulty' or 'detached' in which case all
++ *       matching devices are removed.
++ * 'f' - set the device faulty SET_DISK_FAULTY
++ *       device can be 'detached' in which case any device that
++ *       is inaccessible will be marked faulty.
++ * 'I' - remove device by using incremental fail
++ *       which is executed when device is removed surprisingly.
++ * 'R' - mark this device as wanting replacement.
++ * 'W' - this device is added if necessary and activated as
++ *       a replacement for a previous 'R' device.
++ * -----
++ * 'w' - 'W' will be changed to 'w' when it is paired with
++ *       a 'R' device.  If a 'W' is found while walking the list
++ *       it must be unpaired, and is an error.
++ * 'M' - this is created by a 'missing' target.  It is a slight
++ *       variant on 'A'
++ * 'F' - Another variant of 'A', where the device was faulty
++ *       so must be removed from the array first.
++ * 'c' - confirm the device as found (for clustered environments)
++ *
++ * For 'f' and 'r', the device can also be a kernel-internal
++ * name such as 'sdb'.
++ *
++ * Return: 0 on success, otherwise 1 or 2.
++ */
+ int Manage_subdevs(char *devname, int fd,
+                  struct mddev_dev *devlist, int verbose, int test,
+                  enum update_opt update, int force)
+ {
+-      /* Do something to each dev.
+-       * devmode can be
+-       *  'a' - add the device
+-       *  'S' - add the device as a spare - don't try re-add
+-       *  'j' - add the device as a journal device
+-       *  'A' - re-add the device
+-       *  'r' - remove the device: HOT_REMOVE_DISK
+-       *        device can be 'faulty' or 'detached' in which case all
+-       *        matching devices are removed.
+-       *  'f' - set the device faulty SET_DISK_FAULTY
+-       *        device can be 'detached' in which case any device that
+-       *        is inaccessible will be marked faulty.
+-       *  'R' - mark this device as wanting replacement.
+-       *  'W' - this device is added if necessary and activated as
+-       *        a replacement for a previous 'R' device.
+-       * -----
+-       *  'w' - 'W' will be changed to 'w' when it is paired with
+-       *        a 'R' device.  If a 'W' is found while walking the list
+-       *        it must be unpaired, and is an error.
+-       *  'M' - this is created by a 'missing' target.  It is a slight
+-       *        variant on 'A'
+-       *  'F' - Another variant of 'A', where the device was faulty
+-       *        so must be removed from the array first.
+-       *  'c' - confirm the device as found (for clustered environments)
+-       *
+-       * For 'f' and 'r', the device can also be a kernel-internal
+-       * name such as 'sdb'.
+-       */
+       mdu_array_info_t array;
+       unsigned long long array_size;
+       struct mddev_dev *dv;
+-- 
+2.38.1
+
diff --git a/0084-Revert-mdadm-systemd-remove-KillMode-none-from-servi.patch b/0084-Revert-mdadm-systemd-remove-KillMode-none-from-servi.patch
new file mode 100644 (file)
index 0000000..d824449
--- /dev/null
@@ -0,0 +1,54 @@
+From 28a083955c6f58f8e582734c8c82aff909a7d461 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Thu, 2 Feb 2023 08:56:31 +0100
+Subject: [PATCH 084/120] Revert "mdadm/systemd: remove KillMode=none from
+ service file"
+
+This reverts commit 52c67fcdd6dadc4138ecad73e65599551804d445.
+
+The functionality is marked as deprecated but we don't have alternative
+solution yet. Shutdown hangs if OS is installed on external array:
+
+task:umount state:D stack: 0 pid: 6285 ppid: flags:0x00004084
+Call Trace:
+__schedule+0x2d1/0x830
+? finish_wait+0x80/0x80
+schedule+0x35/0xa0
+md_write_start+0x14b/0x220
+? finish_wait+0x80/0x80
+raid1_make_request+0x3c/0x90 [raid1]
+md_handle_request+0x128/0x1b0
+md_make_request+0x5b/0xb0
+generic_make_request_no_check+0x202/0x330
+submit_bio+0x3c/0x160
+
+Use it until new solution is implemented.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ systemd/mdadm-grow-continue@.service | 1 +
+ systemd/mdmon@.service               | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/systemd/mdadm-grow-continue@.service b/systemd/mdadm-grow-continue@.service
+index 64b8254a..9ccadca3 100644
+--- a/systemd/mdadm-grow-continue@.service
++++ b/systemd/mdadm-grow-continue@.service
+@@ -15,3 +15,4 @@ ExecStart=BINDIR/mdadm --grow --continue /dev/%I
+ StandardInput=null
+ StandardOutput=null
+ StandardError=null
++KillMode=none
+diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service
+index 97a1acd9..cb6482d9 100644
+--- a/systemd/mdmon@.service
++++ b/systemd/mdmon@.service
+@@ -26,3 +26,4 @@ Type=forking
+ # it out) and systemd will remove it when transitioning from
+ # initramfs to rootfs.
+ #PIDFile=/run/mdadm/%I.pid
++KillMode=none
+-- 
+2.38.1
+
diff --git a/0085-Grow-fix-can-t-change-bitmap-type-from-none-to-clust.patch b/0085-Grow-fix-can-t-change-bitmap-type-from-none-to-clust.patch
new file mode 100644 (file)
index 0000000..0bc1069
--- /dev/null
@@ -0,0 +1,45 @@
+From d07e561810a2e33b667a8a9476edaff42eb119b9 Mon Sep 17 00:00:00 2001
+From: Heming Zhao <heming.zhao@suse.com>
+Date: Thu, 23 Feb 2023 22:39:39 +0800
+Subject: [PATCH 085/120] Grow: fix can't change bitmap type from none to
+ clustered.
+
+Commit a042210648ed ("disallow create or grow clustered bitmap with
+writemostly set") introduced this bug. We should use 'true' logic not
+'== 0' to deny setting up clustered array under WRITEMOSTLY condition.
+
+How to trigger
+
+```
+~/mdadm # ./mdadm -Ss && ./mdadm --zero-superblock /dev/sd{a,b}
+~/mdadm # ./mdadm -C /dev/md0 -l mirror -b clustered -e 1.2 -n 2 \
+/dev/sda /dev/sdb --assume-clean
+mdadm: array /dev/md0 started.
+~/mdadm # ./mdadm --grow /dev/md0 --bitmap=none
+~/mdadm # ./mdadm --grow /dev/md0 --bitmap=clustered
+mdadm: /dev/md0 disks marked write-mostly are not supported with clustered bitmap
+```
+
+Signed-off-by: Heming Zhao <heming.zhao@suse.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Grow.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Grow.c b/Grow.c
+index 8f5cf07d..bb5fe45c 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -429,7 +429,7 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
+                       dv = map_dev(disk.major, disk.minor, 1);
+                       if (!dv)
+                               continue;
+-                      if (((disk.state & (1 << MD_DISK_WRITEMOSTLY)) == 0) &&
++                      if ((disk.state & (1 << MD_DISK_WRITEMOSTLY)) &&
+                          (strcmp(s->bitmap_file, "clustered") == 0)) {
+                               pr_err("%s disks marked write-mostly are not supported with clustered bitmap\n",devname);
+                               free(mdi);
+-- 
+2.38.1
+
diff --git a/0086-Fix-NULL-dereference-in-super_by_fd.patch b/0086-Fix-NULL-dereference-in-super_by_fd.patch
new file mode 100644 (file)
index 0000000..95cb79a
--- /dev/null
@@ -0,0 +1,76 @@
+From f1f3ef7d2de5e3a726c27b9f9bb20e270a100dab Mon Sep 17 00:00:00 2001
+From: Li Xiao Keng <lixiaokeng@huawei.com>
+Date: Mon, 27 Feb 2023 11:12:07 +0800
+Subject: [PATCH 086/120] Fix NULL dereference in super_by_fd
+
+When we create 100 partitions (major is 259 not 254) in a raid device,
+mdadm may coredump:
+
+Core was generated by `/usr/sbin/mdadm --detail --export /dev/md1p7'.
+Program terminated with signal SIGSEGV, Segmentation fault.
+#0  __strlen_avx2_rtm () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:74
+74             VPCMPEQ (%rdi), %ymm0, %ymm1
+(gdb) bt
+#0  __strlen_avx2_rtm () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:74
+#1  0x00007fbb9a7e4139 in __strcpy_chk (dest=dest@entry=0x55d55d6a13ac "", src=0x0, destlen=destlen@entry=32) at strcpy_chk.c:28
+#2  0x000055d55ba1766d in strcpy (__src=<optimized out>, __dest=0x55d55d6a13ac "") at /usr/include/bits/string_fortified.h:79
+#3  super_by_fd (fd=fd@entry=3, subarrayp=subarrayp@entry=0x7fff44dfcc48) at util.c:1289
+#4  0x000055d55ba273a6 in Detail (dev=0x7fff44dfef0b "/dev/md1p7", c=0x7fff44dfe440) at Detail.c:101
+#5  0x000055d55ba0de61 in misc_list (c=<optimized out>, ss=<optimized out>, dump_directory=<optimized out>, ident=<optimized out>, devlist=<optimized out>) at mdadm.c:1959
+#6  main (argc=<optimized out>, argv=<optimized out>) at mdadm.c:1629
+
+The direct cause is fd2devnm returning NULL, so add a check.
+
+Signed-off-by: Li Xiao Keng <lixiaokeng@huawei.com>
+Signed-off-by: Wu Guang Hao <wuguanghao3@huawei.com>
+Acked-by: Coly Li <colyli@suse.de>
+Acked-by: Coly Li <colyli@suse.de <mailto:colyli@suse.de>>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ mapfile.c | 4 ++++
+ util.c    | 7 ++++++-
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/mapfile.c b/mapfile.c
+index 6b2207dd..ac351768 100644
+--- a/mapfile.c
++++ b/mapfile.c
+@@ -292,6 +292,10 @@ struct map_ent *map_by_uuid(struct map_ent **map, int uuid[4])
+ struct map_ent *map_by_devnm(struct map_ent **map, char *devnm)
+ {
+       struct map_ent *mp;
++
++      if (!devnm)
++              return NULL;
++
+       if (!*map)
+               map_read(map);
+diff --git a/util.c b/util.c
+index 9cd89fa4..8c7f3fd5 100644
+--- a/util.c
++++ b/util.c
+@@ -1160,6 +1160,11 @@ struct supertype *super_by_fd(int fd, char **subarrayp)
+       int i;
+       char *subarray = NULL;
+       char container[32] = "";
++      char *devnm = NULL;
++
++      devnm = fd2devnm(fd);
++      if (!devnm)
++              return NULL;
+       sra = sysfs_read(fd, NULL, GET_VERSION);
+@@ -1205,7 +1210,7 @@ struct supertype *super_by_fd(int fd, char **subarrayp)
+               if (subarrayp)
+                       *subarrayp = subarray;
+               strcpy(st->container_devnm, container);
+-              strcpy(st->devnm, fd2devnm(fd));
++              strncpy(st->devnm, devnm, MD_NAME_MAX - 1);
+       } else
+               free(subarray);
+-- 
+2.38.1
+
diff --git a/0087-Mdmonitor-Make-alert_info-global.patch b/0087-Mdmonitor-Make-alert_info-global.patch
new file mode 100644 (file)
index 0000000..c8da02b
--- /dev/null
@@ -0,0 +1,369 @@
+From b301516615c441bd3cc4b512fae73fc066d227f1 Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Thu, 2 Feb 2023 12:26:59 +0100
+Subject: [PATCH 087/120] Mdmonitor: Make alert_info global
+
+Move information about --test flag and hostname into alert_info.
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Monitor.c | 124 +++++++++++++++++++++++++++---------------------------
+ 1 file changed, 61 insertions(+), 63 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 188cb8be..9ef4dab8 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -58,21 +58,20 @@ struct state {
+ };
+ struct alert_info {
++      char hostname[HOST_NAME_MAX];
+       char *mailaddr;
+       char *mailfrom;
+       char *alert_cmd;
+       int dosyslog;
+-};
++      int test;
++} info;
+ static int make_daemon(char *pidfile);
+ static int check_one_sharer(int scan);
+ static void write_autorebuild_pid(void);
+-static void alert(const char *event, const char *dev, const char *disc, struct alert_info *info);
+-static int check_array(struct state *st, struct mdstat_ent *mdstat,
+-                     int test, struct alert_info *info,
+-                     int increments, char *prefer);
+-static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
+-                        int test, struct alert_info *info);
+-static void try_spare_migration(struct state *statelist, struct alert_info *info);
++static void alert(const char *event, const char *dev, const char *disc);
++static int check_array(struct state *st, struct mdstat_ent *mdstat, int increments, char *prefer);
++static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist);
++static void try_spare_migration(struct state *statelist);
+ static void link_containers_with_subarrays(struct state *list);
+ static void free_statelist(struct state *statelist);
+ #ifndef NO_LIBUDEV
+@@ -132,7 +131,6 @@ int Monitor(struct mddev_dev *devlist,
+       int finished = 0;
+       struct mdstat_ent *mdstat = NULL;
+       char *mailfrom;
+-      struct alert_info info;
+       struct mddev_ident *mdlist;
+       int delay_for_event = c->delay;
+@@ -166,6 +164,13 @@ int Monitor(struct mddev_dev *devlist,
+       info.mailaddr = mailaddr;
+       info.mailfrom = mailfrom;
+       info.dosyslog = dosyslog;
++      info.test = c->test;
++
++      if (gethostname(info.hostname, sizeof(info.hostname)) != 0) {
++              pr_err("Cannot get hostname.\n");
++              return 1;
++      }
++      info.hostname[sizeof(info.hostname) - 1] = '\0';
+       if (share){
+               if (check_one_sharer(c->scan))
+@@ -241,8 +246,7 @@ int Monitor(struct mddev_dev *devlist,
+               mdstat = mdstat_read(oneshot ? 0 : 1, 0);
+               for (st = statelist; st; st = st->next) {
+-                      if (check_array(st, mdstat, c->test, &info,
+-                                      increments, c->prefer))
++                      if (check_array(st, mdstat, increments, c->prefer))
+                               anydegraded = 1;
+                       /* for external arrays, metadata is filled for
+                        * containers only
+@@ -255,15 +259,14 @@ int Monitor(struct mddev_dev *devlist,
+               /* now check if there are any new devices found in mdstat */
+               if (c->scan)
+-                      new_found = add_new_arrays(mdstat, &statelist, c->test,
+-                                                 &info);
++                      new_found = add_new_arrays(mdstat, &statelist);
+               /* If an array has active < raid && spare == 0 && spare_group != NULL
+                * Look for another array with spare > 0 and active == raid and same spare_group
+                * if found, choose a device and hotremove/hotadd
+                */
+               if (share && anydegraded)
+-                      try_spare_migration(statelist, &info);
++                      try_spare_migration(statelist);
+               if (!new_found) {
+                       if (oneshot)
+                               break;
+@@ -294,7 +297,7 @@ int Monitor(struct mddev_dev *devlist,
+                               mdstat_close();
+                       }
+               }
+-              c->test = 0;
++              info.test = 0;
+               for (stp = &statelist; (st = *stp) != NULL; ) {
+                       if (st->from_auto && st->err > 5) {
+@@ -412,7 +415,7 @@ static void write_autorebuild_pid()
+       }
+ }
+-static void execute_alert_cmd(const char *event, const char *dev, const char *disc, struct alert_info *info)
++static void execute_alert_cmd(const char *event, const char *dev, const char *disc)
+ {
+       int pid = fork();
+@@ -424,15 +427,14 @@ static void execute_alert_cmd(const char *event, const char *dev, const char *di
+               pr_err("Cannot fork to execute alert command");
+               break;
+       case 0:
+-              execl(info->alert_cmd, info->alert_cmd, event, dev, disc, NULL);
++              execl(info.alert_cmd, info.alert_cmd, event, dev, disc, NULL);
+               exit(2);
+       }
+ }
+-static void send_event_email(const char *event, const char *dev, const char *disc, struct alert_info *info)
++static void send_event_email(const char *event, const char *dev, const char *disc)
+ {
+       FILE *mp, *mdstat;
+-      char hname[256];
+       char buf[BUFSIZ];
+       int n;
+@@ -442,14 +444,13 @@ static void send_event_email(const char *event, const char *dev, const char *dis
+               return;
+       }
+-      gethostname(hname, sizeof(hname));
+       signal(SIGPIPE, SIG_IGN);
+-      if (info->mailfrom)
+-              fprintf(mp, "From: %s\n", info->mailfrom);
++      if (info.mailfrom)
++              fprintf(mp, "From: %s\n", info.mailfrom);
+       else
+               fprintf(mp, "From: %s monitoring <root>\n", Name);
+-      fprintf(mp, "To: %s\n", info->mailaddr);
+-      fprintf(mp, "Subject: %s event on %s:%s\n\n", event, dev, hname);
++      fprintf(mp, "To: %s\n", info.mailaddr);
++      fprintf(mp, "Subject: %s event on %s:%s\n\n", event, dev, info.hostname);
+       fprintf(mp, "This is an automatically generated mail message. \n");
+       fprintf(mp, "A %s event had been detected on md device %s.\n\n", event, dev);
+@@ -501,37 +502,36 @@ static void log_event_to_syslog(const char *event, const char *dev, const char *
+               syslog(priority, "%s event detected on md device %s", event, dev);
+ }
+-static void alert(const char *event, const char *dev, const char *disc, struct alert_info *info)
++static void alert(const char *event, const char *dev, const char *disc)
+ {
+-      if (!info->alert_cmd && !info->mailaddr && !info->dosyslog) {
++      if (!info.alert_cmd && !info.mailaddr && !info.dosyslog) {
+               time_t now = time(0);
+               printf("%1.15s: %s on %s %s\n", ctime(&now) + 4,
+                      event, dev, disc?disc:"unknown device");
+       }
+-      if (info->alert_cmd)
+-              execute_alert_cmd(event, dev, disc, info);
++      if (info.alert_cmd)
++              execute_alert_cmd(event, dev, disc);
+-      if (info->mailaddr && (strncmp(event, "Fail", 4) == 0 ||
++      if (info.mailaddr && (strncmp(event, "Fail", 4) == 0 ||
+                              strncmp(event, "Test", 4) == 0 ||
+                              strncmp(event, "Spares", 6) == 0 ||
+                              strncmp(event, "Degrade", 7) == 0)) {
+-              send_event_email(event, dev, disc, info);
++              send_event_email(event, dev, disc);
+       }
+-      if (info->dosyslog)
++      if (info.dosyslog)
+               log_event_to_syslog(event, dev, disc);
+ }
+ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+-                     int test, struct alert_info *ainfo,
+                      int increments, char *prefer)
+ {
+       /* Update the state 'st' to reflect any changes shown in mdstat,
+        * or found by directly examining the array, and return
+        * '1' if the array is degraded, or '0' if it is optimal (or dead).
+        */
+-      struct { int state, major, minor; } info[MAX_DISKS];
++      struct { int state, major, minor; } disks_info[MAX_DISKS];
+       struct mdinfo *sra = NULL;
+       mdu_array_info_t array;
+       struct mdstat_ent *mse = NULL, *mse2;
+@@ -545,8 +545,8 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+       int is_container = 0;
+       unsigned long redundancy_only_flags = 0;
+-      if (test)
+-              alert("TestMessage", dev, NULL, ainfo);
++      if (info.test)
++              alert("TestMessage", dev, NULL);
+       retval = 0;
+@@ -595,7 +595,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+        */
+       if (sra->array.level == 0 || sra->array.level == -1) {
+               if (!st->err && !st->from_config)
+-                      alert("DeviceDisappeared", dev, " Wrong-Level", ainfo);
++                      alert("DeviceDisappeared", dev, " Wrong-Level");
+               st->err++;
+               goto out;
+       }
+@@ -612,7 +612,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+               st->percent = RESYNC_NONE;
+               new_array = 1;
+               if (!is_container)
+-                      alert("NewArray", st->devname, NULL, ainfo);
++                      alert("NewArray", st->devname, NULL);
+       }
+       if (st->utime == array.utime && st->failed == sra->array.failed_disks &&
+@@ -625,14 +625,14 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+       }
+       if (st->utime == 0 && /* new array */
+           mse->pattern && strchr(mse->pattern, '_') /* degraded */)
+-              alert("DegradedArray", dev, NULL, ainfo);
++              alert("DegradedArray", dev, NULL);
+       if (st->utime == 0 && /* new array */ st->expected_spares > 0 &&
+           sra->array.spare_disks < st->expected_spares)
+-              alert("SparesMissing", dev, NULL, ainfo);
++              alert("SparesMissing", dev, NULL);
+       if (st->percent < 0 && st->percent != RESYNC_UNKNOWN &&
+           mse->percent >= 0)
+-              alert("RebuildStarted", dev, NULL, ainfo);
++              alert("RebuildStarted", dev, NULL);
+       if (st->percent >= 0 && mse->percent >= 0 &&
+           (mse->percent / increments) > (st->percent / increments)) {
+               char percentalert[18];
+@@ -647,7 +647,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+                       snprintf(percentalert, sizeof(percentalert),
+                                "Rebuild%02d", mse->percent);
+-              alert(percentalert, dev, NULL, ainfo);
++              alert(percentalert, dev, NULL);
+       }
+       if (mse->percent == RESYNC_NONE && st->percent >= 0) {
+@@ -660,9 +660,9 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+                       snprintf(cnt, sizeof(cnt),
+                                " mismatches found: %d (on raid level %d)",
+                                sra->mismatch_cnt, sra->array.level);
+-                      alert("RebuildFinished", dev, cnt, ainfo);
++                      alert("RebuildFinished", dev, cnt);
+               } else
+-                      alert("RebuildFinished", dev, NULL, ainfo);
++                      alert("RebuildFinished", dev, NULL);
+       }
+       st->percent = mse->percent;
+@@ -671,13 +671,13 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+               mdu_disk_info_t disc;
+               disc.number = i;
+               if (md_get_disk_info(fd, &disc) >= 0) {
+-                      info[i].state = disc.state;
+-                      info[i].major = disc.major;
+-                      info[i].minor = disc.minor;
++                      disks_info[i].state = disc.state;
++                      disks_info[i].major = disc.major;
++                      disks_info[i].minor = disc.minor;
+                       if (disc.major || disc.minor)
+                               remaining_disks --;
+               } else
+-                      info[i].major = info[i].minor = 0;
++                      disks_info[i].major = disks_info[i].minor = 0;
+       }
+       last_disk = i;
+@@ -700,13 +700,13 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+               int change;
+               char *dv = NULL;
+               disc.number = i;
+-              if (i < last_disk && (info[i].major || info[i].minor)) {
+-                      newstate = info[i].state;
+-                      dv = map_dev_preferred(info[i].major, info[i].minor, 1,
++              if (i < last_disk && (disks_info[i].major || disks_info[i].minor)) {
++                      newstate = disks_info[i].state;
++                      dv = map_dev_preferred(disks_info[i].major, disks_info[i].minor, 1,
+                                              prefer);
+                       disc.state = newstate;
+-                      disc.major = info[i].major;
+-                      disc.minor = info[i].minor;
++                      disc.major = disks_info[i].major;
++                      disc.minor = disks_info[i].minor;
+               } else
+                       newstate = (1 << MD_DISK_REMOVED);
+@@ -716,14 +716,14 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+               change = newstate ^ st->devstate[i];
+               if (st->utime && change && !st->err && !new_array) {
+                       if ((st->devstate[i]&change) & (1 << MD_DISK_SYNC))
+-                              alert("Fail", dev, dv, ainfo);
++                              alert("Fail", dev, dv);
+                       else if ((newstate & (1 << MD_DISK_FAULTY)) &&
+                                (disc.major || disc.minor) &&
+                                st->devid[i] == makedev(disc.major,
+                                                        disc.minor))
+-                              alert("FailSpare", dev, dv, ainfo);
++                              alert("FailSpare", dev, dv);
+                       else if ((newstate&change) & (1 << MD_DISK_SYNC))
+-                              alert("SpareActive", dev, dv, ainfo);
++                              alert("SpareActive", dev, dv);
+               }
+               st->devstate[i] = newstate;
+               st->devid[i] = makedev(disc.major, disc.minor);
+@@ -747,13 +747,12 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+  disappeared:
+       if (!st->err && !is_container)
+-              alert("DeviceDisappeared", dev, NULL, ainfo);
++              alert("DeviceDisappeared", dev, NULL);
+       st->err++;
+       goto out;
+ }
+-static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
+-                        int test, struct alert_info *info)
++static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist)
+ {
+       struct mdstat_ent *mse;
+       int new_found = 0;
+@@ -806,8 +805,8 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
+                       } else
+                               st->parent_devnm[0] = 0;
+                       *statelist = st;
+-                      if (test)
+-                              alert("TestMessage", st->devname, NULL, info);
++                      if (info.test)
++                              alert("TestMessage", st->devname, NULL);
+                       new_found = 1;
+               }
+       return new_found;
+@@ -971,7 +970,7 @@ static dev_t container_choose_spare(struct state *from, struct state *to,
+       return dev;
+ }
+-static void try_spare_migration(struct state *statelist, struct alert_info *info)
++static void try_spare_migration(struct state *statelist)
+ {
+       struct state *from;
+       struct state *st;
+@@ -1030,8 +1029,7 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info
+                               if (devid > 0 &&
+                                   move_spare(from->devname, to->devname,
+                                              devid)) {
+-                                      alert("MoveSpare", to->devname,
+-                                            from->devname, info);
++                                      alert("MoveSpare", to->devname, from->devname);
+                                       break;
+                               }
+                       }
+-- 
+2.38.1
+
diff --git a/0088-Mdmonitor-Pass-events-to-alert-using-enums-instead-o.patch b/0088-Mdmonitor-Pass-events-to-alert-using-enums-instead-o.patch
new file mode 100644 (file)
index 0000000..c5f2b97
--- /dev/null
@@ -0,0 +1,313 @@
+From 50232a6ec4a5c46c608181d72d0c633831a03134 Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Thu, 2 Feb 2023 12:27:00 +0100
+Subject: [PATCH 088/120] Mdmonitor: Pass events to alert() using enums instead
+ of strings
+
+Add events enum, and mapping_t struct, that maps them to strings, so
+that enums are passed around instead of strings.
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Monitor.c | 136 +++++++++++++++++++++++++++++++++---------------------
+ 1 file changed, 83 insertions(+), 53 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 9ef4dab8..029e9efd 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -32,6 +32,8 @@
+ #include      <libudev.h>
+ #endif
++#define EVENT_NAME_MAX 32
++
+ struct state {
+       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 */
+@@ -65,10 +67,43 @@ struct alert_info {
+       int dosyslog;
+       int test;
+ } info;
++
++enum event {
++      EVENT_SPARE_ACTIVE = 0,
++      EVENT_NEW_ARRAY,
++      EVENT_MOVE_SPARE,
++      EVENT_TEST_MESSAGE,
++      EVENT_REBUILD_STARTED,
++      EVENT_REBUILD,
++      EVENT_REBUILD_FINISHED,
++      EVENT_SPARES_MISSING,
++      EVENT_DEVICE_DISAPPEARED,
++      EVENT_FAIL,
++      EVENT_FAIL_SPARE,
++      EVENT_DEGRADED_ARRAY,
++      EVENT_UNKNOWN
++};
++
++mapping_t events_map[] = {
++      {"SpareActive", EVENT_SPARE_ACTIVE},
++      {"NewArray", EVENT_NEW_ARRAY},
++      {"MoveSpare", EVENT_MOVE_SPARE},
++      {"TestMessage", EVENT_TEST_MESSAGE},
++      {"RebuildStarted", EVENT_REBUILD_STARTED},
++      {"Rebuild", EVENT_REBUILD},
++      {"RebuildFinished", EVENT_REBUILD_FINISHED},
++      {"SparesMissing", EVENT_SPARES_MISSING},
++      {"DeviceDisappeared", EVENT_DEVICE_DISAPPEARED},
++      {"Fail", EVENT_FAIL},
++      {"FailSpare", EVENT_FAIL_SPARE},
++      {"DegradedArray", EVENT_DEGRADED_ARRAY},
++      {NULL, EVENT_UNKNOWN}
++};
++
+ static int make_daemon(char *pidfile);
+ static int check_one_sharer(int scan);
+ static void write_autorebuild_pid(void);
+-static void alert(const char *event, const char *dev, const char *disc);
++static void alert(const enum event event_enum, const unsigned int progress, const char *dev, const char *disc);
+ static int check_array(struct state *st, struct mdstat_ent *mdstat, int increments, char *prefer);
+ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist);
+ static void try_spare_migration(struct state *statelist);
+@@ -415,7 +450,7 @@ static void write_autorebuild_pid()
+       }
+ }
+-static void execute_alert_cmd(const char *event, const char *dev, const char *disc)
++static void execute_alert_cmd(const char *event_name, const char *dev, const char *disc)
+ {
+       int pid = fork();
+@@ -427,12 +462,12 @@ static void execute_alert_cmd(const char *event, const char *dev, const char *di
+               pr_err("Cannot fork to execute alert command");
+               break;
+       case 0:
+-              execl(info.alert_cmd, info.alert_cmd, event, dev, disc, NULL);
++              execl(info.alert_cmd, info.alert_cmd, event_name, dev, disc, NULL);
+               exit(2);
+       }
+ }
+-static void send_event_email(const char *event, const char *dev, const char *disc)
++static void send_event_email(const char *event_name, const char *dev, const char *disc)
+ {
+       FILE *mp, *mdstat;
+       char buf[BUFSIZ];
+@@ -450,9 +485,9 @@ static void send_event_email(const char *event, const char *dev, const char *dis
+       else
+               fprintf(mp, "From: %s monitoring <root>\n", Name);
+       fprintf(mp, "To: %s\n", info.mailaddr);
+-      fprintf(mp, "Subject: %s event on %s:%s\n\n", event, dev, info.hostname);
++      fprintf(mp, "Subject: %s event on %s:%s\n\n", event_name, dev, info.hostname);
+       fprintf(mp, "This is an automatically generated mail message. \n");
+-      fprintf(mp, "A %s event had been detected on md device %s.\n\n", event, dev);
++      fprintf(mp, "A %s event had been detected on md device %s.\n\n", event_name, dev);
+       if (disc && disc[0] != ' ')
+               fprintf(mp,
+@@ -474,20 +509,20 @@ static void send_event_email(const char *event, const char *dev, const char *dis
+       pclose(mp);
+ }
+-static void log_event_to_syslog(const char *event, const char *dev, const char *disc)
++static void log_event_to_syslog(const enum event event_enum, const char *event_name, const char *dev, const char *disc)
+ {
+       int priority;
+       /* Log at a different severity depending on the event.
+        *
+        * These are the critical events:  */
+-      if (strncmp(event, "Fail", 4) == 0 ||
+-              strncmp(event, "Degrade", 7) == 0 ||
+-              strncmp(event, "DeviceDisappeared", 17) == 0)
++      if (event_enum == EVENT_FAIL ||
++          event_enum == EVENT_DEGRADED_ARRAY ||
++          event_enum == EVENT_DEVICE_DISAPPEARED)
+               priority = LOG_CRIT;
+       /* Good to know about, but are not failures: */
+-      else if (strncmp(event, "Rebuild", 7) == 0 ||
+-                      strncmp(event, "MoveSpare", 9) == 0 ||
+-                      strncmp(event, "Spares", 6) != 0)
++      else if (event_enum == EVENT_REBUILD ||
++               event_enum == EVENT_MOVE_SPARE ||
++               event_enum == EVENT_SPARES_MISSING)
+               priority = LOG_WARNING;
+       /* Everything else: */
+       else
+@@ -495,33 +530,37 @@ static void log_event_to_syslog(const char *event, const char *dev, const char *
+       if (disc && disc[0] != ' ')
+               syslog(priority,
+-                      "%s event detected on md device %s, component device %s", event, dev, disc);
++                     "%s event detected on md device %s, component device %s",
++                     event_name, dev, disc);
+       else if (disc)
+-              syslog(priority, "%s event detected on md device %s: %s", event, dev, disc);
++              syslog(priority, "%s event detected on md device %s: %s", event_name, dev, disc);
+       else
+-              syslog(priority, "%s event detected on md device %s", event, dev);
++              syslog(priority, "%s event detected on md device %s", event_name, dev);
+ }
+-static void alert(const char *event, const char *dev, const char *disc)
++static void alert(const enum event event_enum, const unsigned int progress, const char *dev, const char *disc)
+ {
+-      if (!info.alert_cmd && !info.mailaddr && !info.dosyslog) {
+-              time_t now = time(0);
++      char event_name[EVENT_NAME_MAX];
+-              printf("%1.15s: %s on %s %s\n", ctime(&now) + 4,
+-                     event, dev, disc?disc:"unknown device");
++      if (event_enum == EVENT_REBUILD) {
++              snprintf(event_name, sizeof(event_name), "%s%02d",
++                       map_num_s(events_map, EVENT_REBUILD), progress);
++      } else {
++              snprintf(event_name, sizeof(event_name), "%s", map_num_s(events_map, event_enum));
+       }
++
+       if (info.alert_cmd)
+-              execute_alert_cmd(event, dev, disc);
++              execute_alert_cmd(event_name, dev, disc);
+-      if (info.mailaddr && (strncmp(event, "Fail", 4) == 0 ||
+-                             strncmp(event, "Test", 4) == 0 ||
+-                             strncmp(event, "Spares", 6) == 0 ||
+-                             strncmp(event, "Degrade", 7) == 0)) {
+-              send_event_email(event, dev, disc);
++      if (info.mailaddr && (event_enum == EVENT_FAIL ||
++                            event_enum == EVENT_TEST_MESSAGE ||
++                            event_enum == EVENT_SPARES_MISSING ||
++                            event_enum == EVENT_DEGRADED_ARRAY)) {
++              send_event_email(event_name, dev, disc);
+       }
+       if (info.dosyslog)
+-              log_event_to_syslog(event, dev, disc);
++              log_event_to_syslog(event_enum, event_name, dev, disc);
+ }
+ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+@@ -546,7 +585,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+       unsigned long redundancy_only_flags = 0;
+       if (info.test)
+-              alert("TestMessage", dev, NULL);
++              alert(EVENT_TEST_MESSAGE, 0, dev, NULL);
+       retval = 0;
+@@ -595,7 +634,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+        */
+       if (sra->array.level == 0 || sra->array.level == -1) {
+               if (!st->err && !st->from_config)
+-                      alert("DeviceDisappeared", dev, " Wrong-Level");
++                      alert(EVENT_DEVICE_DISAPPEARED, 0, dev, " Wrong-Level");
+               st->err++;
+               goto out;
+       }
+@@ -612,7 +651,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+               st->percent = RESYNC_NONE;
+               new_array = 1;
+               if (!is_container)
+-                      alert("NewArray", st->devname, NULL);
++                      alert(EVENT_NEW_ARRAY, 0, st->devname, NULL);
+       }
+       if (st->utime == array.utime && st->failed == sra->array.failed_disks &&
+@@ -625,29 +664,20 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+       }
+       if (st->utime == 0 && /* new array */
+           mse->pattern && strchr(mse->pattern, '_') /* degraded */)
+-              alert("DegradedArray", dev, NULL);
++              alert(EVENT_DEGRADED_ARRAY, 0, dev, NULL);
+       if (st->utime == 0 && /* new array */ st->expected_spares > 0 &&
+           sra->array.spare_disks < st->expected_spares)
+-              alert("SparesMissing", dev, NULL);
++              alert(EVENT_SPARES_MISSING, 0, dev, NULL);
+       if (st->percent < 0 && st->percent != RESYNC_UNKNOWN &&
+           mse->percent >= 0)
+-              alert("RebuildStarted", dev, NULL);
++              alert(EVENT_REBUILD_STARTED, 0, dev, NULL);
+       if (st->percent >= 0 && mse->percent >= 0 &&
+           (mse->percent / increments) > (st->percent / increments)) {
+-              char percentalert[18];
+-              /*
+-               * "RebuildNN" (10 chars) or "RebuildStarted" (15 chars)
+-               */
+-
+               if((mse->percent / increments) == 0)
+-                      snprintf(percentalert, sizeof(percentalert),
+-                               "RebuildStarted");
++                      alert(EVENT_REBUILD_STARTED, 0, dev, NULL);
+               else
+-                      snprintf(percentalert, sizeof(percentalert),
+-                               "Rebuild%02d", mse->percent);
+-
+-              alert(percentalert, dev, NULL);
++                      alert(EVENT_REBUILD, mse->percent, dev, NULL);
+       }
+       if (mse->percent == RESYNC_NONE && st->percent >= 0) {
+@@ -660,9 +690,9 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+                       snprintf(cnt, sizeof(cnt),
+                                " mismatches found: %d (on raid level %d)",
+                                sra->mismatch_cnt, sra->array.level);
+-                      alert("RebuildFinished", dev, cnt);
++                      alert(EVENT_REBUILD_FINISHED, 0, dev, cnt);
+               } else
+-                      alert("RebuildFinished", dev, NULL);
++                      alert(EVENT_REBUILD_FINISHED, 0, dev, NULL);
+       }
+       st->percent = mse->percent;
+@@ -716,14 +746,14 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+               change = newstate ^ st->devstate[i];
+               if (st->utime && change && !st->err && !new_array) {
+                       if ((st->devstate[i]&change) & (1 << MD_DISK_SYNC))
+-                              alert("Fail", dev, dv);
++                              alert(EVENT_FAIL, 0, dev, dv);
+                       else if ((newstate & (1 << MD_DISK_FAULTY)) &&
+                                (disc.major || disc.minor) &&
+                                st->devid[i] == makedev(disc.major,
+                                                        disc.minor))
+-                              alert("FailSpare", dev, dv);
++                              alert(EVENT_FAIL_SPARE, 0, dev, dv);
+                       else if ((newstate&change) & (1 << MD_DISK_SYNC))
+-                              alert("SpareActive", dev, dv);
++                              alert(EVENT_SPARE_ACTIVE, 0, dev, dv);
+               }
+               st->devstate[i] = newstate;
+               st->devid[i] = makedev(disc.major, disc.minor);
+@@ -747,7 +777,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+  disappeared:
+       if (!st->err && !is_container)
+-              alert("DeviceDisappeared", dev, NULL);
++              alert(EVENT_DEVICE_DISAPPEARED, 0, dev, NULL);
+       st->err++;
+       goto out;
+ }
+@@ -806,7 +836,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist)
+                               st->parent_devnm[0] = 0;
+                       *statelist = st;
+                       if (info.test)
+-                              alert("TestMessage", st->devname, NULL);
++                              alert(EVENT_TEST_MESSAGE, 0, st->devname, NULL);
+                       new_found = 1;
+               }
+       return new_found;
+@@ -1029,7 +1059,7 @@ static void try_spare_migration(struct state *statelist)
+                               if (devid > 0 &&
+                                   move_spare(from->devname, to->devname,
+                                              devid)) {
+-                                      alert("MoveSpare", to->devname, from->devname);
++                                      alert(EVENT_MOVE_SPARE, 0, to->devname, from->devname);
+                                       break;
+                               }
+                       }
+-- 
+2.38.1
+
diff --git a/0089-Mdmonitor-Add-helper-functions.patch b/0089-Mdmonitor-Add-helper-functions.patch
new file mode 100644 (file)
index 0000000..b8fc968
--- /dev/null
@@ -0,0 +1,406 @@
+From cc3df167c599d2ee0c132149c86fc0ad70d9f14e Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Thu, 2 Feb 2023 12:27:01 +0100
+Subject: [PATCH 089/120] Mdmonitor: Add helper functions
+
+Add functions:
+- is_email_event(),
+- get_syslog_event_priority(),
+- sprint_event_message(),
+with kernel style comments containing more detailed descriptions.
+
+Also update event syslog priorities to be consistent with man. MoveSpare event was described in man as priority info, while implemented as warning. Move event data into a struct, so that it is passed between different functions if needed.
+Sort function declarations alphabetically and remove redundant alert() declaration.
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Monitor.c | 228 +++++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 158 insertions(+), 70 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 029e9efd..39598ba0 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -73,10 +73,12 @@ enum event {
+       EVENT_NEW_ARRAY,
+       EVENT_MOVE_SPARE,
+       EVENT_TEST_MESSAGE,
++      __SYSLOG_PRIORITY_WARNING,
+       EVENT_REBUILD_STARTED,
+       EVENT_REBUILD,
+       EVENT_REBUILD_FINISHED,
+       EVENT_SPARES_MISSING,
++      __SYSLOG_PRIORITY_CRITICAL,
+       EVENT_DEVICE_DISAPPEARED,
+       EVENT_FAIL,
+       EVENT_FAIL_SPARE,
+@@ -100,18 +102,31 @@ mapping_t events_map[] = {
+       {NULL, EVENT_UNKNOWN}
+ };
+-static int make_daemon(char *pidfile);
+-static int check_one_sharer(int scan);
+-static void write_autorebuild_pid(void);
+-static void alert(const enum event event_enum, const unsigned int progress, const char *dev, const char *disc);
+-static int check_array(struct state *st, struct mdstat_ent *mdstat, int increments, char *prefer);
++struct event_data {
++      enum event event_enum;
++      /*
++       * @event_name: Rebuild event name must be in form "RebuildXX", where XX is rebuild progress.
++       */
++      char event_name[EVENT_NAME_MAX];
++      char message[BUFSIZ];
++      const char *description;
++      const char *dev;
++      const char *disc;
++};
++
+ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist);
+ static void try_spare_migration(struct state *statelist);
+ static void link_containers_with_subarrays(struct state *list);
+ static void free_statelist(struct state *statelist);
++static int check_array(struct state *st, struct mdstat_ent *mdstat, int increments, char *prefer);
++static int check_one_sharer(int scan);
+ #ifndef NO_LIBUDEV
+ static int check_udev_activity(void);
+ #endif
++static void link_containers_with_subarrays(struct state *list);
++static int make_daemon(char *pidfile);
++static void try_spare_migration(struct state *statelist);
++static void write_autorebuild_pid(void);
+ int Monitor(struct mddev_dev *devlist,
+           char *mailaddr, char *alert_cmd,
+@@ -450,7 +465,80 @@ static void write_autorebuild_pid()
+       }
+ }
+-static void execute_alert_cmd(const char *event_name, const char *dev, const char *disc)
++#define BASE_MESSAGE "%s event detected on md device %s"
++#define COMPONENT_DEVICE_MESSAGE ", component device %s"
++#define DESCRIPTION_MESSAGE ": %s"
++/*
++ * sprint_event_message() - Writes basic message about detected event to destination ptr.
++ * @dest: message destination, should be at least the size of BUFSIZ
++ * @data: event data
++ *
++ * Return: 0 on success, 1 on error
++ */
++static int sprint_event_message(char *dest, const struct event_data *data)
++{
++      if (!dest || !data)
++              return 1;
++
++      if (data->disc && data->description)
++              snprintf(dest, BUFSIZ, BASE_MESSAGE COMPONENT_DEVICE_MESSAGE DESCRIPTION_MESSAGE,
++                       data->event_name, data->dev, data->disc, data->description);
++      else if (data->disc)
++              snprintf(dest, BUFSIZ, BASE_MESSAGE COMPONENT_DEVICE_MESSAGE,
++                       data->event_name, data->dev, data->disc);
++      else if (data->description)
++              snprintf(dest, BUFSIZ, BASE_MESSAGE DESCRIPTION_MESSAGE,
++                       data->event_name, data->dev, data->description);
++      else
++              snprintf(dest, BUFSIZ, BASE_MESSAGE, data->event_name, data->dev);
++
++      return 0;
++}
++
++/*
++ * get_syslog_event_priority() - Determines event priority.
++ * @event_enum: event to be checked
++ *
++ * Return: LOG_CRIT, LOG_WARNING or LOG_INFO
++ */
++static int get_syslog_event_priority(const enum event event_enum)
++{
++      if (event_enum > __SYSLOG_PRIORITY_CRITICAL)
++              return LOG_CRIT;
++      if (event_enum > __SYSLOG_PRIORITY_WARNING)
++              return LOG_WARNING;
++      return LOG_INFO;
++}
++
++/*
++ * is_email_event() - Determines whether email for event should be sent or not.
++ * @event_enum: event to be checked
++ *
++ * Return: true if email should be sent, false otherwise
++ */
++static bool is_email_event(const enum event event_enum)
++{
++      static const enum event email_events[] = {
++      EVENT_FAIL,
++      EVENT_FAIL_SPARE,
++      EVENT_DEGRADED_ARRAY,
++      EVENT_SPARES_MISSING,
++      EVENT_TEST_MESSAGE
++      };
++      unsigned int i;
++
++      for (i = 0; i < ARRAY_SIZE(email_events); ++i) {
++              if (event_enum == email_events[i])
++                      return true;
++      }
++      return false;
++}
++
++/*
++ * execute_alert_cmd() - Forks and executes command provided as alert_cmd.
++ * @data: event data
++ */
++static void execute_alert_cmd(const struct event_data *data)
+ {
+       int pid = fork();
+@@ -462,12 +550,16 @@ static void execute_alert_cmd(const char *event_name, const char *dev, const cha
+               pr_err("Cannot fork to execute alert command");
+               break;
+       case 0:
+-              execl(info.alert_cmd, info.alert_cmd, event_name, dev, disc, NULL);
++              execl(info.alert_cmd, info.alert_cmd, data->event_name, data->dev, data->disc, NULL);
+               exit(2);
+       }
+ }
+-static void send_event_email(const char *event_name, const char *dev, const char *disc)
++/*
++ * send_event_email() - Sends an email about event detected by monitor.
++ * @data: event data
++ */
++static void send_event_email(const struct event_data *data)
+ {
+       FILE *mp, *mdstat;
+       char buf[BUFSIZ];
+@@ -485,15 +577,9 @@ static void send_event_email(const char *event_name, const char *dev, const char
+       else
+               fprintf(mp, "From: %s monitoring <root>\n", Name);
+       fprintf(mp, "To: %s\n", info.mailaddr);
+-      fprintf(mp, "Subject: %s event on %s:%s\n\n", event_name, dev, info.hostname);
+-      fprintf(mp, "This is an automatically generated mail message. \n");
+-      fprintf(mp, "A %s event had been detected on md device %s.\n\n", event_name, dev);
+-
+-      if (disc && disc[0] != ' ')
+-              fprintf(mp,
+-                      "It could be related to component device %s.\n\n", disc);
+-      if (disc && disc[0] == ' ')
+-              fprintf(mp, "Extra information:%s.\n\n", disc);
++      fprintf(mp, "Subject: %s event on %s:%s\n\n", data->event_name, data->dev, info.hostname);
++      fprintf(mp, "This is an automatically generated mail message.\n");
++      fprintf(mp, "%s\n", data->message);
+       mdstat = fopen("/proc/mdstat", "r");
+       if (!mdstat) {
+@@ -509,58 +595,60 @@ static void send_event_email(const char *event_name, const char *dev, const char
+       pclose(mp);
+ }
+-static void log_event_to_syslog(const enum event event_enum, const char *event_name, const char *dev, const char *disc)
++/*
++ * log_event_to_syslog() - Logs an event into syslog.
++ * @data: event data
++ */
++static void log_event_to_syslog(const struct event_data *data)
+ {
+       int priority;
+-      /* Log at a different severity depending on the event.
+-       *
+-       * These are the critical events:  */
+-      if (event_enum == EVENT_FAIL ||
+-          event_enum == EVENT_DEGRADED_ARRAY ||
+-          event_enum == EVENT_DEVICE_DISAPPEARED)
+-              priority = LOG_CRIT;
+-      /* Good to know about, but are not failures: */
+-      else if (event_enum == EVENT_REBUILD ||
+-               event_enum == EVENT_MOVE_SPARE ||
+-               event_enum == EVENT_SPARES_MISSING)
+-              priority = LOG_WARNING;
+-      /* Everything else: */
+-      else
+-              priority = LOG_INFO;
+-
+-      if (disc && disc[0] != ' ')
+-              syslog(priority,
+-                     "%s event detected on md device %s, component device %s",
+-                     event_name, dev, disc);
+-      else if (disc)
+-              syslog(priority, "%s event detected on md device %s: %s", event_name, dev, disc);
+-      else
+-              syslog(priority, "%s event detected on md device %s", event_name, dev);
++
++      priority = get_syslog_event_priority(data->event_enum);
++
++      syslog(priority, "%s\n", data->message);
+ }
+-static void alert(const enum event event_enum, const unsigned int progress, const char *dev, const char *disc)
++/*
++ * alert() - Alerts about the monitor event.
++ * @event_enum: event to be sent
++ * @description: event description
++ * @progress: rebuild progress
++ * @dev: md device name
++ * @disc: component device
++ *
++ * If needed function executes alert command, sends an email or logs event to syslog.
++ */
++static void alert(const enum event event_enum, const char *description, const uint8_t progress,
++                const char *dev, const char *disc)
+ {
+-      char event_name[EVENT_NAME_MAX];
++      struct event_data data = {.dev = dev, .disc = disc, .description = description};
++
++      if (!dev)
++              return;
+       if (event_enum == EVENT_REBUILD) {
+-              snprintf(event_name, sizeof(event_name), "%s%02d",
++              snprintf(data.event_name, sizeof(data.event_name), "%s%02d",
+                        map_num_s(events_map, EVENT_REBUILD), progress);
+       } else {
+-              snprintf(event_name, sizeof(event_name), "%s", map_num_s(events_map, event_enum));
++              snprintf(data.event_name, sizeof(data.event_name), "%s", map_num_s(events_map, event_enum));
+       }
+-      if (info.alert_cmd)
+-              execute_alert_cmd(event_name, dev, disc);
++      data.event_enum = event_enum;
+-      if (info.mailaddr && (event_enum == EVENT_FAIL ||
+-                            event_enum == EVENT_TEST_MESSAGE ||
+-                            event_enum == EVENT_SPARES_MISSING ||
+-                            event_enum == EVENT_DEGRADED_ARRAY)) {
+-              send_event_email(event_name, dev, disc);
++      if (sprint_event_message(data.message, &data) != 0) {
++              pr_err("Cannot create event message.\n");
++              return;
+       }
++      pr_err("%s\n", data.message);
++
++      if (info.alert_cmd)
++              execute_alert_cmd(&data);
++
++      if (info.mailaddr && is_email_event(event_enum))
++              send_event_email(&data);
+       if (info.dosyslog)
+-              log_event_to_syslog(event_enum, event_name, dev, disc);
++              log_event_to_syslog(&data);
+ }
+ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+@@ -585,7 +673,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+       unsigned long redundancy_only_flags = 0;
+       if (info.test)
+-              alert(EVENT_TEST_MESSAGE, 0, dev, NULL);
++              alert(EVENT_TEST_MESSAGE, NULL, 0, dev, NULL);
+       retval = 0;
+@@ -634,7 +722,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+        */
+       if (sra->array.level == 0 || sra->array.level == -1) {
+               if (!st->err && !st->from_config)
+-                      alert(EVENT_DEVICE_DISAPPEARED, 0, dev, " Wrong-Level");
++                      alert(EVENT_DEVICE_DISAPPEARED, "Wrong-Level", 0, dev, NULL);
+               st->err++;
+               goto out;
+       }
+@@ -651,7 +739,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+               st->percent = RESYNC_NONE;
+               new_array = 1;
+               if (!is_container)
+-                      alert(EVENT_NEW_ARRAY, 0, st->devname, NULL);
++                      alert(EVENT_NEW_ARRAY, NULL, 0, st->devname, NULL);
+       }
+       if (st->utime == array.utime && st->failed == sra->array.failed_disks &&
+@@ -664,20 +752,20 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+       }
+       if (st->utime == 0 && /* new array */
+           mse->pattern && strchr(mse->pattern, '_') /* degraded */)
+-              alert(EVENT_DEGRADED_ARRAY, 0, dev, NULL);
++              alert(EVENT_DEGRADED_ARRAY, NULL, 0, dev, NULL);
+       if (st->utime == 0 && /* new array */ st->expected_spares > 0 &&
+           sra->array.spare_disks < st->expected_spares)
+-              alert(EVENT_SPARES_MISSING, 0, dev, NULL);
++              alert(EVENT_SPARES_MISSING, NULL, 0, dev, NULL);
+       if (st->percent < 0 && st->percent != RESYNC_UNKNOWN &&
+           mse->percent >= 0)
+-              alert(EVENT_REBUILD_STARTED, 0, dev, NULL);
++              alert(EVENT_REBUILD_STARTED, NULL, 0, dev, NULL);
+       if (st->percent >= 0 && mse->percent >= 0 &&
+           (mse->percent / increments) > (st->percent / increments)) {
+               if((mse->percent / increments) == 0)
+-                      alert(EVENT_REBUILD_STARTED, 0, dev, NULL);
++                      alert(EVENT_REBUILD_STARTED, NULL, 0, dev, NULL);
+               else
+-                      alert(EVENT_REBUILD, mse->percent, dev, NULL);
++                      alert(EVENT_REBUILD, NULL, mse->percent, dev, NULL);
+       }
+       if (mse->percent == RESYNC_NONE && st->percent >= 0) {
+@@ -690,9 +778,9 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+                       snprintf(cnt, sizeof(cnt),
+                                " mismatches found: %d (on raid level %d)",
+                                sra->mismatch_cnt, sra->array.level);
+-                      alert(EVENT_REBUILD_FINISHED, 0, dev, cnt);
++                      alert(EVENT_REBUILD_FINISHED, NULL, 0, dev, cnt);
+               } else
+-                      alert(EVENT_REBUILD_FINISHED, 0, dev, NULL);
++                      alert(EVENT_REBUILD_FINISHED, NULL, 0, dev, NULL);
+       }
+       st->percent = mse->percent;
+@@ -746,14 +834,14 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+               change = newstate ^ st->devstate[i];
+               if (st->utime && change && !st->err && !new_array) {
+                       if ((st->devstate[i]&change) & (1 << MD_DISK_SYNC))
+-                              alert(EVENT_FAIL, 0, dev, dv);
++                              alert(EVENT_FAIL, NULL, 0, dev, dv);
+                       else if ((newstate & (1 << MD_DISK_FAULTY)) &&
+                                (disc.major || disc.minor) &&
+                                st->devid[i] == makedev(disc.major,
+                                                        disc.minor))
+-                              alert(EVENT_FAIL_SPARE, 0, dev, dv);
++                              alert(EVENT_FAIL_SPARE, NULL, 0, dev, dv);
+                       else if ((newstate&change) & (1 << MD_DISK_SYNC))
+-                              alert(EVENT_SPARE_ACTIVE, 0, dev, dv);
++                              alert(EVENT_SPARE_ACTIVE, NULL, 0, dev, dv);
+               }
+               st->devstate[i] = newstate;
+               st->devid[i] = makedev(disc.major, disc.minor);
+@@ -777,7 +865,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+  disappeared:
+       if (!st->err && !is_container)
+-              alert(EVENT_DEVICE_DISAPPEARED, 0, dev, NULL);
++              alert(EVENT_DEVICE_DISAPPEARED, NULL, 0, dev, NULL);
+       st->err++;
+       goto out;
+ }
+@@ -836,7 +924,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist)
+                               st->parent_devnm[0] = 0;
+                       *statelist = st;
+                       if (info.test)
+-                              alert(EVENT_TEST_MESSAGE, 0, st->devname, NULL);
++                              alert(EVENT_TEST_MESSAGE, NULL, 0, st->devname, NULL);
+                       new_found = 1;
+               }
+       return new_found;
+@@ -1059,7 +1147,7 @@ static void try_spare_migration(struct state *statelist)
+                               if (devid > 0 &&
+                                   move_spare(from->devname, to->devname,
+                                              devid)) {
+-                                      alert(EVENT_MOVE_SPARE, 0, to->devname, from->devname);
++                                      alert(EVENT_MOVE_SPARE, NULL, 0, to->devname, from->devname);
+                                       break;
+                               }
+                       }
+-- 
+2.38.1
+
diff --git a/0090-Add-helpers-to-determine-whether-directories-or-file.patch b/0090-Add-helpers-to-determine-whether-directories-or-file.patch
new file mode 100644 (file)
index 0000000..7d7ecdd
--- /dev/null
@@ -0,0 +1,83 @@
+From ee9dcf9549e8cbfeb51123812776cc87016c95b0 Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Thu, 2 Feb 2023 12:27:02 +0100
+Subject: [PATCH 090/120] Add helpers to determine whether directories or files
+ are soft links
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ mdadm.h |  2 ++
+ util.c  | 45 +++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 47 insertions(+)
+
+diff --git a/mdadm.h b/mdadm.h
+index 13f8b4cb..1674ce13 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1777,6 +1777,8 @@ 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);
++extern bool is_directory(const char *path);
++extern bool is_file(const char *path);
+ #define _ROUND_UP(val, base)  (((val) + (base) - 1) & ~(base - 1))
+ #define ROUND_UP(val, base)   _ROUND_UP(val, (typeof(val))(base))
+diff --git a/util.c b/util.c
+index 8c7f3fd5..7fc881bf 100644
+--- a/util.c
++++ b/util.c
+@@ -2401,3 +2401,48 @@ void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt)
+               }
+       } while (!wake_after_interrupt && errno == EINTR);
+ }
++
++/* is_directory() - Checks if directory provided by path is indeed a regular directory.
++ * @path: directory path to be checked
++ *
++ * Doesn't accept symlinks.
++ *
++ * Return: true if is a directory, false if not
++ */
++bool is_directory(const char *path)
++{
++      struct stat st;
++
++      if (lstat(path, &st) != 0) {
++              pr_err("%s: %s\n", strerror(errno), path);
++              return false;
++      }
++
++      if (!S_ISDIR(st.st_mode))
++              return false;
++
++      return true;
++}
++
++/*
++ * is_file() - Checks if file provided by path is indeed a regular file.
++ * @path: file path to be checked
++ *
++ * Doesn't accept symlinks.
++ *
++ * Return: true if is  a file, false if not
++ */
++bool is_file(const char *path)
++{
++      struct stat st;
++
++      if (lstat(path, &st) != 0) {
++              pr_err("%s: %s\n", strerror(errno), path);
++              return false;
++      }
++
++      if (!S_ISREG(st.st_mode))
++              return false;
++
++      return true;
++}
+-- 
+2.38.1
+
diff --git a/0091-Mdmonitor-Refactor-write_autorebuild_pid.patch b/0091-Mdmonitor-Refactor-write_autorebuild_pid.patch
new file mode 100644 (file)
index 0000000..0985905
--- /dev/null
@@ -0,0 +1,110 @@
+From b6a84d4e92f876acd120d3062a8302db5dd2498c Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Thu, 2 Feb 2023 12:27:03 +0100
+Subject: [PATCH 091/120] Mdmonitor: Refactor write_autorebuild_pid()
+
+Add better error handling and check for symlinks when opening MDMON_DIR.
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Monitor.c | 55 ++++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 36 insertions(+), 19 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 39598ba0..14a2dfe5 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -33,6 +33,7 @@
+ #endif
+ #define EVENT_NAME_MAX 32
++#define AUTOREBUILD_PID_PATH MDMON_DIR "/autorebuild.pid"
+ struct state {
+       char devname[MD_NAME_MAX + sizeof("/dev/md/")]; /* length of "/dev/md/" + device name + terminating byte*/
+@@ -126,7 +127,7 @@ static int check_udev_activity(void);
+ static void link_containers_with_subarrays(struct state *list);
+ static int make_daemon(char *pidfile);
+ static void try_spare_migration(struct state *statelist);
+-static void write_autorebuild_pid(void);
++static int write_autorebuild_pid(void);
+ int Monitor(struct mddev_dev *devlist,
+           char *mailaddr, char *alert_cmd,
+@@ -234,7 +235,8 @@ int Monitor(struct mddev_dev *devlist,
+       }
+       if (share)
+-              write_autorebuild_pid();
++              if (write_autorebuild_pid() != 0)
++                      return 1;
+       if (devlist == NULL) {
+               mdlist = conf_get_ident(NULL);
+@@ -440,29 +442,44 @@ static int check_one_sharer(int scan)
+       return 0;
+ }
+-static void write_autorebuild_pid()
++/*
++ * write_autorebuild_pid() - Writes pid to autorebuild.pid file.
++ *
++ * Return: 0 on success, 1 on error
++ */
++static int write_autorebuild_pid(void)
+ {
+-      char path[PATH_MAX];
+-      int pid;
+-      FILE *fp = NULL;
+-      sprintf(path, "%s/autorebuild.pid", MDMON_DIR);
++      FILE *fp;
++      int fd;
+       if (mkdir(MDMON_DIR, 0700) < 0 && errno != EEXIST) {
+-              pr_err("Can't create autorebuild.pid file\n");
+-      } else {
+-              int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0700);
++              pr_err("%s: %s\n", strerror(errno), MDMON_DIR);
++              return 1;
++      }
+-              if (fd >= 0)
+-                      fp = fdopen(fd, "w");
++      if (!is_directory(MDMON_DIR)) {
++              pr_err("%s is not a regular directory.\n", MDMON_DIR);
++              return 1;
++      }
+-              if (!fp)
+-                      pr_err("Can't create autorebuild.pid file\n");
+-              else {
+-                      pid = getpid();
+-                      fprintf(fp, "%d\n", pid);
+-                      fclose(fp);
+-              }
++      fd = open(AUTOREBUILD_PID_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0700);
++
++      if (fd < 0) {
++              pr_err("Error opening %s file.\n", AUTOREBUILD_PID_PATH);
++              return 1;
+       }
++
++      fp = fdopen(fd, "w");
++
++      if (!fp) {
++              pr_err("Error opening fd for %s file.\n", AUTOREBUILD_PID_PATH);
++              return 1;
++      }
++
++      fprintf(fp, "%d\n", getpid());
++
++      fclose(fp);
++      return 0;
+ }
+ #define BASE_MESSAGE "%s event detected on md device %s"
+-- 
+2.38.1
+
diff --git a/0092-Mdmonitor-Refactor-check_one_sharer-for-better-error.patch b/0092-Mdmonitor-Refactor-check_one_sharer-for-better-error.patch
new file mode 100644 (file)
index 0000000..a7de95e
--- /dev/null
@@ -0,0 +1,139 @@
+From 0a07dea8d3b78a22a59f4604a5e8da15690f28e3 Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Thu, 2 Feb 2023 12:27:04 +0100
+Subject: [PATCH 092/120] Mdmonitor: Refactor check_one_sharer() for better
+ error handling
+
+Also check if autorebuild.pid is a symlink, which we shouldn't accept.
+
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Monitor.c | 89 ++++++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 62 insertions(+), 27 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 14a2dfe5..44918184 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -32,6 +32,7 @@
+ #include      <libudev.h>
+ #endif
++#define TASK_COMM_LEN 16
+ #define EVENT_NAME_MAX 32
+ #define AUTOREBUILD_PID_PATH MDMON_DIR "/autorebuild.pid"
+@@ -224,7 +225,7 @@ int Monitor(struct mddev_dev *devlist,
+       info.hostname[sizeof(info.hostname) - 1] = '\0';
+       if (share){
+-              if (check_one_sharer(c->scan))
++              if (check_one_sharer(c->scan) == 2)
+                       return 1;
+       }
+@@ -406,39 +407,73 @@ static int make_daemon(char *pidfile)
+       return -1;
+ }
++/*
++ * check_one_sharer() - Checks for other mdmon processes running.
++ *
++ * Return:
++ * 0 - no other processes running,
++ * 1 - warning,
++ * 2 - error, or when scan mode is enabled, and one mdmon process already exists
++ */
+ static int check_one_sharer(int scan)
+ {
+       int pid;
+-      FILE *comm_fp;
+-      FILE *fp;
++      FILE *fp, *comm_fp;
+       char comm_path[PATH_MAX];
+-      char path[PATH_MAX];
+-      char comm[20];
+-
+-      sprintf(path, "%s/autorebuild.pid", MDMON_DIR);
+-      fp = fopen(path, "r");
+-      if (fp) {
+-              if (fscanf(fp, "%d", &pid) != 1)
+-                      pid = -1;
+-              snprintf(comm_path, sizeof(comm_path),
+-                       "/proc/%d/comm", pid);
+-              comm_fp = fopen(comm_path, "r");
+-              if (comm_fp) {
+-                      if (fscanf(comm_fp, "%19s", comm) &&
+-                          strncmp(basename(comm), Name, strlen(Name)) == 0) {
+-                              if (scan) {
+-                                      pr_err("Only one autorebuild process allowed in scan mode, aborting\n");
+-                                      fclose(comm_fp);
+-                                      fclose(fp);
+-                                      return 1;
+-                              } else {
+-                                      pr_err("Warning: One autorebuild process already running.\n");
+-                              }
+-                      }
++      char comm[TASK_COMM_LEN];
++
++      if (!is_directory(MDMON_DIR)) {
++              pr_err("%s is not a regular directory.\n", MDMON_DIR);
++              return 2;
++      }
++
++      if (access(AUTOREBUILD_PID_PATH, F_OK) != 0)
++              return 0;
++
++      if (!is_file(AUTOREBUILD_PID_PATH)) {
++              pr_err("%s is not a regular file.\n", AUTOREBUILD_PID_PATH);
++              return 2;
++      }
++
++      fp = fopen(AUTOREBUILD_PID_PATH, "r");
++      if (!fp) {
++              pr_err("Cannot open %s file.\n", AUTOREBUILD_PID_PATH);
++              return 2;
++      }
++
++      if (fscanf(fp, "%d", &pid) != 1) {
++              pr_err("Cannot read pid from %s file.\n", AUTOREBUILD_PID_PATH);
++              fclose(fp);
++              return 2;
++      }
++
++      snprintf(comm_path, sizeof(comm_path), "/proc/%d/comm", pid);
++
++      comm_fp = fopen(comm_path, "r");
++      if (!comm_fp) {
++              dprintf("Warning: Cannot open %s, continuing\n", comm_path);
++              fclose(fp);
++              return 1;
++      }
++
++      if (fscanf(comm_fp, "%15s", comm) == 0) {
++              dprintf("Warning: Cannot read comm from %s, continuing\n", comm_path);
++              fclose(comm_fp);
++              fclose(fp);
++              return 1;
++      }
++
++      if (strncmp(basename(comm), Name, strlen(Name)) == 0) {
++              if (scan) {
++                      pr_err("Only one autorebuild process allowed in scan mode, aborting\n");
+                       fclose(comm_fp);
++                      fclose(fp);
++                      return 2;
+               }
+-              fclose(fp);
++              pr_err("Warning: One autorebuild process already running.\n");
+       }
++      fclose(comm_fp);
++      fclose(fp);
+       return 0;
+ }
+-- 
+2.38.1
+
diff --git a/0093-util.c-reorder-code-lines-in-parse_layout_faulty.patch b/0093-util.c-reorder-code-lines-in-parse_layout_faulty.patch
new file mode 100644 (file)
index 0000000..b040ba7
--- /dev/null
@@ -0,0 +1,41 @@
+From a0151041642dffff2421c22e18fb7b02b58787d9 Mon Sep 17 00:00:00 2001
+From: Coly Li <colyli@suse.de>
+Date: Sat, 4 Mar 2023 00:21:30 +0800
+Subject: [PATCH 093/120] util.c: reorder code lines in parse_layout_faulty()
+
+Resort the code lines in parse_layout_faulty() to make it more
+comfortable, no logic change.
+
+Signed-off-by: Coly Li <colyli@suse.de>
+Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ util.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/util.c b/util.c
+index 7fc881bf..b0b7aec4 100644
+--- a/util.c
++++ b/util.c
+@@ -421,12 +421,15 @@ int parse_layout_10(char *layout)
+ int parse_layout_faulty(char *layout)
+ {
++      int ln, mode;
++      char *m;
++
+       if (!layout)
+               return -1;
++
+       /* Parse the layout string for 'faulty' */
+-      int ln = strcspn(layout, "0123456789");
+-      char *m = xstrdup(layout);
+-      int mode;
++      ln = strcspn(layout, "0123456789");
++      m = xstrdup(layout);
+       m[ln] = 0;
+       mode = map_name(faultylayout, m);
+       if (mode == UnSet)
+-- 
+2.38.1
+
diff --git a/0094-util.c-fix-memleak-in-parse_layout_faulty.patch b/0094-util.c-fix-memleak-in-parse_layout_faulty.patch
new file mode 100644 (file)
index 0000000..b5d0d09
--- /dev/null
@@ -0,0 +1,32 @@
+From 06ef619582b47af89eb094c164fc5effd46d6048 Mon Sep 17 00:00:00 2001
+From: Wu Guanghao <wuguanghao3@huawei.com>
+Date: Sat, 4 Mar 2023 00:21:31 +0800
+Subject: [PATCH 094/120] util.c: fix memleak in parse_layout_faulty()
+
+char *m is allocated by xstrdup but not free() before return, will cause
+a memory leak
+
+Signed-off-by: Wu Guanghao <wuguanghao3@huawei.com>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ util.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/util.c b/util.c
+index b0b7aec4..9f1e1f7c 100644
+--- a/util.c
++++ b/util.c
+@@ -432,6 +432,8 @@ int parse_layout_faulty(char *layout)
+       m = xstrdup(layout);
+       m[ln] = 0;
+       mode = map_name(faultylayout, m);
++      free(m);
++
+       if (mode == UnSet)
+               return -1;
+-- 
+2.38.1
+
diff --git a/0095-Detail.c-fix-memleak-in-Detail.patch b/0095-Detail.c-fix-memleak-in-Detail.patch
new file mode 100644 (file)
index 0000000..0e9b700
--- /dev/null
@@ -0,0 +1,31 @@
+From dac0b5121dd77bf1659b95248423445f932dfae4 Mon Sep 17 00:00:00 2001
+From: Wu Guanghao <wuguanghao3@huawei.com>
+Date: Sat, 4 Mar 2023 00:21:32 +0800
+Subject: [PATCH 095/120] Detail.c: fix memleak in Detail()
+
+char *sysdev = xstrdup() but not free() in for loop, will cause memory
+leak
+
+Signed-off-by: Wu Guanghao <wuguanghao3@huawei.com>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Detail.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/Detail.c b/Detail.c
+index ce7a8445..4ef26460 100644
+--- a/Detail.c
++++ b/Detail.c
+@@ -303,6 +303,7 @@ int Detail(char *dev, struct context *c)
+                               if (path)
+                                       printf("MD_DEVICE_%s_DEV=%s\n",
+                                              sysdev, path);
++                              free(sysdev);
+                       }
+               }
+               goto out;
+-- 
+2.38.1
+
diff --git a/0096-isuper-intel.c-fix-double-free-in-load_imsm_mpb.patch b/0096-isuper-intel.c-fix-double-free-in-load_imsm_mpb.patch
new file mode 100644 (file)
index 0000000..bf71aa0
--- /dev/null
@@ -0,0 +1,63 @@
+From 50cd06b484bb99bfacdd4f9d2f8ee5e52bfc7bd3 Mon Sep 17 00:00:00 2001
+From: Wu Guanghao <wuguanghao3@huawei.com>
+Date: Sat, 4 Mar 2023 00:21:33 +0800
+Subject: [PATCH 096/120] isuper-intel.c: fix double free in load_imsm_mpb()
+
+In load_imsm_mpb() there is potential double free issue on super->buf.
+
+The first location to free super->buf is from get_super_block() <==
+load_and_parse_mpb() <== load_imsm_mpb():
+ 4514         if (posix_memalign(&super->migr_rec_buf, MAX_SECTOR_SIZE,
+ 4515             MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE) != 0) {
+ 4516                 pr_err("could not allocate migr_rec buffer\n");
+ 4517                 free(super->buf);
+ 4518                 return 2;
+ 4519         }
+
+If the above error condition happens, super->buf is freed and value 2
+is returned to get_super_block() eventually. Then in the following code
+block inside load_imsm_mpb(),
+ 5289  error:
+ 5290         if (!err) {
+ 5291                 s->next = *super_list;
+ 5292                 *super_list = s;
+ 5293         } else {
+ 5294                 if (s)
+ 5295                         free_imsm(s);
+ 5296                 close_fd(&dfd);
+ 5297         }
+at line 5295 when free_imsm() is called, super->buf is freed again from
+the call chain free_imsm() <== __free_imsm(), in following code block,
+ 4651         if (super->buf) {
+ 4652                 free(super->buf);
+ 4653                 super->buf = NULL;
+ 4654         }
+
+This patch sets super->buf as NULL after line 4517 in load_imsm_mpb()
+to avoid the potential double free().
+
+(Coly Li helps to re-compose the commit log)
+
+Signed-off-by: Wu Guanghao <wuguanghao3@huawei.com>
+Reviewed-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super-intel.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/super-intel.c b/super-intel.c
+index 89fac626..4a3da847 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -4515,6 +4515,7 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
+           MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE) != 0) {
+               pr_err("could not allocate migr_rec buffer\n");
+               free(super->buf);
++              super->buf = NULL;
+               return 2;
+       }
+       super->clean_migration_record_by_mdmon = 0;
+-- 
+2.38.1
+
diff --git a/0097-super-intel.c-fix-memleak-in-find_disk_attached_hba.patch b/0097-super-intel.c-fix-memleak-in-find_disk_attached_hba.patch
new file mode 100644 (file)
index 0000000..fd60fe2
--- /dev/null
@@ -0,0 +1,39 @@
+From 5d2434d18b6bc71bd16678b1a6d1cc3a92f1d415 Mon Sep 17 00:00:00 2001
+From: Wu Guanghao <wuguanghao3@huawei.com>
+Date: Sat, 4 Mar 2023 00:21:34 +0800
+Subject: [PATCH 097/120] super-intel.c: fix memleak in
+ find_disk_attached_hba()
+
+If disk_path = diskfd_to_devpath(), we need free(disk_path) before
+return, otherwise there will be a memory leak
+
+Signed-off-by: Wu Guanghao <wuguanghao3@huawei.com>
+Reviewed-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super-intel.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 4a3da847..e155a8ae 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -713,12 +713,12 @@ static struct sys_dev* find_disk_attached_hba(int fd, const char *devname)
+       for (elem = list; elem; elem = elem->next)
+               if (path_attached_to_hba(disk_path, elem->path))
+-                      return elem;
++                      break;
+       if (disk_path != devname)
+               free(disk_path);
+-      return NULL;
++      return elem;
+ }
+ static int find_intel_hba_capability(int fd, struct intel_super *super,
+-- 
+2.38.1
+
diff --git a/0098-super-ddf.c-fix-memleak-in-get_vd_num_of_subarray.patch b/0098-super-ddf.c-fix-memleak-in-get_vd_num_of_subarray.patch
new file mode 100644 (file)
index 0000000..d781036
--- /dev/null
@@ -0,0 +1,46 @@
+From 68b90794adf8287fa534cc8f35efb09772b133d0 Mon Sep 17 00:00:00 2001
+From: Wu Guanghao <wuguanghao3@huawei.com>
+Date: Sat, 4 Mar 2023 00:21:35 +0800
+Subject: [PATCH 098/120] super-ddf.c: fix memleak in get_vd_num_of_subarray()
+
+sra = sysfs_read() should be free before return in
+get_vd_num_of_subarray()
+
+Signed-off-by: Wu Guanghao <wuguanghao3@huawei.com>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super-ddf.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/super-ddf.c b/super-ddf.c
+index 309812df..b86c6acd 100644
+--- a/super-ddf.c
++++ b/super-ddf.c
+@@ -1592,15 +1592,20 @@ static unsigned int get_vd_num_of_subarray(struct supertype *st)
+       sra = sysfs_read(-1, st->devnm, GET_VERSION);
+       if (!sra || sra->array.major_version != -1 ||
+           sra->array.minor_version != -2 ||
+-          !is_subarray(sra->text_version))
++          !is_subarray(sra->text_version)) {
++              if (sra)
++                      sysfs_free(sra);
+               return DDF_NOTFOUND;
++      }
+       sub = strchr(sra->text_version + 1, '/');
+       if (sub != NULL)
+               vcnum = strtoul(sub + 1, &end, 10);
+       if (sub == NULL || *sub == '\0' || *end != '\0' ||
+-          vcnum >= be16_to_cpu(ddf->active->max_vd_entries))
++          vcnum >= be16_to_cpu(ddf->active->max_vd_entries)) {
++              sysfs_free(sra);
+               return DDF_NOTFOUND;
++      }
+       return vcnum;
+ }
+-- 
+2.38.1
+
diff --git a/0099-Create-goto-abort_locked-instead-of-return-1-in-erro.patch b/0099-Create-goto-abort_locked-instead-of-return-1-in-erro.patch
new file mode 100644 (file)
index 0000000..4fb641f
--- /dev/null
@@ -0,0 +1,36 @@
+From ba867e2ebaead20e3d9a7e62ef8fd940176c3110 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 1 Mar 2023 13:41:29 -0700
+Subject: [PATCH 099/120] Create: goto abort_locked instead of return 1 in
+ error path
+
+The return 1 after the fstat_is_blkdev() check should be replaced
+with an error return that goes through the error path to unlock
+resources locked by this function.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Kinga Tanska <kinga.tanska@linux.intel.com>
+Reviewed-by: Xiao Ni <xni@redhat.com>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Create.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Create.c b/Create.c
+index 953e7372..2e8203ec 100644
+--- a/Create.c
++++ b/Create.c
+@@ -939,7 +939,7 @@ int Create(struct supertype *st, char *mddev,
+                                               goto abort_locked;
+                                       }
+                                       if (!fstat_is_blkdev(fd, dv->devname, &rdev))
+-                                              return 1;
++                                              goto abort_locked;
+                                       inf->disk.major = major(rdev);
+                                       inf->disk.minor = minor(rdev);
+                               }
+-- 
+2.38.1
+
diff --git a/0100-Create-remove-safe_mode_delay-local-variable.patch b/0100-Create-remove-safe_mode_delay-local-variable.patch
new file mode 100644 (file)
index 0000000..4b826a8
--- /dev/null
@@ -0,0 +1,64 @@
+From fb2c0f6183e29b014608e5e1aa4d53cb55887326 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 1 Mar 2023 13:41:30 -0700
+Subject: [PATCH 100/120] Create: remove safe_mode_delay local variable
+
+All .getinfo_super() call sets the info.safe_mode_delay variables
+to a constant value, so no matter what the current state is
+that function will always set it to the same value.
+
+Create() calls .getinfo_super() multiple times while creating the array.
+The value is stored in a local variable for every disk in the loop
+to add disks (so the last disc call takes precedence). The local
+variable is then used in the call to sysfs_set_safemode().
+
+This can be simplified by using info.safe_mode_delay directly. The info
+variable had .getinfo_super() called on it early in the function so, by the
+reasoning above, it will have the same value as the local variable which
+can thus be removed.
+
+Doing this allows for factoring out code from Create() in a subsequent
+patch.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Kinga Tanska <kinga.tanska@linux.intel.com>
+Reviewed-by: Xiao Ni <xni@redhat.com>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Create.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/Create.c b/Create.c
+index 2e8203ec..8ded81dc 100644
+--- a/Create.c
++++ b/Create.c
+@@ -137,7 +137,6 @@ int Create(struct supertype *st, char *mddev,
+       int did_default = 0;
+       int do_default_layout = 0;
+       int do_default_chunk = 0;
+-      unsigned long safe_mode_delay = 0;
+       char chosen_name[1024];
+       struct map_ent *map = NULL;
+       unsigned long long newsize;
+@@ -952,7 +951,6 @@ int Create(struct supertype *st, char *mddev,
+                                       goto abort_locked;
+                               }
+                               st->ss->getinfo_super(st, inf, NULL);
+-                              safe_mode_delay = inf->safe_mode_delay;
+                               if (have_container && c->verbose > 0)
+                                       pr_err("Using %s for device %d\n",
+@@ -1065,7 +1063,7 @@ int Create(struct supertype *st, char *mddev,
+                                                   "readonly");
+                               break;
+                       }
+-                      sysfs_set_safemode(&info, safe_mode_delay);
++                      sysfs_set_safemode(&info, info.safe_mode_delay);
+                       if (err) {
+                               pr_err("failed to activate array.\n");
+                               ioctl(mdfd, STOP_ARRAY, NULL);
+-- 
+2.38.1
+
diff --git a/0101-Create-Factor-out-add_disks-helpers.patch b/0101-Create-Factor-out-add_disks-helpers.patch
new file mode 100644 (file)
index 0000000..c4bfcc5
--- /dev/null
@@ -0,0 +1,452 @@
+From 8a4ce2c053866ac97feb436c4c85a54446ee0016 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 1 Mar 2023 13:41:31 -0700
+Subject: [PATCH 101/120] Create: Factor out add_disks() helpers
+
+The Create function is massive with a very large number of variables.
+Reading and understanding the function is almost impossible. To help
+with this, factor out the two pass loop that adds the disks to the array.
+
+This moves about 160 lines into three new helper functions and removes
+a bunch of local variables from the main Create function. The main new
+helper function add_disks() does the two pass loop and calls into
+add_disk_to_super() and update_metadata(). Factoring out the
+latter two helpers also helps to reduce a ton of indentation.
+
+No functional changes intended.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Kinga Tanska <kinga.tanska@linux.intel.com>
+Reviewed-by: Xiao Ni <xni@redhat.com>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Create.c | 382 +++++++++++++++++++++++++++++++------------------------
+ 1 file changed, 213 insertions(+), 169 deletions(-)
+
+diff --git a/Create.c b/Create.c
+index 8ded81dc..6a044664 100644
+--- a/Create.c
++++ b/Create.c
+@@ -91,6 +91,214 @@ int default_layout(struct supertype *st, int level, int verbose)
+       return layout;
+ }
++static int add_disk_to_super(int mdfd, struct shape *s, struct context *c,
++              struct supertype *st, struct mddev_dev *dv,
++              struct mdinfo *info, int have_container, int major_num)
++{
++      dev_t rdev;
++      int fd;
++
++      if (dv->disposition == 'j') {
++              info->disk.raid_disk = MD_DISK_ROLE_JOURNAL;
++              info->disk.state = (1<<MD_DISK_JOURNAL);
++      } else if (info->disk.raid_disk < s->raiddisks) {
++              info->disk.state = (1<<MD_DISK_ACTIVE) |
++                      (1<<MD_DISK_SYNC);
++      } else {
++              info->disk.state = 0;
++      }
++
++      if (dv->writemostly == FlagSet) {
++              if (major_num == BITMAP_MAJOR_CLUSTERED) {
++                      pr_err("Can not set %s --write-mostly with a clustered bitmap\n",dv->devname);
++                      return 1;
++              } else {
++                      info->disk.state |= (1<<MD_DISK_WRITEMOSTLY);
++              }
++
++      }
++
++      if (dv->failfast == FlagSet)
++              info->disk.state |= (1<<MD_DISK_FAILFAST);
++
++      if (have_container) {
++              fd = -1;
++      } else {
++              if (st->ss->external && st->container_devnm[0])
++                      fd = open(dv->devname, O_RDWR);
++              else
++                      fd = open(dv->devname, O_RDWR|O_EXCL);
++
++              if (fd < 0) {
++                      pr_err("failed to open %s after earlier success - aborting\n",
++                             dv->devname);
++                      return 1;
++              }
++              if (!fstat_is_blkdev(fd, dv->devname, &rdev))
++                      return 1;
++              info->disk.major = major(rdev);
++              info->disk.minor = minor(rdev);
++      }
++      if (fd >= 0)
++              remove_partitions(fd);
++      if (st->ss->add_to_super(st, &info->disk, fd, dv->devname,
++                               dv->data_offset)) {
++              ioctl(mdfd, STOP_ARRAY, NULL);
++              return 1;
++      }
++      st->ss->getinfo_super(st, info, NULL);
++
++      if (have_container && c->verbose > 0)
++              pr_err("Using %s for device %d\n",
++                     map_dev(info->disk.major, info->disk.minor, 0),
++                     info->disk.number);
++
++      if (!have_container) {
++              /* getinfo_super might have lost these ... */
++              info->disk.major = major(rdev);
++              info->disk.minor = minor(rdev);
++      }
++
++      return 0;
++}
++
++static int update_metadata(int mdfd, struct shape *s, struct supertype *st,
++                         struct map_ent **map, struct mdinfo *info,
++                         char *chosen_name)
++{
++      struct mdinfo info_new;
++      struct map_ent *me = NULL;
++
++      /* check to see if the uuid has changed due to these
++       * metadata changes, and if so update the member array
++       * and container uuid.  Note ->write_init_super clears
++       * the subarray cursor such that ->getinfo_super once
++       * again returns container info.
++       */
++      st->ss->getinfo_super(st, &info_new, NULL);
++      if (st->ss->external && is_container(s->level) &&
++          !same_uuid(info_new.uuid, info->uuid, 0)) {
++              map_update(map, fd2devnm(mdfd),
++                         info_new.text_version,
++                         info_new.uuid, chosen_name);
++              me = map_by_devnm(map, st->container_devnm);
++      }
++
++      if (st->ss->write_init_super(st)) {
++              st->ss->free_super(st);
++              return 1;
++      }
++
++      /*
++       * Before activating the array, perform extra steps
++       * required to configure the internal write-intent
++       * bitmap.
++       */
++      if (info_new.consistency_policy == CONSISTENCY_POLICY_BITMAP &&
++          st->ss->set_bitmap && st->ss->set_bitmap(st, info)) {
++              st->ss->free_super(st);
++              return 1;
++      }
++
++      /* update parent container uuid */
++      if (me) {
++              char *path = xstrdup(me->path);
++
++              st->ss->getinfo_super(st, &info_new, NULL);
++              map_update(map, st->container_devnm, info_new.text_version,
++                         info_new.uuid, path);
++              free(path);
++      }
++
++      flush_metadata_updates(st);
++      st->ss->free_super(st);
++
++      return 0;
++}
++
++static int add_disks(int mdfd, struct mdinfo *info, struct shape *s,
++                   struct context *c, struct supertype *st,
++                   struct map_ent **map, struct mddev_dev *devlist,
++                   int total_slots, int have_container, int insert_point,
++                   int major_num, char *chosen_name)
++{
++      struct mddev_dev *moved_disk = NULL;
++      int pass, raid_disk_num, dnum;
++      struct mddev_dev *dv;
++      struct mdinfo *infos;
++      int ret = 0;
++
++      infos = xmalloc(sizeof(*infos) * total_slots);
++      enable_fds(total_slots);
++      for (pass = 1; pass <= 2; pass++) {
++              for (dnum = 0, raid_disk_num = 0, dv = devlist; dv;
++                   dv = (dv->next) ? (dv->next) : moved_disk, dnum++) {
++                      if (dnum >= total_slots)
++                              abort();
++                      if (dnum == insert_point) {
++                              raid_disk_num += 1;
++                              moved_disk = dv;
++                              continue;
++                      }
++                      if (strcasecmp(dv->devname, "missing") == 0) {
++                              raid_disk_num += 1;
++                              continue;
++                      }
++                      if (have_container)
++                              moved_disk = NULL;
++                      if (have_container && dnum < total_slots - 1)
++                              /* repeatedly use the container */
++                              moved_disk = dv;
++
++                      switch(pass) {
++                      case 1:
++                              infos[dnum] = *info;
++                              infos[dnum].disk.number = dnum;
++                              infos[dnum].disk.raid_disk = raid_disk_num++;
++
++                              if (dv->disposition == 'j')
++                                      raid_disk_num--;
++
++                              ret = add_disk_to_super(mdfd, s, c, st, dv,
++                                              &infos[dnum], have_container,
++                                              major_num);
++                              if (ret)
++                                      goto out;
++
++                              break;
++                      case 2:
++                              infos[dnum].errors = 0;
++
++                              ret = add_disk(mdfd, st, info, &infos[dnum]);
++                              if (ret) {
++                                      pr_err("ADD_NEW_DISK for %s failed: %s\n",
++                                             dv->devname, strerror(errno));
++                                      if (errno == EINVAL &&
++                                          info->array.level == 0) {
++                                              pr_err("Possibly your kernel doesn't support RAID0 layouts.\n");
++                                              pr_err("Either upgrade, or use --layout=dangerous\n");
++                                      }
++                                      goto out;
++                              }
++                              break;
++                      }
++                      if (!have_container &&
++                          dv == moved_disk && dnum != insert_point) break;
++              }
++
++              if (pass == 1) {
++                      ret = update_metadata(mdfd, s, st, map, info,
++                                            chosen_name);
++                      if (ret)
++                              goto out;
++              }
++      }
++
++out:
++      free(infos);
++      return ret;
++}
++
+ int Create(struct supertype *st, char *mddev,
+          char *name, int *uuid,
+          int subdevs, struct mddev_dev *devlist,
+@@ -117,7 +325,7 @@ int Create(struct supertype *st, char *mddev,
+       unsigned long long minsize = 0, maxsize = 0;
+       char *mindisc = NULL;
+       char *maxdisc = NULL;
+-      int dnum, raid_disk_num;
++      int dnum;
+       struct mddev_dev *dv;
+       dev_t rdev;
+       int fail = 0, warn = 0;
+@@ -126,14 +334,13 @@ int Create(struct supertype *st, char *mddev,
+       int missing_disks = 0;
+       int insert_point = subdevs * 2; /* where to insert a missing drive */
+       int total_slots;
+-      int pass;
+       int rv;
+       int bitmap_fd;
+       int have_container = 0;
+       int container_fd = -1;
+       int need_mdmon = 0;
+       unsigned long long bitmapsize;
+-      struct mdinfo info, *infos;
++      struct mdinfo info;
+       int did_default = 0;
+       int do_default_layout = 0;
+       int do_default_chunk = 0;
+@@ -869,174 +1076,11 @@ int Create(struct supertype *st, char *mddev,
+               }
+       }
+-      infos = xmalloc(sizeof(*infos) * total_slots);
+-      enable_fds(total_slots);
+-      for (pass = 1; pass <= 2; pass++) {
+-              struct mddev_dev *moved_disk = NULL; /* the disk that was moved out of the insert point */
+-
+-              for (dnum = 0, raid_disk_num = 0, dv = devlist; dv;
+-                   dv = (dv->next) ? (dv->next) : moved_disk, dnum++) {
+-                      int fd;
+-                      struct mdinfo *inf = &infos[dnum];
+-
+-                      if (dnum >= total_slots)
+-                              abort();
+-                      if (dnum == insert_point) {
+-                              raid_disk_num += 1;
+-                              moved_disk = dv;
+-                              continue;
+-                      }
+-                      if (strcasecmp(dv->devname, "missing") == 0) {
+-                              raid_disk_num += 1;
+-                              continue;
+-                      }
+-                      if (have_container)
+-                              moved_disk = NULL;
+-                      if (have_container && dnum < info.array.raid_disks - 1)
+-                              /* repeatedly use the container */
+-                              moved_disk = dv;
+-
+-                      switch(pass) {
+-                      case 1:
+-                              *inf = info;
+-
+-                              inf->disk.number = dnum;
+-                              inf->disk.raid_disk = raid_disk_num++;
+-
+-                              if (dv->disposition == 'j') {
+-                                      inf->disk.raid_disk = MD_DISK_ROLE_JOURNAL;
+-                                      inf->disk.state = (1<<MD_DISK_JOURNAL);
+-                                      raid_disk_num--;
+-                              } else if (inf->disk.raid_disk < s->raiddisks)
+-                                      inf->disk.state = (1<<MD_DISK_ACTIVE) |
+-                                              (1<<MD_DISK_SYNC);
+-                              else
+-                                      inf->disk.state = 0;
+-
+-                              if (dv->writemostly == FlagSet) {
+-                                      if (major_num == BITMAP_MAJOR_CLUSTERED) {
+-                                              pr_err("Can not set %s --write-mostly with a clustered bitmap\n",dv->devname);
+-                                              goto abort_locked;
+-                                      } else
+-                                              inf->disk.state |= (1<<MD_DISK_WRITEMOSTLY);
+-                              }
+-                              if (dv->failfast == FlagSet)
+-                                      inf->disk.state |= (1<<MD_DISK_FAILFAST);
+-
+-                              if (have_container)
+-                                      fd = -1;
+-                              else {
+-                                      if (st->ss->external &&
+-                                          st->container_devnm[0])
+-                                              fd = open(dv->devname, O_RDWR);
+-                                      else
+-                                              fd = open(dv->devname, O_RDWR|O_EXCL);
+-
+-                                      if (fd < 0) {
+-                                              pr_err("failed to open %s after earlier success - aborting\n",
+-                                                      dv->devname);
+-                                              goto abort_locked;
+-                                      }
+-                                      if (!fstat_is_blkdev(fd, dv->devname, &rdev))
+-                                              goto abort_locked;
+-                                      inf->disk.major = major(rdev);
+-                                      inf->disk.minor = minor(rdev);
+-                              }
+-                              if (fd >= 0)
+-                                      remove_partitions(fd);
+-                              if (st->ss->add_to_super(st, &inf->disk,
+-                                                       fd, dv->devname,
+-                                                       dv->data_offset)) {
+-                                      ioctl(mdfd, STOP_ARRAY, NULL);
+-                                      goto abort_locked;
+-                              }
+-                              st->ss->getinfo_super(st, inf, NULL);
+-
+-                              if (have_container && c->verbose > 0)
+-                                      pr_err("Using %s for device %d\n",
+-                                              map_dev(inf->disk.major,
+-                                                      inf->disk.minor,
+-                                                      0), dnum);
+-
+-                              if (!have_container) {
+-                                      /* getinfo_super might have lost these ... */
+-                                      inf->disk.major = major(rdev);
+-                                      inf->disk.minor = minor(rdev);
+-                              }
+-                              break;
+-                      case 2:
+-                              inf->errors = 0;
+-
+-                              rv = add_disk(mdfd, st, &info, inf);
+-
+-                              if (rv) {
+-                                      pr_err("ADD_NEW_DISK for %s failed: %s\n",
+-                                             dv->devname, strerror(errno));
+-                                      if (errno == EINVAL &&
+-                                          info.array.level == 0) {
+-                                              pr_err("Possibly your kernel doesn't support RAID0 layouts.\n");
+-                                              pr_err("Either upgrade, or use --layout=dangerous\n");
+-                                      }
+-                                      goto abort_locked;
+-                              }
+-                              break;
+-                      }
+-                      if (!have_container &&
+-                          dv == moved_disk && dnum != insert_point) break;
+-              }
+-              if (pass == 1) {
+-                      struct mdinfo info_new;
+-                      struct map_ent *me = NULL;
+-
+-                      /* check to see if the uuid has changed due to these
+-                       * metadata changes, and if so update the member array
+-                       * and container uuid.  Note ->write_init_super clears
+-                       * the subarray cursor such that ->getinfo_super once
+-                       * again returns container info.
+-                       */
+-                      st->ss->getinfo_super(st, &info_new, NULL);
+-                      if (st->ss->external && !is_container(s->level) &&
+-                          !same_uuid(info_new.uuid, info.uuid, 0)) {
+-                              map_update(&map, fd2devnm(mdfd),
+-                                         info_new.text_version,
+-                                         info_new.uuid, chosen_name);
+-                              me = map_by_devnm(&map, st->container_devnm);
+-                      }
+-
+-                      if (st->ss->write_init_super(st)) {
+-                              st->ss->free_super(st);
+-                              goto abort_locked;
+-                      }
+-                      /*
+-                       * Before activating the array, perform extra steps
+-                       * required to configure the internal write-intent
+-                       * bitmap.
+-                       */
+-                      if (info_new.consistency_policy ==
+-                                  CONSISTENCY_POLICY_BITMAP &&
+-                          st->ss->set_bitmap &&
+-                          st->ss->set_bitmap(st, &info)) {
+-                              st->ss->free_super(st);
+-                              goto abort_locked;
+-                      }
+-
+-                      /* update parent container uuid */
+-                      if (me) {
+-                              char *path = xstrdup(me->path);
+-
+-                              st->ss->getinfo_super(st, &info_new, NULL);
+-                              map_update(&map, st->container_devnm,
+-                                         info_new.text_version,
+-                                         info_new.uuid, path);
+-                              free(path);
+-                      }
++      if (add_disks(mdfd, &info, s, c, st, &map, devlist, total_slots,
++                    have_container, insert_point, major_num, chosen_name))
++              goto abort_locked;
+-                      flush_metadata_updates(st);
+-                      st->ss->free_super(st);
+-              }
+-      }
+       map_unlock(&map);
+-      free(infos);
+       if (is_container(s->level)) {
+               /* No need to start.  But we should signal udev to
+-- 
+2.38.1
+
diff --git a/0102-mdadm-Introduce-pr_info.patch b/0102-mdadm-Introduce-pr_info.patch
new file mode 100644 (file)
index 0000000..196624f
--- /dev/null
@@ -0,0 +1,72 @@
+From 9364dbfb264e89ab9467dfc0d2b813033e320640 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 1 Mar 2023 13:41:32 -0700
+Subject: [PATCH 102/120] mdadm: Introduce pr_info()
+
+Feedback was given to avoid informational pr_err() calls that print
+to stderr, even though that's done all through out the code.
+
+Using printf() directly doesn't maintain the same format (an "mdadm"
+prefix on every line.
+
+So introduce pr_info() which prints to stdout with the same format
+and use it for a couple informational pr_err() calls in Create().
+
+Future work can make this call used in more cases.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Kinga Tanska <kinga.tanska@linux.intel.com>
+Reviewed-by: Xiao Ni <xni@redhat.com>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Acked-by: Coly Li <colyli@suse.de>
+Acked-by: Paul Menzel <pmenzel@molgen.mpg.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Create.c | 7 ++++---
+ mdadm.h  | 2 ++
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/Create.c b/Create.c
+index 6a044664..4acda30c 100644
+--- a/Create.c
++++ b/Create.c
+@@ -984,11 +984,12 @@ int Create(struct supertype *st, char *mddev,
+                       mdi = sysfs_read(-1, devnm, GET_VERSION);
+-                      pr_err("Creating array inside %s container %s\n",
++                      pr_info("Creating array inside %s container %s\n",
+                               mdi?mdi->text_version:"managed", devnm);
+                       sysfs_free(mdi);
+               } else
+-                      pr_err("Defaulting to version %s metadata\n", info.text_version);
++                      pr_info("Defaulting to version %s metadata\n",
++                              info.text_version);
+       }
+       map_update(&map, fd2devnm(mdfd), info.text_version,
+@@ -1145,7 +1146,7 @@ int Create(struct supertype *st, char *mddev,
+                       ioctl(mdfd, RESTART_ARRAY_RW, NULL);
+               }
+               if (c->verbose >= 0)
+-                      pr_err("array %s started.\n", mddev);
++                      pr_info("array %s started.\n", mddev);
+               if (st->ss->external && st->container_devnm[0]) {
+                       if (need_mdmon)
+                               start_mdmon(st->container_devnm);
+diff --git a/mdadm.h b/mdadm.h
+index 1674ce13..4336be4d 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1854,6 +1854,8 @@ static inline int xasprintf(char **strp, const char *fmt, ...) {
+ #endif
+ #define cont_err(fmt ...) fprintf(stderr, "       " fmt)
++#define pr_info(fmt, args...) printf("%s: "fmt, Name, ##args)
++
+ void *xmalloc(size_t len);
+ void *xrealloc(void *ptr, size_t len);
+ void *xcalloc(size_t num, size_t size);
+-- 
+2.38.1
+
diff --git a/0103-mdadm-Add-write-zeros-option-for-Create.patch b/0103-mdadm-Add-write-zeros-option-for-Create.patch
new file mode 100644 (file)
index 0000000..1e06a73
--- /dev/null
@@ -0,0 +1,346 @@
+From 577fd10486d8d1472a6b559066f344ac30a3a391 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 1 Mar 2023 13:41:33 -0700
+Subject: [PATCH 103/120] mdadm: Add --write-zeros option for Create
+
+Add the --write-zeros option for Create which will send a write zeros
+request to all the disks before assembling the array. After zeroing
+the array, the disks will be in a known clean state and the initial
+sync may be skipped.
+
+Writing zeroes is best used when there is a hardware offload method
+to zero the data. But even still, zeroing can take several minutes on
+a large device. Because of this, all disks are zeroed in parallel using
+their own forked process and a message is printed to the user. The main
+process will proceed only after all the zeroing processes have completed
+successfully.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Kinga Tanska <kinga.tanska@linux.intel.com>
+Reviewed-by: Xiao Ni <xni@redhat.com>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Create.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ ReadMe.c |   2 +
+ mdadm.c  |   9 +++
+ mdadm.h  |   5 ++
+ 4 files changed, 190 insertions(+), 2 deletions(-)
+
+diff --git a/Create.c b/Create.c
+index 4acda30c..bbe9e13d 100644
+--- a/Create.c
++++ b/Create.c
+@@ -26,6 +26,10 @@
+ #include      "md_u.h"
+ #include      "md_p.h"
+ #include      <ctype.h>
++#include      <fcntl.h>
++#include      <signal.h>
++#include      <sys/signalfd.h>
++#include      <sys/wait.h>
+ static int round_size_and_verify(unsigned long long *size, int chunk)
+ {
+@@ -91,9 +95,149 @@ int default_layout(struct supertype *st, int level, int verbose)
+       return layout;
+ }
++static pid_t write_zeroes_fork(int fd, struct shape *s, struct supertype *st,
++                             struct mddev_dev *dv)
++
++{
++      const unsigned long long req_size = 1 << 30;
++      unsigned long long offset_bytes, size_bytes, sz;
++      sigset_t sigset;
++      int ret = 0;
++      pid_t pid;
++
++      size_bytes = KIB_TO_BYTES(s->size);
++
++      /*
++       * If size_bytes is zero, this is a zoned raid array where
++       * each disk is of a different size and uses its full
++       * disk. Thus zero the entire disk.
++       */
++      if (!size_bytes && !get_dev_size(fd, dv->devname, &size_bytes))
++              return -1;
++
++      if (dv->data_offset != INVALID_SECTORS)
++              offset_bytes = SEC_TO_BYTES(dv->data_offset);
++      else
++              offset_bytes = SEC_TO_BYTES(st->data_offset);
++
++      pr_info("zeroing data from %lld to %lld on: %s\n",
++              offset_bytes, size_bytes, dv->devname);
++
++      pid = fork();
++      if (pid < 0) {
++              pr_err("Could not fork to zero disks: %s\n", strerror(errno));
++              return pid;
++      } else if (pid != 0) {
++              return pid;
++      }
++
++      sigemptyset(&sigset);
++      sigaddset(&sigset, SIGINT);
++      sigprocmask(SIG_UNBLOCK, &sigset, NULL);
++
++      while (size_bytes) {
++              /*
++               * Split requests to the kernel into 1GB chunks seeing the
++               * fallocate() call is not interruptible and blocking a
++               * ctrl-c for several minutes is not desirable.
++               *
++               * 1GB is chosen as a compromise: the user may still have
++               * to wait several seconds if they ctrl-c on devices that
++               * zero slowly, but will reduce the number of requests
++               * required and thus the overhead on devices that perform
++               * better.
++               */
++              sz = size_bytes;
++              if (sz >= req_size)
++                      sz = req_size;
++
++              if (fallocate(fd, FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE,
++                            offset_bytes, sz)) {
++                      pr_err("zeroing %s failed: %s\n", dv->devname,
++                             strerror(errno));
++                      ret = 1;
++                      break;
++              }
++
++              offset_bytes += sz;
++              size_bytes -= sz;
++      }
++
++      exit(ret);
++}
++
++static int wait_for_zero_forks(int *zero_pids, int count)
++{
++      int wstatus, ret = 0, i, sfd, wait_count = 0;
++      struct signalfd_siginfo fdsi;
++      bool interrupted = false;
++      sigset_t sigset;
++      ssize_t s;
++
++      for (i = 0; i < count; i++)
++              if (zero_pids[i])
++                      wait_count++;
++      if (!wait_count)
++              return 0;
++
++      sigemptyset(&sigset);
++      sigaddset(&sigset, SIGINT);
++      sigaddset(&sigset, SIGCHLD);
++      sigprocmask(SIG_BLOCK, &sigset, NULL);
++
++      sfd = signalfd(-1, &sigset, 0);
++      if (sfd < 0) {
++              pr_err("Unable to create signalfd: %s\n", strerror(errno));
++              return 1;
++      }
++
++      while (1) {
++              s = read(sfd, &fdsi, sizeof(fdsi));
++              if (s != sizeof(fdsi)) {
++                      pr_err("Invalid signalfd read: %s\n", strerror(errno));
++                      close(sfd);
++                      return 1;
++              }
++
++              if (fdsi.ssi_signo == SIGINT) {
++                      printf("\n");
++                      pr_info("Interrupting zeroing processes, please wait...\n");
++                      interrupted = true;
++              } else if (fdsi.ssi_signo == SIGCHLD) {
++                      if (!--wait_count)
++                              break;
++              }
++      }
++
++      close(sfd);
++
++      for (i = 0; i < count; i++) {
++              if (!zero_pids[i])
++                      continue;
++
++              waitpid(zero_pids[i], &wstatus, 0);
++              zero_pids[i] = 0;
++              if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus))
++                      ret = 1;
++      }
++
++      if (interrupted) {
++              pr_err("zeroing interrupted!\n");
++              return 1;
++      }
++
++      if (ret)
++              pr_err("zeroing failed!\n");
++      else
++              pr_info("zeroing finished\n");
++
++      return ret;
++}
++
+ static int add_disk_to_super(int mdfd, struct shape *s, struct context *c,
+               struct supertype *st, struct mddev_dev *dv,
+-              struct mdinfo *info, int have_container, int major_num)
++              struct mdinfo *info, int have_container, int major_num,
++              int *zero_pid)
+ {
+       dev_t rdev;
+       int fd;
+@@ -148,6 +292,14 @@ static int add_disk_to_super(int mdfd, struct shape *s, struct context *c,
+       }
+       st->ss->getinfo_super(st, info, NULL);
++      if (fd >= 0 && s->write_zeroes) {
++              *zero_pid = write_zeroes_fork(fd, s, st, dv);
++              if (*zero_pid <= 0) {
++                      ioctl(mdfd, STOP_ARRAY, NULL);
++                      return 1;
++              }
++      }
++
+       if (have_container && c->verbose > 0)
+               pr_err("Using %s for device %d\n",
+                      map_dev(info->disk.major, info->disk.minor, 0),
+@@ -224,10 +376,23 @@ static int add_disks(int mdfd, struct mdinfo *info, struct shape *s,
+ {
+       struct mddev_dev *moved_disk = NULL;
+       int pass, raid_disk_num, dnum;
++      int zero_pids[total_slots];
+       struct mddev_dev *dv;
+       struct mdinfo *infos;
++      sigset_t sigset, orig_sigset;
+       int ret = 0;
++      /*
++       * Block SIGINT so the main thread will always wait for the
++       * zeroing processes when being interrupted. Otherwise the
++       * zeroing processes will finish their work in the background
++       * keeping the disk busy.
++       */
++      sigemptyset(&sigset);
++      sigaddset(&sigset, SIGINT);
++      sigprocmask(SIG_BLOCK, &sigset, &orig_sigset);
++      memset(zero_pids, 0, sizeof(zero_pids));
++
+       infos = xmalloc(sizeof(*infos) * total_slots);
+       enable_fds(total_slots);
+       for (pass = 1; pass <= 2; pass++) {
+@@ -261,7 +426,7 @@ static int add_disks(int mdfd, struct mdinfo *info, struct shape *s,
+                               ret = add_disk_to_super(mdfd, s, c, st, dv,
+                                               &infos[dnum], have_container,
+-                                              major_num);
++                                              major_num, &zero_pids[dnum]);
+                               if (ret)
+                                       goto out;
+@@ -287,6 +452,10 @@ static int add_disks(int mdfd, struct mdinfo *info, struct shape *s,
+               }
+               if (pass == 1) {
++                      ret = wait_for_zero_forks(zero_pids, total_slots);
++                      if (ret)
++                              goto out;
++
+                       ret = update_metadata(mdfd, s, st, map, info,
+                                             chosen_name);
+                       if (ret)
+@@ -295,7 +464,10 @@ static int add_disks(int mdfd, struct mdinfo *info, struct shape *s,
+       }
+ out:
++      if (ret)
++              wait_for_zero_forks(zero_pids, total_slots);
+       free(infos);
++      sigprocmask(SIG_SETMASK, &orig_sigset, NULL);
+       return ret;
+ }
+diff --git a/ReadMe.c b/ReadMe.c
+index bd8d50d2..db251ed2 100644
+--- a/ReadMe.c
++++ b/ReadMe.c
+@@ -138,6 +138,7 @@ struct option long_options[] = {
+     {"size",    1, 0, 'z'},
+     {"auto",    1, 0, Auto}, /* also for --assemble */
+     {"assume-clean",0,0, AssumeClean },
++    {"write-zeroes",0,0, WriteZeroes },
+     {"metadata",  1, 0, 'e'}, /* superblock format */
+     {"bitmap",          1, 0, Bitmap},
+     {"bitmap-chunk", 1, 0, BitmapChunk},
+@@ -390,6 +391,7 @@ char Help_create[] =
+ "  --write-journal=      : Specify journal device for RAID-4/5/6 array\n"
+ "  --consistency-policy= : Specify the policy that determines how the array\n"
+ "                     -k : maintains consistency in case of unexpected shutdown.\n"
++"  --write-zeroes        : Write zeroes to the disks before creating. This will bypass initial sync.\n"
+ "\n"
+ ;
+diff --git a/mdadm.c b/mdadm.c
+index 57e8e6fa..4685ad6b 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -590,6 +590,10 @@ int main(int argc, char *argv[])
+                       s.assume_clean = 1;
+                       continue;
++              case O(CREATE, WriteZeroes):
++                      s.write_zeroes = 1;
++                      continue;
++
+               case O(GROW,'n'):
+               case O(CREATE,'n'):
+               case O(BUILD,'n'): /* number of raid disks */
+@@ -1251,6 +1255,11 @@ int main(int argc, char *argv[])
+               }
+       }
++      if (s.write_zeroes && !s.assume_clean) {
++              pr_info("Disk zeroing requested, setting --assume-clean to skip resync\n");
++              s.assume_clean = 1;
++      }
++
+       if (!mode && devs_found) {
+               mode = MISC;
+               devmode = 'Q';
+diff --git a/mdadm.h b/mdadm.h
+index 4336be4d..b9127f9a 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -275,6 +275,9 @@ static inline void __put_unaligned32(__u32 val, void *p)
+ #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
++#define KIB_TO_BYTES(x)       ((x) << 10)
++#define SEC_TO_BYTES(x)       ((x) << 9)
++
+ extern const char Name[];
+ struct md_bb_entry {
+@@ -435,6 +438,7 @@ extern char Version[], Usage[], Help[], OptionHelp[],
+  */
+ enum special_options {
+       AssumeClean = 300,
++      WriteZeroes,
+       BitmapChunk,
+       WriteBehind,
+       ReAdd,
+@@ -640,6 +644,7 @@ struct shape {
+       int     bitmap_chunk;
+       char    *bitmap_file;
+       int     assume_clean;
++      bool    write_zeroes;
+       int     write_behind;
+       unsigned long long size;
+       unsigned long long data_offset;
+-- 
+2.38.1
+
diff --git a/0104-tests-00raid5-zero-Introduce-test-to-exercise-write-.patch b/0104-tests-00raid5-zero-Introduce-test-to-exercise-write-.patch
new file mode 100644 (file)
index 0000000..6c32b5c
--- /dev/null
@@ -0,0 +1,44 @@
+From c918cf2af993b55bca9f396c79713e54d3f8b6fb Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 1 Mar 2023 13:41:34 -0700
+Subject: [PATCH 104/120] tests/00raid5-zero: Introduce test to exercise
+ --write-zeros.
+
+Attempt to create a raid5 array with --write-zeros. If it is successful
+check the array to ensure it is in sync.
+
+If it is unsuccessful and an unsupported error is printed, skip the
+test.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Kinga Tanska <kinga.tanska@linux.intel.com>
+Reviewed-by: Xiao Ni <xni@redhat.com>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ tests/00raid5-zero | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+ create mode 100644 tests/00raid5-zero
+
+diff --git a/tests/00raid5-zero b/tests/00raid5-zero
+new file mode 100644
+index 00000000..7d0f05a1
+--- /dev/null
++++ b/tests/00raid5-zero
+@@ -0,0 +1,12 @@
++
++if mdadm -CfR $md0 -l 5 -n3 $dev0 $dev1 $dev2 --write-zeroes ; then
++  check nosync
++  echo check > /sys/block/md0/md/sync_action;
++  check wait
++elif grep "zeroing [^ ]* failed: Operation not supported" \
++     $targetdir/stderr; then
++  echo "write-zeros not supported, skipping"
++else
++  echo >&2 "ERROR: mdadm return failure without not supported message"
++  exit 1
++fi
+-- 
+2.38.1
+
diff --git a/0105-manpage-Add-write-zeroes-option-to-manpage.patch b/0105-manpage-Add-write-zeroes-option-to-manpage.patch
new file mode 100644 (file)
index 0000000..489faca
--- /dev/null
@@ -0,0 +1,56 @@
+From 33831d845a48b9a2ac4d1e954c88a3dd8cb15753 Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Wed, 1 Mar 2023 13:41:35 -0700
+Subject: [PATCH 105/120] manpage: Add --write-zeroes option to manpage
+
+Document the new --write-zeroes option in the manpage.
+
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Acked-by: Kinga Tanska <kinga.tanska@linux.intel.com>
+Reviewed-by: Xiao Ni <xni@redhat.com>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Acked-by: Coly Li <colyli@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ mdadm.8.in | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/mdadm.8.in b/mdadm.8.in
+index 64f71ed1..6f0f6c13 100644
+--- a/mdadm.8.in
++++ b/mdadm.8.in
+@@ -837,6 +837,22 @@ array is resynced at creation.  From Linux version 3.0,
+ .B \-\-assume\-clean
+ can be used with that command to avoid the automatic resync.
++.TP
++.BR \-\-write-zeroes
++When creating an array, send write zeroes requests to all the block
++devices.  This should zero the data area on all disks such that the
++initial sync is not necessary and, if successfull, will behave
++as if
++.B \-\-assume\-clean
++was specified.
++.IP
++This is intended for use with devices that have hardware offload for
++zeroing, but despite this zeroing can still take several minutes for
++large disks.  Thus a message is printed before and after zeroing and
++each disk is zeroed in parallel with the others.
++.IP
++This is only meaningful with --create.
++
+ .TP
+ .BR \-\-backup\-file=
+ This is needed when
+@@ -1370,7 +1386,7 @@ and
+ .B layout\-alternate
+ options are for RAID0 arrays with non-uniform devices size that were in
+ use before Linux 5.4.  If the array was being used with Linux 3.13 or
+-earlier, then to assemble the array on a new kernel, 
++earlier, then to assemble the array on a new kernel,
+ .B \-\-update=layout\-original
+ must be given.  If the array was created and used with a kernel from Linux 3.14 to
+ Linux 5.3, then
+-- 
+2.38.1
+
diff --git a/0106-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch b/0106-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch
new file mode 100644 (file)
index 0000000..acb55ed
--- /dev/null
@@ -0,0 +1,53 @@
+From 566844b93e6823a04ed65827ba3e03cb123b3a03 Mon Sep 17 00:00:00 2001
+From: Khem Raj <raj.khem@gmail.com>
+Date: Wed, 18 Jan 2023 00:32:36 -0800
+Subject: [PATCH 106/120] Define alignof using _Alignof when using C11 or newer
+
+WG14 N2350 made very clear that it is an UB having type definitions
+within "offsetof" [1]. This patch enhances the implementation of macro
+alignof_slot to use builtin "_Alignof" to avoid undefined behavior on
+when using std=c11 or newer
+
+clang 16+ has started to flag this [2]
+
+Fixes build when using -std >= gnu11 and using clang16+
+
+Older compilers gcc < 4.9 or clang < 8 has buggy _Alignof even though it
+may support C11, exclude those compilers too
+
+[1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2350.htm
+[2] https://reviews.llvm.org/D133574
+
+Upstream-Status: Pending
+Signed-off-by: Khem Raj <raj.khem@gmail.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ sha1.c | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/sha1.c b/sha1.c
+index 89b32f46..1e4ad5d9 100644
+--- a/sha1.c
++++ b/sha1.c
+@@ -229,7 +229,17 @@ sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx)
+   if (len >= 64)
+     {
+ #if !_STRING_ARCH_unaligned
+-# define alignof(type) offsetof (struct { char c; type x; }, x)
++/* GCC releases before GCC 4.9 had a bug in _Alignof.  See GCC bug 52023
++   <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>.
++   clang versions < 8.0.0 have the same bug.  */
++# if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \
++      || (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \
++   && !defined __clang__) \
++      || (defined __clang__ && __clang_major__ < 8))
++#  define alignof(type) offsetof (struct { char c; type x; }, x)
++# else
++#  define alignof(type) _Alignof(type)
++# endif
+ # define UNALIGNED_P(p) (((size_t) p) % alignof (sha1_uint32) != 0)
+       if (UNALIGNED_P (buffer))
+       while (len > 64)
+-- 
+2.38.1
+
diff --git a/0107-Use-existence-of-etc-initrd-release-to-detect-initrd.patch b/0107-Use-existence-of-etc-initrd-release-to-detect-initrd.patch
new file mode 100644 (file)
index 0000000..f7b06c5
--- /dev/null
@@ -0,0 +1,41 @@
+From eb45d0add7cf2918f838bec2d93d99cf2d9c662f Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Mon, 13 Mar 2023 14:42:58 +1100
+Subject: [PATCH 107/120] Use existence of /etc/initrd-release to detect
+ initrd.
+
+Since v183, systemd has used the existence of /etc/initrd-release to
+detect if it is running in an initrd, rather than looking at the magic
+number of the root filesystem's device.  It is time for mdadm to do the
+same.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ util.c | 10 +---------
+ 1 file changed, 1 insertion(+), 9 deletions(-)
+
+diff --git a/util.c b/util.c
+index 9f1e1f7c..509fb43e 100644
+--- a/util.c
++++ b/util.c
+@@ -2227,15 +2227,7 @@ int continue_via_systemd(char *devnm, char *service_name)
+ int in_initrd(void)
+ {
+-      /* This is based on similar function in systemd. */
+-      struct statfs s;
+-      /* statfs.f_type is signed long on s390x and MIPS, causing all
+-         sorts of sign extension problems with RAMFS_MAGIC being
+-         defined as 0x858458f6 */
+-      return  statfs("/", &s) >= 0 &&
+-              ((unsigned long)s.f_type == TMPFS_MAGIC ||
+-               ((unsigned long)s.f_type & 0xFFFFFFFFUL) ==
+-               ((unsigned long)RAMFS_MAGIC & 0xFFFFFFFFUL));
++      return access("/etc/initrd-release", F_OK) >= 0;
+ }
+ void reopen_mddev(int mdfd)
+-- 
+2.38.1
+
diff --git a/0108-mdmon-don-t-test-both-all-and-container_name.patch b/0108-mdmon-don-t-test-both-all-and-container_name.patch
new file mode 100644 (file)
index 0000000..479e5a5
--- /dev/null
@@ -0,0 +1,47 @@
+From d39fd87e31024804dd7f2c16c03af0379b71f5f1 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Mon, 13 Mar 2023 14:42:58 +1100
+Subject: [PATCH 108/120] mdmon: don't test both 'all' and 'container_name'.
+
+If 'all' is not set, then container_name must be NULL, as nothing else
+can set it.  So simplify the test to ignore container_name.
+This makes the purpose of the code more obvious.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ mdmon.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+diff --git a/mdmon.c b/mdmon.c
+index 60ba3182..f8fd2f0f 100644
+--- a/mdmon.c
++++ b/mdmon.c
+@@ -352,7 +352,6 @@ int main(int argc, char *argv[])
+               }
+       }
+-
+       if (in_initrd()) {
+               /*
+                * set first char of argv[0] to @. This is used by
+@@ -362,12 +361,10 @@ int main(int argc, char *argv[])
+               argv[0][0] = '@';
+       }
+-      if (all == 0 && container_name == NULL) {
+-              if (argv[optind]) {
+-                      container_name = get_md_name(argv[optind]);
+-                      if (!container_name)
+-                              return 1;
+-              }
++      if (!all && argv[optind]) {
++              container_name = get_md_name(argv[optind]);
++              if (!container_name)
++                      return 1;
+       }
+       if (container_name == NULL || argc - optind > 1)
+-- 
+2.38.1
+
diff --git a/0109-mdmon-change-systemd-unit-file-to-use-foreground.patch b/0109-mdmon-change-systemd-unit-file-to-use-foreground.patch
new file mode 100644 (file)
index 0000000..49240d5
--- /dev/null
@@ -0,0 +1,33 @@
+From 6660e33edde76329bd3b7f03383856c7efee2aa9 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Mon, 13 Mar 2023 14:42:58 +1100
+Subject: [PATCH 109/120] mdmon: change systemd unit file to use --foreground
+
+There is no value in mdmon forking when it is running under systemd -
+systemd can still track it anyway.
+
+So add --foreground option, and remove "Type=forking".
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ systemd/mdmon@.service | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service
+index cb6482d9..bba9b0eb 100644
+--- a/systemd/mdmon@.service
++++ b/systemd/mdmon@.service
+@@ -20,8 +20,7 @@ Environment=IMSM_NO_PLATFORM=1
+ # 'takeover'.  As the '--offroot --takeover' don't hurt when
+ # not necessary, are are useful with root-on-md in dracut,
+ # have them always present.
+-ExecStart=BINDIR/mdmon --offroot --takeover %I
+-Type=forking
++ExecStart=BINDIR/mdmon --foreground --offroot --takeover %I
+ # Don't set the PIDFile.  It isn't necessary (systemd can work
+ # it out) and systemd will remove it when transitioning from
+ # initramfs to rootfs.
+-- 
+2.38.1
+
diff --git a/0110-mdmon-Remove-need-for-KillMode-none.patch b/0110-mdmon-Remove-need-for-KillMode-none.patch
new file mode 100644 (file)
index 0000000..5e6cc63
--- /dev/null
@@ -0,0 +1,55 @@
+From 0f9a4b3e11fbe4f8631d20b1f89cf43e9219db55 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Mon, 13 Mar 2023 14:42:58 +1100
+Subject: [PATCH 110/120] mdmon: Remove need for KillMode=none
+
+mdmon needs to keep running during the switchroot out of (at boot) and
+then back into (at shutdown) the initrd.  It runs until a new mdmon
+takes over.
+
+Killmode=none is used to achieve this, with the help of --offroot which
+sets argv[0][0] to '@' which systemd understands.
+
+This is needed because mdmon is currently run in system-mdmon.slice
+which conflicts with shutdown.target so without Killmode=none mdmon
+would get killed early in shutdown when system.mdmon.slice is removed.
+
+As described in systemd.service(5), this conflict with shutdown can be
+resolved by explicitly requesting system.slice, which is a natural
+counterpart to DefaultDependencies=no.
+
+So add that, and also add IgnoreOnIsolate=true to avoid another possible
+source of an early death.  With these we no longer need KillMode=none
+which the systemd developers have marked as "deprecated".
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ systemd/mdmon@.service | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service
+index bba9b0eb..303ad05c 100644
+--- a/systemd/mdmon@.service
++++ b/systemd/mdmon@.service
+@@ -10,6 +10,9 @@ Description=MD Metadata Monitor on /dev/%I
+ DefaultDependencies=no
+ Before=initrd-switch-root.target
+ Documentation=man:mdmon(8)
++# Allow mdmon to keep running after switchroot, until a new
++# instance is started.
++IgnoreOnIsolate=true
+ [Service]
+ # mdmon should never complain due to lack of a platform,
+@@ -25,4 +28,6 @@ ExecStart=BINDIR/mdmon --foreground --offroot --takeover %I
+ # it out) and systemd will remove it when transitioning from
+ # initramfs to rootfs.
+ #PIDFile=/run/mdadm/%I.pid
+-KillMode=none
++# The default slice is system-mdmon.slice which Conflicts
++# with shutdown, causing mdmon to exit early.  So use system.slice.
++Slice=system.slice
+-- 
+2.38.1
+
diff --git a/0111-mdmon-Improve-switchroot-interactions.patch b/0111-mdmon-Improve-switchroot-interactions.patch
new file mode 100644 (file)
index 0000000..65654a0
--- /dev/null
@@ -0,0 +1,166 @@
+From 723d1df4946eb40337bf494f9b2549500c1399b2 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Mon, 13 Mar 2023 14:42:58 +1100
+Subject: [PATCH 111/120] mdmon: Improve switchroot interactions.
+
+We need a new mdmon@mdfoo instance to run in the root filesystem after
+switch root, as /sys and /dev are removed from the initrd.
+
+systemd will not start a new unit with the same name running while the
+old unit is still active, and we want the two mdmon processes to overlap
+in time to avoid any risk of deadlock, which can happen when a write is
+attempted with no mdmon running.
+
+So we need a different unit name in the initrd than in the root.  Apart
+from the name, everything else should be the same.
+
+This is easily achieved using a different instance name as the
+mdmon@.service unit file already supports multiple instances (for
+different arrays).
+
+So start "mdmon@mdfoo.service" from root, but
+"mdmon@initrd-mdfoo.service" from the initrd.  udev can tell which
+circumstance is the case by looking for /etc/initrd-release.
+continue_from_systemd() is enhanced so that the "initrd-" prefix can be
+requested.
+
+Teach mdmon that a container name like "initrd/foo" should be treated
+just like "foo".  Note that systemd passes the instance name
+"initrd-foo" as "initrd/foo".
+
+We don't need a similar mechanism at shutdown because dracut runs
+"mdmon --takeover --all" when appropriate.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Grow.c                    | 4 ++--
+ mdadm.h                   | 2 +-
+ mdmon.c                   | 7 ++++++-
+ systemd/mdmon@.service    | 2 +-
+ udev-md-raid-arrays.rules | 3 ++-
+ util.c                    | 7 ++++---
+ 6 files changed, 16 insertions(+), 9 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index bb5fe45c..06001f2d 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -3516,7 +3516,7 @@ started:
+       if (!forked)
+               if (continue_via_systemd(container ?: sra->sys_name,
+-                                       GROW_SERVICE)) {
++                                       GROW_SERVICE, NULL)) {
+                       free(fdlist);
+                       free(offsets);
+                       sysfs_free(sra);
+@@ -3714,7 +3714,7 @@ int reshape_container(char *container, char *devname,
+       ping_monitor(container);
+       if (!forked && !freeze_reshape)
+-              if (continue_via_systemd(container, GROW_SERVICE))
++              if (continue_via_systemd(container, GROW_SERVICE, NULL))
+                       return 0;
+       switch (forked ? 0 : fork()) {
+diff --git a/mdadm.h b/mdadm.h
+index b9127f9a..1e518276 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1608,7 +1608,7 @@ extern int same_dev(char *one, char *two);
+ extern int compare_paths (char* path1,char* path2);
+ extern void enable_fds(int devices);
+ extern void manage_fork_fds(int close_all);
+-extern int continue_via_systemd(char *devnm, char *service_name);
++extern int continue_via_systemd(char *devnm, char *service_name, char *prefix);
+ extern void ident_init(struct mddev_ident *ident);
+diff --git a/mdmon.c b/mdmon.c
+index f8fd2f0f..096b4d76 100644
+--- a/mdmon.c
++++ b/mdmon.c
+@@ -362,7 +362,12 @@ int main(int argc, char *argv[])
+       }
+       if (!all && argv[optind]) {
+-              container_name = get_md_name(argv[optind]);
++              static const char prefix[] = "initrd/";
++              container_name = argv[optind];
++              if (strncmp(container_name, prefix,
++                          sizeof(prefix) - 1) == 0)
++                      container_name += sizeof(prefix)-1;
++              container_name = get_md_name(container_name);
+               if (!container_name)
+                       return 1;
+       }
+diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service
+index 303ad05c..23a375f6 100644
+--- a/systemd/mdmon@.service
++++ b/systemd/mdmon@.service
+@@ -6,7 +6,7 @@
+ #  (at your option) any later version.
+ [Unit]
+-Description=MD Metadata Monitor on /dev/%I
++Description=MD Metadata Monitor on %I
+ DefaultDependencies=no
+ Before=initrd-switch-root.target
+ Documentation=man:mdmon(8)
+diff --git a/udev-md-raid-arrays.rules b/udev-md-raid-arrays.rules
+index 2967ace1..4e64b249 100644
+--- a/udev-md-raid-arrays.rules
++++ b/udev-md-raid-arrays.rules
+@@ -38,7 +38,8 @@ ENV{MD_LEVEL}=="raid[1-9]*", ENV{SYSTEMD_WANTS}+="mdmonitor.service"
+ # Tell systemd to run mdmon for our container, if we need it.
+ ENV{MD_LEVEL}=="raid[1-9]*", ENV{MD_CONTAINER}=="?*", PROGRAM="/usr/bin/readlink $env{MD_CONTAINER}", ENV{MD_MON_THIS}="%c"
+-ENV{MD_MON_THIS}=="?*", PROGRAM="/usr/bin/basename $env{MD_MON_THIS}", ENV{SYSTEMD_WANTS}+="mdmon@%c.service"
++ENV{MD_MON_THIS}=="?*", TEST=="/etc/initrd-release", PROGRAM="/usr/bin/basename $env{MD_MON_THIS}", ENV{SYSTEMD_WANTS}+="mdmon@initrd-%c.service"
++ENV{MD_MON_THIS}=="?*", TEST!="/etc/initrd-release", PROGRAM="/usr/bin/basename $env{MD_MON_THIS}", ENV{SYSTEMD_WANTS}+="mdmon@%c.service"
+ ENV{RESHAPE_ACTIVE}=="yes", PROGRAM="/usr/bin/basename $env{MD_MON_THIS}", ENV{SYSTEMD_WANTS}+="mdadm-grow-continue@%c.service"
+ LABEL="md_end"
+diff --git a/util.c b/util.c
+index 509fb43e..d70ca43b 100644
+--- a/util.c
++++ b/util.c
+@@ -1916,6 +1916,7 @@ int start_mdmon(char *devnm)
+       int len;
+       pid_t pid;
+       int status;
++      char *prefix = in_initrd() ? "initrd-" : "";
+       char pathbuf[1024];
+       char *paths[4] = {
+               pathbuf,
+@@ -1926,7 +1927,7 @@ int start_mdmon(char *devnm)
+       if (check_env("MDADM_NO_MDMON"))
+               return 0;
+-      if (continue_via_systemd(devnm, MDMON_SERVICE))
++      if (continue_via_systemd(devnm, MDMON_SERVICE, prefix))
+               return 0;
+       /* That failed, try running mdmon directly */
+@@ -2197,7 +2198,7 @@ void manage_fork_fds(int close_all)
+  *    1- if systemd service has been started
+  *    0- otherwise
+  */
+-int continue_via_systemd(char *devnm, char *service_name)
++int continue_via_systemd(char *devnm, char *service_name, char *prefix)
+ {
+       int pid, status;
+       char pathbuf[1024];
+@@ -2209,7 +2210,7 @@ int continue_via_systemd(char *devnm, char *service_name)
+       case  0:
+               manage_fork_fds(1);
+               snprintf(pathbuf, sizeof(pathbuf),
+-                       "%s@%s.service", service_name, devnm);
++                       "%s@%s%s.service", service_name, prefix ?: "", devnm);
+               status = execl("/usr/bin/systemctl", "systemctl", "restart",
+                              pathbuf, NULL);
+               status = execl("/bin/systemctl", "systemctl", "restart",
+-- 
+2.38.1
+
diff --git a/0112-mdopen-always-try-create_named_array.patch b/0112-mdopen-always-try-create_named_array.patch
new file mode 100644 (file)
index 0000000..bfd899c
--- /dev/null
@@ -0,0 +1,40 @@
+From 2e10c46d0906b1a1ec40e8f5005ccb63125dcd9e Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Tue, 14 Mar 2023 11:06:25 +1100
+Subject: [PATCH 112/120] mdopen: always try create_named_array()
+
+mdopen() will use create_named_array() to ask the kernel to create the
+given md array, but only if it is given a number or name.
+If it is NOT given a name and is required to choose one itself using
+find_free_devnm() it does NOT use create_named_array().
+
+On kernels with CONFIG_BLOCK_LEGACY_AUTOLOAD not set, this can result in
+failure to assemble an array.  This can particularly seen when the
+"name" of the array begins with a host name different to the name of the
+host running the command.
+
+So add the missing call to create_named_array().
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217074
+Signed-off-by: NeilBrown <neilb@suse.de>
+Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ mdopen.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/mdopen.c b/mdopen.c
+index d18c9319..810f79a3 100644
+--- a/mdopen.c
++++ b/mdopen.c
+@@ -370,6 +370,7 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy,
+               }
+               if (block_udev)
+                       udev_block(devnm);
++              create_named_array(devnm);
+       }
+       sprintf(devname, "/dev/%s", devnm);
+-- 
+2.38.1
+
diff --git a/0113-Improvements-for-IMSM_NO_PLATFORM-testing.patch b/0113-Improvements-for-IMSM_NO_PLATFORM-testing.patch
new file mode 100644 (file)
index 0000000..d4e6a4f
--- /dev/null
@@ -0,0 +1,172 @@
+From 420dafcd38c5949c2ddb90ad6873e7edd625db30 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Mon, 20 Mar 2023 14:43:54 +1100
+Subject: [PATCH 113/120] Improvements for IMSM_NO_PLATFORM testing.
+
+Factor out IMSM_NO_PLATFORM testing into a single function that caches
+the result.
+
+Allow mdmon to explicitly set the result to "1" so that we don't need
+the ENV var in the unit file
+
+Check if the kernel command line contains "mdadm.imsm.test=1" and in
+that case assert NO_PLATFORM.  This simplifies testing in a virtual
+machine.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ mdadm.8.in             |  5 +++++
+ mdadm.h                |  2 ++
+ mdmon.c                |  6 ++++++
+ super-intel.c          | 45 +++++++++++++++++++++++++++++++++++++++---
+ systemd/mdmon@.service |  3 ---
+ 5 files changed, 55 insertions(+), 6 deletions(-)
+
+diff --git a/mdadm.8.in b/mdadm.8.in
+index 6f0f6c13..b7159509 100644
+--- a/mdadm.8.in
++++ b/mdadm.8.in
+@@ -3197,6 +3197,11 @@ environment.  This can be useful for testing or for disaster
+ recovery.  You should be aware that interoperability may be
+ compromised by setting this value.
++These change can also be suppressed by adding 
++.B mdadm.imsm.test=1
++to the kernel command line. This makes it easy to test IMSM
++code in a virtual machine that doesn't have IMSM virtual hardware.
++
+ .TP
+ .B MDADM_GROW_ALLOW_OLD
+ If an array is stopped while it is performing a reshape and that
+diff --git a/mdadm.h b/mdadm.h
+index 1e518276..0d995445 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1263,6 +1263,8 @@ extern struct superswitch super0, super1;
+ extern struct superswitch super_imsm, super_ddf;
+ extern struct superswitch mbr, gpt;
++void imsm_set_no_platform(int v);
++
+ struct metadata_update {
+       int     len;
+       char    *buf;
+diff --git a/mdmon.c b/mdmon.c
+index 096b4d76..cef5bbc8 100644
+--- a/mdmon.c
++++ b/mdmon.c
+@@ -318,6 +318,12 @@ int main(int argc, char *argv[])
+               {NULL, 0, NULL, 0}
+       };
++      /*
++       * mdmon should never complain due to lack of a platform,
++       * that is mdadm's job if at all.
++       */
++      imsm_set_no_platform(1);
++
+       while ((opt = getopt_long(argc, argv, "thaF", options, NULL)) != -1) {
+               switch (opt) {
+               case 'a':
+diff --git a/super-intel.c b/super-intel.c
+index e155a8ae..a5c86cb2 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -20,6 +20,7 @@
+ #define HAVE_STDINT_H 1
+ #include "mdadm.h"
+ #include "mdmon.h"
++#include "dlink.h"
+ #include "sha1.h"
+ #include "platform-intel.h"
+ #include <values.h>
+@@ -629,6 +630,44 @@ static const char *_sys_dev_type[] = {
+       [SYS_DEV_VMD] = "VMD"
+ };
++static int no_platform = -1;
++
++static int check_no_platform(void)
++{
++      static const char search[] = "mdadm.imsm.test=1";
++      FILE *fp;
++
++      if (no_platform >= 0)
++              return no_platform;
++
++      if (check_env("IMSM_NO_PLATFORM")) {
++              no_platform = 1;
++              return 1;
++      }
++      fp = fopen("/proc/cmdline", "r");
++      if (fp) {
++              char *l = conf_line(fp);
++              char *w = l;
++
++              do {
++                      if (strcmp(w, search) == 0)
++                              no_platform = 1;
++                      w = dl_next(w);
++              } while (w != l);
++              free_line(l);
++              fclose(fp);
++              if (no_platform >= 0)
++                      return no_platform;
++      }
++      no_platform = 0;
++      return 0;
++}
++
++void imsm_set_no_platform(int v)
++{
++      no_platform = v;
++}
++
+ const char *get_sys_dev_type(enum sys_dev_type type)
+ {
+       if (type >= SYS_DEV_MAX)
+@@ -2699,7 +2738,7 @@ static int detail_platform_imsm(int verbose, int enumerate_only, char *controlle
+       int result=1;
+       if (enumerate_only) {
+-              if (check_env("IMSM_NO_PLATFORM"))
++              if (check_no_platform())
+                       return 0;
+               list = find_intel_devices();
+               if (!list)
+@@ -4722,7 +4761,7 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
+                      devname);
+               return 1;
+       }
+-      if (!is_fd_valid(fd) || check_env("IMSM_NO_PLATFORM")) {
++      if (!is_fd_valid(fd) || check_no_platform()) {
+               super->orom = NULL;
+               super->hba = NULL;
+               return 0;
+@@ -10697,7 +10736,7 @@ static int imsm_get_allowed_degradation(int level, int raid_disks,
+  ******************************************************************************/
+ int validate_container_imsm(struct mdinfo *info)
+ {
+-      if (check_env("IMSM_NO_PLATFORM"))
++      if (check_no_platform())
+               return 0;
+       struct sys_dev *idev;
+diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service
+index 23a375f6..020cc7e1 100644
+--- a/systemd/mdmon@.service
++++ b/systemd/mdmon@.service
+@@ -15,9 +15,6 @@ Documentation=man:mdmon(8)
+ IgnoreOnIsolate=true
+ [Service]
+-# mdmon should never complain due to lack of a platform,
+-# that is mdadm's job if at all.
+-Environment=IMSM_NO_PLATFORM=1
+ # The mdmon starting in the initramfs (with dracut at least)
+ # cannot see sysfs after root is mounted, so we will have to
+ # 'takeover'.  As the '--offroot --takeover' don't hurt when
+-- 
+2.38.1
+
diff --git a/0114-Revert-Revert-mdadm-systemd-remove-KillMode-none-fro.patch b/0114-Revert-Revert-mdadm-systemd-remove-KillMode-none-fro.patch
new file mode 100644 (file)
index 0000000..39b1809
--- /dev/null
@@ -0,0 +1,29 @@
+From 9b6e3b43381245cb128ad98bf117a565ce5defe5 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Date: Thu, 23 Mar 2023 17:13:18 +0100
+Subject: [PATCH 114/120] Revert "Revert "mdadm/systemd: remove KillMode=none
+ from service file""
+
+This reverts commit 28a083955c6f58f8e582734c8c82aff909a7d461.
+
+Resolved by commit 723d1df4946e ("mdmon: Improve switchroot
+interactions.") We are ready to drop it.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ systemd/mdadm-grow-continue@.service | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/systemd/mdadm-grow-continue@.service b/systemd/mdadm-grow-continue@.service
+index 9ccadca3..64b8254a 100644
+--- a/systemd/mdadm-grow-continue@.service
++++ b/systemd/mdadm-grow-continue@.service
+@@ -15,4 +15,3 @@ ExecStart=BINDIR/mdadm --grow --continue /dev/%I
+ StandardInput=null
+ StandardOutput=null
+ StandardError=null
+-KillMode=none
+-- 
+2.38.1
+
diff --git a/0115-Create-Fix-checking-for-container-in-update_metadata.patch b/0115-Create-Fix-checking-for-container-in-update_metadata.patch
new file mode 100644 (file)
index 0000000..0868469
--- /dev/null
@@ -0,0 +1,38 @@
+From ef6236da232e968dcf08b486178cd20d5ea97e2a Mon Sep 17 00:00:00 2001
+From: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Date: Thu, 23 Mar 2023 12:50:00 +0100
+Subject: [PATCH 115/120] Create: Fix checking for container in update_metadata
+
+The commit 8a4ce2c05386 ("Create: Factor out add_disks() helpers")
+introduced a regression that caused timeouts and udev failing to create
+links.
+
+Steps to reproduce the issue were as following:
+$ mdadm -CR imsm -e imsm -n4 /dev/nvme[0-3]n1
+$ mdadm -CR vol -l5 -n4 /dev/nvme[0-3]n1 --assume-clean
+
+I found the check for container was wrong because negation was missing.
+
+Fixes: 8a4ce2c05386 ("Create: Factor out add_disks() helpers")
+Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Create.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Create.c b/Create.c
+index bbe9e13d..0911bf92 100644
+--- a/Create.c
++++ b/Create.c
+@@ -328,7 +328,7 @@ static int update_metadata(int mdfd, struct shape *s, struct supertype *st,
+        * again returns container info.
+        */
+       st->ss->getinfo_super(st, &info_new, NULL);
+-      if (st->ss->external && is_container(s->level) &&
++      if (st->ss->external && !is_container(s->level) &&
+           !same_uuid(info_new.uuid, info->uuid, 0)) {
+               map_update(map, fd2devnm(mdfd),
+                          info_new.text_version,
+-- 
+2.38.1
+
diff --git a/0116-Fix-null-pointer-for-incremental-in-mdadm.patch b/0116-Fix-null-pointer-for-incremental-in-mdadm.patch
new file mode 100644 (file)
index 0000000..53bc051
--- /dev/null
@@ -0,0 +1,43 @@
+From 890212d6800646153210ac264ce73035cc7dd5cc Mon Sep 17 00:00:00 2001
+From: miaoguanqin <miaoguanqin@huawei.com>
+Date: Tue, 4 Apr 2023 19:31:24 +0800
+Subject: [PATCH 116/120] Fix null pointer for incremental in mdadm
+
+when we excute mdadm --assemble, udev-md-raid-assembly.rules is triggered.
+Then we stop array, we found an coredump for mdadm --incremental.func
+stack are as follows:
+
+#0  enough (level=10, raid_disks=4, layout=258, clean=1,
+    avail=avail@entry=0x0) at util.c:555
+#1  0x0000562170c26965 in Incremental (devlist=<optimized out>,
+    c=<optimized out>, st=0x5621729b6dc0) at Incremental.c:514
+#2  0x0000562170bfb6ff in main (argc=<optimized out>,
+    argv=<optimized out>) at mdadm.c:1762
+
+func enough() use array avail,avail allocate space in func count_active,
+it may not alloc space, causing a coredump.We fix this coredump.
+
+Signed-off-by: Guanqin Miao <miaoguanqin@huawei.com>
+Signed-off-by: lixiaokeng <lixiaokeng@huawei.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Incremental.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/Incremental.c b/Incremental.c
+index 09b94b9f..49a71f72 100644
+--- a/Incremental.c
++++ b/Incremental.c
+@@ -507,6 +507,9 @@ int Incremental(struct mddev_dev *devlist, struct context *c,
+                                   GET_OFFSET | GET_SIZE));
+       active_disks = count_active(st, sra, mdfd, &avail, &info);
++      if (!avail)
++              goto out_unlock;
++
+       journal_device_missing = (info.journal_device_required) && (info.journal_clean == 0);
+       if (info.consistency_policy == CONSISTENCY_POLICY_PPL)
+-- 
+2.38.1
+
diff --git a/0117-super1-fix-truncation-check-for-journal-device.patch b/0117-super1-fix-truncation-check-for-journal-device.patch
new file mode 100644 (file)
index 0000000..bf985c8
--- /dev/null
@@ -0,0 +1,33 @@
+From 1c6f2a1dbfe17df14dd5b062fc53a60c5c387e47 Mon Sep 17 00:00:00 2001
+From: Hristo Venev <hristo@venev.name>
+Date: Sat, 1 Apr 2023 23:01:35 +0300
+Subject: [PATCH 117/120] super1: fix truncation check for journal device
+
+The journal device can be smaller than the component devices.
+
+Fixes: 171e9743881e ("super1: report truncated device")
+Signed-off-by: Hristo Venev <hristo@venev.name>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super1.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/super1.c b/super1.c
+index f7020320..44d6ecad 100644
+--- a/super1.c
++++ b/super1.c
+@@ -2359,8 +2359,9 @@ static int load_super1(struct supertype *st, int fd, char *devname)
+       if (st->minor_version >= 1 &&
+           st->ignore_hw_compat == 0 &&
+-          (dsize < (__le64_to_cpu(super->data_offset) +
+-                    __le64_to_cpu(super->size))
++          ((role_from_sb(super) != MD_DISK_ROLE_JOURNAL &&
++                dsize < (__le64_to_cpu(super->data_offset) +
++                    __le64_to_cpu(super->size)))
+            ||
+            dsize < (__le64_to_cpu(super->data_offset) +
+                     __le64_to_cpu(super->data_size)))) {
+-- 
+2.38.1
+
diff --git a/0118-Fix-some-cases-eyesore-formatting.patch b/0118-Fix-some-cases-eyesore-formatting.patch
new file mode 100644 (file)
index 0000000..4da8078
--- /dev/null
@@ -0,0 +1,433 @@
+From d3bb888d885fc96fc6239fbf6c22c63143eba461 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jes@trained-monkey.org>
+Date: Mon, 10 Apr 2023 11:40:42 -0400
+Subject: [PATCH 118/120] Fix some cases eyesore formatting
+
+Summary: No functional change .... just make it more readable.
+
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ super1.c | 117 ++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 60 insertions(+), 57 deletions(-)
+
+diff --git a/super1.c b/super1.c
+index 44d6ecad..1d20ef55 100644
+--- a/super1.c
++++ b/super1.c
+@@ -192,7 +192,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
+       unsigned int disk_csum, csum;
+       unsigned long long newcsum;
+       int size = sizeof(*sb) + __le32_to_cpu(sb->max_dev)*2;
+-      unsigned int *isuper = (unsigned int*)sb;
++      unsigned int *isuper = (unsigned int *)sb;
+ /* make sure I can count... */
+       if (offsetof(struct mdp_superblock_1,data_offset) != 128 ||
+@@ -204,7 +204,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
+       disk_csum = sb->sb_csum;
+       sb->sb_csum = 0;
+       newcsum = 0;
+-      for (; size>=4; size -= 4 ) {
++      for (; size >= 4; size -= 4) {
+               newcsum += __le32_to_cpu(*isuper);
+               isuper++;
+       }
+@@ -319,7 +319,7 @@ static inline unsigned int choose_ppl_space(int chunk)
+ static void examine_super1(struct supertype *st, char *homehost)
+ {
+       struct mdp_superblock_1 *sb = st->sb;
+-      bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb)+MAX_SB_SIZE);
++      bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
+       time_t atime;
+       unsigned int d;
+       int role;
+@@ -343,8 +343,9 @@ static void examine_super1(struct supertype *st, char *homehost)
+               printf(".0\n");
+       printf("    Feature Map : 0x%x\n", __le32_to_cpu(sb->feature_map));
+       printf("     Array UUID : ");
+-      for (i=0; i<16; i++) {
+-              if ((i&3)==0 && i != 0) printf(":");
++      for (i = 0; i < 16; i++) {
++              if ((i & 3) == 0 && i != 0)
++                      printf(":");
+               printf("%02x", sb->set_uuid[i]);
+       }
+       printf("\n");
+@@ -416,11 +417,11 @@ static void examine_super1(struct supertype *st, char *homehost)
+                              UINT64_MAX - info.space_after);
+       }
+       printf("          State : %s%s\n",
+-             (__le64_to_cpu(sb->resync_offset)+1) ? "active":"clean",
++             (__le64_to_cpu(sb->resync_offset) + 1) ? "active":"clean",
+              (info.space_after > INT64_MAX)       ? " TRUNCATED DEVICE" : "");
+       printf("    Device UUID : ");
+-      for (i=0; i<16; i++) {
+-              if ((i&3)==0 && i != 0)
++      for (i = 0; i < 16; i++) {
++              if ((i & 3)==0 && i != 0)
+                       printf(":");
+               printf("%02x", sb->device_uuid[i]);
+       }
+@@ -546,7 +547,7 @@ static void examine_super1(struct supertype *st, char *homehost)
+ #if 0
+       /* This turns out to just be confusing */
+       printf("    Array Slot : %d (", __le32_to_cpu(sb->dev_number));
+-      for (i = __le32_to_cpu(sb->max_dev); i> 0 ; i--)
++      for (i = __le32_to_cpu(sb->max_dev); i > 0 ; i--)
+               if (__le16_to_cpu(sb->dev_roles[i-1]) != MD_DISK_ROLE_SPARE)
+                       break;
+       for (d = 0; d < i; d++) {
+@@ -597,7 +598,7 @@ static void examine_super1(struct supertype *st, char *homehost)
+ #if 0
+       /* This is confusing too */
+       faulty = 0;
+-      for (i = 0; i< __le32_to_cpu(sb->max_dev); i++) {
++      for (i = 0; i < __le32_to_cpu(sb->max_dev); i++) {
+               int role = __le16_to_cpu(sb->dev_roles[i]);
+               if (role == MD_DISK_ROLE_FAULTY)
+                       faulty++;
+@@ -616,10 +617,12 @@ static void examine_super1(struct supertype *st, char *homehost)
+       if (inconsistent) {
+               printf("WARNING Array state is inconsistent - each number should appear only once\n");
+               for (d = 0; d < __le32_to_cpu(sb->max_dev); d++)
+-                      if (__le16_to_cpu(sb->dev_roles[d]) >= MD_DISK_ROLE_FAULTY)
++                      if (__le16_to_cpu(sb->dev_roles[d]) >=
++                          MD_DISK_ROLE_FAULTY)
+                               printf(" %d:-", d);
+                       else
+-                              printf(" %d:%d", d, __le16_to_cpu(sb->dev_roles[d]));
++                              printf(" %d:%d", d,
++                                     __le16_to_cpu(sb->dev_roles[d]));
+               printf("\n");
+       }
+ }
+@@ -659,7 +662,7 @@ static void brief_examine_super1(struct supertype *st, int verbose)
+               printf("num-devices=%d ", __le32_to_cpu(sb->raid_disks));
+       printf("UUID=");
+       for (i = 0; i < 16; i++) {
+-              if ((i&3)==0 && i != 0)
++              if ((i & 3)==0 && i != 0)
+                       printf(":");
+               printf("%02x", sb->set_uuid[i]);
+       }
+@@ -713,7 +716,7 @@ static void export_examine_super1(struct supertype *st)
+       }
+       printf("MD_UUID=");
+       for (i = 0; i < 16; i++) {
+-              if ((i&3) == 0 && i != 0)
++              if ((i & 3) == 0 && i != 0)
+                       printf(":");
+               printf("%02x", sb->set_uuid[i]);
+       }
+@@ -722,7 +725,7 @@ static void export_examine_super1(struct supertype *st)
+              __le64_to_cpu(sb->utime) & 0xFFFFFFFFFFULL);
+       printf("MD_DEV_UUID=");
+       for (i = 0; i < 16; i++) {
+-              if ((i&3) == 0 && i != 0)
++              if ((i & 3) == 0 && i != 0)
+                       printf(":");
+               printf("%02x", sb->device_uuid[i]);
+       }
+@@ -812,7 +815,7 @@ static int copy_metadata1(struct supertype *st, int from, int to)
+                               /* have the header, can calculate
+                                * correct bitmap bytes */
+                               bitmap_super_t *bms;
+-                              bms = (void*)buf;
++                              bms = (void *)buf;
+                               bytes = calc_bitmap_size(bms, 512);
+                               if (n > bytes)
+                                       n =  bytes;
+@@ -867,7 +870,7 @@ err:
+ static void detail_super1(struct supertype *st, char *homehost, char *subarray)
+ {
+       struct mdp_superblock_1 *sb = st->sb;
+-      bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE);
++      bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
+       int i;
+       int l = homehost ? strlen(homehost) : 0;
+@@ -880,7 +883,7 @@ static void detail_super1(struct supertype *st, char *homehost, char *subarray)
+               printf("\n      Cluster Name : %-64s", bms->cluster_name);
+       printf("\n              UUID : ");
+       for (i = 0; i < 16; i++) {
+-              if ((i&3) == 0 && i != 0)
++              if ((i & 3) == 0 && i != 0)
+                       printf(":");
+               printf("%02x", sb->set_uuid[i]);
+       }
+@@ -939,7 +942,7 @@ static int examine_badblocks_super1(struct supertype *st, int fd, char *devname)
+       }
+       size = __le16_to_cpu(sb->bblog_size)* 512;
+-      if (posix_memalign((void**)&bbl, 4096, size) != 0) {
++      if (posix_memalign((void **)&bbl, 4096, size) != 0) {
+               pr_err("could not allocate badblocks list\n");
+               return 0;
+       }
+@@ -987,7 +990,7 @@ static int match_home1(struct supertype *st, char *homehost)
+ static void uuid_from_super1(struct supertype *st, int uuid[4])
+ {
+       struct mdp_superblock_1 *super = st->sb;
+-      char *cuuid = (char*)uuid;
++      char *cuuid = (char *)uuid;
+       int i;
+       for (i = 0; i < 16; i++)
+               cuuid[i] = super->set_uuid[i];
+@@ -996,9 +999,9 @@ static void uuid_from_super1(struct supertype *st, int uuid[4])
+ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map)
+ {
+       struct mdp_superblock_1 *sb = st->sb;
+-      struct bitmap_super_s *bsb = (void*)(((char*)sb)+MAX_SB_SIZE);
++      struct bitmap_super_s *bsb = (void *)(((char *)sb) + MAX_SB_SIZE);
+       struct misc_dev_info *misc =
+-              (void*)(((char*)sb)+MAX_SB_SIZE+BM_SUPER_SIZE);
++              (void *)(((char *)sb) + MAX_SB_SIZE+BM_SUPER_SIZE);
+       int working = 0;
+       unsigned int i;
+       unsigned int role;
+@@ -1166,7 +1169,7 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map)
+       info->recovery_blocked = info->reshape_active;
+       if (map)
+-              for (i=0; i<map_disks; i++)
++              for (i = 0; i < map_disks; i++)
+                       map[i] = 0;
+       for (i = 0; i < __le32_to_cpu(sb->max_dev); i++) {
+               role = __le16_to_cpu(sb->dev_roles[i]);
+@@ -1217,7 +1220,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+        */
+       int rv = 0;
+       struct mdp_superblock_1 *sb = st->sb;
+-      bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE);
++      bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
+       if (update == UOPT_HOMEHOST && homehost) {
+               /*
+@@ -1228,9 +1231,10 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+               update = UOPT_NAME;
+               c = strchr(sb->set_name, ':');
+               if (c)
+-                      snprintf(info->name, sizeof(info->name), "%s", c+1);
++                      snprintf(info->name, sizeof(info->name), "%s", c + 1);
+               else
+-                      snprintf(info->name, sizeof(info->name), "%s", sb->set_name);
++                      snprintf(info->name, sizeof(info->name), "%s",
++                               sb->set_name);
+       }
+       switch (update) {
+@@ -1331,7 +1335,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+               sb->dev_number = __cpu_to_le32(i);
+               if (i == max)
+-                      sb->max_dev = __cpu_to_le32(max+1);
++                      sb->max_dev = __cpu_to_le32(max + 1);
+               if (i > max)
+                       return -2;
+@@ -1350,8 +1354,8 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+                               sb->data_size = __cpu_to_le64(
+                                       ds - __le64_to_cpu(sb->data_offset));
+                       } else {
+-                              ds -= 8*2;
+-                              ds &= ~(unsigned long long)(4*2-1);
++                              ds -= 8 * 2;
++                              ds &= ~(unsigned long long)(4 * 2 - 1);
+                               sb->super_offset = __cpu_to_le64(ds);
+                               sb->data_size = __cpu_to_le64(
+                                       ds - __le64_to_cpu(sb->data_offset));
+@@ -1367,7 +1371,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
+               if (i > max)
+                       return -2;
+               if (i == max)
+-                      sb->max_dev = __cpu_to_le32(max+1);
++                      sb->max_dev = __cpu_to_le32(max + 1);
+               sb->raid_disks = __cpu_to_le32(info->array.raid_disks);
+               sb->dev_roles[info->disk.number] =
+                       __cpu_to_le16(info->disk.raid_disk);
+@@ -1645,7 +1649,7 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info,
+       char defname[10];
+       int sbsize;
+-      if (posix_memalign((void**)&sb, 4096, SUPER1_SIZE) != 0) {
++      if (posix_memalign((void **)&sb, 4096, SUPER1_SIZE) != 0) {
+               pr_err("could not allocate superblock\n");
+               return 0;
+       }
+@@ -1679,8 +1683,8 @@ static int init_super1(struct supertype *st, mdu_array_info_t *info,
+               name = defname;
+       }
+       if (homehost &&
+-          strchr(name, ':')== NULL &&
+-          strlen(homehost)+1+strlen(name) < 32) {
++          strchr(name, ':') == NULL &&
++          strlen(homehost) + 1 + strlen(name) < 32) {
+               strcpy(sb->set_name, homehost);
+               strcat(sb->set_name, ":");
+               strcat(sb->set_name, name);
+@@ -1759,7 +1763,7 @@ static int add_to_super1(struct supertype *st, mdu_disk_info_t *dk,
+       if (dk->number >= (int)__le32_to_cpu(sb->max_dev) &&
+           __le32_to_cpu(sb->max_dev) < MAX_DEVS)
+-              sb->max_dev = __cpu_to_le32(dk->number+1);
++              sb->max_dev = __cpu_to_le32(dk->number + 1);
+       sb->dev_number = __cpu_to_le32(dk->number);
+       sb->devflags = 0; /* don't copy another disks flags */
+@@ -1840,8 +1844,8 @@ static int store_super1(struct supertype *st, int fd)
+               return 4;
+       if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BITMAP_OFFSET)) {
+-              struct bitmap_super_s *bm = (struct bitmap_super_s*)
+-                      (((char*)sb)+MAX_SB_SIZE);
++              struct bitmap_super_s *bm;
++              bm = (struct bitmap_super_s *)(((char *)sb) + MAX_SB_SIZE);
+               if (__le32_to_cpu(bm->magic) == BITMAP_MAGIC) {
+                       locate_bitmap1(st, fd, 0);
+                       if (awrite(&afd, bm, sizeof(*bm)) != sizeof(*bm))
+@@ -1928,7 +1932,7 @@ static int write_empty_r5l_meta_block(struct supertype *st, int fd)
+       init_afd(&afd, fd);
+-      if (posix_memalign((void**)&mb, 4096, META_BLOCK_SIZE) != 0) {
++      if (posix_memalign((void **)&mb, 4096, META_BLOCK_SIZE) != 0) {
+               pr_err("Could not allocate memory for the meta block.\n");
+               return 1;
+       }
+@@ -2197,7 +2201,7 @@ static int compare_super1(struct supertype *st, struct supertype *tst,
+               return 1;
+       if (!first) {
+-              if (posix_memalign((void**)&first, 4096, SUPER1_SIZE) != 0) {
++              if (posix_memalign((void **)&first, 4096, SUPER1_SIZE) != 0) {
+                       pr_err("could not allocate superblock\n");
+                       return 1;
+               }
+@@ -2310,7 +2314,7 @@ static int load_super1(struct supertype *st, int fd, char *devname)
+               return 1;
+       }
+-      if (posix_memalign((void**)&super, 4096, SUPER1_SIZE) != 0) {
++      if (posix_memalign((void **)&super, 4096, SUPER1_SIZE) != 0) {
+               pr_err("could not allocate superblock\n");
+               return 1;
+       }
+@@ -2349,10 +2353,10 @@ static int load_super1(struct supertype *st, int fd, char *devname)
+               return 2;
+       }
+-      bsb = (struct bitmap_super_s *)(((char*)super)+MAX_SB_SIZE);
++      bsb = (struct bitmap_super_s *)(((char *)super) + MAX_SB_SIZE);
+       misc = (struct misc_dev_info*)
+-        (((char*)super)+MAX_SB_SIZE+BM_SUPER_SIZE);
++              (((char *)super) + MAX_SB_SIZE+BM_SUPER_SIZE);
+       misc->device_size = dsize;
+       if (st->data_offset == INVALID_SECTORS)
+               st->data_offset = __le64_to_cpu(super->data_offset);
+@@ -2360,9 +2364,8 @@ static int load_super1(struct supertype *st, int fd, char *devname)
+       if (st->minor_version >= 1 &&
+           st->ignore_hw_compat == 0 &&
+           ((role_from_sb(super) != MD_DISK_ROLE_JOURNAL &&
+-                dsize < (__le64_to_cpu(super->data_offset) +
+-                    __le64_to_cpu(super->size)))
+-           ||
++            dsize < (__le64_to_cpu(super->data_offset) +
++                     __le64_to_cpu(super->size))) ||
+            dsize < (__le64_to_cpu(super->data_offset) +
+                     __le64_to_cpu(super->data_size)))) {
+               if (devname)
+@@ -2391,8 +2394,8 @@ static int load_super1(struct supertype *st, int fd, char *devname)
+       return 0;
+  no_bitmap:
+-      super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map)
+-                                         & ~MD_FEATURE_BITMAP_OFFSET);
++      super->feature_map = __cpu_to_le32(__le32_to_cpu(super->feature_map) &
++                                         ~MD_FEATURE_BITMAP_OFFSET);
+       return 0;
+ }
+@@ -2450,7 +2453,7 @@ static __u64 avail_size1(struct supertype *st, __u64 devsize,
+       if (__le32_to_cpu(super->feature_map) & MD_FEATURE_BITMAP_OFFSET) {
+               /* hot-add. allow for actual size of bitmap */
+               struct bitmap_super_s *bsb;
+-              bsb = (struct bitmap_super_s *)(((char*)super)+MAX_SB_SIZE);
++              bsb = (struct bitmap_super_s *)(((char *)super) + MAX_SB_SIZE);
+               bmspace = calc_bitmap_size(bsb, 4096) >> 9;
+       } else if (md_feature_any_ppl_on(super->feature_map)) {
+               bmspace = __le16_to_cpu(super->ppl.size);
+@@ -2519,7 +2522,7 @@ add_internal_bitmap1(struct supertype *st,
+       int creating = 0;
+       int len;
+       struct mdp_superblock_1 *sb = st->sb;
+-      bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE);
++      bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
+       int uuid[4];
+       if (__le64_to_cpu(sb->data_size) == 0)
+@@ -2607,10 +2610,10 @@ add_internal_bitmap1(struct supertype *st,
+       max_bits = (room * 512 - sizeof(bitmap_super_t)) * 8;
+       min_chunk = 4096; /* sub-page chunks don't work yet.. */
+-      bits = (size*512)/min_chunk +1;
++      bits = (size * 512) / min_chunk + 1;
+       while (bits > max_bits) {
+               min_chunk *= 2;
+-              bits = (bits+1)/2;
++              bits = (bits + 1) / 2;
+       }
+       if (chunk == UnSet) {
+               /* For practical purpose, 64Meg is a good
+@@ -2628,8 +2631,8 @@ add_internal_bitmap1(struct supertype *st,
+               /* start bitmap on a 4K boundary with enough space for
+                * the bitmap
+                */
+-              bits = (size*512) / chunk + 1;
+-              room = ((bits+7)/8 + sizeof(bitmap_super_t) +4095)/4096;
++              bits = (size * 512) / chunk + 1;
++              room = ((bits + 7) / 8 + sizeof(bitmap_super_t) + 4095) / 4096;
+               room *= 8; /* convert 4K blocks to sectors */
+               offset = -room - bbl_size;
+       }
+@@ -2683,7 +2686,7 @@ static int locate_bitmap1(struct supertype *st, int fd, int node_num)
+       offset = __le64_to_cpu(sb->super_offset) + (int32_t)__le32_to_cpu(sb->bitmap_offset);
+       if (node_num) {
+-              bms = (bitmap_super_t*)(((char*)sb)+MAX_SB_SIZE);
++              bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
+               bm_sectors_per_node = calc_bitmap_size(bms, 4096) >> 9;
+               offset += bm_sectors_per_node * node_num;
+       }
+@@ -2696,7 +2699,7 @@ static int locate_bitmap1(struct supertype *st, int fd, int node_num)
+ static int write_bitmap1(struct supertype *st, int fd, enum bitmap_update update)
+ {
+       struct mdp_superblock_1 *sb = st->sb;
+-      bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb)+MAX_SB_SIZE);
++      bitmap_super_t *bms = (bitmap_super_t *)(((char *)sb) + MAX_SB_SIZE);
+       int rv = 0;
+       void *buf;
+       int towrite, n, len;
+@@ -2970,16 +2973,16 @@ void *super1_make_v0(struct supertype *st, struct mdinfo *info, mdp_super_t *sb0
+       copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid);
+       sprintf(sb->set_name, "%d", sb0->md_minor);
+-      sb->ctime = __cpu_to_le32(info->array.ctime+1);
++      sb->ctime = __cpu_to_le32(info->array.ctime + 1);
+       sb->level = __cpu_to_le32(info->array.level);
+       sb->layout = __cpu_to_le32(info->array.layout);
+       sb->size = __cpu_to_le64(info->component_size);
+-      sb->chunksize = __cpu_to_le32(info->array.chunk_size/512);
++      sb->chunksize = __cpu_to_le32(info->array.chunk_size / 512);
+       sb->raid_disks = __cpu_to_le32(info->array.raid_disks);
+       if (info->array.level > 0)
+               sb->data_size = sb->size;
+       else
+-              sb->data_size = st->ss->avail_size(st, st->devsize/512, 0);
++              sb->data_size = st->ss->avail_size(st, st->devsize / 512, 0);
+       sb->resync_offset = MaxSector;
+       sb->max_dev = __cpu_to_le32(MD_SB_DISKS);
+       sb->dev_number = __cpu_to_le32(info->disk.number);
+-- 
+2.38.1
+
diff --git a/0119-Bump-minimum-kernel-version-to-2.6.32.patch b/0119-Bump-minimum-kernel-version-to-2.6.32.patch
new file mode 100644 (file)
index 0000000..7fcbf6c
--- /dev/null
@@ -0,0 +1,136 @@
+From f8d2c4286a92b7acb7872271a401ad1efe336096 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jes@trained-monkey.org>
+Date: Mon, 10 Apr 2023 11:45:34 -0400
+Subject: [PATCH 119/120] Bump minimum kernel version to 2.6.32
+
+Summary: At this point it probably is reasonable to drop support for
+anything prior to 3.10.
+
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ Create.c |  5 -----
+ Grow.c   | 16 ----------------
+ Manage.c | 17 -----------------
+ mdadm.c  |  4 ++--
+ super1.c |  5 -----
+ 5 files changed, 2 insertions(+), 45 deletions(-)
+
+diff --git a/Create.c b/Create.c
+index 0911bf92..aa0472dd 100644
+--- a/Create.c
++++ b/Create.c
+@@ -636,11 +636,6 @@ int Create(struct supertype *st, char *mddev,
+               break;
+       case LEVEL_LINEAR:
+               /* a chunksize of zero 0s perfectly valid (and preferred) since 2.6.16 */
+-              if (get_linux_version() < 2006016 && s->chunk == 0) {
+-                      s->chunk = 64;
+-                      if (c->verbose > 0)
+-                              pr_err("chunk size defaults to 64K\n");
+-              }
+               break;
+       case 1:
+       case LEVEL_FAULTY:
+diff --git a/Grow.c b/Grow.c
+index 06001f2d..8fa97875 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1708,14 +1708,6 @@ char *analyse_change(char *devname, struct mdinfo *info, struct reshape *re)
+               return NULL;
+       }
+-      if (re->after.data_disks == re->before.data_disks &&
+-          get_linux_version() < 2006032)
+-              return "in-place reshape is not safe before 2.6.32 - sorry.";
+-
+-      if (re->after.data_disks < re->before.data_disks &&
+-          get_linux_version() < 2006030)
+-              return "reshape to fewer devices is not supported before 2.6.30 - sorry.";
+-
+       re->backup_blocks = compute_backup_blocks(
+               info->new_chunk, info->array.chunk_size,
+               re->after.data_disks, re->before.data_disks);
+@@ -1895,14 +1887,6 @@ int Grow_reshape(char *devname, int fd,
+               return 1;
+       }
+-      if (s->raiddisks && s->raiddisks < array.raid_disks &&
+-          array.level > 1 && get_linux_version() < 2006032 &&
+-          !check_env("MDADM_FORCE_FEWER")) {
+-              pr_err("reducing the number of devices is not safe before Linux 2.6.32\n"
+-                      "       Please use a newer kernel\n");
+-              return 1;
+-      }
+-
+       if (array.level > 1 && s->size > 1 &&
+           (unsigned long long) (array.chunk_size / 1024) > s->size) {
+               pr_err("component size must be larger than chunk size.\n");
+diff --git a/Manage.c b/Manage.c
+index fde6aba3..f54de7c6 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -461,17 +461,6 @@ done:
+               goto out;
+       }
+-      if (get_linux_version() < 2006028) {
+-              /* prior to 2.6.28, KOBJ_CHANGE was not sent when an md array
+-               * was stopped, so We'll do it here just to be sure.  Drop any
+-               * partitions as well...
+-               */
+-              if (fd >= 0)
+-                      ioctl(fd, BLKRRPART, 0);
+-              if (mdi)
+-                      sysfs_uevent(mdi, "change");
+-      }
+-
+       if (devnm[0] && use_udev()) {
+               struct map_ent *mp = map_by_devnm(&map, devnm);
+               remove_devices(devnm, mp ? mp->path : NULL);
+@@ -621,12 +610,6 @@ int attempt_re_add(int fd, int tfd, struct mddev_dev *dv,
+                * though.
+                */
+               mdu_disk_info_t disc;
+-              /* re-add doesn't work for version-1 superblocks
+-               * before 2.6.18 :-(
+-               */
+-              if (array->major_version == 1 &&
+-                  get_linux_version() <= 2006018)
+-                      goto skip_re_add;
+               disc.number = mdi.disk.number;
+               if (md_get_disk_info(fd, &disc) != 0 ||
+                   disc.major != 0 || disc.minor != 0)
+diff --git a/mdadm.c b/mdadm.c
+index 4685ad6b..2296911d 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -107,8 +107,8 @@ int main(int argc, char *argv[])
+       srandom(time(0) ^ getpid());
+-      if (get_linux_version() < 2006015) {
+-              pr_err("This version of mdadm does not support kernels older than 2.6.15\n");
++      if (get_linux_version() < 2006032) {
++              pr_err("This version of mdadm does not support kernels older than 2.6.32\n");
+               exit(1);
+       }
+diff --git a/super1.c b/super1.c
+index 1d20ef55..938c3a68 100644
+--- a/super1.c
++++ b/super1.c
+@@ -2033,11 +2033,6 @@ static int write_init_super1(struct supertype *st)
+                               /* same array, so preserve events and
+                                * dev_number */
+                               sb->events = refsb->events;
+-                              /* bugs in 2.6.17 and earlier mean the
+-                               * dev_number chosen in Manage must be preserved
+-                               */
+-                              if (get_linux_version() >= 2006018)
+-                                      sb->dev_number = refsb->dev_number;
+                       }
+                       free_super1(refst);
+               }
+-- 
+2.38.1
+
diff --git a/0120-Remove-the-config-files-in-mdcheck_start-continue-se.patch b/0120-Remove-the-config-files-in-mdcheck_start-continue-se.patch
new file mode 100644 (file)
index 0000000..cb73179
--- /dev/null
@@ -0,0 +1,42 @@
+From 76c224c6cfc8ff154bd041d30b9551faecd593c1 Mon Sep 17 00:00:00 2001
+From: Xiao Ni <xni@redhat.com>
+Date: Fri, 7 Apr 2023 08:45:28 +0800
+Subject: [PATCH 120/120] Remove the config files in mdcheck_start|continue
+ service
+
+We set MDADM_CHECK_DURATION in the mdcheck_start|continue.service files.
+And mdcheck doesn't use any configs from the config file. So we can remove
+the dependencies.
+
+Signed-off-by: Xiao Ni <xni@redhat.com>
+Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
+---
+ systemd/mdcheck_continue.service | 2 --
+ systemd/mdcheck_start.service    | 2 --
+ 2 files changed, 4 deletions(-)
+
+diff --git a/systemd/mdcheck_continue.service b/systemd/mdcheck_continue.service
+index f5324905..70892a1f 100644
+--- a/systemd/mdcheck_continue.service
++++ b/systemd/mdcheck_continue.service
+@@ -13,6 +13,4 @@ Documentation=man:mdadm(8)
+ [Service]
+ Type=oneshot
+ Environment="MDADM_CHECK_DURATION=6 hours"
+-EnvironmentFile=-/run/sysconfig/mdadm
+-ExecStartPre=-/usr/lib/mdadm/mdadm_env.sh
+ ExecStart=/usr/share/mdadm/mdcheck --continue --duration ${MDADM_CHECK_DURATION}
+diff --git a/systemd/mdcheck_start.service b/systemd/mdcheck_start.service
+index 703a6583..fc4fc438 100644
+--- a/systemd/mdcheck_start.service
++++ b/systemd/mdcheck_start.service
+@@ -13,6 +13,4 @@ Documentation=man:mdadm(8)
+ [Service]
+ Type=oneshot
+ Environment="MDADM_CHECK_DURATION=6 hours"
+-EnvironmentFile=-/run/sysconfig/mdadm
+-ExecStartPre=-/usr/lib/mdadm/mdadm_env.sh
+ ExecStart=/usr/share/mdadm/mdcheck --duration ${MDADM_CHECK_DURATION}
+-- 
+2.38.1
+
index bd09d1389fd73c2ba3fddc912c2cc39c23ca3e0a..5d284dd5309c1eb26e58b6df487f983f1b1f0e3e 100644 (file)
@@ -8,7 +8,7 @@ Summary:        Tool for creating and maintaining software RAID devices
 Summary(pl.UTF-8):     Narzędzie do tworzenia i obsługi programowych macierzy RAID
 Name:          mdadm
 Version:       4.2
-Release:       0.1
+Release:       0.2
 License:       GPL v2+
 Group:         Base
 Source0:       https://www.kernel.org/pub/linux/utils/raid/mdadm/%{name}-%{version}.tar.xz
@@ -20,6 +20,127 @@ Source4:    %{name}-checkarray
 Source5:       cronjob-%{name}.timer
 Source6:       cronjob-%{name}.service
 URL:           https://www.kernel.org/pub/linux/utils/raid/mdadm/
+# Upstream patches
+Patch000:      0001-Unify-error-message.patch
+Patch001:      0002-%{name}-Fix-double-free.patch
+Patch002:      0003-Grow_reshape-Add-r0-grow-size-error-message-and-upda.patch
+Patch003:      0004-udev-adapt-rules-to-systemd-v247.patch
+Patch004:      0005-Replace-error-prone-signal-with-sigaction.patch
+Patch005:      0006-%{name}-Respect-config-file-location-in-man.patch
+Patch006:      0007-%{name}-Update-ReadMe.patch
+Patch007:      0008-%{name}-Update-config-man-regarding-default-files-and-.patch
+Patch008:      0009-%{name}-Update-config-manual.patch
+Patch009:      0010-Create-Build-use-default_layout.patch
+Patch010:      0011-%{name}-add-map_num_s.patch
+Patch011:      0012-%{name}-systemd-remove-KillMode-none-from-service-file.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-%{name}-fix-coredump-of-mdadm-monitor-r.patch
+Patch020:      0021-util-replace-ioctl-use-with-function.patch
+Patch021:      0022-%{name}-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-%{name}-block-update-ppl-for-non-raid456-levels.patch
+Patch026:      0027-%{name}-Fix-array-size-mismatch-after-grow.patch
+Patch027:      0028-%{name}-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-%{name}-Grow-Fix-use-after-close-bug-by-closing-after-.patch
+Patch034:      0035-monitor-Avoid-segfault-when-calling-NULL-get_bad_blo.patch
+Patch035:      0036-%{name}-Fix-mdadm-r-remove-option-regression.patch
+Patch036:      0037-%{name}-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-%{name}-test-Add-a-mode-to-repeat-specified-tests.patch
+Patch042:      0043-%{name}-test-Mark-and-ignore-broken-test-failures.patch
+Patch043:      0044-tests-Add-broken-files-for-all-broken-tests.patch
+Patch044:      0045-%{name}-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-%{name}-remove-symlink-option.patch
+Patch048:      0049-%{name}-move-data_offset-to-struct-shape.patch
+Patch049:      0050-%{name}-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
+Patch052:      0053-super1-report-truncated-device.patch
+Patch053:      0054-%{name}-Correct-typos-punctuation-and-grammar-in-man.patch
+Patch054:      0055-Manage-Block-unsafe-member-failing.patch
+Patch055:      0056-Monitor-Fix-statelist-memory-leaks.patch
+Patch056:      0057-%{name}-added-support-for-Intel-Alderlake-RST-on-VMD-p.patch
+Patch057:      0058-%{name}-Add-Documentation-entries-to-systemd-services.patch
+Patch058:      0059-ReadMe-fix-command-line-help.patch
+Patch059:      0060-%{name}-replace-container-level-checking-with-inline.patch
+Patch060:      0061-Mdmonitor-Omit-non-md-devices.patch
+Patch061:      0062-Mdmonitor-Split-alert-into-separate-functions.patch
+Patch062:      0063-Monitor-block-if-monitor-modes-are-combined.patch
+Patch063:      0064-Update-%{name}-Monitor-manual.patch
+Patch064:      0065-Grow-fix-possible-memory-leak.patch
+Patch065:      0066-%{name}-create-ident_init.patch
+Patch066:      0067-%{name}-Add-option-validation-for-update-subarray.patch
+Patch067:      0068-Fix-update-subarray-on-active-volume.patch
+Patch068:      0069-Add-code-specific-update-options-to-enum.patch
+Patch069:      0070-super-ddf-Remove-update_super_ddf.patch
+Patch070:      0071-super0-refactor-the-code-for-enum.patch
+Patch071:      0072-super1-refactor-the-code-for-enum.patch
+Patch072:      0073-super-intel-refactor-the-code-for-enum.patch
+Patch073:      0074-Change-update-to-enum-in-update_super-and-update_sub.patch
+Patch074:      0075-Manage-Incremental-code-refactor-string-to-enum.patch
+Patch075:      0076-Change-char-to-enum-in-context-update-refactor-code.patch
+Patch076:      0077-mdmon-fix-segfault.patch
+Patch077:      0078-util-remove-obsolete-code-from-get_md_name.patch
+Patch078:      0079-%{name}-udev-Don-t-handle-change-event-on-raw-devices.patch
+Patch079:      0080-Manage-do-not-check-array-state-when-drive-is-remove.patch
+Patch080:      0081-incremental-manage-do-not-verify-if-remove-is-safe.patch
+Patch081:      0082-super-intel-make-freesize-not-required-for-chunk-siz.patch
+Patch082:      0083-manage-move-comment-with-function-description.patch
+Patch083:      0084-Revert-%{name}-systemd-remove-KillMode-none-from-servi.patch
+Patch084:      0085-Grow-fix-can-t-change-bitmap-type-from-none-to-clust.patch
+Patch085:      0086-Fix-NULL-dereference-in-super_by_fd.patch
+Patch086:      0087-Mdmonitor-Make-alert_info-global.patch
+Patch087:      0088-Mdmonitor-Pass-events-to-alert-using-enums-instead-o.patch
+Patch088:      0089-Mdmonitor-Add-helper-functions.patch
+Patch089:      0090-Add-helpers-to-determine-whether-directories-or-file.patch
+Patch090:      0091-Mdmonitor-Refactor-write_autorebuild_pid.patch
+Patch091:      0092-Mdmonitor-Refactor-check_one_sharer-for-better-error.patch
+Patch092:      0093-util.c-reorder-code-lines-in-parse_layout_faulty.patch
+Patch093:      0094-util.c-fix-memleak-in-parse_layout_faulty.patch
+Patch094:      0095-Detail.c-fix-memleak-in-Detail.patch
+Patch095:      0096-isuper-intel.c-fix-double-free-in-load_imsm_mpb.patch
+Patch096:      0097-super-intel.c-fix-memleak-in-find_disk_attached_hba.patch
+Patch097:      0098-super-ddf.c-fix-memleak-in-get_vd_num_of_subarray.patch
+Patch098:      0099-Create-goto-abort_locked-instead-of-return-1-in-erro.patch
+Patch099:      0100-Create-remove-safe_mode_delay-local-variable.patch
+Patch100:      0101-Create-Factor-out-add_disks-helpers.patch
+Patch101:      0102-%{name}-Introduce-pr_info.patch
+Patch102:      0103-%{name}-Add-write-zeros-option-for-Create.patch
+Patch103:      0104-tests-00raid5-zero-Introduce-test-to-exercise-write-.patch
+Patch104:      0105-manpage-Add-write-zeroes-option-to-manpage.patch
+Patch105:      0106-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch
+Patch106:      0107-Use-existence-of-etc-initrd-release-to-detect-initrd.patch
+Patch107:      0108-mdmon-don-t-test-both-all-and-container_name.patch
+Patch108:      0109-mdmon-change-systemd-unit-file-to-use-foreground.patch
+Patch109:      0110-mdmon-Remove-need-for-KillMode-none.patch
+Patch110:      0111-mdmon-Improve-switchroot-interactions.patch
+Patch111:      0112-mdopen-always-try-create_named_array.patch
+Patch112:      0113-Improvements-for-IMSM_NO_PLATFORM-testing.patch
+Patch113:      0114-Revert-Revert-%{name}-systemd-remove-KillMode-none-fro.patch
+Patch114:      0115-Create-Fix-checking-for-container-in-update_metadata.patch
+Patch115:      0116-Fix-null-pointer-for-incremental-in-%{name}.patch
+Patch116:      0117-super1-fix-truncation-check-for-journal-device.patch
+Patch117:      0118-Fix-some-cases-eyesore-formatting.patch
+Patch118:      0119-Bump-minimum-kernel-version-to-2.6.32.patch
+Patch119:      0120-Remove-the-config-files-in-mdcheck_start-continue-se.patch
 BuildRequires: corosync-devel
 BuildRequires: dlm-devel
 BuildRequires: groff
@@ -70,6 +191,126 @@ skonsolidowane na potrzeby initrd.
 
 %prep
 %setup -q
+%patch000 -p1
+%patch001 -p1
+%patch002 -p1
+%patch003 -p1
+%patch004 -p1
+%patch005 -p1
+%patch006 -p1
+%patch007 -p1
+%patch008 -p1
+%patch009 -p1
+%patch010 -p1
+%patch011 -p1
+%patch012 -p1
+%patch013 -p1
+%patch014 -p1
+%patch015 -p1
+%patch016 -p1
+%patch017 -p1
+%patch018 -p1
+%patch019 -p1
+%patch020 -p1
+%patch021 -p1
+%patch022 -p1
+%patch023 -p1
+%patch024 -p1
+%patch025 -p1
+%patch026 -p1
+%patch027 -p1
+%patch028 -p1
+%patch029 -p1
+%patch030 -p1
+%patch031 -p1
+%patch032 -p1
+%patch033 -p1
+%patch034 -p1
+%patch035 -p1
+%patch036 -p1
+%patch037 -p1
+%patch038 -p1
+%patch039 -p1
+%patch040 -p1
+%patch041 -p1
+%patch042 -p1
+%patch043 -p1
+%patch044 -p1
+%patch045 -p1
+%patch046 -p1
+%patch047 -p1
+%patch048 -p1
+%patch049 -p1
+%patch050 -p1
+%patch051 -p1
+%patch052 -p1
+%patch053 -p1
+%patch054 -p1
+%patch055 -p1
+%patch056 -p1
+%patch057 -p1
+%patch058 -p1
+%patch059 -p1
+%patch060 -p1
+%patch061 -p1
+%patch062 -p1
+%patch063 -p1
+%patch064 -p1
+%patch065 -p1
+%patch066 -p1
+%patch067 -p1
+%patch068 -p1
+%patch069 -p1
+%patch070 -p1
+%patch071 -p1
+%patch072 -p1
+%patch073 -p1
+%patch074 -p1
+%patch075 -p1
+%patch076 -p1
+%patch077 -p1
+%patch078 -p1
+%patch079 -p1
+%patch080 -p1
+%patch081 -p1
+%patch082 -p1
+%patch083 -p1
+%patch084 -p1
+%patch085 -p1
+%patch086 -p1
+%patch087 -p1
+%patch088 -p1
+%patch089 -p1
+%patch090 -p1
+%patch091 -p1
+%patch092 -p1
+%patch093 -p1
+%patch094 -p1
+%patch095 -p1
+%patch096 -p1
+%patch097 -p1
+%patch098 -p1
+%patch099 -p1
+%patch100 -p1
+%patch101 -p1
+%patch102 -p1
+%patch103 -p1
+%patch104 -p1
+%patch105 -p1
+%patch106 -p1
+%patch107 -p1
+%patch108 -p1
+%patch109 -p1
+%patch110 -p1
+%patch111 -p1
+%patch112 -p1
+%patch113 -p1
+%patch114 -p1
+%patch115 -p1
+%patch116 -p1
+%patch117 -p1
+%patch118 -p1
+%patch119 -p1
 
 %build
 %if %{with initrd}
This page took 1.070483 seconds and 4 git commands to generate.