]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Grow.c
Remove race for starting container devices.
[thirdparty/mdadm.git] / Grow.c
diff --git a/Grow.c b/Grow.c
index b7234e4517b0632f7731623e601010c56295e02e..0e4dd108aa9617f35111503c68aa94641a655996 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -78,9 +78,9 @@ int restore_backup(struct supertype *st,
                                   backup_file, verbose > 0);
 
        while (next_spare > 0) {
-               disk_count--;
-               if (fdlist[disk_count] >= 0)
-                       close(fdlist[disk_count]);
+               next_spare--;
+               if (fdlist[next_spare] >= 0)
+                       close(fdlist[next_spare]);
        }
        free(fdlist);
        if (err) {
@@ -696,15 +696,19 @@ static int subarray_set_num(char *container, struct mdinfo *sra, char *name, int
        return rc;
 }
 
-int start_reshape(struct mdinfo *sra, int already_running)
+int start_reshape(struct mdinfo *sra, int already_running, int data_disks)
 {
        int err;
+       unsigned long long sync_max_to_set;
+
        sysfs_set_num(sra, NULL, "suspend_lo", 0x7FFFFFFFFFFFFFFFULL);
-       err = sysfs_set_num(sra, NULL, "suspend_hi", 0);
-       err = err ?: sysfs_set_num(sra, NULL, "suspend_lo", 0);
+       err = sysfs_set_num(sra, NULL, "suspend_hi", sra->reshape_progress);
+       err = err ?: sysfs_set_num(sra, NULL, "suspend_lo",
+                                  sra->reshape_progress);
+       sync_max_to_set = sra->reshape_progress / data_disks;
        if (!already_running)
-               sysfs_set_num(sra, NULL, "sync_min", 0);
-       err = err ?: sysfs_set_num(sra, NULL, "sync_max", 0);
+               sysfs_set_num(sra, NULL, "sync_min", sync_max_to_set);
+       err = err ?: sysfs_set_num(sra, NULL, "sync_max", sync_max_to_set);
        if (!already_running)
                err = err ?: sysfs_set_str(sra, NULL, "sync_action", "reshape");
 
@@ -1344,13 +1348,13 @@ static int reshape_array(char *container, int fd, char *devname,
                         struct supertype *st, struct mdinfo *info,
                         int force, struct mddev_dev *devlist,
                         char *backup_file, int quiet, int forked,
-                        int restart);
+                        int restart, int freeze_reshape);
 static int reshape_container(char *container, char *devname,
                             struct supertype *st, 
                             struct mdinfo *info,
                             int force,
                             char *backup_file,
-                            int quiet, int restart);
+                            int quiet, int restart, int freeze_reshape);
 
 int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                 long long size,
@@ -1644,8 +1648,12 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                        rv = 1;
                        goto release;
                }
-               /* FIXME this is added with no justification - why is it here */
-               ping_monitor(container);
+               /* Make sure mdmon has seen the device removal
+                * and updated metadata before we continue with
+                * level change
+                */
+               if (container)
+                       ping_monitor(container);
        }
 
        memset(&info, 0, sizeof(info));
@@ -1761,7 +1769,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                 * performed at the level of the container
                 */
                rv = reshape_container(container, devname, st, &info,
-                                      force, backup_file, quiet, 0);
+                                      force, backup_file, quiet, 0, 0);
                frozen = 0;
        } else {
                /* get spare devices from external metadata
@@ -1789,7 +1797,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                }
                sync_metadata(st);
                rv = reshape_array(container, fd, devname, st, &info, force,
-                                  devlist, backup_file, quiet, 0, 0);
+                                  devlist, backup_file, quiet, 0, 0, 0);
                frozen = 0;
        }
 release:
@@ -1802,7 +1810,7 @@ static int reshape_array(char *container, int fd, char *devname,
                         struct supertype *st, struct mdinfo *info,
                         int force, struct mddev_dev *devlist,
                         char *backup_file, int quiet, int forked,
-                        int restart)
+                        int restart, int freeze_reshape)
 {
        struct reshape reshape;
        int spares_needed;
@@ -2241,7 +2249,8 @@ started:
                }
        }
 
-       err = start_reshape(sra, restart);
+       err = start_reshape(sra, restart,
+                           info->array.raid_disks - reshape.parity);
        if (err) {
                fprintf(stderr, 
                        Name ": Cannot %s reshape for %s\n",
@@ -2251,6 +2260,15 @@ started:
        }
        if (restart)
                sysfs_set_str(sra, NULL, "array_state", "active");
+       if (freeze_reshape) {
+               free(fdlist);
+               free(offsets);
+               sysfs_free(sra);
+               fprintf(stderr, Name ": Reshape has to be continued from"
+                       " location %llu when root fileststem has been mounted\n",
+                       sra->reshape_progress);
+               return 1;
+       }
 
        /* Now we just need to kick off the reshape and watch, while
         * handling backups of the data...
@@ -2265,6 +2283,7 @@ started:
        default:
                return 0;
        case 0:
+               map_fork();
                break;
        }
 
@@ -2389,7 +2408,7 @@ int reshape_container(char *container, char *devname,
                      struct mdinfo *info,
                      int force,
                      char *backup_file,
-                     int quiet, int restart)
+                     int quiet, int restart, int freeze_reshape)
 {
        struct mdinfo *cc = NULL;
        int rv = restart;
@@ -2418,9 +2437,12 @@ int reshape_container(char *container, char *devname,
                unfreeze(st);
                return 1;
        default: /* parent */
-               printf(Name ": multi-array reshape continues in background\n");
+               if (!freeze_reshape)
+                       printf(Name ": multi-array reshape continues"
+                              " in background\n");
                return 0;
        case 0: /* child */
+               map_fork();
                break;
        }
 
