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

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