]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Retry HOT_REMOVE_DISK a few times.
authorNeilBrown <neilb@suse.com>
Mon, 27 Mar 2017 01:50:16 +0000 (12:50 +1100)
committerJes Sorensen <Jes.Sorensen@gmail.com>
Tue, 28 Mar 2017 18:25:23 +0000 (14:25 -0400)
HOT_REMOVE_DISK can fail with EBUSY if there are outstanding
IO request that have not completed yet.  It can sometimes
be helpful to wait a little while for these to complete.

We already do this in impose_level() when reshaping a device,
but not in Manage.c in response to an explicit --remove request.

So create hot_remove_disk() to central this code, and call it
where-ever it makes sense to wait for a HOT_REMOVE_DISK to succeed.

Signed-off-by: NeilBrown <neilb@suse.com>
Signed-off-by: Jes Sorensen <Jes.Sorensen@gmail.com>
Grow.c
Manage.c
mdadm.h
util.c

diff --git a/Grow.c b/Grow.c
index 455c5f90bf58c27408235396c5914bbcfc02ec85..218a70649c1f8cb582f7b9a32f55c5d3ce85e170 100755 (executable)
--- a/Grow.c
+++ b/Grow.c
@@ -2736,7 +2736,6 @@ static int impose_level(int fd, int level, char *devname, int verbose)
                for (d = 0, found = 0;
                     d < MAX_DISKS && found < array.nr_disks;
                     d++) {
-                       int cnt;
                        mdu_disk_info_t disk;
                        disk.number = d;
                        if (ioctl(fd, GET_DISK_INFO, &disk) < 0)
@@ -2750,13 +2749,7 @@ static int impose_level(int fd, int level, char *devname, int verbose)
                                continue;
                        ioctl(fd, SET_DISK_FAULTY,
                              makedev(disk.major, disk.minor));
-                       cnt = 5;
-                       while (ioctl(fd, HOT_REMOVE_DISK,
-                                    makedev(disk.major, disk.minor)) < 0
-                              && errno == EBUSY
-                              && cnt--) {
-                               usleep(10000);
-                       }
+                       hot_remove_disk(fd, makedev(disk.major, disk.minor));
                }
        }
        c = map_num(pers, level);
index 5c3d2b9b1a9fceb630aa186ab83a7ac912c1f004..9139f96e1431ae43a8247a72144c9a42da428f3f 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -1183,7 +1183,7 @@ int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv,
                else
                        err = 0;
        } else {
-               err = ioctl(fd, HOT_REMOVE_DISK, rdev);
+               err = hot_remove_disk(fd, rdev);
                if (err && errno == ENODEV) {
                        /* Old kernels rejected this if no personality
                         * is registered */
@@ -1607,7 +1607,7 @@ int Manage_subdevs(char *devname, int fd,
 
                        if (dv->disposition == 'F')
                                /* Need to remove first */
-                               ioctl(fd, HOT_REMOVE_DISK, rdev);
+                               hot_remove_disk(fd, rdev);
                        /* Make sure it isn't in use (in 2.6 or later) */
                        tfd = dev_open(dv->devname, O_RDONLY|O_EXCL);
                        if (tfd >= 0) {
diff --git a/mdadm.h b/mdadm.h
index 91fd9eb1252a7574506d3a4a23f82cf2406eb210..5bcfb8610ad2e49a93b1dc17fe8100ec38a61b37 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -1476,6 +1476,7 @@ extern int add_disk(int mdfd, struct supertype *st,
                    struct mdinfo *sra, struct mdinfo *info);
 extern int remove_disk(int mdfd, struct supertype *st,
                       struct mdinfo *sra, struct mdinfo *info);
+extern int hot_remove_disk(int mdfd, unsigned long dev);
 extern int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info);
 unsigned long long min_recovery_start(struct mdinfo *array);
 
diff --git a/util.c b/util.c
index 32bd909b241d8295e0a7417fc0503618703c90b7..d09a7e2d40f430d494117b5fb28b337b4c340bea 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1795,6 +1795,24 @@ int remove_disk(int mdfd, struct supertype *st,
        return rv;
 }
 
+int hot_remove_disk(int mdfd, unsigned long dev)
+{
+       int cnt = 5;
+       int ret;
+
+       /* HOT_REMOVE_DISK can fail with EBUSY if there are
+        * outstanding IO requests to the device.
+        * In this case, it can be helpful to wait a little while,
+        * up to half a second, for that IO to flush.
+        */
+       while ((ret = ioctl(mdfd, HOT_REMOVE_DISK, dev)) == -1 &&
+              errno == EBUSY &&
+              cnt-- > 0)
+               usleep(10000);
+
+       return ret;
+}
+
 int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info)
 {
        /* Initialise kernel's knowledge of array.