FIX: Meet SET_ARRAY_INFO ioctl requirements

Problem has been observed when raid10<->raid0 takeover operation
is executed.
In code updating layout, raid_disks and chunk_size for non-restriping
operations in reshape array functions SET_ARRAY_INFO ioctl call was
not succeeded.
Takeover process finish execution with error, mdadm shows message:
"mdadm: failed to set disks"

Cause is not meeting SET_ARRAY_INFO ioctl requirements:
- only one parameter may be changed at one time
- level of current array info and new info should be the same

Patch introduces solution for this issue.
At the beginning of discussed code we read current information
about array and then compare them with new values should be set.
If particular value is different (and should be set),
we are overwrite only this one in array info and then call ioctl.

Signed-off-by: Krzysztof Wojcik <krzysztof.wojcik@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
Krzysztof Wojcik 2011-01-27 17:46:58 +01:00 committed by NeilBrown
parent d5ca4a23fc
commit 24aebf3add
1 changed files with 20 additions and 11 deletions

31
Grow.c
View File

@ -1716,35 +1716,44 @@ static int reshape_array(char *container, int fd, char *devname,
/* No restriping needed, but we might need to impose
* some more changes: layout, raid_disks, chunk_size
*/
/* read current array info */
if (ioctl(fd, GET_ARRAY_INFO, &array) != 0) {
dprintf("Canot get array information.\n");
goto release;
}
/* compare current array info with new values and if
* it is different update them to new */
if (info->new_layout != UnSet &&
info->new_layout != info->array.layout) {
info->array.layout = info->new_layout;
if (ioctl(fd, SET_ARRAY_INFO, &info->array) != 0) {
info->new_layout != array.layout) {
array.layout = info->new_layout;
if (ioctl(fd, SET_ARRAY_INFO, &array) != 0) {
fprintf(stderr, Name ": failed to set new layout\n");
goto release;
} else if (!quiet)
printf("layout for %s set to %d\n",
devname, info->array.layout);
devname, array.layout);
}
if (info->delta_disks != UnSet &&
info->delta_disks != 0) {
info->array.raid_disks += info->delta_disks;
if (ioctl(fd, SET_ARRAY_INFO, &info->array) != 0) {
info->delta_disks != 0 &&
array.raid_disks != (info->array.raid_disks + info->delta_disks)) {
array.raid_disks += info->delta_disks;
if (ioctl(fd, SET_ARRAY_INFO, &array) != 0) {
fprintf(stderr, Name ": failed to set raid disks\n");
goto release;
} else if (!quiet)
} else if (!quiet) {
printf("raid_disks for %s set to %d\n",
devname, info->array.raid_disks);
devname, array.raid_disks);
}
}
if (info->new_chunk != 0 &&
info->new_chunk != info->array.chunk_size) {
info->new_chunk != array.chunk_size) {
if (sysfs_set_num(info, NULL,
"chunk_size", info->new_chunk) != 0) {
fprintf(stderr, Name ": failed to set chunk size\n");
goto release;
} else if (!quiet)
printf("chunk size for %s set to %d\n",
devname, info->array.chunk_size);
devname, array.chunk_size);
}
unfreeze(st);
return 0;