summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-03-22 15:34:17 +1100
committerNeilBrown <neilb@suse.de>2012-03-22 15:34:17 +1100
commit0073a6e189c41ca92123ac11278faddf6355125a (patch)
tree1bc653ff701acfde4e808fe91d54be91f6cec31d
parente62b778573d4df5e729cf3941fe17eff1fe4e758 (diff)
downloadmdadm-0073a6e189c41ca92123ac11278faddf6355125a.tar.gz
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 <neilb@suse.de>
-rw-r--r--Grow.c28
1 files 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;
}
}