]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
mdadm/Incremental: wait a while before removing a member
authorXiao Ni <xni@redhat.com>
Fri, 17 Oct 2025 09:04:25 +0000 (17:04 +0800)
committerNigel Croxon <109605997+ncroxon@users.noreply.github.com>
Tue, 21 Oct 2025 12:06:49 +0000 (08:06 -0400)
We encountered a regression that member disk can't be removed in
incremental remove mode:
mdadm -If /dev/loop0
mdadm: Cannot remove member device loop0 from md127

It doesn't allow to remove a member if sync thread is running. mdadm -If
sets member disk faulty first, then it removes the disk. If sync thread
is running, it will be interrupted by setting a member faulty. But the sync
thread hasn't been reapped. So it needs to wait a while to let kernel to
reap sync thread.

Signed-off-by: Xiao Ni <xni@redhat.com>
Incremental.c

index ba3810e6157faaf64ccea63253735883c119080f..f30697fa684f0bdaae1dca82e6c56f1ee895cd20 100644 (file)
@@ -1715,6 +1715,7 @@ int Incremental_remove(char *devname, char *id_path, int verbose)
        struct mdstat_ent *ent;
        struct mdinfo mdi;
        int mdfd = -1;
+       int retry = 25;
 
        if (strcmp(devnm, devname) != 0)
                if (!is_devnode_path(devname)) {
@@ -1790,11 +1791,26 @@ int Incremental_remove(char *devname, char *id_path, int verbose)
 
        /* Native arrays are handled separatelly to provide more detailed error handling */
        rv = sysfs_set_memb_state(ent->devnm, devnm, MEMB_STATE_FAULTY);
-       if (rv && verbose >= 0)
-               pr_err("Cannot fail member device %s in array %s.\n", devnm, ent->devnm);
+       if (rv) {
+               if (verbose >= 0)
+                       pr_err("Cannot fail member device %s in array %s.\n", devnm, ent->devnm);
+               goto out;
+       }
 
-       if (rv == MDADM_STATUS_SUCCESS)
+       /*
+        * If resync/recovery is running, sync thread is interrupted by setting member faulty.
+        * And it needs to wait some time to let kernel to reap sync thread. If not, it will
+        * fail to remove it.
+        */
+       while (retry) {
                rv = sysfs_set_memb_state(ent->devnm, devnm, MEMB_STATE_REMOVE);
+               if (rv) {
+                       sleep_for(0, MSEC_TO_NSEC(200), true);
+                       retry--;
+                       continue;
+               }
+               break;
+       }
 
        if (rv && verbose >= 0)
                pr_err("Cannot remove member device %s from %s.\n", devnm, ent->devnm);