Blame SOURCES/0055-Manage-Block-unsafe-member-failing.patch

01ff50
From fc6fd4063769f4194c3fb8f77b32b2819e140fb9 Mon Sep 17 00:00:00 2001
01ff50
From: Mateusz Kusiak <mateusz.kusiak@intel.com>
01ff50
Date: Thu, 18 Aug 2022 11:47:21 +0200
01ff50
Subject: [PATCH 55/83] Manage: Block unsafe member failing
01ff50
01ff50
Kernel may or may not block mdadm from removing member device if it
01ff50
will cause arrays failed state. It depends on raid personality
01ff50
implementation in kernel.
01ff50
Add verification on requested removal path (#mdadm --set-faulty
01ff50
command).
01ff50
01ff50
Signed-off-by: Mateusz Kusiak <mateusz.kusiak@intel.com>
01ff50
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
01ff50
---
01ff50
 Manage.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
01ff50
 1 file changed, 52 insertions(+), 1 deletion(-)
01ff50
01ff50
diff --git a/Manage.c b/Manage.c
01ff50
index a142f8bd..b1d0e630 100644
01ff50
--- a/Manage.c
01ff50
+++ b/Manage.c
01ff50
@@ -1285,6 +1285,50 @@ int Manage_with(struct supertype *tst, int fd, struct mddev_dev *dv,
01ff50
 	return -1;
01ff50
 }
01ff50
 
01ff50
+/**
01ff50
+ * is_remove_safe() - Check if remove is safe.
01ff50
+ * @array: Array info.
01ff50
+ * @fd: Array file descriptor.
01ff50
+ * @devname: Name of device to remove.
01ff50
+ * @verbose: Verbose.
01ff50
+ *
01ff50
+ * The function determines if array will be operational
01ff50
+ * after removing &devname.
01ff50
+ *
01ff50
+ * Return: True if array will be operational, false otherwise.
01ff50
+ */
01ff50
+bool is_remove_safe(mdu_array_info_t *array, const int fd, char *devname, const int verbose)
01ff50
+{
01ff50
+	dev_t devid = devnm2devid(devname + 5);
01ff50
+	struct mdinfo *mdi = sysfs_read(fd, NULL, GET_DEVS | GET_DISKS | GET_STATE);
01ff50
+
01ff50
+	if (!mdi) {
01ff50
+		if (verbose)
01ff50
+			pr_err("Failed to read sysfs attributes for %s\n", devname);
01ff50
+		return false;
01ff50
+	}
01ff50
+
01ff50
+	char *avail = xcalloc(array->raid_disks, sizeof(char));
01ff50
+
01ff50
+	for (mdi = mdi->devs; mdi; mdi = mdi->next) {
01ff50
+		if (mdi->disk.raid_disk < 0)
01ff50
+			continue;
01ff50
+		if (!(mdi->disk.state & (1 << MD_DISK_SYNC)))
01ff50
+			continue;
01ff50
+		if (makedev(mdi->disk.major, mdi->disk.minor) == devid)
01ff50
+			continue;
01ff50
+		avail[mdi->disk.raid_disk] = 1;
01ff50
+	}
01ff50
+	sysfs_free(mdi);
01ff50
+
01ff50
+	bool is_enough = enough(array->level, array->raid_disks,
01ff50
+				array->layout, (array->state & 1),
01ff50
+				avail);
01ff50
+
01ff50
+	free(avail);
01ff50
+	return is_enough;
01ff50
+}
01ff50
+
01ff50
 int Manage_subdevs(char *devname, int fd,
01ff50
 		   struct mddev_dev *devlist, int verbose, int test,
01ff50
 		   char *update, int force)
01ff50
@@ -1598,7 +1642,14 @@ int Manage_subdevs(char *devname, int fd,
01ff50
 			break;
01ff50
 
01ff50
 		case 'f': /* set faulty */
01ff50
-			/* FIXME check current member */
01ff50
+			if (!is_remove_safe(&array, fd, dv->devname, verbose)) {
01ff50
+				pr_err("Cannot remove %s from %s, array will be failed.\n",
01ff50
+				       dv->devname, devname);
01ff50
+				if (sysfd >= 0)
01ff50
+					close(sysfd);
01ff50
+				goto abort;
01ff50
+			}
01ff50
+
01ff50
 			if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) ||
01ff50
 			    (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY,
01ff50
 						rdev))) {
01ff50
-- 
01ff50
2.38.1
01ff50