Grow: warn if growing an array will make it degraded.

Growing an array when there aren't enough spares can make the array
degraded.  This works but might not be what is wanted.
So warn the user in this case and require a --force to go ahead
with the reshape.

Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
NeilBrown 2010-12-09 11:51:13 +11:00
parent f80c8614b0
commit 691a36b76f
3 changed files with 49 additions and 3 deletions

46
Grow.c
View File

@ -996,7 +996,8 @@ unsigned long compute_backup_blocks(int nchunk, int ochunk,
int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
long long size,
int level, char *layout_str, int chunksize, int raid_disks)
int level, char *layout_str, int chunksize, int raid_disks,
int force)
{
/* Make some changes in the shape of an array.
* The kernel must support the change.
@ -1128,6 +1129,19 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
if (mdmon_running(container_dev))
st->update_tail = &st->updates;
}
if (raid_disks > array.raid_disks &&
array.spare_disks < (raid_disks - array.raid_disks) &&
!force) {
fprintf(stderr,
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",
array.spare_disks);
return 1;
}
sra = sysfs_read(fd, 0, GET_LEVEL | GET_DISKS | GET_DEVS | GET_STATE);
@ -1309,6 +1323,36 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
rv = 1;/* not possible */
goto release;
}
if (!force) {
/* Need to check there are enough spares */
int spares_needed = 0;
switch (array.level * 16 + level) {
case 0x05:
spares_needed = 1; break;
case 0x06:
spares_needed = 2; break;
case 0x15:
spares_needed = 1; break;
case 0x16:
spares_needed = 2; break;
case 0x56:
spares_needed = 1; break;
}
if (raid_disks > array.raid_disks)
spares_needed += raid_disks-array.raid_disks;
if (spares_needed > array.spare_disks) {
fprintf(stderr,
Name ": Need %d spare%s to avoid"
" degraded array, and only have %d.\n"
" Use --force to over-ride"
" this check.\n",
spares_needed,
spares_needed == 1 ? "" : "s",
array.spare_disks);
rv = 1;
goto release;
}
}
err = sysfs_set_str(sra, NULL, "level", c);
if (err) {
err = errno;

View File

@ -1610,7 +1610,8 @@ int main(int argc, char *argv[])
} else if (size >= 0 || raiddisks != 0 || layout_str != NULL
|| chunk != 0 || level != UnSet) {
rv = Grow_reshape(devlist->devname, mdfd, quiet, backup_file,
size, level, layout_str, chunk, raiddisks);
size, level, layout_str, chunk, raiddisks,
force);
} else if (array_size < 0)
fprintf(stderr, Name ": no changes to --grow\n");
break;

View File

@ -965,7 +965,8 @@ extern int Grow_Add_device(char *devname, int fd, char *newdev);
extern int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int write_behind, int force);
extern int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
long long size,
int level, char *layout_str, int chunksize, int raid_disks);
int level, char *layout_str, int chunksize, int raid_disks,
int force);
extern int Grow_restart(struct supertype *st, struct mdinfo *info,
int *fdlist, int cnt, char *backup_file, int verbose);
extern int Grow_continue(int mdfd, struct supertype *st,