]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
revert-reshape: make sure reshape_position is acceptable.
authorNeilBrown <neilb@suse.de>
Thu, 27 Jun 2013 06:38:53 +0000 (16:38 +1000)
committerNeilBrown <neilb@suse.de>
Thu, 27 Jun 2013 06:38:53 +0000 (16:38 +1000)
We can only revert a reshape if the reshape_position aligns
properly for the old geometry.
If it doesn't we just fail for now.

Also fix a +/- error with updating raid_disks for super1.c

Signed-off-by: NeilBrown <neilb@suse.de>
super0.c
super1.c

index ff4c657c223ca28c9aeea157335b0c4e1ef69afd..b2019dfaff2a152da26ed96c9d816cb73954e0f7 100644 (file)
--- a/super0.c
+++ b/super0.c
@@ -654,7 +654,16 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
                               devname);
                else {
                        int tmp;
+                       int parity = sb->level == 6 ? 2 : 1;
                        rv = 0;
+
+                       if (sb->reshape_position % (
+                                   sb->new_chunk/512 *
+                                   (sb->raid_disks - sb->delta_disks - parity))) {
+                               pr_err("Reshape position is not suitably aligned.\n");
+                               pr_err("Try normal assembly as stop again\n");
+                               return -2;
+                       }
                        sb->raid_disks -= sb->delta_disks;
                        sb->delta_disks = -sb->delta_disks;
 
index 088df4bf3e9d13764961e2e0af12b0fc59fa061f..b6e1e91955601e0a0cc2caa824ff8f60cf7317c0 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -57,7 +57,7 @@ struct mdp_superblock_1 {
        __u64   reshape_position;       /* next address in array-space for reshape */
        __u32   delta_disks;    /* change in number of raid_disks               */
        __u32   new_layout;     /* new layout                                   */
-       __u32   new_chunk;      /* new chunk size (bytes)                       */
+       __u32   new_chunk;      /* new chunk size (sectors)                     */
        __u32   new_offset;     /* signed number to add to data_offset in new
                                 * layout.  0 == no-change.  This can be
                                 * different on each device in the array.
@@ -1259,9 +1259,33 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
                        pr_err("No active reshape to revert on %s\n",
                               devname);
                else {
-                       rv = 0;
                        __u32 temp;
-                       sb->raid_disks = __cpu_to_le32(__le32_to_cpu(sb->raid_disks) +
+                       unsigned long long reshape_sectors;
+                       long reshape_chunk;
+                       rv = 0;
+                       /* reshape_position is a little messy.
+                        * Its value must be a multiple of the larger
+                        * chunk size, and of the "after" data disks.
+                        * So when reverting we need to change it to
+                        * be a multiple of the new "after" data disks,
+                        * which is the old "before".
+                        * If it isn't already a multiple of 'before',
+                        * the only thing we could do would be
+                        * copy some block around on the disks, which
+                        * is easy to get wrong.
+                        * So we reject a revert-reshape unless the
+                        * alignment is good.
+                        */
+                       reshape_sectors = __le64_to_cpu(sb->reshape_position);
+                       reshape_chunk = __le32_to_cpu(sb->new_chunk);
+                       reshape_chunk *= __le32_to_cpu(sb->raid_disks) - __le32_to_cpu(sb->delta_disks) -
+                               (__le32_to_cpu(sb->level)==6 ? 2 : 1);
+                       if (reshape_sectors % reshape_chunk) {
+                               pr_err("Reshape position is not suitably aligned.\n");
+                               pr_err("Try normal assembly as stop again\n");
+                               return -2;
+                       }
+                       sb->raid_disks = __cpu_to_le32(__le32_to_cpu(sb->raid_disks) -
                                                       __le32_to_cpu(sb->delta_disks));
                        if (sb->delta_disks == 0)
                                sb->feature_map ^= __cpu_to_le32(MD_FEATURE_RESHAPE_BACKWARDS);