From 0073a6e189c41ca92123ac11278faddf6355125a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 22 Mar 2012 15:34:17 +1100 Subject: [PATCH] Remove possible crash during RAID6 -> RAID5 reshape. If a RAID6 array is in a state which doesn't have a RAID5 equivalent, the code currently dereferences a NULL. If it does have an equivalent - use that. If it doesn't but it already in the RAID5-compatible layout with the Q block last, handle that case, else require the new layout to be explicitly requested. Signed-off-by: NeilBrown --- Grow.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/Grow.c b/Grow.c index 239b50d..a0dbb20 100644 --- a/Grow.c +++ b/Grow.c @@ -1275,7 +1275,7 @@ char *analyse_change(struct mdinfo *info, struct reshape *re) break; case 5: - /* We get to RAID5 for RAID5 or RAID6 */ + /* We get to RAID5 from RAID5 or RAID6 */ if (re->level != 5 && re->level != 6) return "Cannot convert to RAID5 from this level"; @@ -1297,11 +1297,27 @@ char *analyse_change(struct mdinfo *info, struct reshape *re) char layout[40]; char *ls = map_num(r5layout, info->new_layout); int l; - strcat(strcpy(layout, ls), "-6"); - l = map_name(r6layout, layout); - if (l == UnSet) - return "Cannot find RAID6 layout" - " to convert to"; + if (ls) { + /* Current RAID6 layout has a RAID5 + * equivalent - good + */ + strcat(strcpy(layout, ls), "-6"); + l = map_name(r6layout, layout); + if (l == UnSet) + return "Cannot find RAID6 layout" + " to convert to"; + } else { + /* Current RAID6 has no equivalent. + * If it is already a '-6' layout we + * can leave it unchanged, else we must + * fail + */ + ls = map_num(r6layout, info->new_layout); + if (!ls || + strcmp(ls+strlen(ls)-2, "-6") != 0) + return "Please specify new layout"; + l = info->new_layout; + } re->after.layout = l; } }