]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Enhance incremental removal.
authorNeilBrown <neilb@suse.de>
Mon, 4 Mar 2013 22:46:34 +0000 (09:46 +1100)
committerNeilBrown <neilb@suse.de>
Mon, 4 Mar 2013 22:46:34 +0000 (09:46 +1100)
When asked to incrementally-remove a device, try marking the array
read-auto first.  That will delay recording the failure in the
metadata until it is really relevant.
This way, if the device are just unplugged when the array is not
really in use, the metadata will remain clean.

If marking the default as faulty fails because it is EBUSY, that
implies that the array would be failed without the device.  As the
device has (presumably gone) - that means the array is dead.  So try
to stop it.  If that fails because it is in use, send a uevent to
report that it is gone.  Hopefully whoever mounted it will now let go.

This means that if  you plug in some devices and they are
auto-assembled, then unplugging them will auto-deassemble relatively
cleanly.

To be complete, we really need the kernel to disassemble the array
after the last close somehow.  Maybe if a REMOVE has failed and a STOP
has failed and nothing else much has happened, it could safely stop
the array on last close.

Signed-off-by: NeilBrown <neilb@suse.de>
Incremental.c
Manage.c

index 36f79ef5814bd0491d6a2334dc14234c7ad45635..1b7ebfaf7bf9932ecd6bd1cc179d3c62ff0ba927 100644 (file)
@@ -1578,9 +1578,11 @@ static int Incremental_container(struct supertype *st, char *devname,
 int IncrementalRemove(char *devname, char *id_path, int verbose)
 {
        int mdfd;
-       int rv;
+       int rv = 0;
        struct mdstat_ent *ent;
        struct mddev_dev devlist;
+       struct mdinfo mdi;
+       char buf[32];
 
        if (!id_path)
                dprintf(Name ": incremental removal without --path <id_path> "
@@ -1598,6 +1600,14 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
                        "of any array\n", devname);
                return 1;
        }
+       sysfs_init(&mdi, -1, ent->devnm);
+       if (sysfs_get_str(&mdi, NULL, "array_state",
+                         buf, sizeof(buf)) > 0) {
+               if (strncmp(buf, "active", 6) == 0 ||
+                   strncmp(buf, "clean", 5) == 0)
+                       sysfs_set_str(&mdi, NULL,
+                                     "array_state", "read-auto");
+       }
        mdfd = open_dev(ent->devnm);
        if (mdfd < 0) {
                pr_err("Cannot open array %s!!\n", ent->dev);
@@ -1625,17 +1635,30 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
                        if (is_container_member(memb, ent->dev)) {
                                int subfd = open_dev(memb->devnm);
                                if (subfd >= 0) {
-                                       Manage_subdevs(memb->dev, subfd,
-                                                      &devlist, verbose, 0,
-                                                      NULL, 0);
+                                       rv |= Manage_subdevs(
+                                               memb->dev, subfd,
+                                               &devlist, verbose, 0,
+                                               NULL, 0);
                                        close(subfd);
                                }
                        }
                free_mdstat(mdstat);
        } else
-               Manage_subdevs(ent->dev, mdfd, &devlist, verbose, 0, NULL, 0);
-       devlist.disposition = 'r';
-       rv = Manage_subdevs(ent->dev, mdfd, &devlist, verbose, 0, NULL, 0);
+               rv |= Manage_subdevs(ent->dev, mdfd, &devlist,
+                                   verbose, 0, NULL, 0);
+       if (rv & 2) {
+               /* Failed due to EBUSY, try to stop the array
+                */
+               rv = Manage_runstop(ent->dev, mdfd, -1,
+                                   verbose, 1);
+               if (rv)
+                       /* At least we can try to trigger a 'remove' */
+                       sysfs_uevent(&mdi, "remove");
+       } else {
+               devlist.disposition = 'r';
+               rv = Manage_subdevs(ent->dev, mdfd, &devlist,
+                                   verbose, 0, NULL, 0);
+       }
        close(mdfd);
        free_mdstat(ent);
        return rv;
index 6267c0ca28c71e4a4c5105f67183b01a10bca398..c7738e1e80b9b2df0802d70e3789f695c1fcd114 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -222,7 +222,10 @@ int Manage_runstop(char *devname, int fd, int runstop,
                 * to stop is probably a bad idea.
                 */
                close(fd);
-               fd = open(devname, O_RDONLY|O_EXCL);
+               if (devnm[0] == '/')
+                       fd = open(devname, O_RDONLY|O_EXCL);
+               else
+                       fd = open_dev_flags(devnm, O_RDONLY|O_EXCL);
                if (fd < 0 || strcmp(fd2devnm(fd), devnm) != 0) {
                        if (fd >= 0)
                                close(fd);
@@ -1100,6 +1103,7 @@ int Manage_subdevs(char *devname, int fd,
        int count = 0; /* number of actions taken */
        struct mdinfo info;
        int frozen = 0;
+       int busy = 0;
 
        if (ioctl(fd, GET_ARRAY_INFO, &array)) {
                pr_err("Cannot get array info for %s\n",
@@ -1320,6 +1324,8 @@ int Manage_subdevs(char *devname, int fd,
                        if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) ||
                            (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY,
                                                (unsigned long) stb.st_rdev))) {
+                               if (errno == EBUSY)
+                                       busy = 1;
                                pr_err("set device faulty failed for %s:  %s\n",
                                        dv->devname, strerror(errno));
                                if (sysfd >= 0)
@@ -1377,7 +1383,7 @@ int Manage_subdevs(char *devname, int fd,
 abort:
        if (frozen > 0)
                sysfs_set_str(&info, NULL, "sync_action","idle");
-       return 1;
+       return !test && busy ? 2 : 1;
 }
 
 int autodetect(void)