You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mdadm/SOURCES/0171-Incremental-support-de...

152 lines
5.3 KiB

From 9b8933bb6dbfcae1bd5a2f933c87684de99412de Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Tue, 25 Jun 2024 12:53:46 +0200
Subject: [PATCH 171/201] Incremental: support devnode in IncrementalRemove.
There are no reasons to keep this interface different than others.
Allow to use devnode but keep old way for backward compatibility.
Method is added to verify that only devnode or kernel name is used.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
Incremental.c | 60 ++++++++++++++++++++++++-------------
mdadm.h | 5 ++++
udev-md-raid-assembly.rules | 4 +--
3 files changed, 46 insertions(+), 23 deletions(-)
diff --git a/Incremental.c b/Incremental.c
index fc4e68ff..c1389a15 100644
--- a/Incremental.c
+++ b/Incremental.c
@@ -1674,33 +1674,52 @@ static void remove_from_member_array(struct mdstat_ent *memb,
}
}
-/*
- * IncrementalRemove - Attempt to see if the passed in device belongs to any
- * raid arrays, and if so first fail (if needed) and then remove the device.
+/**
+ * is_devnode_path() - check if the devname passed might be devnode path.
+ * @devnode: the path to check.
*
- * @devname - The device we want to remove
- * @id_path - name as found in /dev/disk/by-path for this device
+ * Devnode must be located directly in /dev directory. It is not checking existence of the file
+ * because the device might no longer exist during removal from raid array.
+ */
+static bool is_devnode_path(char *devnode)
+{
+ char *devnm = strrchr(devnode, '/');
+
+ if (!devnm || *(devnm + 1) == 0)
+ return false;
+
+ if (strncmp(devnode, DEV_DIR, DEV_DIR_LEN) == 0 && devnode + DEV_DIR_LEN - 1 == devnm)
+ return true;
+
+ return false;
+}
+
+/**
+ * IncrementalRemove() - Remove the device from all raid arrays.
+ * @devname: the device we want to remove, it could be kernel device name or devnode.
+ * @id_path: optional, /dev/disk/by-path path to save for bare scenarios support.
+ * @verbose: verbose flag.
*
- * Note: the device name must be a kernel name like "sda", so
- * that we can find it in /proc/mdstat
+ * First, fail the device (if needed) and then remove the device from native raid array or external
+ * container. If it is external container, the device is removed from each subarray first.
*/
int IncrementalRemove(char *devname, char *id_path, int verbose)
{
- struct mdstat_ent *ent = NULL;
+ char *devnm = basename(devname);
+ struct mddev_dev devlist = {0};
char buf[SYSFS_MAX_BUF_SIZE];
struct mdstat_ent *mdstat;
- struct mddev_dev devlist;
+ struct mdstat_ent *ent;
struct mdinfo mdi;
int rv = 1;
int mdfd;
- if (!id_path)
- dprintf("incremental removal without --path <id_path> lacks the possibility to re-add new device in this port\n");
-
- if (strchr(devname, '/')) {
- pr_err("incremental removal requires a kernel device name, not a file: %s\n", devname);
- return 1;
- }
+ if (strcmp(devnm, devname) != 0)
+ if (!is_devnode_path(devname)) {
+ pr_err("Cannot remove \"%s\", devnode path or kernel device name is allowed.\n",
+ devname);
+ return 1;
+ }
mdstat = mdstat_read(0, 0);
if (!mdstat) {
@@ -1708,15 +1727,15 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
return 1;
}
- ent = mdstat_find_by_member_name(mdstat, devname);
+ ent = mdstat_find_by_member_name(mdstat, devnm);
if (!ent) {
if (verbose >= 0)
- pr_err("%s does not appear to be a component of any array\n", devname);
+ pr_vrb("%s does not appear to be a component of any array\n", devnm);
goto out;
}
if (sysfs_init(&mdi, -1, ent->devnm)) {
- pr_err("unable to initialize sysfs for: %s\n", devname);
+ pr_err("unable to initialize sysfs for: %s\n", devnm);
goto out;
}
@@ -1746,8 +1765,7 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
map_free(map);
}
- memset(&devlist, 0, sizeof(devlist));
- devlist.devname = devname;
+ devlist.devname = devnm;
devlist.disposition = 'I';
/* for a container, we must fail each member array */
if (is_mdstat_ent_external(ent)) {
diff --git a/mdadm.h b/mdadm.h
index 5c3a9836..f3b9f54c 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -100,6 +100,11 @@ struct dlm_lksb {
#define DEFAULT_BITMAP_DELAY 5
#define DEFAULT_MAX_WRITE_BEHIND 256
+#ifndef DEV_DIR
+#define DEV_DIR "/dev/"
+#define DEV_DIR_LEN (sizeof(DEV_DIR) - 1)
+#endif /* DEV_DIR */
+
/* DEV_NUM_PREF is a subpath to numbered MD devices, e.g. /dev/md1 or directory name.
* DEV_NUM_PREF_LEN is a length with Null byte excluded.
*/
diff --git a/udev-md-raid-assembly.rules b/udev-md-raid-assembly.rules
index d4a7f0a5..4cd2c6f4 100644
--- a/udev-md-raid-assembly.rules
+++ b/udev-md-raid-assembly.rules
@@ -41,7 +41,7 @@ ACTION=="change", KERNEL!="dm-*|md*", GOTO="md_inc_end"
ACTION!="remove", IMPORT{program}="BINDIR/mdadm --incremental --export $devnode --offroot $env{DEVLINKS}"
ACTION!="remove", ENV{MD_STARTED}=="*unsafe*", ENV{MD_FOREIGN}=="no", ENV{SYSTEMD_WANTS}+="mdadm-last-resort@$env{MD_DEVICE}.timer"
-ACTION=="remove", ENV{ID_PATH}=="?*", RUN+="BINDIR/mdadm -If $name --path $env{ID_PATH}"
-ACTION=="remove", ENV{ID_PATH}!="?*", RUN+="BINDIR/mdadm -If $name"
+ACTION=="remove", ENV{ID_PATH}=="?*", RUN+="BINDIR/mdadm -If $devnode --path $env{ID_PATH}"
+ACTION=="remove", ENV{ID_PATH}!="?*", RUN+="BINDIR/mdadm -If $devnode"
LABEL="md_inc_end"
--
2.41.0