diff --git a/Grow.c b/Grow.c index a7e528f..fad4dc8 100644 --- a/Grow.c +++ b/Grow.c @@ -3632,6 +3632,137 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt return 1; } +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]; + int cfd = -1; + int fd2 = -1; + + dprintf("Grow continue from command line called for %s\n", + devname); + + 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); + + /* 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; + } + } + + /* 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) { diff --git a/ReadMe.c b/ReadMe.c index 89dd7af..25426d3 100644 --- a/ReadMe.c +++ b/ReadMe.c @@ -191,6 +191,7 @@ struct option long_options[] = { {"backup-file", 1,0, BackupFile}, {"invalid-backup",0,0,InvalidBackup}, {"array-size", 1, 0, 'Z'}, + {"continue", 0, 0, Continue}, /* For Incremental */ {"rebuild-map", 0, 0, RebuildMapOpt}, diff --git a/mdadm.c b/mdadm.c index af182d0..ebf1c46 100644 --- a/mdadm.c +++ b/mdadm.c @@ -74,6 +74,7 @@ int main(int argc, char *argv[]) int export = 0; int assume_clean = 0; char *symlinks = NULL; + int grow_continue = 0; /* autof indicates whether and how to create device node. * bottom 3 bits are style. Rest (when shifted) are number of parts * 0 - unset @@ -996,6 +997,11 @@ int main(int argc, char *argv[]) backup_file = optarg; continue; + case O(GROW, Continue): + /* Continue interrupted grow + */ + grow_continue = 1; + continue; case O(ASSEMBLE, InvalidBackup): /* Acknowledge that the backupfile is invalid, but ask * to continue anyway @@ -1649,7 +1655,11 @@ int main(int argc, char *argv[]) delay = DEFAULT_BITMAP_DELAY; rv = Grow_addbitmap(devlist->devname, mdfd, bitmap_file, bitmap_chunk, delay, write_behind, force); - } else if (size >= 0 || raiddisks != 0 || layout_str != NULL + } else if (grow_continue) + rv = Grow_continue_command(devlist->devname, + mdfd, backup_file, + verbose); + else if (size >= 0 || raiddisks != 0 || layout_str != NULL || chunk != 0 || level != UnSet) { rv = Grow_reshape(devlist->devname, mdfd, quiet, backup_file, size, level, layout_str, chunk, raiddisks, diff --git a/mdadm.h b/mdadm.h index 4687a21..989d563 100644 --- a/mdadm.h +++ b/mdadm.h @@ -314,6 +314,7 @@ enum special_options { InvalidBackup, UdevRules, FreezeReshape, + Continue, }; /* structures read from config file */ @@ -1041,6 +1042,8 @@ extern int restore_backup(struct supertype *st, int spares, char *backup_file, int verbose); +extern int Grow_continue_command(char *devname, int fd, + char *backup_file, int verbose); extern int Assemble(struct supertype *st, char *mddev, struct mddev_ident *ident,