$ git diff --patch-with-stat --summary 5d5599e4c377ea22254acbb15a27474fe0273911..f76317e6fc2dd61683d04d3744e8168f91755962
...ep-MD_DISK_FAILFAST-and-MD_DISK_WRITEMOST.patch | 39 +++
0002-Document-PART-POLICY-lines.patch | 77 +++++
...olicy-support-devices-with-multiple-paths.patch | 334 ++++++++++++++++++++
...eck-add-systemd-unit-files-to-run-mdcheck.patch | 137 ++++++++
...-system-timer-to-run-oneshot-periodically.patch | 82 +++++
...-metadata-correctly-while-raid10-double-d.patch | 83 +++++
...sk-FAILFAST-and-WRITEMOSTLY-flags-when-fi.patch | 43 +++
...w-avoid-overflow-in-compute_backup_blocks.patch | 34 ++
0009-Grow-report-correct-new-chunk-size.patch | 30 ++
...policy.c-prevent-NULL-pointer-referencing.patch | 31 ++
0011-policy.c-Fix-for-compiler-error.patch | 36 +++
...sh-recovery-when-drive-with-rebuild-fails.patch | 94 ++++++
0013-imsm-fix-reshape-for-2TB-drives.patch | 322 +++++++++++++++++++
0014-Fix-spelling-typos.patch | 101 ++++++
...-not-skip-first-character-when-calling-xs.patch | 46 +++
0016-Fix-reshape-for-decreasing-data-offset.patch | 70 +++++
...s-add-one-test-case-for-failfast-of-raid1.patch | 99 ++++++
...-attempt-to-manage-new-arrays-when-termin.patch | 50 +++
...for-previous-mdmon-to-exit-during-takeove.patch | 57 ++++
...x-starting-array-with-initial-reshape-che.patch | 52 ++++
0021-add-missing-units-to-examine.patch | 59 ++++
...ix-spare-activation-for-old-matrix-arrays.patch | 116 +++++++
0023-Create-Block-rounding-size-to-max.patch | 94 ++++++
...ev-rules-to-create-by-partuuid-for-md-dev.patch | 31 ++
...rong-array-state-when-disk-fails-during-m.patch | 109 +++++++
...nable-probe_roms-to-scan-more-than-6-roms.patch | 212 +++++++++++++
...intel-Fix-issue-with-abs-being-irrelevant.patch | 38 +++
...roduced-unaligned-get-put-_unaligned-16-3.patch | 57 ++++
...uper-intel-Use-put_unaligned-in-split_ull.patch | 38 +++
...default-sysfs-attributes-after-assemblati.patch | 344 +++++++++++++++++++++
...adm.h-include-sysmacros.h-unconditionally.patch | 34 ++
...o-devices-to-avoid-component-devices-deta.patch | 161 ++++++++++
...o-devices-option-for-calling-mdadm-detail.patch | 42 +++
0034-imsm-close-removed-drive-fd.patch | 44 +++
...-value-returned-by-snprintf-against-error.patch | 45 +++
...duce-new-array-state-broken-for-raid0-lin.patch | 163 ++++++++++
0037-mdadm-force-a-uuid-swap-on-big-endian.patch | 40 +++
...add-the-descriptions-for-bitmap-sysfs-nod.patch | 98 ++++++
0039-Init-devlist-as-an-array.patch | 35 +++
...to-check-recovery-after-re-add-when-no-I-.patch | 31 ++
...udev-allow-for-udev-attribute-reading-bug.patch | 47 +++
0042-imsm-save-current_vol-number.patch | 40 +++
...-imsm-allow-to-specify-second-volume-size.patch | 50 +++
...n-mdcheck_start-is-enabled-enable-mdcheck.patch | 45 +++
0045-mdcheck-use-to-pass-variable-to-mdcheck.patch | 51 +++
...-mdadm_env.sh-handle-MDADM_CHECK_DURATION.patch | 28 ++
...l-don-t-mark-structs-packed-unnecessarily.patch | 121 ++++++++
mdadm.rules | 2 +-
mdadm.spec | 53 +++-
49 files changed, 4042 insertions(+), 3 deletions(-)
create mode 100644 0001-Assemble-keep-MD_DISK_FAILFAST-and-MD_DISK_WRITEMOST.patch
create mode 100644 0002-Document-PART-POLICY-lines.patch
create mode 100644 0003-policy-support-devices-with-multiple-paths.patch
create mode 100644 0004-mdcheck-add-systemd-unit-files-to-run-mdcheck.patch
create mode 100644 0005-Monitor-add-system-timer-to-run-oneshot-periodically.patch
create mode 100644 0006-imsm-update-metadata-correctly-while-raid10-double-d.patch
create mode 100644 0007-Assemble-mask-FAILFAST-and-WRITEMOSTLY-flags-when-fi.patch
create mode 100644 0008-Grow-avoid-overflow-in-compute_backup_blocks.patch
create mode 100644 0009-Grow-report-correct-new-chunk-size.patch
create mode 100644 0010-policy.c-prevent-NULL-pointer-referencing.patch
create mode 100644 0011-policy.c-Fix-for-compiler-error.patch
create mode 100644 0012-imsm-finish-recovery-when-drive-with-rebuild-fails.patch
create mode 100644 0013-imsm-fix-reshape-for-2TB-drives.patch
create mode 100644 0014-Fix-spelling-typos.patch
create mode 100644 0015-Detail.c-do-not-skip-first-character-when-calling-xs.patch
create mode 100644 0016-Fix-reshape-for-decreasing-data-offset.patch
create mode 100644 0017-mdadm-tests-add-one-test-case-for-failfast-of-raid1.patch
create mode 100644 0018-mdmon-don-t-attempt-to-manage-new-arrays-when-termin.patch
create mode 100644 0019-mdmon-wait-for-previous-mdmon-to-exit-during-takeove.patch
create mode 100644 0020-Assemble-Fix-starting-array-with-initial-reshape-che.patch
create mode 100644 0021-add-missing-units-to-examine.patch
create mode 100644 0022-imsm-fix-spare-activation-for-old-matrix-arrays.patch
create mode 100644 0023-Create-Block-rounding-size-to-max.patch
create mode 100644 0024-udev-Add-udev-rules-to-create-by-partuuid-for-md-dev.patch
create mode 100644 0025-mdmon-fix-wrong-array-state-when-disk-fails-during-m.patch
create mode 100644 0026-Enable-probe_roms-to-scan-more-than-6-roms.patch
create mode 100644 0027-super-intel-Fix-issue-with-abs-being-irrelevant.patch
create mode 100644 0028-mdadm.h-Introduced-unaligned-get-put-_unaligned-16-3.patch
create mode 100644 0029-super-intel-Use-put_unaligned-in-split_ull.patch
create mode 100644 0030-mdadm-load-default-sysfs-attributes-after-assemblati.patch
create mode 100644 0031-mdadm.h-include-sysmacros.h-unconditionally.patch
create mode 100644 0032-mdadm-add-no-devices-to-avoid-component-devices-deta.patch
create mode 100644 0033-udev-add-no-devices-option-for-calling-mdadm-detail.patch
create mode 100644 0034-imsm-close-removed-drive-fd.patch
create mode 100644 0035-mdadm-check-value-returned-by-snprintf-against-error.patch
create mode 100644 0036-mdadm-Introduce-new-array-state-broken-for-raid0-lin.patch
create mode 100644 0037-mdadm-force-a-uuid-swap-on-big-endian.patch
create mode 100644 0038-mdadm-md.4-add-the-descriptions-for-bitmap-sysfs-nod.patch
create mode 100644 0039-Init-devlist-as-an-array.patch
create mode 100644 0040-Don-t-need-to-check-recovery-after-re-add-when-no-I-.patch
create mode 100644 0041-udev-allow-for-udev-attribute-reading-bug.patch
create mode 100644 0042-imsm-save-current_vol-number.patch
create mode 100644 0043-imsm-allow-to-specify-second-volume-size.patch
create mode 100644 0044-mdcheck-when-mdcheck_start-is-enabled-enable-mdcheck.patch
create mode 100644 0045-mdcheck-use-to-pass-variable-to-mdcheck.patch
create mode 100644 0046-SUSE-mdadm_env.sh-handle-MDADM_CHECK_DURATION.patch
create mode 100644 0047-super-intel-don-t-mark-structs-packed-unnecessarily.patch
diff --git a/0001-Assemble-keep-MD_DISK_FAILFAST-and-MD_DISK_WRITEMOST.patch b/0001-Assemble-keep-MD_DISK_FAILFAST-and-MD_DISK_WRITEMOST.patch
new file mode 100644
index 0000000..5968c08
--- /dev/null
+++ b/0001-Assemble-keep-MD_DISK_FAILFAST-and-MD_DISK_WRITEMOST.patch
@@ -0,0 +1,39 @@
+From 0833f9c3dbaaee202b92ea956f9e2decc7b9593a Mon Sep 17 00:00:00 2001
+From: Gioh Kim <gi-oh.kim@profitbricks.com>
+Date: Tue, 6 Nov 2018 15:27:42 +0100
+Subject: [PATCH 01/47] Assemble: keep MD_DISK_FAILFAST and MD_DISK_WRITEMOSTLY
+ flag
+
+Before updating superblock of slave disks, desired_state value
+is set for the target state of the slave disks. But it forgets
+to check MD_DISK_FAILFAST and MD_DISK_WRITEMOSTLY flags. Then
+start_arrays() calls ADD_NEW_DISK ioctl-call and pass the state
+without MD_DISK_FAILFAST and MD_DISK_WRITEMOSTLY.
+
+Currenlty it does not generate any problem because kernel does not
+care MD_DISK_FAILFAST or MD_DISK_WRITEMOSTLY flags.
+
+Reviewed-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Gioh Kim <gi-oh.kim@profitbricks.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/Assemble.c b/Assemble.c
+index a79466c..f39c9e1 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -1704,6 +1704,9 @@ try_again:
+ else
+ desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC);
+
++ desired_state |= devices[j].i.disk.state & ((1<<MD_DISK_FAILFAST) |
++ (1<<MD_DISK_WRITEMOSTLY));
++
+ if (!devices[j].uptodate)
+ continue;
+
+--
+2.24.0
+
diff --git a/0002-Document-PART-POLICY-lines.patch b/0002-Document-PART-POLICY-lines.patch
new file mode 100644
index 0000000..61e8317
--- /dev/null
+++ b/0002-Document-PART-POLICY-lines.patch
@@ -0,0 +1,77 @@
+From 6b6112842030309c297a521918d1a2e982426fa3 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.com>
+Date: Fri, 9 Nov 2018 17:12:33 +1100
+Subject: [PATCH 02/47] Document PART-POLICY lines
+
+PART-POLICY has been accepted in mdadm.conf since the same
+time that POLICY was accepted, but it was never documented.
+So add the missing documentation.
+
+Also fix a bug which would have stopped it from working if
+anyone had ever tried to use it.
+
+Signed-off-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ mdadm.conf.5 | 24 +++++++++++++++++++++++-
+ policy.c | 2 +-
+ 2 files changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/mdadm.conf.5 b/mdadm.conf.5
+index 18512cb..47c962a 100644
+--- a/mdadm.conf.5
++++ b/mdadm.conf.5
+@@ -501,7 +501,7 @@ To update hot plug configuration it is necessary to execute
+ .B mdadm \-\-udev\-rules
+ command after changing the config file
+
+-Key words used in the
++Keywords used in the
+ .I POLICY
+ line and supported values are:
+
+@@ -565,6 +565,28 @@ be automatically added to that array (or it's container)
+ 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.
++
+ .SH EXAMPLE
+ DEVICE /dev/sd[bcdjkl]1
+ .br
+diff --git a/policy.c b/policy.c
+index c0d18a7..258f393 100644
+--- a/policy.c
++++ b/policy.c
+@@ -300,7 +300,7 @@ static int path_has_part(char *path, char **part)
+ l--;
+ if (l < 5 || strncmp(path+l-5, "-part", 5) != 0)
+ return 0;
+- *part = path+l-4;
++ *part = path+l-5;
+ return 1;
+ }
+
+--
+2.24.0
+
diff --git a/0003-policy-support-devices-with-multiple-paths.patch b/0003-policy-support-devices-with-multiple-paths.patch
new file mode 100644
index 0000000..f183271
--- /dev/null
+++ b/0003-policy-support-devices-with-multiple-paths.patch
@@ -0,0 +1,334 @@
+From cd72f9d114da206baa01fd56ff2d8ffcc08f3239 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.com>
+Date: Fri, 9 Nov 2018 17:12:33 +1100
+Subject: [PATCH 03/47] policy: support devices with multiple paths.
+
+As new releases of Linux some time change the name of
+a path, some distros keep "legacy" names as well. This
+is useful, but confuses mdadm which assumes each device has
+precisely one path.
+
+So change this assumption: allow a disk to have several
+paths, and allow any to match when looking for a policy
+which matches a disk.
+
+Reported-and-tested-by: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Signed-off-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Incremental.c | 5 +-
+ mdadm.h | 2 +-
+ policy.c | 163 ++++++++++++++++++++++++++++----------------------
+ 3 files changed, 95 insertions(+), 75 deletions(-)
+
+diff --git a/Incremental.c b/Incremental.c
+index a4ff7d4..d4d3c35 100644
+--- a/Incremental.c
++++ b/Incremental.c
+@@ -1080,6 +1080,7 @@ static int partition_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
+ struct supertype *st2 = NULL;
+ char *devname = NULL;
+ unsigned long long devsectors;
++ char *pathlist[2];
+
+ if (de->d_ino == 0 || de->d_name[0] == '.' ||
+ (de->d_type != DT_LNK && de->d_type != DT_UNKNOWN))
+@@ -1094,7 +1095,9 @@ static int partition_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
+ /* This is a partition - skip it */
+ goto next;
+
+- pol2 = path_policy(de->d_name, type_disk);
++ pathlist[0] = de->d_name;
++ pathlist[1] = NULL;
++ pol2 = path_policy(pathlist, type_disk);
+
+ domain_merge(&domlist, pol2, st ? st->ss->name : NULL);
+ if (domain_test(domlist, pol, st ? st->ss->name : NULL) != 1)
+diff --git a/mdadm.h b/mdadm.h
+index 387e681..705bd9b 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1247,7 +1247,7 @@ extern void policyline(char *line, char *type);
+ extern void policy_add(char *type, ...);
+ extern void policy_free(void);
+
+-extern struct dev_policy *path_policy(char *path, char *type);
++extern struct dev_policy *path_policy(char **paths, char *type);
+ extern struct dev_policy *disk_policy(struct mdinfo *disk);
+ extern struct dev_policy *devid_policy(int devid);
+ extern void dev_policy_free(struct dev_policy *p);
+diff --git a/policy.c b/policy.c
+index 258f393..fa67d55 100644
+--- a/policy.c
++++ b/policy.c
+@@ -189,15 +189,17 @@ struct dev_policy *pol_find(struct dev_policy *pol, char *name)
+ return pol;
+ }
+
+-static char *disk_path(struct mdinfo *disk)
++static char **disk_paths(struct mdinfo *disk)
+ {
+ struct stat stb;
+ int prefix_len;
+ DIR *by_path;
+ char symlink[PATH_MAX] = "/dev/disk/by-path/";
+- char nm[PATH_MAX];
++ char **paths;
++ int cnt = 0;
+ struct dirent *ent;
+- int rv;
++
++ paths = xmalloc(sizeof(*paths) * (cnt+1));
+
+ by_path = opendir(symlink);
+ if (by_path) {
+@@ -214,22 +216,13 @@ static char *disk_path(struct mdinfo *disk)
+ continue;
+ if (stb.st_rdev != makedev(disk->disk.major, disk->disk.minor))
+ continue;
+- closedir(by_path);
+- return xstrdup(ent->d_name);
++ paths[cnt++] = xstrdup(ent->d_name);
++ paths = xrealloc(paths, sizeof(*paths) * (cnt+1));
+ }
+ closedir(by_path);
+ }
+- /* A NULL path isn't really acceptable - use the devname.. */
+- sprintf(symlink, "/sys/dev/block/%d:%d", disk->disk.major, disk->disk.minor);
+- rv = readlink(symlink, nm, sizeof(nm)-1);
+- if (rv > 0) {
+- char *dname;
+- nm[rv] = 0;
+- dname = strrchr(nm, '/');
+- if (dname)
+- return xstrdup(dname + 1);
+- }
+- return xstrdup("unknown");
++ paths[cnt] = NULL;
++ return paths;
+ }
+
+ char type_part[] = "part";
+@@ -246,18 +239,53 @@ static char *disk_type(struct mdinfo *disk)
+ return type_disk;
+ }
+
+-static int pol_match(struct rule *rule, char *path, char *type)
++static int path_has_part(char *path, char **part)
++{
++ /* check if path ends with "-partNN" and
++ * if it does, place a pointer to "-pathNN"
++ * in 'part'.
++ */
++ int l;
++ if (!path)
++ return 0;
++ l = strlen(path);
++ while (l > 1 && isdigit(path[l-1]))
++ l--;
++ if (l < 5 || strncmp(path+l-5, "-part", 5) != 0)
++ return 0;
++ *part = path+l-5;
++ return 1;
++}
++
++static int pol_match(struct rule *rule, char **paths, char *type, char **part)
+ {
+- /* check if this rule matches on path and type */
++ /* Check if this rule matches on any path and type.
++ * If 'part' is not NULL, then 'path' must end in -partN, which
++ * we ignore for matching, and return in *part on success.
++ */
+ int pathok = 0; /* 0 == no path, 1 == match, -1 == no match yet */
+ int typeok = 0;
+
+- while (rule) {
++ for (; rule; rule = rule->next) {
+ if (rule->name == rule_path) {
++ char *p;
++ int i;
+ if (pathok == 0)
+ pathok = -1;
+- if (path && fnmatch(rule->value, path, 0) == 0)
+- pathok = 1;
++ if (!paths)
++ continue;
++ for (i = 0; paths[i]; i++) {
++ if (part) {
++ if (!path_has_part(paths[i], &p))
++ continue;
++ *p = '\0';
++ *part = p+1;
++ }
++ if (fnmatch(rule->value, paths[i], 0) == 0)
++ pathok = 1;
++ if (part)
++ *p = '-';
++ }
+ }
+ if (rule->name == rule_type) {
+ if (typeok == 0)
+@@ -265,7 +293,6 @@ static int pol_match(struct rule *rule, char *path, char *type)
+ if (type && strcmp(rule->value, type) == 0)
+ typeok = 1;
+ }
+- rule = rule->next;
+ }
+ return pathok >= 0 && typeok >= 0;
+ }
+@@ -286,24 +313,6 @@ static void pol_merge(struct dev_policy **pol, struct rule *rule)
+ pol_new(pol, r->name, r->value, metadata);
+ }
+
+-static int path_has_part(char *path, char **part)
+-{
+- /* check if path ends with "-partNN" and
+- * if it does, place a pointer to "-pathNN"
+- * in 'part'.
+- */
+- int l;
+- if (!path)
+- return 0;
+- l = strlen(path);
+- while (l > 1 && isdigit(path[l-1]))
+- l--;
+- if (l < 5 || strncmp(path+l-5, "-part", 5) != 0)
+- return 0;
+- *part = path+l-5;
+- return 1;
+-}
+-
+ static void pol_merge_part(struct dev_policy **pol, struct rule *rule, char *part)
+ {
+ /* copy any name assignments from rule into pol, appending
+@@ -352,7 +361,7 @@ static int config_rules_has_path = 0;
+ * path_policy() gathers policy information for the
+ * disk described in the given a 'path' and a 'type'.
+ */
+-struct dev_policy *path_policy(char *path, char *type)
++struct dev_policy *path_policy(char **paths, char *type)
+ {
+ struct pol_rule *rules;
+ struct dev_policy *pol = NULL;
+@@ -361,27 +370,24 @@ struct dev_policy *path_policy(char *path, char *type)
+ rules = config_rules;
+
+ while (rules) {
+- char *part;
++ char *part = NULL;
+ if (rules->type == rule_policy)
+- if (pol_match(rules->rule, path, type))
++ if (pol_match(rules->rule, paths, type, NULL))
+ pol_merge(&pol, rules->rule);
+ if (rules->type == rule_part && strcmp(type, type_part) == 0)
+- if (path_has_part(path, &part)) {
+- *part = 0;
+- if (pol_match(rules->rule, path, type_disk))
+- pol_merge_part(&pol, rules->rule, part+1);
+- *part = '-';
+- }
++ if (pol_match(rules->rule, paths, type_disk, &part))
++ pol_merge_part(&pol, rules->rule, part);
+ rules = rules->next;
+ }
+
+ /* Now add any metadata-specific internal knowledge
+ * about this path
+ */
+- for (i=0; path && superlist[i]; i++)
++ for (i=0; paths[0] && superlist[i]; i++)
+ if (superlist[i]->get_disk_controller_domain) {
+ const char *d =
+- superlist[i]->get_disk_controller_domain(path);
++ superlist[i]->get_disk_controller_domain(
++ paths[0]);
+ if (d)
+ pol_new(&pol, pol_domain, d, superlist[i]->name);
+ }
+@@ -400,22 +406,34 @@ void pol_add(struct dev_policy **pol,
+ pol_dedup(*pol);
+ }
+
++static void free_paths(char **paths)
++{
++ int i;
++
++ if (!paths)
++ return;
++
++ for (i = 0; paths[i]; i++)
++ free(paths[i]);
++ free(paths);
++}
++
+ /*
+ * disk_policy() gathers policy information for the
+ * disk described in the given mdinfo (disk.{major,minor}).
+ */
+ struct dev_policy *disk_policy(struct mdinfo *disk)
+ {
+- char *path = NULL;
++ char **paths = NULL;
+ char *type = disk_type(disk);
+ struct dev_policy *pol = NULL;
+
+ if (config_rules_has_path)
+- path = disk_path(disk);
++ paths = disk_paths(disk);
+
+- pol = path_policy(path, type);
++ pol = path_policy(paths, type);
+
+- free(path);
++ free_paths(paths);
+ return pol;
+ }
+
+@@ -756,27 +774,26 @@ int policy_check_path(struct mdinfo *disk, struct map_ent *array)
+ {
+ char path[PATH_MAX];
+ FILE *f = NULL;
+- char *id_path = disk_path(disk);
+- int rv;
++ char **id_paths = disk_paths(disk);
++ int i;
++ int rv = 0;
+
+- if (!id_path)
+- return 0;
++ for (i = 0; id_paths[i]; i++) {
++ snprintf(path, PATH_MAX, FAILED_SLOTS_DIR "/%s", id_paths[i]);
++ f = fopen(path, "r");
++ if (!f)
++ continue;
+
+- snprintf(path, PATH_MAX, FAILED_SLOTS_DIR "/%s", id_path);
+- f = fopen(path, "r");
+- if (!f) {
+- free(id_path);
+- return 0;
++ rv = fscanf(f, " %s %x:%x:%x:%x\n",
++ array->metadata,
++ array->uuid,
++ array->uuid+1,
++ array->uuid+2,
++ array->uuid+3);
++ fclose(f);
++ break;
+ }
+-
+- rv = fscanf(f, " %s %x:%x:%x:%x\n",
+- array->metadata,
+- array->uuid,
+- array->uuid+1,
+- array->uuid+2,
+- array->uuid+3);
+- fclose(f);
+- free(id_path);
++ free_paths(id_paths);
+ return rv == 5;
+ }
+
+--
+2.24.0
+
diff --git a/0004-mdcheck-add-systemd-unit-files-to-run-mdcheck.patch b/0004-mdcheck-add-systemd-unit-files-to-run-mdcheck.patch
new file mode 100644
index 0000000..752b894
--- /dev/null
+++ b/0004-mdcheck-add-systemd-unit-files-to-run-mdcheck.patch
@@ -0,0 +1,137 @@
+From 4199d3c629c14866505923d19fa50017ee92d2e1 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.com>
+Date: Wed, 5 Dec 2018 16:35:00 +1100
+Subject: [PATCH 04/47] mdcheck: add systemd unit files to run mdcheck.
+
+Having the mdcheck script is not use if is never run.
+This patch adds systemd unit files so that it can easily
+be run on the first Sunday of each month for 6 hours,
+then on every subsequent morning until the check is
+finished.
+
+The units still need to be enabled with
+ systemctl enable mdcheck_start.timer
+
+The timer will only actually be started when an array
+which might need it becomes active.
+
+Signed-off-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Makefile | 5 ++++-
+ systemd/mdcheck_continue.service | 18 ++++++++++++++++++
+ systemd/mdcheck_continue.timer | 13 +++++++++++++
+ systemd/mdcheck_start.service | 17 +++++++++++++++++
+ systemd/mdcheck_start.timer | 15 +++++++++++++++
+ 5 files changed, 67 insertions(+), 1 deletion(-)
+ create mode 100644 systemd/mdcheck_continue.service
+ create mode 100644 systemd/mdcheck_continue.timer
+ create mode 100644 systemd/mdcheck_start.service
+ create mode 100644 systemd/mdcheck_start.timer
+
+diff --git a/Makefile b/Makefile
+index 2767ac6..afb62cc 100644
+--- a/Makefile
++++ b/Makefile
+@@ -276,7 +276,10 @@ install-udev: udev-md-raid-arrays.rules udev-md-raid-assembly.rules udev-md-raid
+
+ install-systemd: systemd/mdmon@.service
+ @for file in mdmon@.service mdmonitor.service mdadm-last-resort@.timer \
+- mdadm-last-resort@.service mdadm-grow-continue@.service; \
++ mdadm-last-resort@.service mdadm-grow-continue@.service \
++ mdcheck_start.timer mdcheck_start.service \
++ mdcheck_continue.timer mdcheck_continue.service \
++ ; \
+ do sed -e 's,BINDIR,$(BINDIR),g' systemd/$$file > .install.tmp.2 && \
+ $(ECHO) $(INSTALL) -D -m 644 systemd/$$file $(DESTDIR)$(SYSTEMD_DIR)/$$file ; \
+ $(INSTALL) -D -m 644 .install.tmp.2 $(DESTDIR)$(SYSTEMD_DIR)/$$file ; \
+diff --git a/systemd/mdcheck_continue.service b/systemd/mdcheck_continue.service
+new file mode 100644
+index 0000000..592c607
+--- /dev/null
++++ b/systemd/mdcheck_continue.service
+@@ -0,0 +1,18 @@
++# This file is part of mdadm.
++#
++# mdadm 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.
++
++[Unit]
++Description=MD array scrubbing - continuation
++ConditionPathExistsGlob = /var/lib/mdcheck/MD_UUID_*
++
++[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_continue.timer b/systemd/mdcheck_continue.timer
+new file mode 100644
+index 0000000..3ccfd78
+--- /dev/null
++++ b/systemd/mdcheck_continue.timer
+@@ -0,0 +1,13 @@
++# This file is part of mdadm.
++#
++# mdadm 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.
++
++[Unit]
++Description=MD array scrubbing - continuation
++
++[Timer]
++OnCalendar= 1:05:00
++
+diff --git a/systemd/mdcheck_start.service b/systemd/mdcheck_start.service
+new file mode 100644
+index 0000000..812141b
+--- /dev/null
++++ b/systemd/mdcheck_start.service
+@@ -0,0 +1,17 @@
++# This file is part of mdadm.
++#
++# mdadm 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.
++
++[Unit]
++Description=MD array scrubbing
++Wants=mdcheck_continue.timer
++
++[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
+diff --git a/systemd/mdcheck_start.timer b/systemd/mdcheck_start.timer
+new file mode 100644
+index 0000000..6480736
+--- /dev/null
++++ b/systemd/mdcheck_start.timer
+@@ -0,0 +1,15 @@
++# This file is part of mdadm.
++#
++# mdadm 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.
++
++[Unit]
++Description=MD array scrubbing
++
++[Timer]
++OnCalendar=Sun *-*-1..7 1:00:00
++
++[Install]
++WantedBy= mdmonitor.service
+--
+2.24.0
+
diff --git a/0005-Monitor-add-system-timer-to-run-oneshot-periodically.patch b/0005-Monitor-add-system-timer-to-run-oneshot-periodically.patch
new file mode 100644
index 0000000..688c403
--- /dev/null
+++ b/0005-Monitor-add-system-timer-to-run-oneshot-periodically.patch
@@ -0,0 +1,82 @@
+From 7cd7e91ab3de5aa75dc963cb08b0618c1885cf0d Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.com>
+Date: Wed, 5 Dec 2018 16:35:00 +1100
+Subject: [PATCH 05/47] Monitor: add system timer to run --oneshot periodically
+
+"mdadm --monitor --oneshot" can be used to get a warning
+if there are any degraded arrays. It can be helpful to get
+this warning periodically while the condition persists.
+
+This patch add a systemd service and timer which can
+be enabled with
+ systemctl enable mdmonitor-oneshot.service
+
+and will then provide daily warnings.
+
+Signed-off-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Makefile | 1 +
+ systemd/mdmonitor-oneshot.service | 15 +++++++++++++++
+ systemd/mdmonitor-oneshot.timer | 15 +++++++++++++++
+ 3 files changed, 31 insertions(+)
+ create mode 100644 systemd/mdmonitor-oneshot.service
+ create mode 100644 systemd/mdmonitor-oneshot.timer
+
+diff --git a/Makefile b/Makefile
+index afb62cc..dfe00b0 100644
+--- a/Makefile
++++ b/Makefile
+@@ -279,6 +279,7 @@ install-systemd: systemd/mdmon@.service
+ mdadm-last-resort@.service mdadm-grow-continue@.service \
+ mdcheck_start.timer mdcheck_start.service \
+ mdcheck_continue.timer mdcheck_continue.service \
++ mdmonitor-oneshot.timer mdmonitor-oneshot.service \
+ ; \
+ do sed -e 's,BINDIR,$(BINDIR),g' systemd/$$file > .install.tmp.2 && \
+ $(ECHO) $(INSTALL) -D -m 644 systemd/$$file $(DESTDIR)$(SYSTEMD_DIR)/$$file ; \
+diff --git a/systemd/mdmonitor-oneshot.service b/systemd/mdmonitor-oneshot.service
+new file mode 100644
+index 0000000..fd469b1
+--- /dev/null
++++ b/systemd/mdmonitor-oneshot.service
+@@ -0,0 +1,15 @@
++# This file is part of mdadm.
++#
++# mdadm 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.
++
++[Unit]
++Description=Reminder for degraded MD arrays
++
++[Service]
++Environment= MDADM_MONITOR_ARGS=--scan
++EnvironmentFile=-/run/sysconfig/mdadm
++ExecStartPre=-/usr/lib/mdadm/mdadm_env.sh
++ExecStart=BINDIR/mdadm --monitor --oneshot $MDADM_MONITOR_ARGS
+diff --git a/systemd/mdmonitor-oneshot.timer b/systemd/mdmonitor-oneshot.timer
+new file mode 100644
+index 0000000..cb54bda
+--- /dev/null
++++ b/systemd/mdmonitor-oneshot.timer
+@@ -0,0 +1,15 @@
++# This file is part of mdadm.
++#
++# mdadm 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.
++
++[Unit]
++Description=Reminder for degraded MD arrays
++
++[Timer]
++OnCalendar= 2:00:00
++
++[Install]
++WantedBy= mdmonitor.service
+--
+2.24.0
+
diff --git a/0006-imsm-update-metadata-correctly-while-raid10-double-d.patch b/0006-imsm-update-metadata-correctly-while-raid10-double-d.patch
new file mode 100644
index 0000000..dc599f1
--- /dev/null
+++ b/0006-imsm-update-metadata-correctly-while-raid10-double-d.patch
@@ -0,0 +1,83 @@
+From d7a1fda2769ba272d89de6caeab35d52b73a9c3c Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Date: Wed, 17 Oct 2018 12:11:41 +0200
+Subject: [PATCH 06/47] imsm: update metadata correctly while raid10 double
+ degradation
+
+Mdmon calls end_migration() when map state changes from normal to
+degraded. It is not valid because in raid 10 double degradation case
+mdmon breaks checkpointing but array is still rebuilding.
+In this case mdmon has to mark map as degraded and continues marking
+recovery checkpoint in metadata. Migration can be finished only if newly
+failed device is a rebuilding device.
+
+Add catching double degraded to degraded transition. Migration is
+finished but map state doesn't change, array is still degraded.
+
+Update failed_disk_num correctly. If double degradation
+happens rebuild will start on the lowest slot, but this variable points
+to the first failed slot. If second fail happens while rebuild this
+variable shouldn't be updated until rebuild is not finished.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 25 +++++++++++++++++++------
+ 1 file changed, 19 insertions(+), 6 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 6438987..d2035cc 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -8136,7 +8136,8 @@ static int mark_failure(struct intel_super *super,
+ set_imsm_ord_tbl_ent(map2, slot2,
+ idx | IMSM_ORD_REBUILD);
+ }
+- if (map->failed_disk_num == 0xff)
++ if (map->failed_disk_num == 0xff ||
++ (!is_rebuilding(dev) && map->failed_disk_num > slot))
+ map->failed_disk_num = slot;
+
+ clear_disk_badblocks(super->bbm_log, ord_to_idx(ord));
+@@ -8558,13 +8559,25 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
+ break;
+ }
+ if (is_rebuilding(dev)) {
+- dprintf_cont("while rebuilding.");
++ dprintf_cont("while rebuilding ");
+ if (map->map_state != map_state) {
+- dprintf_cont(" Map state change");
+- end_migration(dev, super, map_state);
++ dprintf_cont("map state change ");
++ if (n == map->failed_disk_num) {
++ dprintf_cont("end migration");
++ end_migration(dev, super, map_state);
++ } else {
++ dprintf_cont("raid10 double degradation, map state change");
++ map->map_state = map_state;
++ }
+ super->updates_pending++;
+- } else if (!rebuild_done) {
++ } else if (!rebuild_done)
+ break;
++ else if (n == map->failed_disk_num) {
++ /* r10 double degraded to degraded transition */
++ dprintf_cont("raid10 double degradation end migration");
++ end_migration(dev, super, map_state);
++ a->last_checkpoint = 0;
++ super->updates_pending++;
+ }
+
+ /* check if recovery is really finished */
+@@ -8575,7 +8588,7 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
+ }
+ if (recovery_not_finished) {
+ dprintf_cont("\n");
+- dprintf("Rebuild has not finished yet, state not changed");
++ dprintf_cont("Rebuild has not finished yet, map state changes only if raid10 double degradation happens");
+ if (a->last_checkpoint < mdi->recovery_start) {
+ a->last_checkpoint =
+ mdi->recovery_start;
+--
+2.24.0
+
diff --git a/0007-Assemble-mask-FAILFAST-and-WRITEMOSTLY-flags-when-fi.patch b/0007-Assemble-mask-FAILFAST-and-WRITEMOSTLY-flags-when-fi.patch
new file mode 100644
index 0000000..4dbde7d
--- /dev/null
+++ b/0007-Assemble-mask-FAILFAST-and-WRITEMOSTLY-flags-when-fi.patch
@@ -0,0 +1,43 @@
+From 563ac108659980b3d1e226fe416254a86656235f Mon Sep 17 00:00:00 2001
+From: Gioh Kim <gi-oh.kim@cloud.ionos.com>
+Date: Tue, 6 Nov 2018 16:20:17 +0100
+Subject: [PATCH 07/47] Assemble: mask FAILFAST and WRITEMOSTLY flags when
+ finding the most recent device
+
+If devices[].i.disk.state has MD_DISK_FAILFAST or MD_DISK_WRITEMOSTLY
+flag, it cannot be the most recent device. Both flags should be masked
+before checking the state.
+
+Reviewed-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Gioh Kim <gi-oh.kim@cloud.ionos.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index f39c9e1..9f75c68 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -578,6 +578,7 @@ static int load_devices(struct devs *devices, char *devmap,
+ struct supertype *tst;
+ int i;
+ int dfd;
++ int disk_state;
+
+ if (tmpdev->used != 1)
+ continue;
+@@ -711,7 +712,9 @@ static int load_devices(struct devs *devices, char *devmap,
+ devices[devcnt].i.disk.major = major(stb.st_rdev);
+ devices[devcnt].i.disk.minor = minor(stb.st_rdev);
+
+- if (devices[devcnt].i.disk.state == 6) {
++ disk_state = devices[devcnt].i.disk.state & ~((1<<MD_DISK_FAILFAST) |
++ (1<<MD_DISK_WRITEMOSTLY));
++ if (disk_state == ((1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC))) {
+ if (most_recent < 0 ||
+ devices[devcnt].i.events
+ > devices[most_recent].i.events) {
+--
+2.24.0
+
diff --git a/0008-Grow-avoid-overflow-in-compute_backup_blocks.patch b/0008-Grow-avoid-overflow-in-compute_backup_blocks.patch
new file mode 100644
index 0000000..cb80a55
--- /dev/null
+++ b/0008-Grow-avoid-overflow-in-compute_backup_blocks.patch
@@ -0,0 +1,34 @@
+From 085df42259cba7863cd6ebe5cd0d8492ac5b869e Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.com>
+Date: Thu, 6 Dec 2018 10:35:41 +1100
+Subject: [PATCH 08/47] Grow: avoid overflow in compute_backup_blocks()
+
+With a chunk size of 16Meg and data drive count of 8,
+this calculate can easily overflow the 'int' type that
+is used for the multiplications.
+So force it to use "long" instead.
+
+Reported-and-tested-by: Ed Spiridonov <edo.rus@gmail.com>
+Signed-off-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Grow.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/Grow.c b/Grow.c
+index 4436a4d..76f82c0 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1196,7 +1196,8 @@ unsigned long compute_backup_blocks(int nchunk, int ochunk,
+ /* Find GCD */
+ a = GCD(a, b);
+ /* LCM == product / GCD */
+- blocks = (ochunk/512) * (nchunk/512) * odata * ndata / a;
++ blocks = (unsigned long)(ochunk/512) * (unsigned long)(nchunk/512) *
++ odata * ndata / a;
+
+ return blocks;
+ }
+--
+2.24.0
+
diff --git a/0009-Grow-report-correct-new-chunk-size.patch b/0009-Grow-report-correct-new-chunk-size.patch
new file mode 100644
index 0000000..eb61464
--- /dev/null
+++ b/0009-Grow-report-correct-new-chunk-size.patch
@@ -0,0 +1,30 @@
+From 76d505dec6c9f92564553596fc8350324be82463 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.com>
+Date: Thu, 6 Dec 2018 10:36:28 +1100
+Subject: [PATCH 09/47] Grow: report correct new chunk size.
+
+When using "--grow --chunk=" to change chunk
+size, the old chunksize is reported instead of the new.
+
+Signed-off-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Grow.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Grow.c b/Grow.c
+index 76f82c0..363b209 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -3286,7 +3286,7 @@ static int reshape_array(char *container, int fd, char *devname,
+ goto release;
+ } else if (verbose >= 0)
+ printf("chunk size for %s set to %d\n",
+- devname, array.chunk_size);
++ devname, info->new_chunk);
+ }
+ unfreeze(st);
+ return 0;
+--
+2.24.0
+
diff --git a/0010-policy.c-prevent-NULL-pointer-referencing.patch b/0010-policy.c-prevent-NULL-pointer-referencing.patch
new file mode 100644
index 0000000..79dfe69
--- /dev/null
+++ b/0010-policy.c-prevent-NULL-pointer-referencing.patch
@@ -0,0 +1,31 @@
+From 467e6a1b4ece8e552ee638dab7f44a4d235ece1a Mon Sep 17 00:00:00 2001
+From: Gioh Kim <gi-oh.kim@cloud.ionos.com>
+Date: Fri, 7 Dec 2018 12:04:44 +0100
+Subject: [PATCH 10/47] policy.c: prevent NULL pointer referencing
+
+paths could be NULL and paths[0] should be followed by NULL pointer
+checking.
+
+Reviewed-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Gioh Kim <gi-oh.kim@cloud.ionos.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ policy.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/policy.c b/policy.c
+index fa67d55..e3a0671 100644
+--- a/policy.c
++++ b/policy.c
+@@ -383,7 +383,7 @@ struct dev_policy *path_policy(char **paths, char *type)
+ /* Now add any metadata-specific internal knowledge
+ * about this path
+ */
+- for (i=0; paths[0] && superlist[i]; i++)
++ for (i=0; paths && paths[0] && superlist[i]; i++)
+ if (superlist[i]->get_disk_controller_domain) {
+ const char *d =
+ superlist[i]->get_disk_controller_domain(
+--
+2.24.0
+
diff --git a/0011-policy.c-Fix-for-compiler-error.patch b/0011-policy.c-Fix-for-compiler-error.patch
new file mode 100644
index 0000000..fc52a7f
--- /dev/null
+++ b/0011-policy.c-Fix-for-compiler-error.patch
@@ -0,0 +1,36 @@
+From 757e55435997e355ee9b03e5d913b5496a3c39a8 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Date: Tue, 11 Dec 2018 15:04:07 +0100
+Subject: [PATCH 11/47] policy.c: Fix for compiler error
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+After cd72f9d(policy: support devices with multiple paths.) compilation
+on old compilers fails because "āpā may be used uninitialized
+in this function".
+
+Initialize it with NULL to prevent this.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ policy.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/policy.c b/policy.c
+index e3a0671..3c53bd3 100644
+--- a/policy.c
++++ b/policy.c
+@@ -268,7 +268,7 @@ static int pol_match(struct rule *rule, char **paths, char *type, char **part)
+
+ for (; rule; rule = rule->next) {
+ if (rule->name == rule_path) {
+- char *p;
++ char *p = NULL;
+ int i;
+ if (pathok == 0)
+ pathok = -1;
+--
+2.24.0
+
diff --git a/0012-imsm-finish-recovery-when-drive-with-rebuild-fails.patch b/0012-imsm-finish-recovery-when-drive-with-rebuild-fails.patch
new file mode 100644
index 0000000..1085af9
--- /dev/null
+++ b/0012-imsm-finish-recovery-when-drive-with-rebuild-fails.patch
@@ -0,0 +1,94 @@
+From a4e96fd8f3f0b5416783237c1cb6ee87e7eff23d Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Date: Fri, 8 Feb 2019 11:07:10 +0100
+Subject: [PATCH 12/47] imsm: finish recovery when drive with rebuild fails
+
+Commit d7a1fda2769b ("imsm: update metadata correctly while raid10 double
+degradation") resolves main Imsm double degradation problems but it
+omits one case. Now metadata hangs in the rebuilding state if the drive
+under rebuild is removed during recovery from double degradation.
+
+The root cause of this problem is comparing new map_state with current
+and if they both are degraded assuming that nothing new happens.
+
+Don't rely on map states, just check if device is failed. If the drive
+under rebuild fails then finish migration, in other cases update map
+state only (second fail means that destination map state can't be normal).
+
+To avoid problems with reassembling move end_migration (called after
+double degradation successful recovery) after check if recovery really
+finished, for details see (7ce057018 "imsm: fix: rebuild does not
+continue after reboot").
+Remove redundant code responsible for finishing rebuild process. Function
+end_migration do exactly the same. Set last_checkpoint to 0, to prepare
+it for the next rebuild.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 26 +++++++++++---------------
+ 1 file changed, 11 insertions(+), 15 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index d2035cc..38a1b6c 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -8560,26 +8560,22 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
+ }
+ if (is_rebuilding(dev)) {
+ dprintf_cont("while rebuilding ");
+- if (map->map_state != map_state) {
+- dprintf_cont("map state change ");
++ if (state & DS_FAULTY) {
++ dprintf_cont("removing failed drive ");
+ if (n == map->failed_disk_num) {
+ dprintf_cont("end migration");
+ end_migration(dev, super, map_state);
++ a->last_checkpoint = 0;
+ } else {
+- dprintf_cont("raid10 double degradation, map state change");
++ dprintf_cont("fail detected during rebuild, changing map state");
+ map->map_state = map_state;
+ }
+ super->updates_pending++;
+- } else if (!rebuild_done)
+- break;
+- else if (n == map->failed_disk_num) {
+- /* r10 double degraded to degraded transition */
+- dprintf_cont("raid10 double degradation end migration");
+- end_migration(dev, super, map_state);
+- a->last_checkpoint = 0;
+- super->updates_pending++;
+ }
+
++ if (!rebuild_done)
++ break;
++
+ /* check if recovery is really finished */
+ for (mdi = a->info.devs; mdi ; mdi = mdi->next)
+ if (mdi->recovery_start != MaxSector) {
+@@ -8588,7 +8584,7 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
+ }
+ if (recovery_not_finished) {
+ dprintf_cont("\n");
+- dprintf_cont("Rebuild has not finished yet, map state changes only if raid10 double degradation happens");
++ dprintf_cont("Rebuild has not finished yet");
+ if (a->last_checkpoint < mdi->recovery_start) {
+ a->last_checkpoint =
+ mdi->recovery_start;
+@@ -8598,9 +8594,9 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
+ }
+
+ dprintf_cont(" Rebuild done, still degraded");
+- dev->vol.migr_state = 0;
+- set_migr_type(dev, 0);
+- dev->vol.curr_migr_unit = 0;
++ end_migration(dev, super, map_state);
++ a->last_checkpoint = 0;
++ super->updates_pending++;
+
+ for (i = 0; i < map->num_members; i++) {
+ int idx = get_imsm_ord_tbl_ent(dev, i, MAP_0);
+--
+2.24.0
+
diff --git a/0013-imsm-fix-reshape-for-2TB-drives.patch b/0013-imsm-fix-reshape-for-2TB-drives.patch
new file mode 100644
index 0000000..29a9cdf
--- /dev/null
+++ b/0013-imsm-fix-reshape-for-2TB-drives.patch
@@ -0,0 +1,322 @@
+From 9f4218274cd4a1e1f356a1617f9a1d09960cf255 Mon Sep 17 00:00:00 2001
+From: Pawel Baldysiak <pawel.baldysiak@intel.com>
+Date: Mon, 28 Jan 2019 17:10:41 +0100
+Subject: [PATCH 13/47] imsm: fix reshape for >2TB drives
+
+If reshape is performed on drives larger then 2 TB,
+migration checkpoint area that is calculated exeeds 32-bit value.
+This checkpoint area is a reserved space threated as backup
+during reshape - at the end of the drive, right before metadata.
+As a result - wrong space is used and the data that may exists there
+is overwritten.
+
+Adding additional field to migration record to track high order 32-bits
+of pba of this area. Three other fields that may exceed 32-bit value
+for large drives are added as well.
+
+Signed-off-by: Pawel Baldysiak <pawel.baldysiak@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 149 ++++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 107 insertions(+), 42 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 38a1b6c..1cc7d5f 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -296,7 +296,7 @@ struct migr_record {
+ __u32 rec_status; /* Status used to determine how to restart
+ * migration in case it aborts
+ * in some fashion */
+- __u32 curr_migr_unit; /* 0..numMigrUnits-1 */
++ __u32 curr_migr_unit_lo; /* 0..numMigrUnits-1 */
+ __u32 family_num; /* Family number of MPB
+ * containing the RaidDev
+ * that is migrating */
+@@ -306,16 +306,23 @@ struct migr_record {
+ __u32 dest_depth_per_unit; /* Num member blocks each destMap
+ * member disk
+ * advances per unit-of-operation */
+- __u32 ckpt_area_pba; /* Pba of first block of ckpt copy area */
+- __u32 dest_1st_member_lba; /* First member lba on first
+- * stripe of destination */
+- __u32 num_migr_units; /* Total num migration units-of-op */
++ __u32 ckpt_area_pba_lo; /* Pba of first block of ckpt copy area */
++ __u32 dest_1st_member_lba_lo; /* First member lba on first
++ * stripe of destination */
++ __u32 num_migr_units_lo; /* Total num migration units-of-op */
+ __u32 post_migr_vol_cap; /* Size of volume after
+ * migration completes */
+ __u32 post_migr_vol_cap_hi; /* Expansion space for LBA64 */
+ __u32 ckpt_read_disk_num; /* Which member disk in destSubMap[0] the
+ * migration ckpt record was read from
+ * (for recovered migrations) */
++ __u32 curr_migr_unit_hi; /* 0..numMigrUnits-1 high order 32 bits */
++ __u32 ckpt_area_pba_hi; /* Pba of first block of ckpt copy area
++ * high order 32 bits */
++ __u32 dest_1st_member_lba_hi; /* First member lba on first stripe of
++ * destination - high order 32 bits */
++ __u32 num_migr_units_hi; /* Total num migration units-of-op
++ * high order 32 bits */
+ } __attribute__ ((__packed__));
+
+ struct md_list {
+@@ -1208,6 +1215,38 @@ static unsigned long long imsm_dev_size(struct imsm_dev *dev)
+ return join_u32(dev->size_low, dev->size_high);
+ }
+
++static unsigned long long migr_chkp_area_pba(struct migr_record *migr_rec)
++{
++ if (migr_rec == NULL)
++ return 0;
++ return join_u32(migr_rec->ckpt_area_pba_lo,
++ migr_rec->ckpt_area_pba_hi);
++}
++
++static unsigned long long current_migr_unit(struct migr_record *migr_rec)
++{
++ if (migr_rec == NULL)
++ return 0;
++ return join_u32(migr_rec->curr_migr_unit_lo,
++ migr_rec->curr_migr_unit_hi);
++}
++
++static unsigned long long migr_dest_1st_member_lba(struct migr_record *migr_rec)
++{
++ if (migr_rec == NULL)
++ return 0;
++ return join_u32(migr_rec->dest_1st_member_lba_lo,
++ migr_rec->dest_1st_member_lba_hi);
++}
++
++static unsigned long long get_num_migr_units(struct migr_record *migr_rec)
++{
++ if (migr_rec == NULL)
++ return 0;
++ return join_u32(migr_rec->num_migr_units_lo,
++ migr_rec->num_migr_units_hi);
++}
++
+ static void set_total_blocks(struct imsm_disk *disk, unsigned long long n)
+ {
+ split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
+@@ -1233,6 +1272,33 @@ static void set_imsm_dev_size(struct imsm_dev *dev, unsigned long long n)
+ split_ull(n, &dev->size_low, &dev->size_high);
+ }
+
++static void set_migr_chkp_area_pba(struct migr_record *migr_rec,
++ unsigned long long n)
++{
++ split_ull(n, &migr_rec->ckpt_area_pba_lo, &migr_rec->ckpt_area_pba_hi);
++}
++
++static void set_current_migr_unit(struct migr_record *migr_rec,
++ unsigned long long n)
++{
++ split_ull(n, &migr_rec->curr_migr_unit_lo,
++ &migr_rec->curr_migr_unit_hi);
++}
++
++static void set_migr_dest_1st_member_lba(struct migr_record *migr_rec,
++ unsigned long long n)
++{
++ split_ull(n, &migr_rec->dest_1st_member_lba_lo,
++ &migr_rec->dest_1st_member_lba_hi);
++}
++
++static void set_num_migr_units(struct migr_record *migr_rec,
++ unsigned long long n)
++{
++ split_ull(n, &migr_rec->num_migr_units_lo,
++ &migr_rec->num_migr_units_hi);
++}
++
+ static unsigned long long per_dev_array_size(struct imsm_map *map)
+ {
+ unsigned long long array_size = 0;
+@@ -1629,12 +1695,14 @@ void convert_to_4k_imsm_migr_rec(struct intel_super *super)
+ struct migr_record *migr_rec = super->migr_rec;
+
+ migr_rec->blocks_per_unit /= IMSM_4K_DIV;
+- migr_rec->ckpt_area_pba /= IMSM_4K_DIV;
+- migr_rec->dest_1st_member_lba /= IMSM_4K_DIV;
+ migr_rec->dest_depth_per_unit /= IMSM_4K_DIV;
+ split_ull((join_u32(migr_rec->post_migr_vol_cap,
+ migr_rec->post_migr_vol_cap_hi) / IMSM_4K_DIV),
+ &migr_rec->post_migr_vol_cap, &migr_rec->post_migr_vol_cap_hi);
++ set_migr_chkp_area_pba(migr_rec,
++ migr_chkp_area_pba(migr_rec) / IMSM_4K_DIV);
++ set_migr_dest_1st_member_lba(migr_rec,
++ migr_dest_1st_member_lba(migr_rec) / IMSM_4K_DIV);
+ }
+
+ void convert_to_4k_imsm_disk(struct imsm_disk *disk)
+@@ -1727,8 +1795,8 @@ void examine_migr_rec_imsm(struct intel_super *super)
+ printf("Normal\n");
+ else
+ printf("Contains Data\n");
+- printf(" Current Unit : %u\n",
+- __le32_to_cpu(migr_rec->curr_migr_unit));
++ printf(" Current Unit : %llu\n",
++ current_migr_unit(migr_rec));
+ printf(" Family : %u\n",
+ __le32_to_cpu(migr_rec->family_num));
+ printf(" Ascending : %u\n",
+@@ -1737,16 +1805,15 @@ void examine_migr_rec_imsm(struct intel_super *super)
+ __le32_to_cpu(migr_rec->blocks_per_unit));
+ printf(" Dest. Depth Per Unit : %u\n",
+ __le32_to_cpu(migr_rec->dest_depth_per_unit));
+- printf(" Checkpoint Area pba : %u\n",
+- __le32_to_cpu(migr_rec->ckpt_area_pba));
+- printf(" First member lba : %u\n",
+- __le32_to_cpu(migr_rec->dest_1st_member_lba));
+- printf(" Total Number of Units : %u\n",
+- __le32_to_cpu(migr_rec->num_migr_units));
+- printf(" Size of volume : %u\n",
+- __le32_to_cpu(migr_rec->post_migr_vol_cap));
+- printf(" Expansion space for LBA64 : %u\n",
+- __le32_to_cpu(migr_rec->post_migr_vol_cap_hi));
++ printf(" Checkpoint Area pba : %llu\n",
++ migr_chkp_area_pba(migr_rec));
++ printf(" First member lba : %llu\n",
++ migr_dest_1st_member_lba(migr_rec));
++ printf(" Total Number of Units : %llu\n",
++ get_num_migr_units(migr_rec));
++ printf(" Size of volume : %llu\n",
++ join_u32(migr_rec->post_migr_vol_cap,
++ migr_rec->post_migr_vol_cap_hi));
+ printf(" Record was read from : %u\n",
+ __le32_to_cpu(migr_rec->ckpt_read_disk_num));
+
+@@ -1759,13 +1826,15 @@ void convert_from_4k_imsm_migr_rec(struct intel_super *super)
+ struct migr_record *migr_rec = super->migr_rec;
+
+ migr_rec->blocks_per_unit *= IMSM_4K_DIV;
+- migr_rec->ckpt_area_pba *= IMSM_4K_DIV;
+- migr_rec->dest_1st_member_lba *= IMSM_4K_DIV;
+ migr_rec->dest_depth_per_unit *= IMSM_4K_DIV;
+ split_ull((join_u32(migr_rec->post_migr_vol_cap,
+ migr_rec->post_migr_vol_cap_hi) * IMSM_4K_DIV),
+ &migr_rec->post_migr_vol_cap,
+ &migr_rec->post_migr_vol_cap_hi);
++ set_migr_chkp_area_pba(migr_rec,
++ migr_chkp_area_pba(migr_rec) * IMSM_4K_DIV);
++ set_migr_dest_1st_member_lba(migr_rec,
++ migr_dest_1st_member_lba(migr_rec) * IMSM_4K_DIV);
+ }
+
+ void convert_from_4k(struct intel_super *super)
+@@ -3096,7 +3165,7 @@ static int imsm_create_metadata_checkpoint_update(
+ return 0;
+ }
+ (*u)->type = update_general_migration_checkpoint;
+- (*u)->curr_migr_unit = __le32_to_cpu(super->migr_rec->curr_migr_unit);
++ (*u)->curr_migr_unit = current_migr_unit(super->migr_rec);
+ dprintf("prepared for %u\n", (*u)->curr_migr_unit);
+
+ return update_memory_size;
+@@ -3397,13 +3466,13 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
+ case MIGR_GEN_MIGR: {
+ __u64 blocks_per_unit = blocks_per_migr_unit(super,
+ dev);
+- __u64 units = __le32_to_cpu(migr_rec->curr_migr_unit);
++ __u64 units = current_migr_unit(migr_rec);
+ unsigned long long array_blocks;
+ int used_disks;
+
+ if (__le32_to_cpu(migr_rec->ascending_migr) &&
+ (units <
+- (__le32_to_cpu(migr_rec->num_migr_units)-1)) &&
++ (get_num_migr_units(migr_rec)-1)) &&
+ (super->migr_rec->rec_status ==
+ __cpu_to_le32(UNIT_SRC_IN_CP_AREA)))
+ units++;
+@@ -10697,7 +10766,7 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
+
+ if (array_blocks % __le32_to_cpu(migr_rec->blocks_per_unit))
+ num_migr_units++;
+- migr_rec->num_migr_units = __cpu_to_le32(num_migr_units);
++ set_num_migr_units(migr_rec, num_migr_units);
+
+ migr_rec->post_migr_vol_cap = dev->size_low;
+ migr_rec->post_migr_vol_cap_hi = dev->size_high;
+@@ -10714,7 +10783,7 @@ void init_migr_record_imsm(struct supertype *st, struct imsm_dev *dev,
+ min_dev_sectors = dev_sectors;
+ close(fd);
+ }
+- migr_rec->ckpt_area_pba = __cpu_to_le32(min_dev_sectors -
++ set_migr_chkp_area_pba(migr_rec, min_dev_sectors -
+ RAID_DISK_RESERVED_BLOCKS_IMSM_HI);
+
+ write_imsm_migr_rec(st);
+@@ -10765,8 +10834,7 @@ int save_backup_imsm(struct supertype *st,
+
+ start = info->reshape_progress * 512;
+ for (i = 0; i < new_disks; i++) {
+- target_offsets[i] = (unsigned long long)
+- __le32_to_cpu(super->migr_rec->ckpt_area_pba) * 512;
++ target_offsets[i] = migr_chkp_area_pba(super->migr_rec) * 512;
+ /* move back copy area adderss, it will be moved forward
+ * in restore_stripes() using start input variable
+ */
+@@ -10845,12 +10913,11 @@ int save_checkpoint_imsm(struct supertype *st, struct mdinfo *info, int state)
+ if (info->reshape_progress % blocks_per_unit)
+ curr_migr_unit++;
+
+- super->migr_rec->curr_migr_unit =
+- __cpu_to_le32(curr_migr_unit);
++ set_current_migr_unit(super->migr_rec, curr_migr_unit);
+ super->migr_rec->rec_status = __cpu_to_le32(state);
+- super->migr_rec->dest_1st_member_lba =
+- __cpu_to_le32(curr_migr_unit *
+- __le32_to_cpu(super->migr_rec->dest_depth_per_unit));
++ set_migr_dest_1st_member_lba(super->migr_rec,
++ super->migr_rec->dest_depth_per_unit * curr_migr_unit);
++
+ if (write_imsm_migr_rec(st) < 0) {
+ dprintf("imsm: Cannot write migration record outside backup area\n");
+ return 1;
+@@ -10884,8 +10951,8 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
+ char *buf = NULL;
+ int retval = 1;
+ unsigned int sector_size = super->sector_size;
+- unsigned long curr_migr_unit = __le32_to_cpu(migr_rec->curr_migr_unit);
+- unsigned long num_migr_units = __le32_to_cpu(migr_rec->num_migr_units);
++ unsigned long curr_migr_unit = current_migr_unit(migr_rec);
++ unsigned long num_migr_units = get_num_migr_units(migr_rec);
+ char buffer[20];
+ int skipped_disks = 0;
+
+@@ -10912,11 +10979,9 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
+ map_dest = get_imsm_map(id->dev, MAP_0);
+ new_disks = map_dest->num_members;
+
+- read_offset = (unsigned long long)
+- __le32_to_cpu(migr_rec->ckpt_area_pba) * 512;
++ read_offset = migr_chkp_area_pba(migr_rec) * 512;
+
+- write_offset = ((unsigned long long)
+- __le32_to_cpu(migr_rec->dest_1st_member_lba) +
++ write_offset = (migr_dest_1st_member_lba(migr_rec) +
+ pba_of_lba0(map_dest)) * 512;
+
+ unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512;
+@@ -12019,12 +12084,12 @@ static int imsm_manage_reshape(
+ max_position = sra->component_size * ndata;
+ source_layout = imsm_level_to_layout(map_src->raid_level);
+
+- while (__le32_to_cpu(migr_rec->curr_migr_unit) <
+- __le32_to_cpu(migr_rec->num_migr_units)) {
++ while (current_migr_unit(migr_rec) <
++ get_num_migr_units(migr_rec)) {
+ /* current reshape position [blocks] */
+ unsigned long long current_position =
+ __le32_to_cpu(migr_rec->blocks_per_unit)
+- * __le32_to_cpu(migr_rec->curr_migr_unit);
++ * current_migr_unit(migr_rec);
+ unsigned long long border;
+
+ /* Check that array hasn't become failed.
+--
+2.24.0
+
diff --git a/0014-Fix-spelling-typos.patch b/0014-Fix-spelling-typos.patch
new file mode 100644
index 0000000..abbe4b0
--- /dev/null
+++ b/0014-Fix-spelling-typos.patch
@@ -0,0 +1,101 @@
+From ebf3be9931f31df54df52b1821479e6a80a4d9c6 Mon Sep 17 00:00:00 2001
+From: Dimitri John Ledkov <xnox@ubuntu.com>
+Date: Tue, 15 Jan 2019 19:08:37 +0000
+Subject: [PATCH 14/47] Fix spelling typos.
+
+Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c | 2 +-
+ Create.c | 2 +-
+ Grow.c | 6 +++---
+ super-ddf.c | 2 +-
+ super-intel.c | 2 +-
+ 5 files changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index 9f75c68..9f050c1 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -879,7 +879,7 @@ static int force_array(struct mdinfo *content,
+ current_events = devices[chosen_drive].i.events;
+ add_another:
+ if (c->verbose >= 0)
+- pr_err("forcing event count in %s(%d) from %d upto %d\n",
++ pr_err("forcing event count in %s(%d) from %d up to %d\n",
+ devices[chosen_drive].devname,
+ devices[chosen_drive].i.disk.raid_disk,
+ (int)(devices[chosen_drive].i.events),
+diff --git a/Create.c b/Create.c
+index 04b1dfc..6f1b228 100644
+--- a/Create.c
++++ b/Create.c
+@@ -823,7 +823,7 @@ int Create(struct supertype *st, char *mddev,
+ }
+ bitmap_fd = open(s->bitmap_file, O_RDWR);
+ if (bitmap_fd < 0) {
+- pr_err("weird: %s cannot be openned\n",
++ pr_err("weird: %s cannot be opened\n",
+ s->bitmap_file);
+ goto abort_locked;
+ }
+diff --git a/Grow.c b/Grow.c
+index 363b209..6d32661 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -446,7 +446,7 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
+ if (offset_setable) {
+ st->ss->getinfo_super(st, mdi, NULL);
+ if (sysfs_init(mdi, fd, NULL)) {
+- pr_err("failed to intialize sysfs.\n");
++ pr_err("failed to initialize sysfs.\n");
+ free(mdi);
+ }
+ rv = sysfs_set_num_signed(mdi, NULL, "bitmap/location",
+@@ -2178,7 +2178,7 @@ size_change_error:
+ memset(&info, 0, sizeof(info));
+ info.array = array;
+ if (sysfs_init(&info, fd, NULL)) {
+- pr_err("failed to intialize sysfs.\n");
++ pr_err("failed to initialize sysfs.\n");
+ rv = 1;
+ goto release;
+ }
+@@ -2903,7 +2903,7 @@ static int impose_level(int fd, int level, char *devname, int verbose)
+ struct mdinfo info;
+
+ if (sysfs_init(&info, fd, NULL)) {
+- pr_err("failed to intialize sysfs.\n");
++ pr_err("failed to initialize sysfs.\n");
+ return 1;
+ }
+
+diff --git a/super-ddf.c b/super-ddf.c
+index 618542c..c095e8a 100644
+--- a/super-ddf.c
++++ b/super-ddf.c
+@@ -1900,7 +1900,7 @@ static struct vd_config *find_vdcr(struct ddf_super *ddf, unsigned int inst,
+ return conf;
+ }
+ bad:
+- pr_err("Could't find disk %d in array %u\n", n, inst);
++ pr_err("Couldn't find disk %d in array %u\n", n, inst);
+ return NULL;
+ }
+
+diff --git a/super-intel.c b/super-intel.c
+index 1cc7d5f..c399433 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -10034,7 +10034,7 @@ static void imsm_process_update(struct supertype *st,
+ break;
+ }
+ default:
+- pr_err("error: unsuported process update type:(type: %d)\n", type);
++ pr_err("error: unsupported process update type:(type: %d)\n", type);
+ }
+ }
+
+--
+2.24.0
+
diff --git a/0015-Detail.c-do-not-skip-first-character-when-calling-xs.patch b/0015-Detail.c-do-not-skip-first-character-when-calling-xs.patch
new file mode 100644
index 0000000..9c177a2
--- /dev/null
+++ b/0015-Detail.c-do-not-skip-first-character-when-calling-xs.patch
@@ -0,0 +1,46 @@
+From e3615ecb5b6ad8eb408296878aad5628e0e27166 Mon Sep 17 00:00:00 2001
+From: Coly Li <colyli@suse.de>
+Date: Tue, 12 Feb 2019 12:53:18 +0800
+Subject: [PATCH 15/47] Detail.c: do not skip first character when calling
+ xstrdup in Detail()
+
+'Commit b9c9bd9bacaa ("Detail: ensure --export names are acceptable as
+shell variables")' duplicates mdi->sys_name to sysdev string by,
+ char *sysdev = xstrdup(mdi->sys_name + 1);
+which skips the first character of mdi->sys_name. Then when running
+mdadm --detail <md device> --export, the output looks like,
+ MD_DEVICE_ev_sda2_ROLE=1
+ MD_DEVICE_ev_sda2_DEV=/dev/sda2
+The first character of md device (between MD_DEVICE and _ROLE/_DEV)
+is dropped. The expected output should be,
+ MD_DEVICE_dev_sda2_ROLE=1
+ MD_DEVICE_dev_sda2_DEV=/dev/sda2
+
+This patch removes the '+ 1' from calling xstrdup() in Detail(), which
+gets the dropped first character back.
+
+Reported-by: Arvin Schnell <aschnell@suse.com>
+Fixes: b9c9bd9bacaa ("Detail: ensure --export names are acceptable as 4 shell variables")
+Signed-off-by: Coly Li <colyli@suse.de>
+Cc: NeilBrown <neilb@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Detail.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Detail.c b/Detail.c
+index b3e857a..20ea03a 100644
+--- a/Detail.c
++++ b/Detail.c
+@@ -284,7 +284,7 @@ int Detail(char *dev, struct context *c)
+ struct mdinfo *mdi;
+ for (mdi = sra->devs; mdi; mdi = mdi->next) {
+ char *path;
+- char *sysdev = xstrdup(mdi->sys_name + 1);
++ char *sysdev = xstrdup(mdi->sys_name);
+ char *cp;
+
+ path = map_dev(mdi->disk.major,
+--
+2.24.0
+
diff --git a/0016-Fix-reshape-for-decreasing-data-offset.patch b/0016-Fix-reshape-for-decreasing-data-offset.patch
new file mode 100644
index 0000000..6420933
--- /dev/null
+++ b/0016-Fix-reshape-for-decreasing-data-offset.patch
@@ -0,0 +1,70 @@
+From cab114c5ca870e5f1b57fb2602cd9a038271c2e0 Mon Sep 17 00:00:00 2001
+From: Corey Hickey <bugfood-c@fatooh.org>
+Date: Mon, 11 Feb 2019 17:18:38 -0800
+Subject: [PATCH 16/47] Fix reshape for decreasing data offset
+
+...when not changing the number of disks.
+
+This patch needs context to explain. These are the relevant parts of
+the original code (condensed and annotated):
+
+if (dir > 0) {
+ /* Increase data offset (reshape backwards) */
+ if (data_offset < sd->data_offset + min) {
+ pr_err("--data-offset too small on %s\n",
+ dn);
+ goto release;
+ }
+} else {
+ /* Decrease data offset (reshape forwards) */
+ if (data_offset < sd->data_offset - min) {
+ pr_err("--data-offset too small on %s\n",
+ dn);
+ goto release;
+ }
+}
+
+When this code is reached, mdadm has already decided on a reshape
+direction. When increasing the data offset, the reshape runs backwards
+(dir==1); when decreasing the data offset, the reshape runs forwards
+(dir==-1).
+
+The conditional within the backwards reshape is correct: the requested
+offset must be larger than the old offset plus a minimum delta; thus the
+reshape has room to work.
+
+For the forwards reshape, the requested offset needs to be smaller than
+the old offset minus a minimum delta; to do this correctly, the
+comparison must be reversed.
+
+Also update the error message.
+
+Note: I have tested this change on a RAID 5 on Linux 4.18.0 and verified
+that there were no errors from the kernel and that the device data
+remained intact. I do not know if there are considerations for different
+RAID levels.
+
+Signed-off-by: Corey Hickey <bugfood-c@fatooh.org>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Grow.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index 6d32661..764374f 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -2613,8 +2613,8 @@ static int set_new_data_offset(struct mdinfo *sra, struct supertype *st,
+ goto release;
+ }
+ if (data_offset != INVALID_SECTORS &&
+- data_offset < sd->data_offset - min) {
+- pr_err("--data-offset too small on %s\n",
++ data_offset > sd->data_offset - min) {
++ pr_err("--data-offset too large on %s\n",
+ dn);
+ goto release;
+ }
+--
+2.24.0
+
diff --git a/0017-mdadm-tests-add-one-test-case-for-failfast-of-raid1.patch b/0017-mdadm-tests-add-one-test-case-for-failfast-of-raid1.patch
new file mode 100644
index 0000000..b64c176
--- /dev/null
+++ b/0017-mdadm-tests-add-one-test-case-for-failfast-of-raid1.patch
@@ -0,0 +1,99 @@
+From 76b906d2406cdf136f64de77e881eb2d180108d9 Mon Sep 17 00:00:00 2001
+From: Gioh Kim <gi-oh.kim@cloud.ionos.com>
+Date: Fri, 7 Dec 2018 14:30:09 +0100
+Subject: [PATCH 17/47] mdadm/tests: add one test case for failfast of raid1
+
+This creates raid1 device with the failfast option and check all
+slaves have the failfast flag. And it does assembling and growing
+the raid1 device and check the failfast works fine.
+
+Signed-off-by: Gioh Kim <gi-oh.kim@cloud.ionos.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ tests/05r1-failfast | 74 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 74 insertions(+)
+ create mode 100644 tests/05r1-failfast
+
+diff --git a/tests/05r1-failfast b/tests/05r1-failfast
+new file mode 100644
+index 0000000..823dd6f
+--- /dev/null
++++ b/tests/05r1-failfast
+@@ -0,0 +1,74 @@
++
++# create a simple mirror and check failfast flag works
++mdadm -CR $md0 -e1.2 --level=raid1 --failfast -n2 $dev0 $dev1
++check raid1
++if grep -v failfast /sys/block/md0/md/rd*/state > /dev/null
++then
++ die "failfast missing"
++fi
++
++# Removing works with the failfast flag
++mdadm $md0 -f $dev0
++mdadm $md0 -r $dev0
++if grep -v failfast /sys/block/md0/md/rd1/state > /dev/null
++then
++ die "failfast missing"
++fi
++
++# Adding works with the failfast flag
++mdadm $md0 -a --failfast $dev0
++check wait
++if grep -v failfast /sys/block/md0/md/rd0/state > /dev/null
++then
++ die "failfast missing"
++fi
++
++mdadm -S $md0
++
++# Assembling works with the failfast flag
++mdadm -A $md0 $dev0 $dev1
++check raid1
++if grep -v failfast /sys/block/md0/md/rd*/state > /dev/null
++then
++ die "failfast missing"
++fi
++
++# Adding works with the nofailfast flag
++mdadm $md0 -f $dev0
++mdadm $md0 -r $dev0
++mdadm $md0 -a --nofailfast $dev0
++check wait
++if grep failfast /sys/block/md0/md/rd0/state > /dev/null
++then
++ die "failfast should be missing"
++fi
++
++# Assembling with one faulty slave works with the failfast flag
++mdadm $md0 -f $dev0
++mdadm $md0 -r $dev0
++mdadm -S $md0
++mdadm -A $md0 $dev0 $dev1
++check raid1
++mdadm -S $md0
++
++# Spare works with the failfast flag
++mdadm -CR $md0 -e1.2 --level=raid1 --failfast -n2 $dev0 $dev1
++check raid1
++mdadm $md0 -a --failfast $dev2
++check wait
++check spares 1
++if grep -v failfast /sys/block/md0/md/rd*/state > /dev/null
++then
++ die "failfast missing"
++fi
++
++# Grow works with the failfast flag
++mdadm -G $md0 --raid-devices=3
++check wait
++if grep -v failfast /sys/block/md0/md/rd*/state > /dev/null
++then
++ die "failfast missing"
++fi
++mdadm -S $md0
++
++exit 0
+--
+2.24.0
+
diff --git a/0018-mdmon-don-t-attempt-to-manage-new-arrays-when-termin.patch b/0018-mdmon-don-t-attempt-to-manage-new-arrays-when-termin.patch
new file mode 100644
index 0000000..c543ca5
--- /dev/null
+++ b/0018-mdmon-don-t-attempt-to-manage-new-arrays-when-termin.patch
@@ -0,0 +1,50 @@
+From 69d084784de196acec8ab703cd1b379af211d624 Mon Sep 17 00:00:00 2001
+From: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
+Date: Fri, 22 Feb 2019 10:15:45 +0100
+Subject: [PATCH 18/47] mdmon: don't attempt to manage new arrays when
+ terminating
+
+When mdmon gets a SIGTERM, it stops managing arrays that are clean. If
+there is more that one array in the container and one of them is dirty
+and the clean one is still present in mdstat, mdmon will treat it as a
+new array and start managing it again. This leads to a cycle of
+remove_old() / manage_new() calls for the clean array, until the other
+one also becomes clean.
+
+Prevent this by not calling manage_new() if sigterm is set. Also, remove
+a check for sigterm in manage_new() because the condition will never be
+true.
+
+Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ managemon.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/managemon.c b/managemon.c
+index 101231c..29b91ba 100644
+--- a/managemon.c
++++ b/managemon.c
+@@ -727,9 +727,7 @@ static void manage_new(struct mdstat_ent *mdstat,
+ dprintf("inst: %s action: %d state: %d\n", inst,
+ new->action_fd, new->info.state_fd);
+
+- if (sigterm)
+- new->info.safe_mode_delay = 1;
+- else if (mdi->safe_mode_delay >= 50)
++ if (mdi->safe_mode_delay >= 50)
+ /* Normal start, mdadm set this. */
+ new->info.safe_mode_delay = mdi->safe_mode_delay;
+ else
+@@ -803,7 +801,7 @@ void manage(struct mdstat_ent *mdstat, struct supertype *container)
+ break;
+ }
+ }
+- if (a == NULL || !a->container)
++ if ((a == NULL || !a->container) && !sigterm)
+ manage_new(mdstat, container, a);
+ }
+ }
+--
+2.24.0
+
diff --git a/0019-mdmon-wait-for-previous-mdmon-to-exit-during-takeove.patch b/0019-mdmon-wait-for-previous-mdmon-to-exit-during-takeove.patch
new file mode 100644
index 0000000..28cac58
--- /dev/null
+++ b/0019-mdmon-wait-for-previous-mdmon-to-exit-during-takeove.patch
@@ -0,0 +1,57 @@
+From d2e11da4b7fd0453e942f43e4196dc63b3dbd708 Mon Sep 17 00:00:00 2001
+From: Pawel Baldysiak <pawel.baldysiak@intel.com>
+Date: Fri, 22 Feb 2019 13:30:27 +0100
+Subject: [PATCH 19/47] mdmon: wait for previous mdmon to exit during takeover
+
+Since the patch c76242c5("mdmon: get safe mode delay file descriptor
+early"), safe_mode_dalay is set properly by initrd mdmon. But in some
+cases with filesystem traffic since the very start of the system, it
+might take a while to transit to clean state. Due to fact that new
+mdmon does not wait for the old one to exit - it might happen that the
+new one switches safe_mode_delay back to seconds, before old one exits.
+As the result two mdmons are running concurrently on same array.
+
+Wait for the old mdmon to exit by pinging it with SIGUSR1 signal, just
+in case it is sleeping.
+
+Signed-off-by: Pawel Baldysiak <pawel.baldysiak@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ mdmon.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/mdmon.c b/mdmon.c
+index 0955fcc..ff985d2 100644
+--- a/mdmon.c
++++ b/mdmon.c
+@@ -171,6 +171,7 @@ static void try_kill_monitor(pid_t pid, char *devname, int sock)
+ int fd;
+ int n;
+ long fl;
++ int rv;
+
+ /* first rule of survival... don't off yourself */
+ if (pid == getpid())
+@@ -201,9 +202,16 @@ static void try_kill_monitor(pid_t pid, char *devname, int sock)
+ fl &= ~O_NONBLOCK;
+ fcntl(sock, F_SETFL, fl);
+ n = read(sock, buf, 100);
+- /* Ignore result, it is just the wait that
+- * matters
+- */
++
++ /* If there is I/O going on it might took some time to get to
++ * clean state. Wait for monitor to exit fully to avoid races.
++ * Ping it with SIGUSR1 in case that it is sleeping */
++ for (n = 0; n < 25; n++) {
++ rv = kill(pid, SIGUSR1);
++ if (rv < 0)
++ break;
++ usleep(200000);
++ }
+ }
+
+ void remove_pidfile(char *devname)
+--
+2.24.0
+
diff --git a/0020-Assemble-Fix-starting-array-with-initial-reshape-che.patch b/0020-Assemble-Fix-starting-array-with-initial-reshape-che.patch
new file mode 100644
index 0000000..64af38f
--- /dev/null
+++ b/0020-Assemble-Fix-starting-array-with-initial-reshape-che.patch
@@ -0,0 +1,52 @@
+From 2b57e4fe041d52ae29866c93a878a11c07223cff Mon Sep 17 00:00:00 2001
+From: Pawel Baldysiak <pawel.baldysiak@intel.com>
+Date: Fri, 22 Feb 2019 12:56:27 +0100
+Subject: [PATCH 20/47] Assemble: Fix starting array with initial reshape
+ checkpoint
+
+If array was stopped during reshape initialization,
+there might be a "0" checkpoint recorded in metadata.
+If array with such condition (reshape with position 0)
+is passed to kernel - it will refuse to start such array.
+
+Treat such array as normal during assemble, Grow_continue() will
+reinitialize and start the reshape.
+
+Signed-off-by: Pawel Baldysiak <pawel.baldysiak@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index 9f050c1..420c7b3 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -2061,8 +2061,22 @@ int assemble_container_content(struct supertype *st, int mdfd,
+ spare, &c->backup_file, c->verbose) == 1)
+ return 1;
+
+- err = sysfs_set_str(content, NULL,
+- "array_state", "readonly");
++ if (content->reshape_progress == 0) {
++ /* If reshape progress is 0 - we are assembling the
++ * array that was stopped, before reshape has started.
++ * Array needs to be started as active, Grow_continue()
++ * will start the reshape.
++ */
++ sysfs_set_num(content, NULL, "reshape_position",
++ MaxSector);
++ err = sysfs_set_str(content, NULL,
++ "array_state", "active");
++ sysfs_set_num(content, NULL, "reshape_position", 0);
++ } else {
++ err = sysfs_set_str(content, NULL,
++ "array_state", "readonly");
++ }
++
+ if (err)
+ return 1;
+
+--
+2.24.0
+
diff --git a/0021-add-missing-units-to-examine.patch b/0021-add-missing-units-to-examine.patch
new file mode 100644
index 0000000..7f75c72
--- /dev/null
+++ b/0021-add-missing-units-to-examine.patch
@@ -0,0 +1,59 @@
+From 227aeaa872d4898273cf87a4253898823d556c43 Mon Sep 17 00:00:00 2001
+From: Corey Hickey <bugfood-c@fatooh.org>
+Date: Mon, 11 Feb 2019 17:42:27 -0800
+Subject: [PATCH 21/47] add missing units to --examine
+
+Within the output of "mdadm --examine", there are three sizes reported
+on adjacent lines. For example:
+
+$ sudo mdadm --examine /dev/md3
+[...]
+ Avail Dev Size : 17580545024 (8383.06 GiB 9001.24 GB)
+ Array Size : 17580417024 (16765.99 GiB 18002.35 GB)
+ Used Dev Size : 11720278016 (5588.66 GiB 6000.78 GB)
+[...]
+
+This can be confusing, since the first and third line are in 512-byte
+sectors, and the second is in KiB.
+
+Add units to avoid ambiguity.
+
+(I don't particularly like the "KiB" notation, but it is at least
+unambiguous.)
+
+Signed-off-by: Corey Hickey <bugfood-c@fatooh.org>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super1.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/super1.c b/super1.c
+index 636a286..b85dc20 100644
+--- a/super1.c
++++ b/super1.c
+@@ -360,7 +360,7 @@ static void examine_super1(struct supertype *st, char *homehost)
+ printf(" Raid Level : %s\n", c?c:"-unknown-");
+ printf(" Raid Devices : %d\n", __le32_to_cpu(sb->raid_disks));
+ printf("\n");
+- printf(" Avail Dev Size : %llu%s\n",
++ printf(" Avail Dev Size : %llu sectors%s\n",
+ (unsigned long long)__le64_to_cpu(sb->data_size),
+ human_size(__le64_to_cpu(sb->data_size)<<9));
+ if (__le32_to_cpu(sb->level) > 0) {
+@@ -378,11 +378,11 @@ static void examine_super1(struct supertype *st, char *homehost)
+ if (ddsks) {
+ long long asize = __le64_to_cpu(sb->size);
+ asize = (asize << 9) * ddsks / ddsks_denom;
+- printf(" Array Size : %llu%s\n",
++ printf(" Array Size : %llu KiB%s\n",
+ asize >> 10, human_size(asize));
+ }
+ if (sb->size != sb->data_size)
+- printf(" Used Dev Size : %llu%s\n",
++ printf(" Used Dev Size : %llu sectors%s\n",
+ (unsigned long long)__le64_to_cpu(sb->size),
+ human_size(__le64_to_cpu(sb->size)<<9));
+ }
+--
+2.24.0
+
diff --git a/0022-imsm-fix-spare-activation-for-old-matrix-arrays.patch b/0022-imsm-fix-spare-activation-for-old-matrix-arrays.patch
new file mode 100644
index 0000000..1f2e582
--- /dev/null
+++ b/0022-imsm-fix-spare-activation-for-old-matrix-arrays.patch
@@ -0,0 +1,116 @@
+From 05501181f18cdccdb0b3cec1d8cf59f0995504d7 Mon Sep 17 00:00:00 2001
+From: Pawel Baldysiak <pawel.baldysiak@intel.com>
+Date: Fri, 8 Mar 2019 12:19:11 +0100
+Subject: [PATCH 22/47] imsm: fix spare activation for old matrix arrays
+
+During spare activation get_extents() calculates metadata reserved space based
+on smallest active RAID member or it will take the defaults. Since patch
+611d9529("imsm: change reserved space to 4MB") default is extended. If array
+was created prior that patch, reserved space is smaller. In case of matrix
+RAID - spare is activated in each array one-by-one, so it is spare for first
+activation, but treated as "active" during second one.
+
+In case of adding spare drive to old matrix RAID with the size the same as
+already existing member drive the routine will take the defaults during second
+run and mdmon will refuse to rebuild second volume, claiming that the drive
+does not have enough free space.
+
+Add parameter to get_extents(), so the during spare activation reserved space
+is always based on smallest active drive - even if given drive is already
+active in some other array of matrix RAID.
+
+Signed-off-by: Pawel Baldysiak <pawel.baldysiak@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index c399433..5a7c9f8 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -1313,7 +1313,8 @@ static unsigned long long per_dev_array_size(struct imsm_map *map)
+ return array_size;
+ }
+
+-static struct extent *get_extents(struct intel_super *super, struct dl *dl)
++static struct extent *get_extents(struct intel_super *super, struct dl *dl,
++ int get_minimal_reservation)
+ {
+ /* find a list of used extents on the given physical device */
+ struct extent *rv, *e;
+@@ -1325,7 +1326,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
+ * regardless of whether the OROM has assigned sectors from the
+ * IMSM_RESERVED_SECTORS region
+ */
+- if (dl->index == -1)
++ if (dl->index == -1 || get_minimal_reservation)
+ reservation = imsm_min_reserved_sectors(super);
+ else
+ reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
+@@ -1386,7 +1387,7 @@ static __u32 imsm_reserved_sectors(struct intel_super *super, struct dl *dl)
+ if (dl->index == -1)
+ return MPB_SECTOR_CNT;
+
+- e = get_extents(super, dl);
++ e = get_extents(super, dl, 0);
+ if (!e)
+ return MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
+
+@@ -1478,7 +1479,7 @@ static __u32 imsm_min_reserved_sectors(struct intel_super *super)
+ return rv;
+
+ /* find last lba used by subarrays on the smallest active disk */
+- e = get_extents(super, dl_min);
++ e = get_extents(super, dl_min, 0);
+ if (!e)
+ return rv;
+ for (i = 0; e[i].size; i++)
+@@ -1519,7 +1520,7 @@ int get_spare_criteria_imsm(struct supertype *st, struct spare_criteria *c)
+ if (!dl)
+ return -EINVAL;
+ /* find last lba used by subarrays */
+- e = get_extents(super, dl);
++ e = get_extents(super, dl, 0);
+ if (!e)
+ return -EINVAL;
+ for (i = 0; e[i].size; i++)
+@@ -7203,7 +7204,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
+
+ pos = 0;
+ i = 0;
+- e = get_extents(super, dl);
++ e = get_extents(super, dl, 0);
+ if (!e) continue;
+ do {
+ unsigned long long esize;
+@@ -7261,7 +7262,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
+ }
+
+ /* retrieve the largest free space block */
+- e = get_extents(super, dl);
++ e = get_extents(super, dl, 0);
+ maxsize = 0;
+ i = 0;
+ if (e) {
+@@ -7359,7 +7360,7 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks,
+ if (super->orom && dl->index < 0 && mpb->num_raid_devs)
+ continue;
+
+- e = get_extents(super, dl);
++ e = get_extents(super, dl, 0);
+ if (!e)
+ continue;
+ for (i = 1; e[i-1].size; i++)
+@@ -8846,7 +8847,7 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot,
+ /* Does this unused device have the requisite free space?
+ * It needs to be able to cover all member volumes
+ */
+- ex = get_extents(super, dl);
++ ex = get_extents(super, dl, 1);
+ if (!ex) {
+ dprintf("cannot get extents\n");
+ continue;
+--
+2.24.0
+
diff --git a/0023-Create-Block-rounding-size-to-max.patch b/0023-Create-Block-rounding-size-to-max.patch
new file mode 100644
index 0000000..9bf3c9f
--- /dev/null
+++ b/0023-Create-Block-rounding-size-to-max.patch
@@ -0,0 +1,94 @@
+From 22dc741f63e6403d59c2c14f56fd4791265f9bbb Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Date: Mon, 1 Apr 2019 16:53:41 +0200
+Subject: [PATCH 23/47] Create: Block rounding size to max
+
+When passed size is smaller than chunk, mdadm rounds it to 0 but 0 there
+means max available space.
+Block it for every metadata. Remove the same check from imsm routine.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Create.c | 23 ++++++++++++++++++++---
+ super-intel.c | 5 ++---
+ 2 files changed, 22 insertions(+), 6 deletions(-)
+
+diff --git a/Create.c b/Create.c
+index 6f1b228..292f92a 100644
+--- a/Create.c
++++ b/Create.c
+@@ -27,6 +27,18 @@
+ #include "md_p.h"
+ #include <ctype.h>
+
++static int round_size_and_verify(unsigned long long *size, int chunk)
++{
++ if (*size == 0)
++ return 0;
++ *size &= ~(unsigned long long)(chunk - 1);
++ if (*size == 0) {
++ pr_err("Size cannot be smaller than chunk.\n");
++ return 1;
++ }
++ return 0;
++}
++
+ static int default_layout(struct supertype *st, int level, int verbose)
+ {
+ int layout = UnSet;
+@@ -248,11 +260,14 @@ int Create(struct supertype *st, char *mddev,
+ pr_err("unknown level %d\n", s->level);
+ return 1;
+ }
++
+ if (s->size == MAX_SIZE)
+ /* use '0' to mean 'max' now... */
+ s->size = 0;
+ if (s->size && s->chunk && s->chunk != UnSet)
+- s->size &= ~(unsigned long long)(s->chunk - 1);
++ if (round_size_and_verify(&s->size, s->chunk))
++ return 1;
++
+ newsize = s->size * 2;
+ if (st && ! st->ss->validate_geometry(st, s->level, s->layout, s->raiddisks,
+ &s->chunk, s->size*2,
+@@ -267,7 +282,8 @@ int Create(struct supertype *st, char *mddev,
+ /* default chunk was just set */
+ if (c->verbose > 0)
+ pr_err("chunk size defaults to %dK\n", s->chunk);
+- s->size &= ~(unsigned long long)(s->chunk - 1);
++ if (round_size_and_verify(&s->size, s->chunk))
++ return 1;
+ do_default_chunk = 0;
+ }
+ }
+@@ -413,7 +429,8 @@ int Create(struct supertype *st, char *mddev,
+ /* default chunk was just set */
+ if (c->verbose > 0)
+ pr_err("chunk size defaults to %dK\n", s->chunk);
+- s->size &= ~(unsigned long long)(s->chunk - 1);
++ if (round_size_and_verify(&s->size, s->chunk))
++ return 1;
+ do_default_chunk = 0;
+ }
+ }
+diff --git a/super-intel.c b/super-intel.c
+index 5a7c9f8..2ba045a 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -7455,9 +7455,8 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+ verbose);
+ }
+
+- if (size && ((size < 1024) || (*chunk != UnSet &&
+- size < (unsigned long long) *chunk))) {
+- pr_err("Given size must be greater than 1M and chunk size.\n");
++ if (size && (size < 1024)) {
++ pr_err("Given size must be greater than 1M.\n");
+ /* Depends on algorithm in Create.c :
+ * if container was given (dev == NULL) return -1,
+ * if block device was given ( dev != NULL) return 0.
+--
+2.24.0
+
diff --git a/0024-udev-Add-udev-rules-to-create-by-partuuid-for-md-dev.patch b/0024-udev-Add-udev-rules-to-create-by-partuuid-for-md-dev.patch
new file mode 100644
index 0000000..e5490b6
--- /dev/null
+++ b/0024-udev-Add-udev-rules-to-create-by-partuuid-for-md-dev.patch
@@ -0,0 +1,31 @@
+From 3c9b46cf9ae15a9be98fc47e2080bd9494496246 Mon Sep 17 00:00:00 2001
+From: Liwei Song <liwei.song@windriver.com>
+Date: Tue, 19 Mar 2019 23:51:05 -0400
+Subject: [PATCH 24/47] udev: Add udev rules to create by-partuuid for md
+ device
+
+This rules will create link under /dev/disk/by-partuuid/ for
+MD devices partition, with which will support specify
+root=PARTUUID=XXX to boot rootfs.
+
+Signed-off-by: Liwei Song <liwei.song@windriver.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ udev-md-raid-arrays.rules | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/udev-md-raid-arrays.rules b/udev-md-raid-arrays.rules
+index c95ec7b..5b99d58 100644
+--- a/udev-md-raid-arrays.rules
++++ b/udev-md-raid-arrays.rules
+@@ -30,6 +30,7 @@ IMPORT{builtin}="blkid"
+ OPTIONS+="link_priority=100"
+ OPTIONS+="watch"
+ ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}"
++ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}"
+ ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
+
+ ENV{MD_LEVEL}=="raid[1-9]*", ENV{SYSTEMD_WANTS}+="mdmonitor.service"
+--
+2.24.0
+
diff --git a/0025-mdmon-fix-wrong-array-state-when-disk-fails-during-m.patch b/0025-mdmon-fix-wrong-array-state-when-disk-fails-during-m.patch
new file mode 100644
index 0000000..abb69af
--- /dev/null
+++ b/0025-mdmon-fix-wrong-array-state-when-disk-fails-during-m.patch
@@ -0,0 +1,109 @@
+From ae7d61e35ec2ab6361c3e509a8db00698ef3396f Mon Sep 17 00:00:00 2001
+From: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
+Date: Tue, 7 May 2019 16:08:47 +0200
+Subject: [PATCH 25/47] mdmon: fix wrong array state when disk fails during
+ mdmon startup
+
+If a member drive disappears and is set faulty by the kernel during
+mdmon startup, after ss->load_container() but before manage_new(), mdmon
+will try to readd the faulty drive to the array and start rebuilding.
+Metadata on the active drive is updated, but the faulty drive is not
+removed from the array and is left in a "blocked" state and any write
+request to the array will block. If the faulty drive reappears in the
+system e.g. after a reboot, the array will not assemble because metadata
+on the drives will be incompatible (at least on imsm).
+
+Fix this by adding a new option for sysfs_read(): "GET_DEVS_ALL". This
+is an extension for the "GET_DEVS" option and causes all member devices
+to be returned, even if the associated block device has been removed.
+Use this option in manage_new() to include the faulty device on the
+active_array's devices list. Mdmon will then properly remove the faulty
+device from the array and update the metadata to reflect the degraded
+state.
+
+Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ managemon.c | 2 +-
+ mdadm.h | 1 +
+ super-intel.c | 2 +-
+ sysfs.c | 23 ++++++++++++++---------
+ 4 files changed, 17 insertions(+), 11 deletions(-)
+
+diff --git a/managemon.c b/managemon.c
+index 29b91ba..200cf83 100644
+--- a/managemon.c
++++ b/managemon.c
+@@ -678,7 +678,7 @@ static void manage_new(struct mdstat_ent *mdstat,
+ mdi = sysfs_read(-1, mdstat->devnm,
+ GET_LEVEL|GET_CHUNK|GET_DISKS|GET_COMPONENT|
+ GET_SAFEMODE|GET_DEVS|GET_OFFSET|GET_SIZE|GET_STATE|
+- GET_LAYOUT);
++ GET_LAYOUT|GET_DEVS_ALL);
+
+ if (!mdi)
+ return;
+diff --git a/mdadm.h b/mdadm.h
+index 705bd9b..427cc52 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -647,6 +647,7 @@ enum sysfs_read_flags {
+ GET_ERROR = (1 << 24),
+ GET_ARRAY_STATE = (1 << 25),
+ GET_CONSISTENCY_POLICY = (1 << 26),
++ GET_DEVS_ALL = (1 << 27),
+ };
+
+ /* If fd >= 0, get the array it is open on,
+diff --git a/super-intel.c b/super-intel.c
+index 2ba045a..4fd5e84 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -8560,7 +8560,7 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
+ disk = get_imsm_disk(super, ord_to_idx(ord));
+
+ /* check for new failures */
+- if (state & DS_FAULTY) {
++ if (disk && (state & DS_FAULTY)) {
+ if (mark_failure(super, dev, disk, ord_to_idx(ord)))
+ super->updates_pending++;
+ }
+diff --git a/sysfs.c b/sysfs.c
+index df6fdda..2dd9ab6 100644
+--- a/sysfs.c
++++ b/sysfs.c
+@@ -313,17 +313,22 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
+ /* assume this is a stale reference to a hot
+ * removed device
+ */
+- free(dev);
+- continue;
++ if (!(options & GET_DEVS_ALL)) {
++ free(dev);
++ continue;
++ }
++ } else {
++ sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
+ }
+- sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
+
+- /* special case check for block devices that can go 'offline' */
+- strcpy(dbase, "block/device/state");
+- if (load_sys(fname, buf, sizeof(buf)) == 0 &&
+- strncmp(buf, "offline", 7) == 0) {
+- free(dev);
+- continue;
++ if (!(options & GET_DEVS_ALL)) {
++ /* special case check for block devices that can go 'offline' */
++ strcpy(dbase, "block/device/state");
++ if (load_sys(fname, buf, sizeof(buf)) == 0 &&
++ strncmp(buf, "offline", 7) == 0) {
++ free(dev);
++ continue;
++ }
+ }
+
+ /* finally add this disk to the array */
+--
+2.24.0
+
diff --git a/0026-Enable-probe_roms-to-scan-more-than-6-roms.patch b/0026-Enable-probe_roms-to-scan-more-than-6-roms.patch
new file mode 100644
index 0000000..b9c1de0
--- /dev/null
+++ b/0026-Enable-probe_roms-to-scan-more-than-6-roms.patch
@@ -0,0 +1,212 @@
+From 4ec389e3f0c1233f5aa2d5b4e63d96e33d2a37f0 Mon Sep 17 00:00:00 2001
+From: Roman Sobanski <roman.sobanski@intel.com>
+Date: Tue, 2 Jul 2019 13:29:27 +0200
+Subject: [PATCH 26/47] Enable probe_roms to scan more than 6 roms.
+
+In some cases if more than 6 oroms exist, resource for particular
+controller may not be found. Change method for storing
+adapter_rom_resources from array to list.
+
+Signed-off-by: Roman Sobanski <roman.sobanski@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ probe_roms.c | 98 ++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 56 insertions(+), 42 deletions(-)
+
+diff --git a/probe_roms.c b/probe_roms.c
+index b0b0883..7ea04c7 100644
+--- a/probe_roms.c
++++ b/probe_roms.c
+@@ -35,6 +35,9 @@ static const int rom_len = 0xf0000 - 0xc0000; /* option-rom memory region */
+ static int _sigbus;
+ static unsigned long rom_align;
+
++static void roms_deinit(void);
++static int roms_init(void);
++
+ static void sigbus(int sig)
+ {
+ _sigbus = 1;
+@@ -75,6 +78,7 @@ void probe_roms_exit(void)
+ munmap(rom_mem, rom_len);
+ rom_mem = MAP_FAILED;
+ }
++ roms_deinit();
+ }
+
+ int probe_roms_init(unsigned long align)
+@@ -91,6 +95,9 @@ int probe_roms_init(unsigned long align)
+ else
+ return -1;
+
++ if (roms_init())
++ return -1;
++
+ if (signal(SIGBUS, sigbus) == SIG_ERR)
+ rc = -1;
+ if (rc == 0) {
+@@ -131,6 +138,7 @@ struct resource {
+ unsigned long end;
+ unsigned long data;
+ const char *name;
++ struct resource *next;
+ };
+
+ static struct resource system_rom_resource = {
+@@ -147,37 +155,7 @@ static struct resource extension_rom_resource = {
+ .end = 0xeffff,
+ };
+
+-static struct resource adapter_rom_resources[] = { {
+- .name = "Adapter ROM",
+- .start = 0xc8000,
+- .data = 0,
+- .end = 0,
+-}, {
+- .name = "Adapter ROM",
+- .start = 0,
+- .data = 0,
+- .end = 0,
+-}, {
+- .name = "Adapter ROM",
+- .start = 0,
+- .data = 0,
+- .end = 0,
+-}, {
+- .name = "Adapter ROM",
+- .start = 0,
+- .data = 0,
+- .end = 0,
+-}, {
+- .name = "Adapter ROM",
+- .start = 0,
+- .data = 0,
+- .end = 0,
+-}, {
+- .name = "Adapter ROM",
+- .start = 0,
+- .data = 0,
+- .end = 0,
+-} };
++static struct resource *adapter_rom_resources;
+
+ static struct resource video_rom_resource = {
+ .name = "Video ROM",
+@@ -186,8 +164,35 @@ static struct resource video_rom_resource = {
+ .end = 0xc7fff,
+ };
+
++static int roms_init(void)
++{
++ adapter_rom_resources = malloc(sizeof(struct resource));
++ if (adapter_rom_resources == NULL)
++ return 1;
++ adapter_rom_resources->name = "Adapter ROM";
++ adapter_rom_resources->start = 0xc8000;
++ adapter_rom_resources->data = 0;
++ adapter_rom_resources->end = 0;
++ adapter_rom_resources->next = NULL;
++ return 0;
++}
++
++static void roms_deinit(void)
++{
++ struct resource *res;
++
++ res = adapter_rom_resources;
++ while (res) {
++ struct resource *tmp = res;
++
++ res = res->next;
++ free(tmp);
++ }
++}
++
+ #define ROMSIGNATURE 0xaa55
+
++
+ static int romsignature(const unsigned char *rom)
+ {
+ const unsigned short * const ptr = (const unsigned short *)rom;
+@@ -208,16 +213,14 @@ static int romchecksum(const unsigned char *rom, unsigned long length)
+ int scan_adapter_roms(scan_fn fn)
+ {
+ /* let scan_fn examing each of the adapter roms found by probe_roms */
+- unsigned int i;
++ struct resource *res = adapter_rom_resources;
+ int found;
+
+ if (rom_fd < 0)
+ return 0;
+
+ found = 0;
+- for (i = 0; i < ARRAY_SIZE(adapter_rom_resources); i++) {
+- struct resource *res = &adapter_rom_resources[i];
+-
++ while (res) {
+ if (res->start) {
+ found = fn(isa_bus_to_virt(res->start),
+ isa_bus_to_virt(res->end),
+@@ -226,6 +229,7 @@ int scan_adapter_roms(scan_fn fn)
+ break;
+ } else
+ break;
++ res = res->next;
+ }
+
+ return found;
+@@ -241,14 +245,14 @@ void probe_roms(void)
+ const void *rom;
+ unsigned long start, length, upper;
+ unsigned char c;
+- unsigned int i;
++ struct resource *res = adapter_rom_resources;
+ __u16 val=0;
+
+ if (rom_fd < 0)
+ return;
+
+ /* video rom */
+- upper = adapter_rom_resources[0].start;
++ upper = res->start;
+ for (start = video_rom_resource.start; start < upper; start += rom_align) {
+ rom = isa_bus_to_virt(start);
+ if (!romsignature(rom))
+@@ -283,8 +287,9 @@ void probe_roms(void)
+ upper = extension_rom_resource.start;
+ }
+
++ struct resource *prev_res = res;
+ /* check for adapter roms on 2k boundaries */
+- for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += rom_align) {
++ for (; start < upper; start += rom_align) {
+ rom = isa_bus_to_virt(start);
+ if (!romsignature(rom))
+ continue;
+@@ -308,10 +313,19 @@ void probe_roms(void)
+ if (!length || start + length > upper || !romchecksum(rom, length))
+ continue;
+
+- adapter_rom_resources[i].start = start;
+- adapter_rom_resources[i].data = start + (unsigned long) val;
+- adapter_rom_resources[i].end = start + length - 1;
++ if (res == NULL) {
++ res = calloc(1, sizeof(struct resource));
++ if (res == NULL)
++ return;
++ prev_res->next = res;
++ }
++
++ res->start = start;
++ res->data = start + (unsigned long)val;
++ res->end = start + length - 1;
+
+- start = adapter_rom_resources[i++].end & ~(rom_align - 1);
++ start = res->end & ~(rom_align - 1);
++ prev_res = res;
++ res = res->next;
+ }
+ }
+--
+2.24.0
+
diff --git a/0027-super-intel-Fix-issue-with-abs-being-irrelevant.patch b/0027-super-intel-Fix-issue-with-abs-being-irrelevant.patch
new file mode 100644
index 0000000..6a509a3
--- /dev/null
+++ b/0027-super-intel-Fix-issue-with-abs-being-irrelevant.patch
@@ -0,0 +1,38 @@
+From a4f7290c20c2ff78328c9db0b18029165cfb05b2 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Tue, 9 Jul 2019 13:26:08 -0400
+Subject: [PATCH 27/47] super-intel: Fix issue with abs() being irrelevant
+
+gcc9 complains about subtracting unsigned from unsigned and code
+assuming the result can be negative.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 4fd5e84..230e164 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -2875,7 +2875,7 @@ static unsigned long long calc_component_size(struct imsm_map *map,
+ {
+ unsigned long long component_size;
+ unsigned long long dev_size = imsm_dev_size(dev);
+- unsigned long long calc_dev_size = 0;
++ long long calc_dev_size = 0;
+ unsigned int member_disks = imsm_num_data_members(map);
+
+ if (member_disks == 0)
+@@ -2889,7 +2889,7 @@ static unsigned long long calc_component_size(struct imsm_map *map,
+ * 2048 blocks per each device. If the difference is higher it means
+ * that array size was expanded and num_data_stripes was not updated.
+ */
+- if ((unsigned int)abs(calc_dev_size - dev_size) >
++ if (llabs(calc_dev_size - (long long)dev_size) >
+ (1 << SECT_PER_MB_SHIFT) * member_disks) {
+ component_size = dev_size / member_disks;
+ dprintf("Invalid num_data_stripes in metadata; expected=%llu, found=%llu\n",
+--
+2.24.0
+
diff --git a/0028-mdadm.h-Introduced-unaligned-get-put-_unaligned-16-3.patch b/0028-mdadm.h-Introduced-unaligned-get-put-_unaligned-16-3.patch
new file mode 100644
index 0000000..572a1c2
--- /dev/null
+++ b/0028-mdadm.h-Introduced-unaligned-get-put-_unaligned-16-3.patch
@@ -0,0 +1,57 @@
+From 7039d1f8200b9599b23db5953934fdb43b0442e0 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Tue, 9 Jul 2019 14:15:38 -0400
+Subject: [PATCH 28/47] mdadm.h: Introduced unaligned
+ {get,put}_unaligned{16,32}()
+
+We need these to avoid gcc9 going all crazy on us.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ mdadm.h | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/mdadm.h b/mdadm.h
+index 427cc52..0fa9e1b 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -191,6 +191,36 @@ struct dlm_lksb {
+ #endif
+ #endif /* __KLIBC__ */
+
++/*
++ * Partially stolen from include/linux/unaligned/packed_struct.h
++ */
++struct __una_u16 { __u16 x; } __attribute__ ((packed));
++struct __una_u32 { __u32 x; } __attribute__ ((packed));
++
++static inline __u16 __get_unaligned16(const void *p)
++{
++ const struct __una_u16 *ptr = (const struct __una_u16 *)p;
++ return ptr->x;
++}
++
++static inline __u32 __get_unaligned32(const void *p)
++{
++ const struct __una_u32 *ptr = (const struct __una_u32 *)p;
++ return ptr->x;
++}
++
++static inline void __put_unaligned16(__u16 val, void *p)
++{
++ struct __una_u16 *ptr = (struct __una_u16 *)p;
++ ptr->x = val;
++}
++
++static inline void __put_unaligned32(__u32 val, void *p)
++{
++ struct __una_u32 *ptr = (struct __una_u32 *)p;
++ ptr->x = val;
++}
++
+ /*
+ * Check at compile time that something is of a particular type.
+ * Always evaluates to 1 so you may use it easily in comparisons.
+--
+2.24.0
+
diff --git a/0029-super-intel-Use-put_unaligned-in-split_ull.patch b/0029-super-intel-Use-put_unaligned-in-split_ull.patch
new file mode 100644
index 0000000..ec46d6a
--- /dev/null
+++ b/0029-super-intel-Use-put_unaligned-in-split_ull.patch
@@ -0,0 +1,38 @@
+From 486720e0c2418e7e2e0a16221f7c42a308622254 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Tue, 9 Jul 2019 14:49:22 -0400
+Subject: [PATCH 29/47] super-intel: Use put_unaligned in split_ull
+
+Shut up some gcc9 errors by using put_unaligned() accessors. Not pretty,
+but better than it was.
+
+Also correct to the correct swap macros.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 230e164..d7e8a65 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -1165,12 +1165,12 @@ static int count_memberships(struct dl *dl, struct intel_super *super)
+
+ static __u32 imsm_min_reserved_sectors(struct intel_super *super);
+
+-static int split_ull(unsigned long long n, __u32 *lo, __u32 *hi)
++static int split_ull(unsigned long long n, void *lo, void *hi)
+ {
+ if (lo == 0 || hi == 0)
+ return 1;
+- *lo = __le32_to_cpu((unsigned)n);
+- *hi = __le32_to_cpu((unsigned)(n >> 32));
++ __put_unaligned32(__cpu_to_le32((__u32)n), lo);
++ __put_unaligned32(__cpu_to_le32((n >> 32)), hi);
+ return 0;
+ }
+
+--
+2.24.0
+
diff --git a/0030-mdadm-load-default-sysfs-attributes-after-assemblati.patch b/0030-mdadm-load-default-sysfs-attributes-after-assemblati.patch
new file mode 100644
index 0000000..f2f69ae
--- /dev/null
+++ b/0030-mdadm-load-default-sysfs-attributes-after-assemblati.patch
@@ -0,0 +1,344 @@
+From b06815989179e0f153e44e4336290e655edce9a1 Mon Sep 17 00:00:00 2001
+From: Mariusz Dabrowski <mariusz.dabrowski@intel.com>
+Date: Wed, 10 Jul 2019 13:38:53 +0200
+Subject: [PATCH 30/47] mdadm: load default sysfs attributes after assemblation
+
+Added new type of line to mdadm.conf which allows to specify values of
+sysfs attributes for MD devices that should be loaded after the array is
+assembled. Each line is interpreted as list of structures containing
+sysname of MD device (md126 etc.) and list of sysfs attributes and their
+values.
+
+Signed-off-by: Mariusz Dabrowski <mariusz.dabrowski@intel.com>
+Signed-off-by: Krzysztof Smolinski <krzysztof.smolinski@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Assemble.c | 12 +++-
+ Incremental.c | 1 +
+ config.c | 7 ++-
+ mdadm.conf.5 | 25 ++++++++
+ mdadm.h | 3 +
+ sysfs.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 202 insertions(+), 4 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index 420c7b3..b2e6914 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -1063,9 +1063,12 @@ static int start_array(int mdfd,
+ mddev, okcnt + sparecnt + journalcnt,
+ okcnt + sparecnt + journalcnt == 1 ? "" : "s");
+ if (okcnt < (unsigned)content->array.raid_disks)
+- fprintf(stderr, " (out of %d)",
++ fprintf(stderr, " (out of %d)\n",
+ content->array.raid_disks);
+- fprintf(stderr, "\n");
++ else {
++ fprintf(stderr, "\n");
++ sysfs_rules_apply(mddev, content);
++ }
+ }
+
+ if (st->ss->validate_container) {
+@@ -1139,6 +1142,7 @@ static int start_array(int mdfd,
+ rv = ioctl(mdfd, RUN_ARRAY, NULL);
+ reopen_mddev(mdfd); /* drop O_EXCL */
+ if (rv == 0) {
++ sysfs_rules_apply(mddev, content);
+ if (c->verbose >= 0) {
+ pr_err("%s has been started with %d drive%s",
+ mddev, okcnt, okcnt==1?"":"s");
+@@ -2130,10 +2134,12 @@ int assemble_container_content(struct supertype *st, int mdfd,
+ pr_err("array %s now has %d device%s",
+ chosen_name, working + preexist,
+ working + preexist == 1 ? "":"s");
+- else
++ else {
++ sysfs_rules_apply(chosen_name, content);
+ pr_err("Started %s with %d device%s",
+ chosen_name, working + preexist,
+ working + preexist == 1 ? "":"s");
++ }
+ if (preexist)
+ fprintf(stderr, " (%d new)", working);
+ if (expansion)
+diff --git a/Incremental.c b/Incremental.c
+index d4d3c35..98dbcd9 100644
+--- a/Incremental.c
++++ b/Incremental.c
+@@ -480,6 +480,7 @@ int Incremental(struct mddev_dev *devlist, struct context *c,
+ pr_err("container %s now has %d device%s\n",
+ chosen_name, info.array.working_disks,
+ info.array.working_disks == 1?"":"s");
++ sysfs_rules_apply(chosen_name, &info);
+ wait_for(chosen_name, mdfd);
+ if (st->ss->external)
+ strcpy(devnm, fd2devnm(mdfd));
+diff --git a/config.c b/config.c
+index e14eae0..7592b2d 100644
+--- a/config.c
++++ b/config.c
+@@ -80,7 +80,8 @@ char DefaultAltConfFile[] = CONFFILE2;
+ char DefaultAltConfDir[] = CONFFILE2 ".d";
+
+ enum linetype { Devices, Array, Mailaddr, Mailfrom, Program, CreateDev,
+- Homehost, HomeCluster, AutoMode, Policy, PartPolicy, LTEnd };
++ Homehost, HomeCluster, AutoMode, Policy, PartPolicy, Sysfs,
++ LTEnd };
+ char *keywords[] = {
+ [Devices] = "devices",
+ [Array] = "array",
+@@ -93,6 +94,7 @@ char *keywords[] = {
+ [AutoMode] = "auto",
+ [Policy] = "policy",
+ [PartPolicy]="part-policy",
++ [Sysfs] = "sysfs",
+ [LTEnd] = NULL
+ };
+
+@@ -764,6 +766,9 @@ void conf_file(FILE *f)
+ case PartPolicy:
+ policyline(line, rule_part);
+ break;
++ case Sysfs:
++ sysfsline(line);
++ break;
+ default:
+ pr_err("Unknown keyword %s\n", line);
+ }
+diff --git a/mdadm.conf.5 b/mdadm.conf.5
+index 47c962a..27dbab1 100644
+--- a/mdadm.conf.5
++++ b/mdadm.conf.5
+@@ -587,6 +587,26 @@ be based on the domain, but with
+ appended, when N is the partition number for the partition that was
+ found.
+
++.TP
++.B SYSFS
++The 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.
++.TP
++.RS 7
++
+ .SH EXAMPLE
+ DEVICE /dev/sd[bcdjkl]1
+ .br
+@@ -657,6 +677,11 @@ CREATE group=system mode=0640 auto=part\-8
+ 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
+
+ .SH SEE ALSO
+ .BR mdadm (8),
+diff --git a/mdadm.h b/mdadm.h
+index 0fa9e1b..c36d7fd 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1322,6 +1322,9 @@ void domain_add(struct domainlist **domp, char *domain);
+ extern void policy_save_path(char *id_path, struct map_ent *array);
+ extern int policy_check_path(struct mdinfo *disk, struct map_ent *array);
+
++extern void sysfs_rules_apply(char *devnm, struct mdinfo *dev);
++extern void sysfsline(char *line);
++
+ #if __GNUC__ < 3
+ struct stat64;
+ #endif
+diff --git a/sysfs.c b/sysfs.c
+index 2dd9ab6..c313781 100644
+--- a/sysfs.c
++++ b/sysfs.c
+@@ -26,9 +26,22 @@
+ #include "mdadm.h"
+ #include <dirent.h>
+ #include <ctype.h>
++#include "dlink.h"
+
+ #define MAX_SYSFS_PATH_LEN 120
+
++struct dev_sysfs_rule {
++ struct dev_sysfs_rule *next;
++ char *devname;
++ int uuid[4];
++ int uuid_set;
++ struct sysfs_entry {
++ struct sysfs_entry *next;
++ char *name;
++ char *value;
++ } *entry;
++};
++
+ int load_sys(char *path, char *buf, int len)
+ {
+ int fd = open(path, O_RDONLY);
+@@ -999,3 +1012,148 @@ int sysfs_wait(int fd, int *msec)
+ }
+ return n;
+ }
++
++int sysfs_rules_apply_check(const struct mdinfo *sra,
++ const struct sysfs_entry *ent)
++{
++ /* Check whether parameter is regular file,
++ * exists and is under specified directory.
++ */
++ char fname[MAX_SYSFS_PATH_LEN];
++ char dname[MAX_SYSFS_PATH_LEN];
++ char resolved_path[PATH_MAX];
++ char resolved_dir[PATH_MAX];
++
++ if (sra == NULL || ent == NULL)
++ return -1;
++
++ snprintf(dname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/", sra->sys_name);
++ snprintf(fname, MAX_SYSFS_PATH_LEN, "%s/%s", dname, ent->name);
++
++ if (realpath(fname, resolved_path) == NULL ||
++ realpath(dname, resolved_dir) == NULL)
++ return -1;
++
++ if (strncmp(resolved_dir, resolved_path,
++ strnlen(resolved_dir, PATH_MAX)) != 0)
++ return -1;
++
++ return 0;
++}
++
++static struct dev_sysfs_rule *sysfs_rules;
++
++void sysfs_rules_apply(char *devnm, struct mdinfo *dev)
++{
++ struct dev_sysfs_rule *rules = sysfs_rules;
++
++ while (rules) {
++ struct sysfs_entry *ent = rules->entry;
++ int match = 0;
++
++ if (!rules->uuid_set) {
++ if (rules->devname)
++ match = strcmp(devnm, rules->devname) == 0;
++ } else {
++ match = memcmp(dev->uuid, rules->uuid,
++ sizeof(int[4])) == 0;
++ }
++
++ while (match && ent) {
++ if (sysfs_rules_apply_check(dev, ent) < 0)
++ pr_err("SYSFS: failed to write '%s' to '%s'\n",
++ ent->value, ent->name);
++ else
++ sysfs_set_str(dev, NULL, ent->name, ent->value);
++ ent = ent->next;
++ }
++ rules = rules->next;
++ }
++}
++
++static void sysfs_rule_free(struct dev_sysfs_rule *rule)
++{
++ struct sysfs_entry *entry;
++
++ while (rule) {
++ struct dev_sysfs_rule *tmp = rule->next;
++
++ entry = rule->entry;
++ while (entry) {
++ struct sysfs_entry *tmp = entry->next;
++
++ free(entry->name);
++ free(entry->value);
++ free(entry);
++ entry = tmp;
++ }
++
++ if (rule->devname)
++ free(rule->devname);
++ free(rule);
++ rule = tmp;
++ }
++}
++
++void sysfsline(char *line)
++{
++ struct dev_sysfs_rule *sr;
++ char *w;
++
++ sr = xcalloc(1, sizeof(*sr));
++ for (w = dl_next(line); w != line ; w = dl_next(w)) {
++ if (strncasecmp(w, "name=", 5) == 0) {
++ char *devname = w + 5;
++
++ if (strncmp(devname, "/dev/md/", 8) == 0) {
++ if (sr->devname)
++ pr_err("Only give one device per SYSFS line: %s\n",
++ devname);
++ else
++ sr->devname = xstrdup(devname);
++ } else {
++ pr_err("%s is an invalid name for an md device - ignored.\n",
++ devname);
++ }
++ } else if (strncasecmp(w, "uuid=", 5) == 0) {
++ char *uuid = w + 5;
++
++ if (sr->uuid_set) {
++ pr_err("Only give one uuid per SYSFS line: %s\n",
++ uuid);
++ } else {
++ if (parse_uuid(w + 5, sr->uuid) &&
++ memcmp(sr->uuid, uuid_zero,
++ sizeof(int[4])) != 0)
++ sr->uuid_set = 1;
++ else
++ pr_err("Invalid uuid: %s\n", uuid);
++ }
++ } else {
++ struct sysfs_entry *prop;
++
++ char *sep = strchr(w, '=');
++
++ if (sep == NULL || *(sep + 1) == 0) {
++ pr_err("Cannot parse \"%s\" - ignoring.\n", w);
++ continue;
++ }
++
++ prop = xmalloc(sizeof(*prop));
++ prop->value = xstrdup(sep + 1);
++ *sep = 0;
++ prop->name = xstrdup(w);
++ prop->next = sr->entry;
++ sr->entry = prop;
++ }
++ }
++
++ if (!sr->devname && !sr->uuid_set) {
++ pr_err("Device name not found in sysfs config entry - ignoring.\n");
++ sysfs_rule_free(sr);
++ return;
++ }
++
++ sr->next = sysfs_rules;
++ sysfs_rules = sr;
++}
+--
+2.24.0
+
diff --git a/0031-mdadm.h-include-sysmacros.h-unconditionally.patch b/0031-mdadm.h-include-sysmacros.h-unconditionally.patch
new file mode 100644
index 0000000..3efe012
--- /dev/null
+++ b/0031-mdadm.h-include-sysmacros.h-unconditionally.patch
@@ -0,0 +1,34 @@
+From 452dc4d13a012cdcb05088c0dbc699959c4d6c73 Mon Sep 17 00:00:00 2001
+From: Baruch Siach <baruch@tkos.co.il>
+Date: Tue, 6 Aug 2019 16:05:23 +0300
+Subject: [PATCH 31/47] mdadm.h: include sysmacros.h unconditionally
+
+musl libc now also requires sys/sysmacros.h for the major/minor macros.
+All supported libc implementations carry sys/sysmacros.h, including
+diet-libc, klibc, and uclibc-ng.
+
+Cc: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Baruch Siach <baruch@tkos.co.il>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ mdadm.h | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/mdadm.h b/mdadm.h
+index c36d7fd..d61a9ca 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -45,10 +45,8 @@ extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
+ #include <errno.h>
+ #include <string.h>
+ #include <syslog.h>
+-#ifdef __GLIBC__
+ /* Newer glibc requires sys/sysmacros.h directly for makedev() */
+ #include <sys/sysmacros.h>
+-#endif
+ #ifdef __dietlibc__
+ #include <strings.h>
+ /* dietlibc has deprecated random and srandom!! */
+--
+2.24.0
+
diff --git a/0032-mdadm-add-no-devices-to-avoid-component-devices-deta.patch b/0032-mdadm-add-no-devices-to-avoid-component-devices-deta.patch
new file mode 100644
index 0000000..467095a
--- /dev/null
+++ b/0032-mdadm-add-no-devices-to-avoid-component-devices-deta.patch
@@ -0,0 +1,161 @@
+From d11abe4bd5cad39803726ddff1888674e417bda5 Mon Sep 17 00:00:00 2001
+From: Coly Li <colyli@suse.de>
+Date: Wed, 31 Jul 2019 13:29:29 +0800
+Subject: [PATCH 32/47] mdadm: add --no-devices to avoid component devices
+ detail information
+
+When people assemble a md raid device with a large number of
+component deivces (e.g. 1500 DASD disks), the raid device detail
+information generated by 'mdadm --detail --export $devnode' is very
+large. It is because the detail information contains information of
+all the component disks (even the missing/failed ones).
+
+In such condition, when udev-md-raid-arrays.rules is triggered and
+internally calls "mdadm --detail --no-devices --export $devnode",
+user may observe systemd error message ""invalid message length". It
+is because the following on-stack raw message buffer in systemd code
+is not big enough,
+ systemd/src/libudev/libudev-monitor.c
+ _public_ struct udev_device *udev_monito ...
+ struct ucred *cred;
+ union {
+ struct udev_monitor_netlink_header nlh;
+ char raw[8192];
+ } buf;
+Even change size of raw[] from 8KB to larger size, it may still be not
+enough for detail message of a md raid device with much larger number of
+component devices.
+
+To fix this problem, an extra option '--no-devices' is added (the
+original idea is proposed by Neil Brown). When printing detailed
+information of a md raid device, if '--no-devices' is specified, then
+all component devices information will not be printed, then the output
+message size can be restricted to a small number, even with the systemd
+only has 8KB on-disk raw buffer, the md raid array udev rules can work
+correctly without failure message.
+
+Signed-off-by: Coly Li <colyli@suse.de>
+Reviewed-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Detail.c | 24 ++++++++++++++++--------
+ ReadMe.c | 1 +
+ mdadm.c | 4 ++++
+ mdadm.h | 2 ++
+ 4 files changed, 23 insertions(+), 8 deletions(-)
+
+diff --git a/Detail.c b/Detail.c
+index 20ea03a..ad60434 100644
+--- a/Detail.c
++++ b/Detail.c
+@@ -56,7 +56,7 @@ int Detail(char *dev, struct context *c)
+ */
+ int fd = open(dev, O_RDONLY);
+ mdu_array_info_t array;
+- mdu_disk_info_t *disks;
++ mdu_disk_info_t *disks = NULL;
+ int next;
+ int d;
+ time_t atime;
+@@ -280,7 +280,7 @@ int Detail(char *dev, struct context *c)
+ }
+ map_free(map);
+ }
+- if (sra) {
++ if (!c->no_devices && sra) {
+ struct mdinfo *mdi;
+ for (mdi = sra->devs; mdi; mdi = mdi->next) {
+ char *path;
+@@ -655,12 +655,17 @@ This is pretty boring
+ printf("\n\n");
+ }
+
+- if (array.raid_disks)
+- printf(" Number Major Minor RaidDevice State\n");
+- else
+- printf(" Number Major Minor RaidDevice\n");
++ if (!c->no_devices) {
++ if (array.raid_disks)
++ printf(" Number Major Minor RaidDevice State\n");
++ else
++ printf(" Number Major Minor RaidDevice\n");
++ }
+ }
+- free(info);
++
++ /* if --no_devices specified, not print component devices info */
++ if (c->no_devices)
++ goto skip_devices_state;
+
+ for (d = 0; d < max_disks * 2; d++) {
+ char *dv;
+@@ -747,6 +752,8 @@ This is pretty boring
+ if (!c->brief)
+ printf("\n");
+ }
++
++skip_devices_state:
+ if (spares && c->brief && array.raid_disks)
+ printf(" spares=%d", spares);
+ if (c->brief && st && st->sb)
+@@ -766,8 +773,9 @@ This is pretty boring
+ !enough(array.level, array.raid_disks, array.layout, 1, avail))
+ rv = 2;
+
+- free(disks);
+ out:
++ free(info);
++ free(disks);
+ close(fd);
+ free(subarray);
+ free(avail);
+diff --git a/ReadMe.c b/ReadMe.c
+index 12ccf83..eaf1042 100644
+--- a/ReadMe.c
++++ b/ReadMe.c
+@@ -181,6 +181,7 @@ struct option long_options[] = {
+
+ /* For Detail/Examine */
+ {"brief", 0, 0, Brief},
++ {"no-devices",0, 0, NoDevices},
+ {"export", 0, 0, 'Y'},
+ {"sparc2.2", 0, 0, Sparc22},
+ {"test", 0, 0, 't'},
+diff --git a/mdadm.c b/mdadm.c
+index 25a1abd..1fb8086 100644
+--- a/mdadm.c
++++ b/mdadm.c
+@@ -159,6 +159,10 @@ int main(int argc, char *argv[])
+ c.brief = 1;
+ continue;
+
++ case NoDevices:
++ c.no_devices = 1;
++ continue;
++
+ case 'Y': c.export++;
+ continue;
+
+diff --git a/mdadm.h b/mdadm.h
+index d61a9ca..43b07d5 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -440,6 +440,7 @@ enum special_options {
+ NoSharing,
+ HelpOptions,
+ Brief,
++ NoDevices,
+ ManageOpt,
+ Add,
+ AddSpare,
+@@ -550,6 +551,7 @@ struct context {
+ int runstop;
+ int verbose;
+ int brief;
++ int no_devices;
+ int force;
+ char *homehost;
+ int require_homehost;
+--
+2.24.0
+
diff --git a/0033-udev-add-no-devices-option-for-calling-mdadm-detail.patch b/0033-udev-add-no-devices-option-for-calling-mdadm-detail.patch
new file mode 100644
index 0000000..71681b5
--- /dev/null
+++ b/0033-udev-add-no-devices-option-for-calling-mdadm-detail.patch
@@ -0,0 +1,42 @@
+From 1a52f1fc0266d438c996789d4addbfac999a6139 Mon Sep 17 00:00:00 2001
+From: Coly Li <colyli@suse.de>
+Date: Wed, 31 Jul 2019 13:29:30 +0800
+Subject: [PATCH 33/47] udev: add --no-devices option for calling 'mdadm
+ --detail'
+
+When creating symlink of a md raid device, the detailed information of
+component disks are unnecessary for rule udev-md-raid-arrays.rules. For
+md raid devices with huge number of component disks (e.g. 1500 DASD
+disks), the detail information of component devices can be very large
+and exceed udev monitor's on-stack message buffer.
+
+This patch adds '--no-devices' option when calling mdadm by,
+IMPORT{program}="BINDIR/mdadm --detail --no-devices --export $devnode"
+
+Now the detailed output won't include component disks information,
+and the error message "invalid message length" reported by systemd can
+be removed.
+
+Signed-off-by: Coly Li <colyli@suse.de>
+Reviewed-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ udev-md-raid-arrays.rules | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/udev-md-raid-arrays.rules b/udev-md-raid-arrays.rules
+index 5b99d58..d391665 100644
+--- a/udev-md-raid-arrays.rules
++++ b/udev-md-raid-arrays.rules
+@@ -17,7 +17,7 @@ TEST!="md/array_state", ENV{SYSTEMD_READY}="0", GOTO="md_end"
+ ATTR{md/array_state}=="|clear|inactive", ENV{SYSTEMD_READY}="0", GOTO="md_end"
+ LABEL="md_ignore_state"
+
+-IMPORT{program}="BINDIR/mdadm --detail --export $devnode"
++IMPORT{program}="BINDIR/mdadm --detail --no-devices --export $devnode"
+ ENV{DEVTYPE}=="disk", ENV{MD_NAME}=="?*", SYMLINK+="disk/by-id/md-name-$env{MD_NAME}", OPTIONS+="string_escape=replace"
+ ENV{DEVTYPE}=="disk", ENV{MD_UUID}=="?*", SYMLINK+="disk/by-id/md-uuid-$env{MD_UUID}"
+ ENV{DEVTYPE}=="disk", ENV{MD_DEVNAME}=="?*", SYMLINK+="md/$env{MD_DEVNAME}"
+--
+2.24.0
+
diff --git a/0034-imsm-close-removed-drive-fd.patch b/0034-imsm-close-removed-drive-fd.patch
new file mode 100644
index 0000000..1923cc9
--- /dev/null
+++ b/0034-imsm-close-removed-drive-fd.patch
@@ -0,0 +1,44 @@
+From 91c97c5432028875db5f8abeddb5cb5f31902001 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Date: Mon, 15 Jul 2019 09:25:35 +0200
+Subject: [PATCH 34/47] imsm: close removed drive fd.
+
+When member drive fails, managemon prepares metadata update and adds
+the drive to disk_mgmt_list with DISK_REMOVE flag. It fills only
+minor and major. It is enough to recognize the device later.
+
+Monitor thread while processing this update will remove the drive from
+super only if it is a spare. It never removes failed member from
+disks list. As a result, it still keeps opened descriptor to
+non-existing device.
+
+If removed drive is not a spare fill fd in disk_cfg structure
+(prepared by managemon), monitor will close fd during freeing it.
+
+Also set this drive fd to -1 in super to avoid double closing because
+monitor will close the fd (if needed) while replacing removed drive
+in array.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/super-intel.c b/super-intel.c
+index d7e8a65..a103a3f 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -9200,6 +9200,9 @@ static int add_remove_disk_update(struct intel_super *super)
+ remove_disk_super(super,
+ disk_cfg->major,
+ disk_cfg->minor);
++ } else {
++ disk_cfg->fd = disk->fd;
++ disk->fd = -1;
+ }
+ }
+ /* release allocate disk structure */
+--
+2.24.0
+
diff --git a/0035-mdadm-check-value-returned-by-snprintf-against-error.patch b/0035-mdadm-check-value-returned-by-snprintf-against-error.patch
new file mode 100644
index 0000000..d79923e
--- /dev/null
+++ b/0035-mdadm-check-value-returned-by-snprintf-against-error.patch
@@ -0,0 +1,45 @@
+From fd5b09c9a9107f0393ce194c4aac6e7b8f163e85 Mon Sep 17 00:00:00 2001
+From: Krzysztof Smolinski <krzysztof.smolinski@intel.com>
+Date: Fri, 16 Aug 2019 11:06:17 +0200
+Subject: [PATCH 35/47] mdadm: check value returned by snprintf against errors
+
+GCC 8 checks possible truncation during snprintf more strictly
+than GCC 7 which result in compilation errors. To fix this
+problem checking result of snprintf against errors has been added.
+
+Signed-off-by: Krzysztof Smolinski <krzysztof.smolinski@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ sysfs.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/sysfs.c b/sysfs.c
+index c313781..2995713 100644
+--- a/sysfs.c
++++ b/sysfs.c
+@@ -1023,12 +1023,20 @@ int sysfs_rules_apply_check(const struct mdinfo *sra,
+ char dname[MAX_SYSFS_PATH_LEN];
+ char resolved_path[PATH_MAX];
+ char resolved_dir[PATH_MAX];
++ int result;
+
+ if (sra == NULL || ent == NULL)
+ return -1;
+
+- snprintf(dname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/", sra->sys_name);
+- snprintf(fname, MAX_SYSFS_PATH_LEN, "%s/%s", dname, ent->name);
++ result = snprintf(dname, MAX_SYSFS_PATH_LEN,
++ "/sys/block/%s/md/", sra->sys_name);
++ if (result < 0 || result >= MAX_SYSFS_PATH_LEN)
++ return -1;
++
++ result = snprintf(fname, MAX_SYSFS_PATH_LEN,
++ "%s/%s", dname, ent->name);
++ if (result < 0 || result >= MAX_SYSFS_PATH_LEN)
++ return -1;
+
+ if (realpath(fname, resolved_path) == NULL ||
+ realpath(dname, resolved_dir) == NULL)
+--
+2.24.0
+
diff --git a/0036-mdadm-Introduce-new-array-state-broken-for-raid0-lin.patch b/0036-mdadm-Introduce-new-array-state-broken-for-raid0-lin.patch
new file mode 100644
index 0000000..ce77b3f
--- /dev/null
+++ b/0036-mdadm-Introduce-new-array-state-broken-for-raid0-lin.patch
@@ -0,0 +1,163 @@
+From 43ebc9105e9dafe5145b3e801c05da4736bf6e02 Mon Sep 17 00:00:00 2001
+From: "Guilherme G. Piccoli" <gpiccoli@canonical.com>
+Date: Tue, 3 Sep 2019 16:49:01 -0300
+Subject: [PATCH 36/47] mdadm: Introduce new array state 'broken' for
+ raid0/linear
+
+Currently if a md raid0/linear array gets one or more members removed while
+being mounted, kernel keeps showing state 'clean' in the 'array_state'
+sysfs attribute. Despite udev signaling the member device is gone, 'mdadm'
+cannot issue the STOP_ARRAY ioctl successfully, given the array is mounted.
+
+Nothing else hints that something is wrong (except that the removed devices
+don't show properly in the output of mdadm 'detail' command). There is no
+other property to be checked, and if user is not performing reads/writes
+to the array, even kernel log is quiet and doesn't give a clue about the
+missing member.
+
+This patch is the mdadm counterpart of kernel new array state 'broken'.
+The 'broken' state mimics the state 'clean' in every aspect, being useful
+only to distinguish if an array has some member missing. All necessary
+paths in mdadm were changed to deal with 'broken' state, and in case the
+tool runs in a kernel that is not updated, it'll work normally, i.e., it
+doesn't require the 'broken' state in order to work.
+Also, this patch changes the way the array state is showed in the 'detail'
+command (for raid0/linear only) - now it takes the 'array_state' sysfs
+attribute into account instead of only rely in the MD_SB_CLEAN flag.
+
+Cc: Jes Sorensen <jes.sorensen@gmail.com>
+Cc: NeilBrown <neilb@suse.de>
+Cc: Song Liu <songliubraving@fb.com>
+Signed-off-by: Guilherme G. Piccoli <gpiccoli@canonical.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Detail.c | 14 ++++++++++++--
+ Monitor.c | 8 ++++++--
+ maps.c | 1 +
+ mdadm.h | 1 +
+ mdmon.h | 2 +-
+ monitor.c | 4 ++--
+ 6 files changed, 23 insertions(+), 7 deletions(-)
+
+diff --git a/Detail.c b/Detail.c
+index ad60434..3e61e37 100644
+--- a/Detail.c
++++ b/Detail.c
+@@ -81,6 +81,7 @@ int Detail(char *dev, struct context *c)
+ int external;
+ int inactive;
+ int is_container = 0;
++ char *arrayst;
+
+ if (fd < 0) {
+ pr_err("cannot open %s: %s\n",
+@@ -485,9 +486,18 @@ int Detail(char *dev, struct context *c)
+ else
+ st = ", degraded";
+
++ if (array.state & (1 << MD_SB_CLEAN)) {
++ if ((array.level == 0) ||
++ (array.level == LEVEL_LINEAR))
++ arrayst = map_num(sysfs_array_states,
++ sra->array_state);
++ else
++ arrayst = "clean";
++ } else
++ arrayst = "active";
++
+ printf(" State : %s%s%s%s%s%s \n",
+- (array.state & (1 << MD_SB_CLEAN)) ?
+- "clean" : "active", st,
++ arrayst, st,
+ (!e || (e->percent < 0 &&
+ e->percent != RESYNC_PENDING &&
+ e->percent != RESYNC_DELAYED)) ?
+diff --git a/Monitor.c b/Monitor.c
+index 036103f..b527165 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -1055,8 +1055,11 @@ int Wait(char *dev)
+ }
+ }
+
++/* The state "broken" is used only for RAID0/LINEAR - it's the same as
++ * "clean", but used in case the array has one or more members missing.
++ */
+ static char *clean_states[] = {
+- "clear", "inactive", "readonly", "read-auto", "clean", NULL };
++ "clear", "inactive", "readonly", "read-auto", "clean", "broken", NULL };
+
+ int WaitClean(char *dev, int verbose)
+ {
+@@ -1116,7 +1119,8 @@ int WaitClean(char *dev, int verbose)
+ rv = read(state_fd, buf, sizeof(buf));
+ if (rv < 0)
+ break;
+- if (sysfs_match_word(buf, clean_states) <= 4)
++ if (sysfs_match_word(buf, clean_states) <
++ (int)ARRAY_SIZE(clean_states) - 1)
+ break;
+ rv = sysfs_wait(state_fd, &delay);
+ if (rv < 0 && errno != EINTR)
+diff --git a/maps.c b/maps.c
+index 02a0474..49b7f2c 100644
+--- a/maps.c
++++ b/maps.c
+@@ -150,6 +150,7 @@ mapping_t sysfs_array_states[] = {
+ { "read-auto", ARRAY_READ_AUTO },
+ { "clean", ARRAY_CLEAN },
+ { "write-pending", ARRAY_WRITE_PENDING },
++ { "broken", ARRAY_BROKEN },
+ { NULL, ARRAY_UNKNOWN_STATE }
+ };
+
+diff --git a/mdadm.h b/mdadm.h
+index 43b07d5..c88ceab 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -373,6 +373,7 @@ struct mdinfo {
+ ARRAY_ACTIVE,
+ ARRAY_WRITE_PENDING,
+ ARRAY_ACTIVE_IDLE,
++ ARRAY_BROKEN,
+ ARRAY_UNKNOWN_STATE,
+ } array_state;
+ struct md_bb bb;
+diff --git a/mdmon.h b/mdmon.h
+index 818367c..b3d72ac 100644
+--- a/mdmon.h
++++ b/mdmon.h
+@@ -21,7 +21,7 @@
+ extern const char Name[];
+
+ enum array_state { clear, inactive, suspended, readonly, read_auto,
+- clean, active, write_pending, active_idle, bad_word};
++ clean, active, write_pending, active_idle, broken, bad_word};
+
+ enum sync_action { idle, reshape, resync, recover, check, repair, bad_action };
+
+diff --git a/monitor.c b/monitor.c
+index 81537ed..e0d3be6 100644
+--- a/monitor.c
++++ b/monitor.c
+@@ -26,7 +26,7 @@
+
+ static char *array_states[] = {
+ "clear", "inactive", "suspended", "readonly", "read-auto",
+- "clean", "active", "write-pending", "active-idle", NULL };
++ "clean", "active", "write-pending", "active-idle", "broken", NULL };
+ static char *sync_actions[] = {
+ "idle", "reshape", "resync", "recover", "check", "repair", NULL
+ };
+@@ -476,7 +476,7 @@ static int read_and_act(struct active_array *a, fd_set *fds)
+ a->next_state = clean;
+ ret |= ARRAY_DIRTY;
+ }
+- if (a->curr_state == clean) {
++ if ((a->curr_state == clean) || (a->curr_state == broken)) {
+ a->container->ss->set_array_state(a, 1);
+ }
+ if (a->curr_state == active ||
+--
+2.24.0
+
diff --git a/0037-mdadm-force-a-uuid-swap-on-big-endian.patch b/0037-mdadm-force-a-uuid-swap-on-big-endian.patch
new file mode 100644
index 0000000..d07f04d
--- /dev/null
+++ b/0037-mdadm-force-a-uuid-swap-on-big-endian.patch
@@ -0,0 +1,40 @@
+From 2c2d9c48d2daf0d78d20494c3779c0f6dc4bfa75 Mon Sep 17 00:00:00 2001
+From: Nigel Croxon <ncroxon@redhat.com>
+Date: Tue, 24 Sep 2019 11:39:24 -0400
+Subject: [PATCH 37/47] mdadm: force a uuid swap on big endian
+
+The code path for metadata 0.90 calls a common routine
+fname_from_uuid that uses metadata 1.2. The code expects member
+swapuuid to be setup and usable. But it is only setup when using
+metadata 1.2. Since the metadata 0.90 did not create swapuuid
+and set it. The test (st->ss == &super1) ? 1 : st->ss->swapuuid
+fails. The swapuuid is set at compile time based on byte order.
+Any call based on metadata 0.90 and on big endian processors,
+the --export uuid will be incorrect.
+
+Signed-Off-by: Nigel Croxon <ncroxon@redhat.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ util.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/util.c b/util.c
+index c26cf5f..64dd409 100644
+--- a/util.c
++++ b/util.c
+@@ -685,8 +685,12 @@ char *fname_from_uuid(struct supertype *st, struct mdinfo *info,
+ // work, but can't have it set if we want this printout to match
+ // all the other uuid printouts in super1.c, so we force swapuuid
+ // to 1 to make our printout match the rest of super1
++#if __BYTE_ORDER == BIG_ENDIAN
++ return __fname_from_uuid(info->uuid, 1, buf, sep);
++#else
+ return __fname_from_uuid(info->uuid, (st->ss == &super1) ? 1 :
+ st->ss->swapuuid, buf, sep);
++#endif
+ }
+
+ int check_ext2(int fd, char *name)
+--
+2.24.0
+
diff --git a/0038-mdadm-md.4-add-the-descriptions-for-bitmap-sysfs-nod.patch b/0038-mdadm-md.4-add-the-descriptions-for-bitmap-sysfs-nod.patch
new file mode 100644
index 0000000..ac2089b
--- /dev/null
+++ b/0038-mdadm-md.4-add-the-descriptions-for-bitmap-sysfs-nod.patch
@@ -0,0 +1,98 @@
+From e53cb968691d9e40d83caf5570da3bb7b83c64e1 Mon Sep 17 00:00:00 2001
+From: Guoqing Jiang <gqjiang@suse.com>
+Date: Fri, 31 May 2019 10:10:00 +0800
+Subject: [PATCH 38/47] mdadm/md.4: add the descriptions for bitmap sysfs nodes
+
+The sysfs nodes under bitmap are not recorded in md.4,
+add them based on md.rst and kernel source code.
+
+Cc: NeilBrown <neilb@suse.com>
+Signed-off-by: Guoqing Jiang <gqjiang@suse.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ md.4 | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 69 insertions(+)
+
+diff --git a/md.4 b/md.4
+index 3a1d677..e86707a 100644
+--- a/md.4
++++ b/md.4
+@@ -1101,6 +1101,75 @@ stripe that requires some "prereading". For fairness this defaults to
+ maximizes sequential-write throughput at the cost of fairness to threads
+ doing small or random writes.
+
++.TP
++.B md/bitmap/backlog
++The value stored in the file only has any effect on RAID1 when write-mostly
++devices are active, and write requests to those devices are proceed in the
++background.
++
++This variable sets a limit on the number of concurrent background writes,
++the valid values are 0 to 16383, 0 means that write-behind is not allowed,
++while any other number means it can happen. If there are more write requests
++than the number, new writes will by synchronous.
++
++.TP
++.B md/bitmap/can_clear
++This is for externally managed bitmaps, where the kernel writes the bitmap
++itself, but metadata describing the bitmap is managed by mdmon or similar.
++
++When the array is degraded, bits mustn't be cleared. When the array becomes
++optimal again, bit can be cleared, but first the metadata needs to record
++the current event count. So md sets this to 'false' and notifies mdmon,
++then mdmon updates the metadata and writes 'true'.
++
++There is no code in mdmon to actually do this, so maybe it doesn't even
++work.
++
++.TP
++.B md/bitmap/chunksize
++The bitmap chunksize can only be changed when no bitmap is active, and
++the value should be power of 2 and at least 512.
++
++.TP
++.B md/bitmap/location
++This indicates where the write-intent bitmap for the array is stored.
++It can be "none" or "file" or a signed offset from the array metadata
++- measured in sectors. You cannot set a file by writing here - that can
++only be done with the SET_BITMAP_FILE ioctl.
++
++Write 'none' to 'bitmap/location' will clear bitmap, and the previous
++location value must be write to it to restore bitmap.
++
++.TP
++.B md/bitmap/max_backlog_used
++This keeps track of the maximum number of concurrent write-behind requests
++for an md array, writing any value to this file will clear it.
++
++.TP
++.B md/bitmap/metadata
++This can be 'internal' or 'clustered' or 'external'. 'internal' is set
++by default, which means the metadata for bitmap is stored in the first 256
++bytes of the bitmap space. 'clustered' means separate bitmap metadata are
++used for each cluster node. 'external' means that bitmap metadata is managed
++externally to the kernel.
++
++.TP
++.B md/bitmap/space
++This shows the space (in sectors) which is available at md/bitmap/location,
++and allows the kernel to know when it is safe to resize the bitmap to match
++a resized array. It should big enough to contain the total bytes in the bitmap.
++
++For 1.0 metadata, assume we can use up to the superblock if before, else
++to 4K beyond superblock. For other metadata versions, assume no change is
++possible.
++
++.TP
++.B md/bitmap/time_base
++This shows the time (in seconds) between disk flushes, and is used to looking
++for bits in the bitmap to be cleared.
++
++The default value is 5 seconds, and it should be an unsigned long value.
++
+ .SS KERNEL PARAMETERS
+
+ The md driver recognised several different kernel parameters.
+--
+2.24.0
+
diff --git a/0039-Init-devlist-as-an-array.patch b/0039-Init-devlist-as-an-array.patch
new file mode 100644
index 0000000..4b2a0d6
--- /dev/null
+++ b/0039-Init-devlist-as-an-array.patch
@@ -0,0 +1,35 @@
+From 8063fd0f9e8abd718bd65928c19bc607cee5acd8 Mon Sep 17 00:00:00 2001
+From: Xiao Ni <xni@redhat.com>
+Date: Mon, 30 Sep 2019 19:47:59 +0800
+Subject: [PATCH 39/47] Init devlist as an array
+
+devlist is an string. It will change to an array if there is disk that
+is sbd disk. If one device is sbd, it runs devlist=().
+This line code changes devlist from a string to an array. If there is
+no sbd device, it can't run this line code. So it will still be a string.
+The later codes need an array, rather than an string. So init devlist
+as an array to fix this problem.
+
+Signed-off-by: Xiao Ni <xni@redhat.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ clustermd_tests/func.sh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/clustermd_tests/func.sh b/clustermd_tests/func.sh
+index 642cc96..801d604 100644
+--- a/clustermd_tests/func.sh
++++ b/clustermd_tests/func.sh
+@@ -39,6 +39,9 @@ fetch_devlist()
+ devlist=($(ls /dev/disk/by-path/*$ISCSI_ID*))
+ fi
+ # sbd disk cannot use in testing
++ # Init devlist as an array
++ i=''
++ devlist=(${devlist[@]#$i})
+ for i in ${devlist[@]}
+ do
+ sbd -d $i dump &> /dev/null
+--
+2.24.0
+
diff --git a/0040-Don-t-need-to-check-recovery-after-re-add-when-no-I-.patch b/0040-Don-t-need-to-check-recovery-after-re-add-when-no-I-.patch
new file mode 100644
index 0000000..82c70e2
--- /dev/null
+++ b/0040-Don-t-need-to-check-recovery-after-re-add-when-no-I-.patch
@@ -0,0 +1,31 @@
+From 611093148574164fcf4f24f8c076d09473f655d7 Mon Sep 17 00:00:00 2001
+From: Xiao Ni <xni@redhat.com>
+Date: Mon, 30 Sep 2019 19:48:00 +0800
+Subject: [PATCH 40/47] Don't need to check recovery after re-add when no I/O
+ writes to raid
+
+If there is no write I/O between removing member disk and re-add it, there is no
+recovery after re-adding member disk.
+
+Signed-off-by: Xiao Ni <xni@redhat.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ clustermd_tests/02r1_Manage_re-add | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/clustermd_tests/02r1_Manage_re-add b/clustermd_tests/02r1_Manage_re-add
+index dd9c416..d0d13e5 100644
+--- a/clustermd_tests/02r1_Manage_re-add
++++ b/clustermd_tests/02r1_Manage_re-add
+@@ -9,8 +9,6 @@ check all state UU
+ check all dmesg
+ mdadm --manage $md0 --fail $dev0 --remove $dev0
+ mdadm --manage $md0 --re-add $dev0
+-check $NODE1 recovery
+-check all wait
+ check all state UU
+ check all dmesg
+ stop_md all $md0
+--
+2.24.0
+
diff --git a/0041-udev-allow-for-udev-attribute-reading-bug.patch b/0041-udev-allow-for-udev-attribute-reading-bug.patch
new file mode 100644
index 0000000..7270307
--- /dev/null
+++ b/0041-udev-allow-for-udev-attribute-reading-bug.patch
@@ -0,0 +1,47 @@
+From 7bd59e7926c6921121087eb067befaa896c900a4 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Wed, 18 Sep 2019 15:12:55 +1000
+Subject: [PATCH 41/47] udev: allow for udev attribute reading bug.
+
+There is a bug in udev (which will hopefully get fixed, but
+we should allow for it anways).
+When reading a sysfs attribute, it first reads the whole
+value of the attribute, then reads again expecting to get
+a read of 0 bytes, like you would with an ordinary file.
+If the sysfs attribute changed between these two reads, it can
+get a mixture of two values.
+
+In particular, if it reads when 'array_state' is changing from
+'clear' to 'inactive', it can find the value as "clear\nve".
+
+This causes the test for "|clear|active" to fail, so systemd is allowed
+to think that the array is ready - when it isn't.
+
+So change the pattern to allow for this but adding a wildcard at
+the end.
+Also don't allow for an empty string - reading array_state will
+never return an empty string - if it exists at all, it will be
+non-empty.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ udev-md-raid-arrays.rules | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/udev-md-raid-arrays.rules b/udev-md-raid-arrays.rules
+index d391665..c8fa8e8 100644
+--- a/udev-md-raid-arrays.rules
++++ b/udev-md-raid-arrays.rules
+@@ -14,7 +14,7 @@ ENV{DEVTYPE}=="partition", GOTO="md_ignore_state"
+ # never leave state 'inactive'
+ ATTR{md/metadata_version}=="external:[A-Za-z]*", ATTR{md/array_state}=="inactive", GOTO="md_ignore_state"
+ TEST!="md/array_state", ENV{SYSTEMD_READY}="0", GOTO="md_end"
+-ATTR{md/array_state}=="|clear|inactive", ENV{SYSTEMD_READY}="0", GOTO="md_end"
++ATTR{md/array_state}=="clear*|inactive", ENV{SYSTEMD_READY}="0", GOTO="md_end"
+ LABEL="md_ignore_state"
+
+ IMPORT{program}="BINDIR/mdadm --detail --no-devices --export $devnode"
+--
+2.24.0
+
diff --git a/0042-imsm-save-current_vol-number.patch b/0042-imsm-save-current_vol-number.patch
new file mode 100644
index 0000000..2103a99
--- /dev/null
+++ b/0042-imsm-save-current_vol-number.patch
@@ -0,0 +1,40 @@
+From b6180160f78f0182b296bdceed6419b26a6fccc7 Mon Sep 17 00:00:00 2001
+From: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Date: Fri, 4 Oct 2019 12:07:28 +0200
+Subject: [PATCH 42/47] imsm: save current_vol number
+
+The imsm container_content routine will set curr_volume index in super
+for getting volume information. This flag has never been restored to
+original value, later other function may rely on it.
+
+Restore this flag to original value.
+
+Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/super-intel.c b/super-intel.c
+index a103a3f..e02bbd7 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -7826,6 +7826,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
+ int sb_errors = 0;
+ struct dl *d;
+ int spare_disks = 0;
++ int current_vol = super->current_vol;
+
+ /* do not assemble arrays when not all attributes are supported */
+ if (imsm_check_attributes(mpb->attributes) == 0) {
+@@ -7993,6 +7994,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
+ rest = this;
+ }
+
++ super->current_vol = current_vol;
+ return rest;
+ }
+
+--
+2.24.0
+
diff --git a/0043-imsm-allow-to-specify-second-volume-size.patch b/0043-imsm-allow-to-specify-second-volume-size.patch
new file mode 100644
index 0000000..bc15944
--- /dev/null
+++ b/0043-imsm-allow-to-specify-second-volume-size.patch
@@ -0,0 +1,50 @@
+From 1a1ced1e2e64a6b4b349a3fb559f6b39e4cf7103 Mon Sep 17 00:00:00 2001
+From: Krzysztof Smolinski <krzysztof.smolinski@intel.com>
+Date: Fri, 8 Nov 2019 11:59:11 +0100
+Subject: [PATCH 43/47] imsm: allow to specify second volume size
+
+Removed checks which limited second volume size only to max value (the
+largest size that fits on all current drives). It is now permitted
+to create second volume with size lower then maximum possible.
+
+Signed-off-by: Krzysztof Smolinski <krzysztof.smolinski@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 14 ++++----------
+ 1 file changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index e02bbd7..713058c 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -7298,11 +7298,8 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
+
+ maxsize = merge_extents(super, i);
+
+- if (!check_env("IMSM_NO_PLATFORM") &&
+- mpb->num_raid_devs > 0 && size && size != maxsize) {
+- pr_err("attempting to create a second volume with size less then remaining space. Aborting...\n");
+- return 0;
+- }
++ if (mpb->num_raid_devs > 0 && size && size != maxsize)
++ pr_err("attempting to create a second volume with size less then remaining space.\n");
+
+ if (maxsize < size || maxsize == 0) {
+ if (verbose) {
+@@ -7393,11 +7390,8 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks,
+ }
+ maxsize = size;
+ }
+- if (!check_env("IMSM_NO_PLATFORM") &&
+- mpb->num_raid_devs > 0 && size && size != maxsize) {
+- pr_err("attempting to create a second volume with size less then remaining space. Aborting...\n");
+- return 0;
+- }
++ 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)
+--
+2.24.0
+
diff --git a/0044-mdcheck-when-mdcheck_start-is-enabled-enable-mdcheck.patch b/0044-mdcheck-when-mdcheck_start-is-enabled-enable-mdcheck.patch
new file mode 100644
index 0000000..54cf75a
--- /dev/null
+++ b/0044-mdcheck-when-mdcheck_start-is-enabled-enable-mdcheck.patch
@@ -0,0 +1,45 @@
+From 6636788aaf4ec0cacaefb6e77592e4a68e70a957 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Wed, 30 Oct 2019 10:32:41 +1100
+Subject: [PATCH 44/47] mdcheck: when mdcheck_start is enabled, enable
+ mdcheck_continue too.
+
+mdcheck_continue continues a regular array scan that was started by
+mdcheck_start.
+mdcheck_start will ensure that mdcheck_continue is active.
+Howver if you reboot after a check has started, but before it finishes,
+then mdcheck_continue won't cause it to continue, because nothing
+starts it on boot.
+
+So add an install option for mdcheck_contine, and make sure it
+gets enabled when mdcheck_start is enabled.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ systemd/mdcheck_continue.timer | 2 ++
+ systemd/mdcheck_start.timer | 1 +
+ 2 files changed, 3 insertions(+)
+
+diff --git a/systemd/mdcheck_continue.timer b/systemd/mdcheck_continue.timer
+index 3ccfd78..dba1074 100644
+--- a/systemd/mdcheck_continue.timer
++++ b/systemd/mdcheck_continue.timer
+@@ -11,3 +11,5 @@ Description=MD array scrubbing - continuation
+ [Timer]
+ OnCalendar= 1:05:00
+
++[Install]
++WantedBy= mdmonitor.service
+diff --git a/systemd/mdcheck_start.timer b/systemd/mdcheck_start.timer
+index 6480736..9e7e02a 100644
+--- a/systemd/mdcheck_start.timer
++++ b/systemd/mdcheck_start.timer
+@@ -13,3 +13,4 @@ OnCalendar=Sun *-*-1..7 1:00:00
+
+ [Install]
+ WantedBy= mdmonitor.service
++Also= mdcheck_continue.timer
+--
+2.24.0
+
diff --git a/0045-mdcheck-use-to-pass-variable-to-mdcheck.patch b/0045-mdcheck-use-to-pass-variable-to-mdcheck.patch
new file mode 100644
index 0000000..06b1f22
--- /dev/null
+++ b/0045-mdcheck-use-to-pass-variable-to-mdcheck.patch
@@ -0,0 +1,51 @@
+From 4ca799c581703d4d0ad840833c037c2fff088ca7 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Wed, 30 Oct 2019 10:32:41 +1100
+Subject: [PATCH 45/47] mdcheck: use ${} to pass variable to mdcheck
+
+$MDADM_CHECK_DURATION allows the value to be split on spaces.
+${MDADM_CHECK_DURATION} avoids such splitting.
+
+Making this change removes the need for double quoting when setting
+the default Environment, and means that double quoting isn't needed
+in the EnvironmentFile.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ systemd/mdcheck_continue.service | 5 ++---
+ systemd/mdcheck_start.service | 4 ++--
+ 2 files changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/systemd/mdcheck_continue.service b/systemd/mdcheck_continue.service
+index 592c607..deac695 100644
+--- a/systemd/mdcheck_continue.service
++++ b/systemd/mdcheck_continue.service
+@@ -11,8 +11,7 @@ ConditionPathExistsGlob = /var/lib/mdcheck/MD_UUID_*
+
+ [Service]
+ Type=oneshot
+-Environment= MDADM_CHECK_DURATION='"6 hours"'
++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
+-
++ExecStart=/usr/share/mdadm/mdcheck --continue --duration ${MDADM_CHECK_DURATION}
+diff --git a/systemd/mdcheck_start.service b/systemd/mdcheck_start.service
+index 812141b..f17f1aa 100644
+--- a/systemd/mdcheck_start.service
++++ b/systemd/mdcheck_start.service
+@@ -11,7 +11,7 @@ Wants=mdcheck_continue.timer
+
+ [Service]
+ Type=oneshot
+-Environment= MDADM_CHECK_DURATION='"6 hours"'
++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
++ExecStart=/usr/share/mdadm/mdcheck --duration ${MDADM_CHECK_DURATION}
+--
+2.24.0
+
diff --git a/0046-SUSE-mdadm_env.sh-handle-MDADM_CHECK_DURATION.patch b/0046-SUSE-mdadm_env.sh-handle-MDADM_CHECK_DURATION.patch
new file mode 100644
index 0000000..23be4bb
--- /dev/null
+++ b/0046-SUSE-mdadm_env.sh-handle-MDADM_CHECK_DURATION.patch
@@ -0,0 +1,28 @@
+From 85b83a7920bca5b93d2458f093f2c640a130614c Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Wed, 30 Oct 2019 10:32:41 +1100
+Subject: [PATCH 46/47] SUSE-mdadm_env.sh: handle MDADM_CHECK_DURATION
+
+The suse sysconfig/mdadm allows MDADM_CHECK_DURATION
+to be set, but it is currently ignored.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ systemd/SUSE-mdadm_env.sh | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/systemd/SUSE-mdadm_env.sh b/systemd/SUSE-mdadm_env.sh
+index 10b2e74..c13b48a 100644
+--- a/systemd/SUSE-mdadm_env.sh
++++ b/systemd/SUSE-mdadm_env.sh
+@@ -43,3 +43,6 @@ fi
+
+ mkdir -p /run/sysconfig
+ echo "MDADM_MONITOR_ARGS=$MDADM_RAIDDEVICES $MDADM_DELAY $MDADM_MAIL $MDADM_PROGRAM $MDADM_SCAN $MDADM_SEND_MAIL $MDADM_CONFIG" > /run/sysconfig/mdadm
++if [ -n "$MDADM_CHECK_DURATION" ]; then
++ echo "MDADM_CHECK_DURATION=$MDADM_CHECK_DURATION" >> /run/sysconfig/mdadm
++fi
+--
+2.24.0
+
diff --git a/0047-super-intel-don-t-mark-structs-packed-unnecessarily.patch b/0047-super-intel-don-t-mark-structs-packed-unnecessarily.patch
new file mode 100644
index 0000000..099a401
--- /dev/null
+++ b/0047-super-intel-don-t-mark-structs-packed-unnecessarily.patch
@@ -0,0 +1,121 @@
+From 761e3bd9f5e3aafa95ad3ae50a637dc67c8774f0 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Thu, 31 Oct 2019 15:15:38 +1100
+Subject: [PATCH 47/47] super-intel: don't mark structs 'packed' unnecessarily
+
+super-intel marks a number of structures 'packed', but this
+doesn't change the layout - they are already well organized.
+
+This is a problem a gcc warns when code takes the address
+of a field in a packet struct - as super-intel sometimes does.
+
+So remove the marking where isn't needed.
+Do ensure this does introduce a regression, add a compile-time
+assertion that the size of the structure is exactly the value
+it had before the 'packed' notation was removed.
+
+Note that a couple of structure do need to be packed.
+As the address of fields is never taken, that is safe.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Acked-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ super-intel.c | 32 ++++++++++++++++++++++++++------
+ 1 file changed, 26 insertions(+), 6 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 713058c..a7fbed4 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -96,6 +96,19 @@
+ * mutliple PPL area
+ */
+
++/*
++ * This macro let's us ensure that no-one accidentally
++ * changes the size of a struct
++ */
++#define ASSERT_SIZE(_struct, size) \
++static inline void __assert_size_##_struct(void) \
++{ \
++ switch (0) { \
++ case 0: break; \
++ case (sizeof(struct _struct) == size): break; \
++ } \
++}
++
+ /* Disk configuration info. */
+ #define IMSM_MAX_DEVICES 255
+ struct imsm_disk {
+@@ -112,6 +125,7 @@ struct imsm_disk {
+ #define IMSM_DISK_FILLERS 3
+ __u32 filler[IMSM_DISK_FILLERS]; /* 0xF5 - 0x107 MPB_DISK_FILLERS for future expansion */
+ };
++ASSERT_SIZE(imsm_disk, 48)
+
+ /* map selector for map managment
+ */
+@@ -146,7 +160,8 @@ struct imsm_map {
+ __u32 disk_ord_tbl[1]; /* disk_ord_tbl[num_members],
+ * top byte contains some flags
+ */
+-} __attribute__ ((packed));
++};
++ASSERT_SIZE(imsm_map, 52)
+
+ struct imsm_vol {
+ __u32 curr_migr_unit;
+@@ -169,7 +184,8 @@ struct imsm_vol {
+ __u32 filler[4];
+ struct imsm_map map[1];
+ /* here comes another one if migr_state */
+-} __attribute__ ((packed));
++};
++ASSERT_SIZE(imsm_vol, 84)
+
+ struct imsm_dev {
+ __u8 volume[MAX_RAID_SERIAL_LEN];
+@@ -220,7 +236,8 @@ struct imsm_dev {
+ #define IMSM_DEV_FILLERS 3
+ __u32 filler[IMSM_DEV_FILLERS];
+ struct imsm_vol vol;
+-} __attribute__ ((packed));
++};
++ASSERT_SIZE(imsm_dev, 164)
+
+ struct imsm_super {
+ __u8 sig[MAX_SIGNATURE_LENGTH]; /* 0x00 - 0x1F */
+@@ -248,7 +265,8 @@ struct imsm_super {
+ struct imsm_disk disk[1]; /* 0xD8 diskTbl[numDisks] */
+ /* here comes imsm_dev[num_raid_devs] */
+ /* here comes BBM logs */
+-} __attribute__ ((packed));
++};
++ASSERT_SIZE(imsm_super, 264)
+
+ #define BBM_LOG_MAX_ENTRIES 254
+ #define BBM_LOG_MAX_LBA_ENTRY_VAL 256 /* Represents 256 LBAs */
+@@ -269,7 +287,8 @@ struct bbm_log {
+ __u32 signature; /* 0xABADB10C */
+ __u32 entry_count;
+ struct bbm_log_entry marked_block_entries[BBM_LOG_MAX_ENTRIES];
+-} __attribute__ ((__packed__));
++};
++ASSERT_SIZE(bbm_log, 2040)
+
+ static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed" };
+
+@@ -323,7 +342,8 @@ struct migr_record {
+ * destination - high order 32 bits */
+ __u32 num_migr_units_hi; /* Total num migration units-of-op
+ * high order 32 bits */
+-} __attribute__ ((__packed__));
++};
++ASSERT_SIZE(migr_record, 64)
+
+ struct md_list {
+ /* usage marker:
+--
+2.24.0
+
diff --git a/mdadm.rules b/mdadm.rules
index e8907c3..5c11dbc 100644
--- a/mdadm.rules
+++ b/mdadm.rules
@@ -25,7 +25,7 @@ ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="md_end"
# anything here, just regular disks, and this also won't get any imsm
# array members either)
SUBSYSTEM=="block", ACTION=="add", ENV{ID_FS_TYPE}=="linux_raid_member", \
- IMPORT{program}="/sbin/mdadm -I $env{DEVNAME} --export $devnode --offroot ${DEVLINKS}"
+ IMPORT{program}="/sbin/mdadm -I $env{DEVNAME} --export $devnode --offroot $env{DEVLINKS}"
SUBSYSTEM=="block", ACTION=="add", ENV{ID_FS_TYPE}=="linux_raid_member", \
ENV{MD_STARTED}=="*unsafe*", ENV{MD_FOREIGN}=="no", ENV{SYSTEMD_WANTS}+="mdadm-last-resort@$env{MD_DEVICE}.timer"
SUBSYSTEM=="block", ACTION=="remove", ENV{ID_PATH}=="?*", \
diff --git a/mdadm.spec b/mdadm.spec
index 187abef..2763c3a 100644
--- a/mdadm.spec
+++ b/mdadm.spec
@@ -1,11 +1,60 @@
Summary: A tool for managing Soft RAID under Linux
Name: mdadm
Version: 4.1
-Release: 4
+Release: 5
Group: System/Kernel and hardware
License: GPLv2+
Url: http://www.kernel.org/pub/linux/utils/raid/mdadm/
Source0: http://www.kernel.org/pub/linux/utils/raid/mdadm/mdadm-%{version}.tar.xz
+# fixes from uptream
+Patch001: 0001-Assemble-keep-MD_DISK_FAILFAST-and-MD_DISK_WRITEMOST.patch
+Patch002: 0002-Document-PART-POLICY-lines.patch
+Patch003: 0003-policy-support-devices-with-multiple-paths.patch
+Patch004: 0004-mdcheck-add-systemd-unit-files-to-run-mdcheck.patch
+Patch005: 0005-Monitor-add-system-timer-to-run-oneshot-periodically.patch
+Patch006: 0006-imsm-update-metadata-correctly-while-raid10-double-d.patch
+Patch007: 0007-Assemble-mask-FAILFAST-and-WRITEMOSTLY-flags-when-fi.patch
+Patch008: 0008-Grow-avoid-overflow-in-compute_backup_blocks.patch
+Patch009: 0009-Grow-report-correct-new-chunk-size.patch
+Patch010: 0010-policy.c-prevent-NULL-pointer-referencing.patch
+Patch011: 0011-policy.c-Fix-for-compiler-error.patch
+Patch012: 0012-imsm-finish-recovery-when-drive-with-rebuild-fails.patch
+Patch013: 0013-imsm-fix-reshape-for-2TB-drives.patch
+Patch014: 0014-Fix-spelling-typos.patch
+Patch015: 0015-Detail.c-do-not-skip-first-character-when-calling-xs.patch
+Patch016: 0016-Fix-reshape-for-decreasing-data-offset.patch
+Patch017: 0017-mdadm-tests-add-one-test-case-for-failfast-of-raid1.patch
+Patch018: 0018-mdmon-don-t-attempt-to-manage-new-arrays-when-termin.patch
+Patch019: 0019-mdmon-wait-for-previous-mdmon-to-exit-during-takeove.patch
+Patch020: 0020-Assemble-Fix-starting-array-with-initial-reshape-che.patch
+Patch021: 0021-add-missing-units-to-examine.patch
+Patch022: 0022-imsm-fix-spare-activation-for-old-matrix-arrays.patch
+Patch023: 0023-Create-Block-rounding-size-to-max.patch
+Patch024: 0024-udev-Add-udev-rules-to-create-by-partuuid-for-md-dev.patch
+Patch025: 0025-mdmon-fix-wrong-array-state-when-disk-fails-during-m.patch
+Patch026: 0026-Enable-probe_roms-to-scan-more-than-6-roms.patch
+Patch027: 0027-super-intel-Fix-issue-with-abs-being-irrelevant.patch
+Patch028: 0028-mdadm.h-Introduced-unaligned-get-put-_unaligned-16-3.patch
+Patch029: 0029-super-intel-Use-put_unaligned-in-split_ull.patch
+Patch030: 0030-mdadm-load-default-sysfs-attributes-after-assemblati.patch
+Patch031: 0031-mdadm.h-include-sysmacros.h-unconditionally.patch
+Patch032: 0032-mdadm-add-no-devices-to-avoid-component-devices-deta.patch
+Patch033: 0033-udev-add-no-devices-option-for-calling-mdadm-detail.patch
+Patch034: 0034-imsm-close-removed-drive-fd.patch
+Patch035: 0035-mdadm-check-value-returned-by-snprintf-against-error.patch
+Patch036: 0036-mdadm-Introduce-new-array-state-broken-for-raid0-lin.patch
+Patch037: 0037-mdadm-force-a-uuid-swap-on-big-endian.patch
+Patch038: 0038-mdadm-md.4-add-the-descriptions-for-bitmap-sysfs-nod.patch
+Patch039: 0039-Init-devlist-as-an-array.patch
+Patch040: 0040-Don-t-need-to-check-recovery-after-re-add-when-no-I-.patch
+Patch041: 0041-udev-allow-for-udev-attribute-reading-bug.patch
+Patch042: 0042-imsm-save-current_vol-number.patch
+Patch043: 0043-imsm-allow-to-specify-second-volume-size.patch
+Patch044: 0044-mdcheck-when-mdcheck_start-is-enabled-enable-mdcheck.patch
+Patch045: 0045-mdcheck-use-to-pass-variable-to-mdcheck.patch
+Patch046: 0046-SUSE-mdadm_env.sh-handle-MDADM_CHECK_DURATION.patch
+Patch047: 0047-super-intel-don-t-mark-structs-packed-unnecessarily.patch
+
# From Fedora
Source3: mdadm-raid-check
Source4: mdadm-raid-check-sysconfig
@@ -39,7 +88,7 @@ some common tasks).
%setup -q
%autopatch -p1
-echo "PROGRAM /sbin/mdadm-syslog-events" >> mdadm.conf-example
+printf '%s\n' "PROGRAM /sbin/mdadm-syslog-events" >> mdadm.conf-example
%build
%setup_compile_flags