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

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