+
+int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info,
+ char *backup_file)
+{
+ /* Array is assembled and ready to be started, but
+ * monitoring is probably required.
+ * So:
+ * - start read-only
+ * - set upper bound for resync
+ * - initialise the 'suspend' boundaries
+ * - switch to read-write
+ * - fork and continue monitoring
+ */
+ int err;
+ int backup_list[1];
+ unsigned long long backup_offsets[1];
+ int odisks, ndisks, ochunk, nchunk,odata,ndata;
+ unsigned long a,b,blocks,stripes;
+ int backup_fd;
+ int *fds;
+ unsigned long long *offsets;
+ int d;
+ struct mdinfo *sra, *sd;
+ int rv;
+ int done = 0;
+
+ err = sysfs_set_str(info, NULL, "array_state", "readonly");
+ if (err)
+ return err;
+
+ /* make sure reshape doesn't progress until we are ready */
+ sysfs_set_str(info, NULL, "sync_max", "0");
+ sysfs_set_str(info, NULL, "array_state", "active"); /* FIXME or clean */
+
+ /* ndisks is not growing, so raid_disks is old and +delta is new */
+ odisks = info->array.raid_disks;
+ ndisks = odisks + info->delta_disks;
+ odata = odisks - 1;
+ ndata = ndisks - 1;
+ if (info->array.level == 6) {
+ odata--;
+ ndata--;
+ }
+ ochunk = info->array.chunk_size;
+ nchunk = info->new_chunk;
+
+
+ a = ochunk/512 * odata;
+ b = nchunk/512 * ndata;
+ /* Find GCD */
+ while (a != b) {
+ if (a < b)
+ b -= a;
+ if (b < a)
+ a -= b;
+ }
+ /* LCM == product / GCD */
+ blocks = ochunk/512 * nchunk/512 * odata * ndata / a;
+
+ if (ndata == odata)
+ blocks *= 16;
+ stripes = blocks / (info->array.chunk_size/512) / odata;
+
+
+ memset(&bsb, 0, 512);
+ memcpy(bsb.magic, "md_backup_data-1", 16);
+ memcpy(&bsb.set_uuid, info->uuid, 16);
+ bsb.mtime = __cpu_to_le64(time(0));
+ bsb.devstart2 = blocks;
+
+ backup_fd = open(backup_file, O_RDWR|O_CREAT, S_IRUSR | S_IWUSR);
+ backup_list[0] = backup_fd;
+ backup_offsets[0] = 8 * 512;
+ fds = malloc(odisks * sizeof(fds[0]));
+ offsets = malloc(odisks * sizeof(offsets[0]));
+ for (d=0; d<odisks; d++)
+ fds[d] = -1;
+
+ sra = sysfs_read(-1, devname2devnum(info->sys_name),
+ GET_COMPONENT|GET_DEVS|GET_OFFSET|GET_STATE|
+ GET_CACHE);
+
+ for (sd = sra->devs; sd; sd = sd->next) {
+ if (sd->disk.state & (1<<MD_DISK_FAULTY))
+ continue;
+ if (sd->disk.state & (1<<MD_DISK_SYNC)) {
+ char *dn = map_dev(sd->disk.major,
+ sd->disk.minor, 1);
+ fds[sd->disk.raid_disk]
+ = dev_open(dn, O_RDONLY);
+ offsets[sd->disk.raid_disk] = sd->data_offset*512;
+ if (fds[sd->disk.raid_disk] < 0) {
+ fprintf(stderr, Name ": %s: cannot open component %s\n",
+ info->sys_name, dn?dn:"-unknown-");
+ rv = 1;
+ goto release;
+ }
+ free(dn);
+ }
+ }
+
+ switch(fork()) {
+ case 0:
+ close(mdfd);
+ mlockall(MCL_FUTURE);
+ if (info->delta_disks < 0)
+ done = child_shrink(-1, info, stripes,
+ fds, offsets,
+ info->array.raid_disks,
+ info->array.chunk_size,
+ info->array.level, info->array.layout,
+ odata,
+ 1, backup_list, backup_offsets);
+ else if (info->delta_disks == 0) {
+ /* The 'start' is a per-device stripe number.
+ * reshape_progress is a per-array sector number.
+ * So divide by ndata * chunk_size
+ */
+ unsigned long long start = info->reshape_progress / ndata;
+ start /= (info->array.chunk_size/512);
+ done = child_same_size(-1, info, stripes,
+ fds, offsets,
+ start,
+ info->array.raid_disks,
+ info->array.chunk_size,
+ info->array.level, info->array.layout,
+ odata,
+ 1, backup_list, backup_offsets);
+ }
+ if (backup_file && done)
+ unlink(backup_file);
+ /* FIXME should I intuit a level change */
+ exit(0);
+ case -1:
+ fprintf(stderr, Name ": Cannot run child to continue monitoring reshape: %s\n",
+ strerror(errno));
+ return 1;
+ default:
+ break;
+ }
+release:
+ return 0;
+}
+
+