]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Grow.c
Check all member devices in enough_fd
[thirdparty/mdadm.git] / Grow.c
diff --git a/Grow.c b/Grow.c
index 0a084482dcb53ac0eeb87545895567d5c7ed2b85..62622bd28b5afb25bc1bcae5c43bbf6a26155bc3 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -521,9 +521,15 @@ static int freeze(struct supertype *st)
        else {
                struct mdinfo *sra = sysfs_read(-1, st->devnum, GET_VERSION);
                int err;
+               char buf[20];
 
                if (!sra)
                        return -1;
+               /* Need to clear any 'read-auto' status */
+               if (sysfs_get_str(sra, NULL, "array_state", buf, 20) > 0 &&
+                   strncmp(buf, "read-auto", 9) == 0)
+                       sysfs_set_str(sra, NULL, "array_state", "clean");
+
                err = sysfs_freeze_array(sra);
                sysfs_free(sra);
                return err;
@@ -1287,7 +1293,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                 long long size,
                 int level, char *layout_str, int chunksize, int raid_disks,
                 struct mddev_dev *devlist,
-                int force)
+                int assume_clean, int force)
 {
        /* Make some changes in the shape of an array.
         * The kernel must support the change.
@@ -1485,6 +1491,14 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                        rv = 1;
                        goto release;
                }
+               if (assume_clean) {
+                       /* This will fail on kernels newer than 2.6.40 unless
+                        * a backport has been arranged.
+                        */
+                       if (sra == NULL ||
+                           sysfs_set_str(sra, NULL, "resync_start", "none") < 0)
+                               fprintf(stderr, Name ": --assume-clean not support with --grow on this kernel\n");
+               }
                ioctl(fd, GET_ARRAY_INFO, &array);
                size = get_component_size(fd)/2;
                if (size == 0)
@@ -2625,10 +2639,9 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
        if (fd < 0)
                goto check_progress;
 
-       if (sysfs_fd_get_ll(fd, &completed) < 0) {
-               close(fd);
+       if (sysfs_fd_get_ll(fd, &completed) < 0)
                goto check_progress;
-       }
+
        while (completed < max_progress && completed < wait_point) {
                /* Check that sync_action is still 'reshape' to avoid
                 * waiting forever on a dead array
@@ -2653,10 +2666,8 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
                FD_ZERO(&rfds);
                FD_SET(fd, &rfds);
                select(fd+1, NULL, NULL, &rfds, NULL);
-               if (sysfs_fd_get_ll(fd, &completed) < 0) {
-                       close(fd);
+               if (sysfs_fd_get_ll(fd, &completed) < 0)
                        goto check_progress;
-               }
        }
        /* Some kernels reset 'sync_completed' to zero,
         * we need to have real point we are in md
@@ -2689,13 +2700,37 @@ check_progress:
        /* if we couldn't read a number from sync_completed, then
         * either the reshape did complete, or it aborted.
         * We can tell which by checking for 'none' in reshape_position.
+        * If it did abort, then it might immediately restart if it
+        * it was just a device failure that leaves us degraded but
+        * functioning.
         */
        strcpy(buf, "hi");
        if (sysfs_get_str(info, NULL, "reshape_position", buf, sizeof(buf)) < 0
-           || strncmp(buf, "none", 4) != 0)
-               return -2; /* abort */
-       else {
+           || strncmp(buf, "none", 4) != 0) {
+               /* The abort might only be temporary.  Wait up to 10
+                * seconds for fd to contain a valid number again.
+                */
+               struct timeval tv;
+               int rv = -2;
+               tv.tv_sec = 10;
+               tv.tv_usec = 0;
+               while (fd >= 0 && rv < 0) {
+                       fd_set rfds;
+                       FD_ZERO(&rfds);
+                       FD_SET(fd, &rfds);
+                       if (select(fd+1, NULL, NULL, &rfds, &tv) != 1)
+                               break;
+                       if (sysfs_fd_get_ll(fd, &completed) >= 0)
+                               /* all good again */
+                               rv = 1;
+               }
+               if (fd >= 0)
+                       close(fd);
+               return rv; /* abort */
+       } else {
                /* Maybe racing with array shutdown - check state */
+               if (fd >= 0)
+                       close(fd);
                if (sysfs_get_str(info, NULL, "array_state", buf, sizeof(buf)) < 0
                    || strncmp(buf, "inactive", 8) == 0
                    || strncmp(buf, "clear",5) == 0)