Blame SOURCES/0025-mdmon-fix-wrong-array-state-when-disk-fails-during-m.patch

2910d5
From ae7d61e35ec2ab6361c3e509a8db00698ef3396f Mon Sep 17 00:00:00 2001
2910d5
From: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
2910d5
Date: Tue, 7 May 2019 16:08:47 +0200
2910d5
Subject: [RHEL7.8 PATCH V2 25/47] mdmon: fix wrong array state when disk fails
2910d5
 during mdmon startup
2910d5
2910d5
If a member drive disappears and is set faulty by the kernel during
2910d5
mdmon startup, after ss->load_container() but before manage_new(), mdmon
2910d5
will try to readd the faulty drive to the array and start rebuilding.
2910d5
Metadata on the active drive is updated, but the faulty drive is not
2910d5
removed from the array and is left in a "blocked" state and any write
2910d5
request to the array will block. If the faulty drive reappears in the
2910d5
system e.g. after a reboot, the array will not assemble because metadata
2910d5
on the drives will be incompatible (at least on imsm).
2910d5
2910d5
Fix this by adding a new option for sysfs_read(): "GET_DEVS_ALL". This
2910d5
is an extension for the "GET_DEVS" option and causes all member devices
2910d5
to be returned, even if the associated block device has been removed.
2910d5
Use this option in manage_new() to include the faulty device on the
2910d5
active_array's devices list. Mdmon will then properly remove the faulty
2910d5
device from the array and update the metadata to reflect the degraded
2910d5
state.
2910d5
2910d5
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
2910d5
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
2910d5
---
2910d5
 managemon.c   |  2 +-
2910d5
 mdadm.h       |  1 +
2910d5
 super-intel.c |  2 +-
2910d5
 sysfs.c       | 23 ++++++++++++++---------
2910d5
 4 files changed, 17 insertions(+), 11 deletions(-)
2910d5
2910d5
diff --git a/managemon.c b/managemon.c
2910d5
index 29b91ba..200cf83 100644
2910d5
--- a/managemon.c
2910d5
+++ b/managemon.c
2910d5
@@ -678,7 +678,7 @@ static void manage_new(struct mdstat_ent *mdstat,
2910d5
 	mdi = sysfs_read(-1, mdstat->devnm,
2910d5
 			 GET_LEVEL|GET_CHUNK|GET_DISKS|GET_COMPONENT|
2910d5
 			 GET_SAFEMODE|GET_DEVS|GET_OFFSET|GET_SIZE|GET_STATE|
2910d5
-			 GET_LAYOUT);
2910d5
+			 GET_LAYOUT|GET_DEVS_ALL);
2910d5
 
2910d5
 	if (!mdi)
2910d5
 		return;
2910d5
diff --git a/mdadm.h b/mdadm.h
2910d5
index 705bd9b..427cc52 100644
2910d5
--- a/mdadm.h
2910d5
+++ b/mdadm.h
2910d5
@@ -647,6 +647,7 @@ enum sysfs_read_flags {
2910d5
 	GET_ERROR	= (1 << 24),
2910d5
 	GET_ARRAY_STATE = (1 << 25),
2910d5
 	GET_CONSISTENCY_POLICY	= (1 << 26),
2910d5
+	GET_DEVS_ALL	= (1 << 27),
2910d5
 };
2910d5
 
2910d5
 /* If fd >= 0, get the array it is open on,
2910d5
diff --git a/super-intel.c b/super-intel.c
2910d5
index 2ba045a..4fd5e84 100644
2910d5
--- a/super-intel.c
2910d5
+++ b/super-intel.c
2910d5
@@ -8560,7 +8560,7 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
2910d5
 	disk = get_imsm_disk(super, ord_to_idx(ord));
2910d5
 
2910d5
 	/* check for new failures */
2910d5
-	if (state & DS_FAULTY) {
2910d5
+	if (disk && (state & DS_FAULTY)) {
2910d5
 		if (mark_failure(super, dev, disk, ord_to_idx(ord)))
2910d5
 			super->updates_pending++;
2910d5
 	}
2910d5
diff --git a/sysfs.c b/sysfs.c
2910d5
index df6fdda..2dd9ab6 100644
2910d5
--- a/sysfs.c
2910d5
+++ b/sysfs.c
2910d5
@@ -313,17 +313,22 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
2910d5
 			/* assume this is a stale reference to a hot
2910d5
 			 * removed device
2910d5
 			 */
2910d5
-			free(dev);
2910d5
-			continue;
2910d5
+			if (!(options & GET_DEVS_ALL)) {
2910d5
+				free(dev);
2910d5
+				continue;
2910d5
+			}
2910d5
+		} else {
2910d5
+			sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
2910d5
 		}
2910d5
-		sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
2910d5
 
2910d5
-		/* special case check for block devices that can go 'offline' */
2910d5
-		strcpy(dbase, "block/device/state");
2910d5
-		if (load_sys(fname, buf, sizeof(buf)) == 0 &&
2910d5
-		    strncmp(buf, "offline", 7) == 0) {
2910d5
-			free(dev);
2910d5
-			continue;
2910d5
+		if (!(options & GET_DEVS_ALL)) {
2910d5
+			/* special case check for block devices that can go 'offline' */
2910d5
+			strcpy(dbase, "block/device/state");
2910d5
+			if (load_sys(fname, buf, sizeof(buf)) == 0 &&
2910d5
+			    strncmp(buf, "offline", 7) == 0) {
2910d5
+				free(dev);
2910d5
+				continue;
2910d5
+			}
2910d5
 		}
2910d5
 
2910d5
 		/* finally add this disk to the array */
2910d5
-- 
2910d5
2.7.5
2910d5