else {
struct mdinfo *sra = sysfs_read(-1, st->devnum, GET_VERSION);
int err;
+ char buf[20];
if (!sra)
return -1;
+ /* Need to clear any 'read-auto' status */
+ if (sysfs_get_str(sra, NULL, "array_state", buf, 20) > 0 &&
+ strncmp(buf, "read-auto", 9) == 0)
+ sysfs_set_str(sra, NULL, "array_state", "clean");
+
err = sysfs_freeze_array(sra);
sysfs_free(sra);
return err;
/* ========= set size =============== */
if (size >= 0 && (size == 0 || size != array.size)) {
- long long orig_size = array.size;
+ long long orig_size = get_component_size(fd)/2;
+ struct mdinfo *mdi;
+
+ if (orig_size == 0)
+ orig_size = array.size;
if (reshape_super(st, size, UnSet, UnSet, 0, 0, UnSet, NULL,
devname, !quiet)) {
goto release;
}
sync_metadata(st);
+
+ /* Update the size of each member device in case
+ * they have been resized. This will never reduce
+ * below the current used-size. The "size" attribute
+ * understand '0' to mean 'max'.
+ */
+ for (mdi = sra->devs; mdi; mdi = mdi->next)
+ sysfs_set_num(sra, mdi, "size", size);
+
array.size = size;
if (array.size != size) {
/* got truncated to 32bit, write to
size = get_component_size(fd)/2;
if (size == 0)
size = array.size;
- if (!quiet)
- fprintf(stderr, Name ": component size of %s has been set to %lluK\n",
- devname, size);
+ if (!quiet) {
+ if (size == orig_size)
+ fprintf(stderr, Name ": component size of %s "
+ "unchanged at %lluK\n",
+ devname, size);
+ else
+ fprintf(stderr, Name ": component size of %s "
+ "has been set to %lluK\n",
+ devname, size);
+ }
changed = 1;
} else if (array.level != LEVEL_CONTAINER) {
size = get_component_size(fd)/2;
size = array.size;
}
+ /* See if there is anything else to do */
+ if ((level == UnSet || level == array.level) &&
+ (layout_str == NULL) &&
+ (chunksize == 0 || chunksize == array.chunk_size) &&
+ (raid_disks == 0 || raid_disks == array.raid_disks)) {
+ /* Nothing more to do */
+ if (!changed && !quiet)
+ fprintf(stderr, Name ": %s: no change requested\n",
+ devname);
+ goto release;
+ }
+
/* ========= check for Raid10/Raid1 -> Raid0 conversion ===============
* current implementation assumes that following conditions must be met:
* - RAID10:
}
}
- if (array.level == LEVEL_CONTAINER) {
+ if (array.level == LEVEL_FAULTY) {
+ if (level != UnSet && level != array.level) {
+ fprintf(stderr, Name ": cannot change level of Faulty device\n");
+ rv =1 ;
+ }
+ if (chunksize) {
+ fprintf(stderr, Name ": cannot set chunksize of Faulty device\n");
+ rv =1 ;
+ }
+ if (raid_disks && raid_disks != 1) {
+ fprintf(stderr, Name ": cannot set raid_disks of Faulty device\n");
+ rv =1 ;
+ }
+ if (layout_str) {
+ if (ioctl(fd, GET_ARRAY_INFO, &array) != 0) {
+ dprintf("Cannot get array information.\n");
+ goto release;
+ }
+ array.layout = info.new_layout;
+ if (ioctl(fd, SET_ARRAY_INFO, &array) != 0) {
+ fprintf(stderr, Name ": failed to set new layout\n");
+ rv = 1;
+ } else if (!quiet)
+ printf("layout for %s set to %d\n",
+ devname, array.layout);
+ }
+ } else if (array.level == LEVEL_CONTAINER) {
/* This change is to be applied to every array in the
* container. This is only needed when the metadata imposes
* restraints of the various arrays in the container.
if (info->reshape_active) {
int new_level = info->new_level;
info->new_level = UnSet;
+ 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 (!restart)
/* Make sure the array isn't read-only */
ioctl(fd, RESTART_ARRAY_RW, 0);
if (restart &&
(reshape.level != info->array.level ||
reshape.before.layout != info->array.layout ||
- reshape.before.data_disks + reshape.parity != info->array.raid_disks)) {
+ reshape.before.data_disks + reshape.parity
+ != info->array.raid_disks - info->delta_disks)) {
fprintf(stderr, Name ": reshape info is not in native format -"
" cannot continue.\n");
goto release;
if (fd < 0)
goto check_progress;
- if (sysfs_fd_get_ll(fd, &completed) < 0) {
- close(fd);
+ if (sysfs_fd_get_ll(fd, &completed) < 0)
goto check_progress;
- }
+
while (completed < max_progress && completed < wait_point) {
/* Check that sync_action is still 'reshape' to avoid
* waiting forever on a dead array
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
select(fd+1, NULL, NULL, &rfds, NULL);
- if (sysfs_fd_get_ll(fd, &completed) < 0) {
- close(fd);
+ if (sysfs_fd_get_ll(fd, &completed) < 0)
goto check_progress;
- }
}
/* Some kernels reset 'sync_completed' to zero,
* we need to have real point we are in md
/* if we couldn't read a number from sync_completed, then
* either the reshape did complete, or it aborted.
* We can tell which by checking for 'none' in reshape_position.
+ * If it did abort, then it might immediately restart if it
+ * it was just a device failure that leaves us degraded but
+ * functioning.
*/
strcpy(buf, "hi");
if (sysfs_get_str(info, NULL, "reshape_position", buf, sizeof(buf)) < 0
- || strncmp(buf, "none", 4) != 0)
- return -2; /* abort */
- else {
+ || strncmp(buf, "none", 4) != 0) {
+ /* The abort might only be temporary. Wait up to 10
+ * seconds for fd to contain a valid number again.
+ */
+ struct timeval tv;
+ int rv = -2;
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+ while (fd >= 0 && rv < 0) {
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+ if (select(fd+1, NULL, NULL, &rfds, &tv) != 1)
+ break;
+ if (sysfs_fd_get_ll(fd, &completed) >= 0)
+ /* all good again */
+ rv = 1;
+ }
+ if (fd >= 0)
+ close(fd);
+ return rv; /* abort */
+ } else {
/* Maybe racing with array shutdown - check state */
+ if (fd >= 0)
+ close(fd);
if (sysfs_get_str(info, NULL, "array_state", buf, sizeof(buf)) < 0
|| strncmp(buf, "inactive", 8) == 0
|| strncmp(buf, "clear",5) == 0)
continue;
ok = st->ss->load_super(st, devfd, NULL);
close(devfd);
- if (ok >= 0)
+ if (ok == 0)
break;
}
if (!sd) {