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) {
fprintf(stderr, Name ": Cannot grow linear sub-arrays yet\n");
free(subarray);
free(st);
+ return 1;
}
nfd = open(newdev, O_RDWR|O_EXCL|O_DIRECT);
return 1;
}
fd2 = dev_open(dv, O_RDWR);
- if (!fd2) {
+ if (fd2 < 0) {
fprintf(stderr, Name ": cannot open device file %s\n", dv);
close(nfd);
free(st);
return 1;
}
if (strcmp(file, "internal") == 0) {
+ int rv;
int d;
+ int offset_setable = 0;
+ struct mdinfo *mdi;
if (st->ss->add_internal_bitmap == NULL) {
fprintf(stderr, Name ": Internal bitmaps not supported "
"with %s metadata\n", st->ss->name);
return 1;
}
+ mdi = sysfs_read(fd, -1, GET_BITMAP_LOCATION);
+ if (mdi)
+ offset_setable = 1;
for (d=0; d< st->max_devs; d++) {
mdu_disk_info_t disk;
char *dv;
if (st->ss->add_internal_bitmap(
st,
&chunk, delay, write_behind,
- bitmapsize, 0, major)
+ bitmapsize, offset_setable,
+ major)
)
st->ss->write_bitmap(st, fd2);
else {
- fprintf(stderr, Name ": failed to create internal bitmap - chunksize problem.\n");
+ fprintf(stderr, Name ": failed "
+ "to create internal bitmap - chunksize problem.\n");
close(fd2);
return 1;
}
close(fd2);
}
}
- array.state |= (1<<MD_SB_BITMAP_PRESENT);
- if (ioctl(fd, SET_ARRAY_INFO, &array)!= 0) {
+ if (offset_setable) {
+ st->ss->getinfo_super(st, mdi, NULL);
+ sysfs_init(mdi, fd, -1);
+ rv = sysfs_set_num(mdi, NULL, "bitmap/location",
+ mdi->bitmap_offset);
+ } else {
+ array.state |= (1<<MD_SB_BITMAP_PRESENT);
+ rv = ioctl(fd, SET_ARRAY_INFO, &array);
+ }
+ if (rv < 0) {
if (errno == EBUSY)
fprintf(stderr, Name
": Cannot add bitmap while array is"
dv = map_dev(disk.major, disk.minor, 1);
if (!dv) continue;
fd2 = dev_open(dv, O_RDONLY);
- if (fd2 >= 0 &&
- st->ss->load_super(st, fd2, NULL) == 0) {
+ if (fd2 >= 0) {
+ if (st->ss->load_super(st, fd2, NULL) == 0) {
+ close(fd2);
+ st->ss->uuid_from_super(st, uuid);
+ break;
+ }
close(fd2);
- st->ss->uuid_from_super(st, uuid);
- break;
}
- close(fd2);
}
if (d == max_devs) {
fprintf(stderr, Name ": cannot find UUID for array!\n");
return 0;
}
-
/*
* When reshaping an array we might need to backup some data.
* This is written to all spares with a 'super_block' describing it.
char container[40];
struct mdstat_ent *ent, *e;
int is_idle = 1;
-
+
fmt_devname(container, container_dev);
ent = mdstat_read(0, 0);
for (e = ent ; e; e = e->next) {
if (!check_idle(st))
return -1;
-
+
fmt_devname(container, container_dev);
if (block_monitor(container, 1)) {
int container_dev = (st->container_dev != NoMdDev
? st->container_dev : st->devnum);
char container[40];
-
+
fmt_devname(container, container_dev);
unblock_monitor(container, 1);
return rc;
}
-int start_reshape(struct mdinfo *sra, int already_running)
+int start_reshape(struct mdinfo *sra, int already_running,
+ int before_data_disks, 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);
+ if (before_data_disks <= data_disks)
+ sync_max_to_set = sra->reshape_progress / data_disks;
+ else
+ sync_max_to_set = (sra->component_size * data_disks
+ - 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");
* raid5 with 2 disks, or
* raid0 with 1 disk
*/
+ if (info->new_level > 1 &&
+ (info->component_size & 7))
+ return "Cannot convert RAID1 of this size - "
+ "reduce size to multiple of 4K first.";
if (info->new_level == 0) {
if (info->delta_disks != UnSet &&
info->delta_disks != 0)
break;
case 5:
- /* We get to RAID5 for RAID5 or RAID6 */
+ /* We get to RAID5 from RAID5 or RAID6 */
if (re->level != 5 && re->level != 6)
return "Cannot convert to RAID5 from this level";
char layout[40];
char *ls = map_num(r5layout, info->new_layout);
int l;
- strcat(strcpy(layout, ls), "-6");
- l = map_name(r6layout, layout);
- if (l == UnSet)
- return "Cannot find RAID6 layout"
- " to convert to";
+ if (ls) {
+ /* Current RAID6 layout has a RAID5
+ * equivalent - good
+ */
+ strcat(strcpy(layout, ls), "-6");
+ l = map_name(r6layout, layout);
+ if (l == UnSet)
+ return "Cannot find RAID6 layout"
+ " to convert to";
+ } else {
+ /* Current RAID6 has no equivalent.
+ * If it is already a '-6' layout we
+ * can leave it unchanged, else we must
+ * fail
+ */
+ ls = map_num(r6layout, info->new_layout);
+ if (!ls ||
+ strcmp(ls+strlen(ls)-2, "-6") != 0)
+ return "Please specify new layout";
+ l = info->new_layout;
+ }
re->after.layout = l;
}
}
return NULL;
}
+static int set_array_size(struct supertype *st, struct mdinfo *sra,
+ char *text_version)
+{
+ struct mdinfo *info;
+ char *subarray;
+ int ret_val = -1;
+
+ if ((st == NULL) || (sra == NULL))
+ return ret_val;
+
+ if (text_version == NULL)
+ text_version = sra->text_version;
+ subarray = strchr(text_version+1, '/')+1;
+ info = st->ss->container_content(st, subarray);
+ if (info) {
+ unsigned long long current_size = 0;
+ unsigned long long new_size =
+ info->custom_array_size/2;
+
+ if (sysfs_get_ll(sra, NULL, "array_size", ¤t_size) == 0 &&
+ new_size > current_size) {
+ if (sysfs_set_num(sra, NULL, "array_size", new_size)
+ < 0)
+ dprintf("Error: Cannot set array size");
+ else {
+ ret_val = 0;
+ dprintf("Array size changed");
+ }
+ dprintf(" from %llu to %llu.\n",
+ current_size, new_size);
+ }
+ sysfs_free(info);
+ } else
+ dprintf("Error: set_array_size(): info pointer in NULL\n");
+
+ return ret_val;
+}
+
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 freeze_reshape);
static int reshape_container(char *container, char *devname,
- struct supertype *st,
+ int mdfd,
+ struct supertype *st,
struct mdinfo *info,
int force,
char *backup_file,
return 1;
}
+ /* check if operation is supported for metadata handler */
+ if (st->ss->container_content) {
+ struct mdinfo *cc = NULL;
+ struct mdinfo *content = NULL;
+
+ cc = st->ss->container_content(st, subarray);
+ for (content = cc; content ; content = content->next) {
+ int allow_reshape = 1;
+
+ /* check if reshape is allowed based on metadata
+ * indications stored in content.array.status
+ */
+ if (content->array.state & (1<<MD_SB_BLOCK_VOLUME))
+ allow_reshape = 0;
+ if (content->array.state
+ & (1<<MD_SB_BLOCK_CONTAINER_RESHAPE))
+ allow_reshape = 0;
+ if (!allow_reshape) {
+ fprintf(stderr, Name
+ " cannot reshape arrays in"
+ " container with unsupported"
+ " metadata: %s(%s)\n",
+ devname, container_buf);
+ sysfs_free(cc);
+ free(subarray);
+ return 1;
+ }
+ }
+ sysfs_free(cc);
+ }
if (mdmon_running(container_dev))
st->update_tail = &st->updates;
}
Name ": Need %d spare%s to avoid degraded array,"
" and only have %d.\n"
" Use --force to over-ride this check.\n",
- raid_disks - array.raid_disks,
- raid_disks - array.raid_disks == 1 ? "" : "s",
+ raid_disks - array.raid_disks,
+ raid_disks - array.raid_disks == 1 ? "" : "s",
array.spare_disks + added_disks);
return 1;
}
sra = sysfs_read(fd, 0, GET_LEVEL | GET_DISKS | GET_DEVS
| GET_STATE | GET_VERSION);
- if (sra) {
+ if (sra) {
if (st->ss->external && subarray == NULL) {
array.level = LEVEL_CONTAINER;
sra->array.level = LEVEL_CONTAINER;
frozen = freeze(st);
if (frozen < -1) {
/* freeze() already spewed the reason */
+ sysfs_free(sra);
return 1;
} else if (frozen < 0) {
fprintf(stderr, Name ": %s is performing resync/recovery and cannot"
" be reshaped\n", devname);
+ sysfs_free(sra);
return 1;
}
"2TB per device\n");
size = min_csize;
}
-
array.size = size;
if (array.size != size) {
/* got truncated to 32bit, write to
"component_size", size);
else
rv = -1;
- } else
+ } else {
rv = ioctl(fd, SET_ARRAY_INFO, &array);
+ /* manage array size when it is managed externally
+ */
+ if ((rv == 0) && st->ss->external)
+ rv = set_array_size(st, sra, sra->text_version);
+ }
+
if (rv != 0) {
int err = errno;
sync_metadata(st);
fprintf(stderr, Name ": Cannot set device size for %s: %s\n",
devname, strerror(err));
- if (err == EBUSY &&
+ if (err == EBUSY &&
(array.state & (1<<MD_SB_BITMAP_PRESENT)))
fprintf(stderr, " Bitmap must be removed before size can be changed\n");
rv = 1;
/* ========= check for Raid10/Raid1 -> Raid0 conversion ===============
* current implementation assumes that following conditions must be met:
* - RAID10:
- * - far_copies == 1
- * - near_copies == 2
+ * - far_copies == 1
+ * - near_copies == 2
*/
if ((level == 0 && array.level == 10 && sra &&
- array.layout == ((1 << 8) + 2) && !(array.raid_disks & 1)) ||
+ array.layout == ((1 << 8) + 2) && !(array.raid_disks & 1)) ||
(level == 0 && array.level == 1 && sra)) {
int err;
err = remove_disks_for_takeover(st, sra, array.layout);
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));
goto release;
}
} else if (strcmp(layout_str, "normalise") == 0 ||
- strcmp(layout_str, "normalize") == 0) {
+ strcmp(layout_str, "normalize") == 0) {
/* If we have a -6 RAID6 layout, remove the '-6'. */
info.new_layout = UnSet;
if (info.array.level == 6 && info.new_level == UnSet) {
* number of devices (On-Line Capacity Expansion) must be
* performed at the level of the container
*/
- rv = reshape_container(container, devname, st, &info,
+ rv = reshape_container(container, devname, -1, st, &info,
force, backup_file, quiet, 0, 0);
frozen = 0;
} else {
frozen = 0;
}
release:
+ sysfs_free(sra);
if (frozen > 0)
unfreeze(st);
return rv;
}
+/* verify_reshape_position()
+ * Function checks if reshape position in metadata is not farther
+ * than position in md.
+ * Return value:
+ * 0 : not valid sysfs entry
+ * it can be caused by not started reshape, it should be started
+ * by reshape array or raid0 array is before takeover
+ * -1 : error, reshape position is obviously wrong
+ * 1 : success, reshape progress correct or updated
+*/
+static int verify_reshape_position(struct mdinfo *info, int level)
+{
+ int ret_val = 0;
+ char buf[40];
+ int rv;
+
+ /* read sync_max, failure can mean raid0 array */
+ rv = sysfs_get_str(info, NULL, "sync_max", buf, 40);
+
+ if (rv > 0) {
+ char *ep;
+ unsigned long long position = strtoull(buf, &ep, 0);
+
+ dprintf(Name": Read sync_max sysfs entry is: %s\n", buf);
+ if (!(ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))) {
+ position *= get_data_disks(level,
+ info->new_layout,
+ info->array.raid_disks);
+ if (info->reshape_progress < position) {
+ dprintf("Corrected reshape progress (%llu) to "
+ "md position (%llu)\n",
+ info->reshape_progress, position);
+ info->reshape_progress = position;
+ ret_val = 1;
+ } else if (info->reshape_progress > position) {
+ fprintf(stderr, Name ": Fatal error: array "
+ "reshape was not properly frozen "
+ "(expected reshape position is %llu, "
+ "but reshape progress is %llu.\n",
+ position, info->reshape_progress);
+ ret_val = -1;
+ } else {
+ dprintf("Reshape position in md and metadata "
+ "are the same;");
+ ret_val = 1;
+ }
+ }
+ } else if (rv == 0) {
+ /* for valid sysfs entry, 0-length content
+ * should be indicated as error
+ */
+ ret_val = -1;
+ }
+
+ return ret_val;
+}
+
static int reshape_array(char *container, int fd, char *devname,
struct supertype *st, struct mdinfo *info,
int force, struct mddev_dev *devlist,
struct mddev_dev *dv;
int added_disks;
- int *fdlist;
- unsigned long long *offsets;
+ int *fdlist = NULL;
+ unsigned long long *offsets = NULL;
int d;
int nrdisks;
int err;
if (info->reshape_active) {
int new_level = info->new_level;
info->new_level = UnSet;
- info->array.raid_disks -= info->delta_disks;
+ if (info->delta_disks > 0)
+ info->array.raid_disks -= info->delta_disks;
msg = analyse_change(info, &reshape);
info->new_level = new_level;
- info->array.raid_disks += info->delta_disks;
+ if (info->delta_disks > 0)
+ info->array.raid_disks += info->delta_disks;
if (!restart)
/* Make sure the array isn't read-only */
ioctl(fd, RESTART_ARRAY_RW, 0);
(reshape.level != info->array.level ||
reshape.before.layout != info->array.layout ||
reshape.before.data_disks + reshape.parity
- != info->array.raid_disks - info->delta_disks)) {
+ != info->array.raid_disks - max(0, info->delta_disks))) {
fprintf(stderr, Name ": reshape info is not in native format -"
" cannot continue.\n");
goto release;
}
+ if (st->ss->external && restart && (info->reshape_progress == 0)) {
+ /* When reshape is restarted from '0', very begin of array
+ * it is possible that for external metadata reshape and array
+ * configuration doesn't happen.
+ * Check if md has the same opinion, and reshape is restarted
+ * from 0. If so, this is regular reshape start after reshape
+ * switch in metadata to next array only.
+ */
+ if ((verify_reshape_position(info, reshape.level) >= 0) &&
+ (info->reshape_progress == 0))
+ restart = 0;
+ }
if (restart) {
/* reshape already started. just skip to monitoring the reshape */
if (reshape.backup_blocks == 0)
" and only have %d.\n"
" Use --force to over-ride this check.\n",
spares_needed,
- spares_needed == 1 ? "" : "s",
+ spares_needed == 1 ? "" : "s",
info->array.spare_disks + added_disks);
goto release;
}
Name ": Need %d spare%s to create working array,"
" and only have %d.\n",
spares_needed,
- spares_needed == 1 ? "" : "s",
+ spares_needed == 1 ? "" : "s",
info->array.spare_disks + added_disks);
goto release;
}
err = errno;
fprintf(stderr, Name ": %s: could not set level to %s\n",
devname, c);
- if (err == EBUSY &&
+ if (err == EBUSY &&
(info->array.state & (1<<MD_SB_BITMAP_PRESENT)))
fprintf(stderr, " Bitmap must be removed"
" before level can be changed\n");
}
if (!quiet)
fprintf(stderr, Name ": level of %s changed to %s\n",
- devname, c);
+ devname, c);
orig_level = array.level;
sysfs_freeze_array(info);
if (reshape.level > 0 && st->ss->external) {
/* make sure mdmon is aware of the new level */
+ if (mdmon_running(st->container_dev))
+ flush_mdmon(container);
+
if (!mdmon_running(st->container_dev))
start_mdmon(st->container_dev);
ping_monitor(container);
* 1/ The array will shrink.
* We need to ensure the reshape will pause before reaching
* the 'critical section'. We also need to fork and wait for
- * that to happen. When it does we
+ * that to happen. When it does we
* suspend/backup/complete/unfreeze
*
* 2/ The array will not change size.
* unit. The number we have so far is just a minimum
*/
blocks = reshape.backup_blocks;
- if (reshape.before.data_disks ==
+ if (reshape.before.data_disks ==
reshape.after.data_disks) {
/* Make 'blocks' bigger for better throughput, but
* not so big that we reject it below.
sra->new_chunk = info->new_chunk;
- if (restart)
+ if (restart) {
+ /* for external metadata checkpoint saved by mdmon can be lost
+ * or missed /due to e.g. crash/. Check if md is not during
+ * restart farther than metadata points to.
+ * If so, this means metadata information is obsolete.
+ */
+ if (st->ss->external)
+ verify_reshape_position(info, reshape.level);
sra->reshape_progress = info->reshape_progress;
- else {
+ } else {
sra->reshape_progress = 0;
if (reshape.after.data_disks < reshape.before.data_disks)
/* start from the end of the new array */
Name ": Cannot set device shape for %s: %s\n",
devname, strerror(errno));
- if (err == EBUSY &&
+ if (err == EBUSY &&
(array.state & (1<<MD_SB_BITMAP_PRESENT)))
fprintf(stderr,
" Bitmap must be removed before"
int err = 0;
if (sysfs_set_num(sra, NULL, "chunk_size", info->new_chunk) < 0)
err = errno;
- if (!err && sysfs_set_num(sra, NULL, "layout",
- reshape.after.layout) < 0)
+ if (!err && sysfs_set_num(sra, NULL, "layout",
+ reshape.after.layout) < 0)
err = errno;
if (!err && subarray_set_num(container, sra, "raid_disks",
- reshape.after.data_disks +
- reshape.parity) < 0)
+ reshape.after.data_disks +
+ reshape.parity) < 0)
err = errno;
if (err) {
fprintf(stderr, Name ": Cannot set device shape for %s\n",
devname);
- if (err == EBUSY &&
+ if (err == EBUSY &&
(array.state & (1<<MD_SB_BITMAP_PRESENT)))
fprintf(stderr,
" Bitmap must be removed before"
}
}
- err = start_reshape(sra, restart);
+ err = start_reshape(sra, restart, reshape.before.data_disks,
+ reshape.after.data_disks);
if (err) {
- fprintf(stderr,
+ fprintf(stderr,
Name ": Cannot %s reshape for %s\n",
restart ? "continue" : "start",
devname);
free(offsets);
sysfs_free(sra);
fprintf(stderr, Name ": Reshape has to be continued from"
- " location %llu when root fileststem has been mounted\n",
+ " location %llu when root filesystem has been mounted.\n",
sra->reshape_progress);
return 1;
}
abort_reshape(sra);
goto release;
default:
+ free(fdlist);
+ free(offsets);
+ sysfs_free(sra);
return 0;
case 0:
map_fork();
d - odisks, fdlist+odisks,
offsets+odisks);
+ free(fdlist);
+ free(offsets);
+
if (backup_file && done)
unlink(backup_file);
if (!done) {
/* no need to wait for the reshape to finish as
* there is nothing more to do.
*/
+ sysfs_free(sra);
exit(0);
}
wait_reshape(sra);
/* Re-load the metadata as much could have changed */
int cfd = open_dev(st->container_dev);
if (cfd >= 0) {
- ping_monitor(container);
+ flush_mdmon(container);
st->ss->free_super(st);
st->ss->load_container(st, cfd, container);
close(cfd);
*/
if (reshape.before.data_disks !=
reshape.after.data_disks &&
- info->custom_array_size) {
- struct mdinfo *info2;
- char *subarray = strchr(info->text_version+1, '/')+1;
-
- info2 = st->ss->container_content(st, subarray);
- if (info2) {
- unsigned long long current_size = 0;
- unsigned long long new_size =
- info2->custom_array_size/2;
-
- if (sysfs_get_ll(sra,
- NULL,
- "array_size",
- ¤t_size) == 0 &&
- new_size > current_size) {
- if (sysfs_set_num(sra, NULL,
- "array_size", new_size)
- < 0)
- dprintf("Error: Cannot"
- " set array size");
- else
- dprintf("Array size "
- "changed");
- dprintf(" from %llu to %llu.\n",
- current_size, new_size);
- }
- sysfs_free(info2);
- }
- }
+ info->custom_array_size)
+ set_array_size(st, info, info->text_version);
if (info->new_level != reshape.level) {
st->update_tail = NULL;
}
out:
+ sysfs_free(sra);
if (forked)
return 0;
unfreeze(st);
exit(0);
release:
+ free(fdlist);
+ free(offsets);
if (orig_level != UnSet && sra) {
c = map_num(pers, orig_level);
if (c && sysfs_set_str(sra, NULL, "level", c) == 0)
fprintf(stderr, Name ": aborting level change\n");
}
+ sysfs_free(sra);
if (!forked)
unfreeze(st);
return 1;
}
+/* mdfd handle is passed to be closed in child process (after fork).
+ */
int reshape_container(char *container, char *devname,
- struct supertype *st,
+ int mdfd,
+ struct supertype *st,
struct mdinfo *info,
int force,
char *backup_file,
{
struct mdinfo *cc = NULL;
int rv = restart;
+ int last_devnum = -1;
/* component_size is not meaningful for a container,
* so pass '-1' meaning 'no change'
break;
}
+ /* close unused handle in child process
+ */
+ if (mdfd > -1)
+ close(mdfd);
+
while(1) {
/* For each member array with reshape_active,
* we need to perform the reshape.
devname2devnum(container));
if (!mdstat)
continue;
+ if (mdstat->active == 0) {
+ fprintf(stderr, Name ": Skipping inactive "
+ "array md%i.\n", mdstat->devnum);
+ free_mdstat(mdstat);
+ mdstat = NULL;
+ continue;
+ }
break;
}
if (!content)
break;
- fd = open_dev(mdstat->devnum);
- if (fd < 0)
- break;
adev = map_dev(dev2major(mdstat->devnum),
dev2minor(mdstat->devnum),
0);
if (!adev)
adev = content->text_version;
+ fd = open_dev(mdstat->devnum);
+ if (fd < 0) {
+ printf(Name ": Device %s cannot be opened for reshape.",
+ adev);
+ break;
+ }
+
+ if (last_devnum == mdstat->devnum) {
+ /* Do not allow for multiple reshape_array() calls for
+ * the same array.
+ * It can happen when reshape_array() returns without
+ * error, when reshape is not finished (wrong reshape
+ * starting/continuation conditions). Mdmon doesn't
+ * switch to next array in container and reentry
+ * conditions for the same array occur.
+ * This is possibly interim until the behaviour of
+ * reshape_array is resolved().
+ */
+ printf(Name ": Multiple reshape execution detected for "
+ "device %s.", adev);
+ close(fd);
+ break;
+ }
+ last_devnum = mdstat->devnum;
+
sysfs_init(content, fd, mdstat->devnum);
+ if (mdmon_running(devname2devnum(container)))
+ flush_mdmon(container);
+
rv = reshape_array(container, fd, adev, st,
content, force, NULL,
backup_file, quiet, 1, restart,
restart = 0;
if (rv)
break;
+
+ if (mdmon_running(devname2devnum(container)))
+ flush_mdmon(container);
}
if (!rv)
unfreeze(st);
* suspend/backup/allow always come together
* wait/resume/discard do too.
* For the same-size case we have two backups to improve flow.
- *
+ *
*/
int progress_reshape(struct mdinfo *info, struct reshape *reshape,
* this much.
*/
target = 64*1024*2 * min(reshape->before.data_disks,
- reshape->after.data_disks);
+ reshape->after.data_disks);
target /= reshape->backup_blocks;
if (target < 2)
target = 2;
- completed;
}
*reshape_completed = completed;
-
+
close(fd);
/* We return the need_backup flag. Caller will decide
}
}
-
/* FIXME return status is never checked */
static int grow_backup(struct mdinfo *sra,
unsigned long long offset, /* per device */
else
lseek64(destfd[i], destoffsets[i], 0);
- rv = save_stripes(sources, offsets,
+ rv = save_stripes(sources, offsets,
disks, chunk, level, layout,
dests, destfd,
offset*512*odata, stripes * chunk * odata,
* every works.
*/
/* FIXME return value is often ignored */
-static int forget_backup(
- int dests, int *destfd, unsigned long long *destoffsets,
- int part)
+static int forget_backup(int dests, int *destfd,
+ unsigned long long *destoffsets,
+ int part)
{
- /*
+ /*
* Erase backup 'part' (which is 0 or 1)
*/
int i;
if ((unsigned long long)lseek64(destfd[i], destoffsets[i]-4096, 0) !=
destoffsets[i]-4096)
rv = -1;
- if (rv == 0 &&
+ if (rv == 0 &&
write(destfd[i], &bsb, 512) != 512)
rv = -1;
fsync(destfd[i]);
fail("magic is bad");
if (memcmp(bsb2.magic, "md_backup_data-2", 16) == 0 &&
bsb2.sb_csum2 != bsb_csum((char*)&bsb2,
- ((char*)&bsb2.sb_csum2)-((char*)&bsb2)))
+ ((char*)&bsb2.sb_csum2)-((char*)&bsb2)))
fail("second csum bad");
if (__le64_to_cpu(bsb2.devstart)*512 != offset)
if ((unsigned long long)read(afd, abuf, len) != len)
fail("read first from array failed");
if (memcmp(bbuf, abuf, len) != 0) {
- #if 0
+#if 0
int i;
printf("offset=%llu len=%llu\n",
(unsigned long long)__le64_to_cpu(bsb2.arraystart)*512, len);
printf("first diff byte %d\n", i);
break;
}
- #endif
+#endif
fail("data1 compare failed");
}
}
nonew:
if (verbose)
fprintf(stderr, Name
- ": backup-metadata found on %s but is not needed\n", devname);
+ ": backup-metadata found on %s but is not needed\n", devname);
continue; /* No new data here */
}
} else {
second_fail:
if (verbose)
fprintf(stderr, Name
- ": Failed to verify secondary backup-metadata block on %s\n",
+ ": Failed to verify secondary backup-metadata block on %s\n",
devname);
continue; /* Cannot seek */
}
if (verbose)
fprintf(stderr, Name ": Error restoring backup from %s\n",
devname);
+ free(offsets);
return 1;
}
-
+
if (bsb.magic[15] == '2' &&
restore_stripes(fdlist, offsets,
info->array.raid_disks,
if (verbose)
fprintf(stderr, Name ": Error restoring second backup from %s\n",
devname);
+ free(offsets);
return 1;
}
+ free(offsets);
/* Ok, so the data is restored. Let's update those superblocks. */
goto Grow_continue_command_exit;
}
- cc = st->ss->container_content(st, NULL);
+ cc = st->ss->container_content(st, subarray);
for (content = cc; content ; content = content->next) {
char *array;
+ int allow_reshape = 1;
if (content->reshape_active == 0)
continue;
+ /* The decision about array or container wide
+ * reshape is taken in Grow_continue based
+ * content->reshape_active state, therefore we
+ * need to check_reshape based on
+ * reshape_active and subarray name
+ */
+ if (content->array.state & (1<<MD_SB_BLOCK_VOLUME))
+ allow_reshape = 0;
+ if (content->reshape_active == CONTAINER_RESHAPE &&
+ (content->array.state
+ & (1<<MD_SB_BLOCK_CONTAINER_RESHAPE)))
+ allow_reshape = 0;
+
+ if (!allow_reshape) {
+ fprintf(stderr, Name
+ ": cannot continue reshape of an array"
+ " in container with unsupported"
+ " metadata: %s(%s)\n",
+ devname, buf);
+ ret_val = 1;
+ goto Grow_continue_command_exit;
+ }
array = strchr(content->text_version+1, '/')+1;
mdstat = mdstat_by_subdev(array, container_dev);
if (!mdstat)
continue;
+ if (mdstat->active == 0) {
+ fprintf(stderr, Name ": Skipping inactive "
+ "array md%i.\n", mdstat->devnum);
+ free_mdstat(mdstat);
+ mdstat = NULL;
+ continue;
+ }
break;
}
if (!content) {
}
}
+ /* verify that array under reshape is started from
+ * correct position
+ */
+ if (verify_reshape_position(content,
+ map_name(pers, mdstat->level)) < 0) {
+ ret_val = 1;
+ goto Grow_continue_command_exit;
+ }
+
/* continue reshape
*/
ret_val = Grow_continue(fd, st, content, backup_file, 0);
int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info,
char *backup_file, int freeze_reshape)
{
- char buf[40];
- char *container = NULL;
- int err;
+ int ret_val = 2;
+
+ if (!info->reshape_active)
+ return ret_val;
- 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);
+ char container[40];
+ int cfd = open_dev(st->container_dev);
- if (!mdmon_running(st->container_dev))
- start_mdmon(st->container_dev);
- ping_monitor_by_id(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, mdfd,
+ 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);
- 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, freeze_reshape);
- }
- }
- return reshape_array(container, mdfd, "array", st, info, 1,
- NULL, backup_file, 0, 0, 1, freeze_reshape);
+ return ret_val;
}