diff options
author | NeilBrown <neilb@suse.de> | 2012-03-22 15:34:17 +1100 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2012-03-22 15:34:17 +1100 |
commit | 0073a6e189c41ca92123ac11278faddf6355125a (patch) | |
tree | 1bc653ff701acfde4e808fe91d54be91f6cec31d | |
parent | e62b778573d4df5e729cf3941fe17eff1fe4e758 (diff) | |
download | mdadm-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.c | 28 |
1 files changed, 22 insertions, 6 deletions
@@ -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; } } |