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 data_disks)
+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;
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 (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", sync_max_to_set);
err = err ?: sysfs_set_num(sra, NULL, "sync_max", sync_max_to_set);
int restart, int freeze_reshape);
static int reshape_container(char *container, char *devname,
int mdfd,
- struct supertype *st,
+ struct supertype *st,
struct mdinfo *info,
int force,
char *backup_file,
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;
}
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);
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) {
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];
+
+ /* read sync_max, failure can mean raid0 array */
+ if (sysfs_get_str(info, NULL, "sync_max", buf, 40) > 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;
+ }
+ }
+ }
+
+ 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,
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;
" 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,
- info->array.raid_disks - reshape.parity);
+ 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;
}
/* 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);
*/
int reshape_container(char *container, char *devname,
int mdfd,
- struct supertype *st,
+ 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'
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. */
char buf[40];
int cfd = -1;
int fd2 = -1;
- char *ep;
- unsigned long long position;
dprintf("Grow continue from command line called for %s\n",
devname);
/* 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");
+ if (verify_reshape_position(content,
+ map_name(pers, mdstat->level)) <= 0) {
ret_val = 1;
goto Grow_continue_command_exit;
}