From a2836f12c4c45738b495403a91a0f0db2e88e0cb Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 27 Jun 2013 16:38:53 +1000 Subject: [PATCH] revert-reshape: make sure reshape_position is acceptable. 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 --- super0.c | 9 +++++++++ super1.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/super0.c b/super0.c index ff4c657c..b2019dfa 100644 --- 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; diff --git a/super1.c b/super1.c index 088df4bf..b6e1e919 100644 --- 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); -- 2.39.2