From 691a36b76f871a63a327641589f41e968b05afa9 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 9 Dec 2010 11:51:13 +1100 Subject: [PATCH] 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 --- Grow.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- mdadm.c | 3 ++- mdadm.h | 3 ++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/Grow.c b/Grow.c index cf09a60..222d755 100644 --- a/Grow.c +++ b/Grow.c @@ -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; diff --git a/mdadm.c b/mdadm.c index 187ad89..dd5311d 100644 --- a/mdadm.c +++ b/mdadm.c @@ -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; diff --git a/mdadm.h b/mdadm.h index 175d228..8e2c231 100644 --- a/mdadm.h +++ b/mdadm.h @@ -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,