]> git.neil.brown.name Git - mdadm.git/commitdiff
Remove possible crash during RAID6 -> RAID5 reshape.
authorNeilBrown <neilb@suse.de>
Thu, 22 Mar 2012 04:34:17 +0000 (15:34 +1100)
committerNeilBrown <neilb@suse.de>
Thu, 22 Mar 2012 04:34:17 +0000 (15:34 +1100)
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>
Grow.c

diff --git a/Grow.c b/Grow.c
index 239b50d6bec08bcfd878277781e6f642218365a5..a0dbb205bf3d2ee2ced1c1ba3b7c417c8cebb1a9 100644 (file)
--- 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;
                        }
                }