@@ -2473,8 +2495,15 @@ int reshape_container(char *container, char *devname,
 
                rv = reshape_array(container, fd, adev, st,
                                   content, force, NULL,
-                                  backup_file, quiet, 1, restart);
+                                  backup_file, quiet, 1, restart,
+                                  freeze_reshape);
                close(fd);
+
+               if (freeze_reshape) {
+                       sysfs_free(cc);
+                       exit(0);
+               }
+
                restart = 0;
                if (rv)
                        break;
@@ -3612,37 +3641,193 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt
        return 1;
 }
 
-int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info,
-                 char *backup_file)
+int Grow_continue_command(char *devname, int fd,
+                         char *backup_file, int verbose)
 {
+       int ret_val = 0;
+       struct supertype *st = NULL;
+       struct mdinfo *content = NULL;
+       struct mdinfo array;
+       char *subarray = NULL;
+       struct mdinfo *cc = NULL;
+       struct mdstat_ent *mdstat = NULL;
        char buf[40];
-       char *container = NULL;
-       int err;
+       int cfd = -1;
+       int fd2 = -1;
+       char *ep;
+       unsigned long long position;
 
-       err = sysfs_set_str(info, NULL, "array_state", "readonly");
-       if (err)
-               return err;
-       if (st->ss->external) {
-               fmt_devname(buf, st->container_dev);
-               container = buf;
-               freeze(st);
+       dprintf("Grow continue from command line called for %s\n",
+               devname);
 
-               if (!mdmon_running(st->container_dev))
-                       start_mdmon(st->container_dev);
-               ping_monitor_by_id(st->container_dev);
+       st = super_by_fd(fd, &subarray);
+       if (!st || !st->ss) {
+               fprintf(stderr,
+                       Name ": Unable to determine metadata format for %s\n",
+                       devname);
+               return 1;
+       }
+       dprintf("Grow continue is run for ");
+       if (st->ss->external == 0) {
+               dprintf("native array (%s)\n", devname);
+               if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) {
+                       fprintf(stderr, Name ": %s is not an active md array -"
+                               " aborting\n", devname);
+                       ret_val = 1;
+                       goto Grow_continue_command_exit;
+               }
+               content = &array;
+               sysfs_init(content, fd, st->devnum);
+       } else {
+               int container_dev;
 
+               if (subarray) {
+                       dprintf("subarray (%s)\n", subarray);
+                       container_dev = st->container_dev;
+                       cfd = open_dev_excl(st->container_dev);
+               } else {
+                       container_dev = st->devnum;
+                       close(fd);
+                       cfd = open_dev_excl(st->devnum);
+                       dprintf("container (%i)\n", container_dev);
+                       fd = cfd;
+               }
+               if (cfd < 0) {
+                       fprintf(stderr, Name ": Unable to open container "
+                               "for %s\n", devname);
+                       ret_val = 1;
+                       goto Grow_continue_command_exit;
+               }
+               fmt_devname(buf, container_dev);
 
-               if (info->reshape_active == 2) {
-                       int cfd = open_dev(st->container_dev);
-                       if (cfd < 0)
-                               return 1;
-                       st->ss->load_container(st, cfd, container);
-                       close(cfd);
-                       return reshape_container(container, NULL,
-                                                st, info, 0, backup_file,
-                                                0, 1);
+               /* find in container array under reshape
+                */
+               ret_val = st->ss->load_container(st, cfd, NULL);
+               if (ret_val) {
+                       fprintf(stderr,
+                               Name ": Cannot read superblock for %s\n",
+                               devname);
+                       ret_val = 1;
+                       goto Grow_continue_command_exit;
+               }
+
+               cc = st->ss->container_content(st, NULL);
+               for (content = cc; content ; content = content->next) {
+                       char *array;
+
+                       if (content->reshape_active == 0)
+                               continue;
+
+                       array = strchr(content->text_version+1, '/')+1;
+                       mdstat = mdstat_by_subdev(array, container_dev);
+                       if (!mdstat)
+                               continue;
+                       break;
+               }
+               if (!content) {
+                       fprintf(stderr,
+                               Name ": Unable to determine reshaped "
+                               "array for %s\n", devname);
+                       ret_val = 1;
+                       goto Grow_continue_command_exit;
+               }
+               fd2 = open_dev(mdstat->devnum);
+               if (fd2 < 0) {
+                       fprintf(stderr, Name ": cannot open (md%i)\n",
+                               mdstat->devnum);
+                       ret_val = 1;
+                       goto Grow_continue_command_exit;
+               }
+
+               sysfs_init(content, fd2, mdstat->devnum);
+
+               /* start mdmon in case it is not running
+                */
+               if (!mdmon_running(container_dev))
+                       start_mdmon(container_dev);
+               ping_monitor(buf);
+
+               if (mdmon_running(container_dev))
+                       st->update_tail = &st->updates;
+               else {
+                       fprintf(stderr, Name ":  No mdmon found. "
+                               "Grow cannot continue.\n");
+                       ret_val = 1;
+                       goto Grow_continue_command_exit;
                }
        }
-       return reshape_array(container, mdfd, "array", st, info, 1,
-                            NULL, backup_file, 0, 0, 1);
+
+       /* verify that array under reshape is started from
+        * correct position
+        */
+       ret_val = sysfs_get_str(content, NULL, "sync_max", buf, 40);
+       if (ret_val <= 0) {
+               fprintf(stderr, Name
+                       ": cannot open verify reshape progress for %s (%i)\n",
+                       content->sys_name, ret_val);
+               ret_val = 1;
+               goto Grow_continue_command_exit;
+       }
+       dprintf(Name ": Read sync_max sysfs entry is: %s\n", buf);
+       position = strtoull(buf, &ep, 0);
+       if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' ')) {
+               fprintf(stderr, Name ": Fatal error: array reshape was"
+                       " not properly frozen\n");
+               ret_val = 1;
+               goto Grow_continue_command_exit;
+       }
+       position *= get_data_disks(map_name(pers, mdstat->level),
+                                  content->new_layout,
+                                  content->array.raid_disks);
+       if (position != content->reshape_progress) {
+               fprintf(stderr, Name ": Fatal error: array reshape was"
+                       " not properly frozen.\n");
+               ret_val = 1;
+               goto Grow_continue_command_exit;
+       }
+
+       /* continue reshape
+        */
+       ret_val = Grow_continue(fd, st, content, backup_file, 0);
+
+Grow_continue_command_exit:
+       if (fd2 > -1)
+               close(fd2);
+       if (cfd > -1)
+               close(cfd);
+       st->ss->free_super(st);
+       free_mdstat(mdstat);
+       sysfs_free(cc);
+       free(subarray);
+
+       return ret_val;
+}
+
+int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info,
+                 char *backup_file, int freeze_reshape)
+{
+       int ret_val = 2;
+
+       if (!info->reshape_active)
+               return ret_val;
+
+       if (st->ss->external) {
+               char container[40];
+               int cfd = open_dev(st->container_dev);
+
+               if (cfd < 0)
+                       return 1;
+
+               fmt_devname(container, st->container_dev);
+               st->ss->load_container(st, cfd, container);
+               close(cfd);
+               ret_val = reshape_container(container, NULL,
+                                           st, info, 0, backup_file,
+                                           0, 1, freeze_reshape);
+       } else
+               ret_val = reshape_array(NULL, mdfd, "array", st, info, 1,
+                                       NULL, backup_file, 0, 0, 1,
+                                       freeze_reshape);
+
+       return ret_val;
 }