Skip to content

Commit 2c810cd

Browse files
committed
md: allow a reshape operation to be reversed.
Currently a reshape operation always progresses from the start of the array to the end unless the number of devices is being reduced, in which case it progressed in the opposite direction. To reverse a partial reshape which changes the number of devices you can stop the array and re-assemble with the raid-disks numbers reversed and it will undo. However for a reshape that does not change the number of devices it is not possible to reverse the reshape in the middle - you have to wait until it completes. So add a 'reshape_direction' attribute with is either 'forwards' or 'backwards' and can be explicitly set when delta_disks is zero. This will become more important when we allow the data_offset to change in a reshape. Then the explicit statement of what direction is being used will be more useful. This can be enabled in raid5 trivially as it already supports reverse reshape and just needs to use a different trigger to request it. Signed-off-by: NeilBrown <neilb@suse.de>
1 parent b5e1b8c commit 2c810cd

File tree

4 files changed

+84
-14
lines changed

4 files changed

+84
-14
lines changed

drivers/md/md.c

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,7 @@ void mddev_init(struct mddev *mddev)
607607
init_waitqueue_head(&mddev->sb_wait);
608608
init_waitqueue_head(&mddev->recovery_wait);
609609
mddev->reshape_position = MaxSector;
610+
mddev->reshape_backwards = 0;
610611
mddev->resync_min = 0;
611612
mddev->resync_max = MaxSector;
612613
mddev->level = LEVEL_NONE;
@@ -1185,13 +1186,16 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
11851186
mddev->events = ev1;
11861187
mddev->bitmap_info.offset = 0;
11871188
mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
1189+
mddev->reshape_backwards = 0;
11881190

11891191
if (mddev->minor_version >= 91) {
11901192
mddev->reshape_position = sb->reshape_position;
11911193
mddev->delta_disks = sb->delta_disks;
11921194
mddev->new_level = sb->new_level;
11931195
mddev->new_layout = sb->new_layout;
11941196
mddev->new_chunk_sectors = sb->new_chunk >> 9;
1197+
if (mddev->delta_disks < 0)
1198+
mddev->reshape_backwards = 1;
11951199
} else {
11961200
mddev->reshape_position = MaxSector;
11971201
mddev->delta_disks = 0;
@@ -1645,7 +1649,8 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
16451649
mddev->events = ev1;
16461650
mddev->bitmap_info.offset = 0;
16471651
mddev->bitmap_info.default_offset = 1024 >> 9;
1648-
1652+
mddev->reshape_backwards = 0;
1653+
16491654
mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
16501655
memcpy(mddev->uuid, sb->set_uuid, 16);
16511656

@@ -1662,6 +1667,11 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
16621667
mddev->new_level = le32_to_cpu(sb->new_level);
16631668
mddev->new_layout = le32_to_cpu(sb->new_layout);
16641669
mddev->new_chunk_sectors = le32_to_cpu(sb->new_chunk);
1670+
if (mddev->delta_disks < 0 ||
1671+
(mddev->delta_disks == 0 &&
1672+
(le32_to_cpu(sb->feature_map)
1673+
& MD_FEATURE_RESHAPE_BACKWARDS)))
1674+
mddev->reshape_backwards = 1;
16651675
} else {
16661676
mddev->reshape_position = MaxSector;
16671677
mddev->delta_disks = 0;
@@ -1781,6 +1791,10 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
17811791
sb->delta_disks = cpu_to_le32(mddev->delta_disks);
17821792
sb->new_level = cpu_to_le32(mddev->new_level);
17831793
sb->new_chunk = cpu_to_le32(mddev->new_chunk_sectors);
1794+
if (mddev->delta_disks == 0 &&
1795+
mddev->reshape_backwards)
1796+
sb->feature_map
1797+
|= cpu_to_le32(MD_FEATURE_RESHAPE_BACKWARDS);
17841798
}
17851799

17861800
if (rdev->badblocks.count == 0)
@@ -3419,6 +3433,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
34193433
mddev->new_chunk_sectors = mddev->chunk_sectors;
34203434
mddev->raid_disks -= mddev->delta_disks;
34213435
mddev->delta_disks = 0;
3436+
mddev->reshape_backwards = 0;
34223437
module_put(pers->owner);
34233438
printk(KERN_WARNING "md: %s: %s would not accept array\n",
34243439
mdname(mddev), clevel);
@@ -3492,6 +3507,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
34923507
mddev->layout = mddev->new_layout;
34933508
mddev->chunk_sectors = mddev->new_chunk_sectors;
34943509
mddev->delta_disks = 0;
3510+
mddev->reshape_backwards = 0;
34953511
mddev->degraded = 0;
34963512
if (mddev->pers->sync_request == NULL) {
34973513
/* this is now an array without redundancy, so
@@ -3585,6 +3601,7 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
35853601
int olddisks = mddev->raid_disks - mddev->delta_disks;
35863602
mddev->delta_disks = n - olddisks;
35873603
mddev->raid_disks = n;
3604+
mddev->reshape_backwards = (mddev->delta_disks < 0);
35883605
} else
35893606
mddev->raid_disks = n;
35903607
return rv ? rv : len;
@@ -4436,6 +4453,7 @@ reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
44364453
return -EINVAL;
44374454
mddev->reshape_position = new;
44384455
mddev->delta_disks = 0;
4456+
mddev->reshape_backwards = 0;
44394457
mddev->new_level = mddev->level;
44404458
mddev->new_layout = mddev->layout;
44414459
mddev->new_chunk_sectors = mddev->chunk_sectors;
@@ -4446,6 +4464,42 @@ static struct md_sysfs_entry md_reshape_position =
44464464
__ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
44474465
reshape_position_store);
44484466

4467+
static ssize_t
4468+
reshape_direction_show(struct mddev *mddev, char *page)
4469+
{
4470+
return sprintf(page, "%s\n",
4471+
mddev->reshape_backwards ? "backwards" : "forwards");
4472+
}
4473+
4474+
static ssize_t
4475+
reshape_direction_store(struct mddev *mddev, const char *buf, size_t len)
4476+
{
4477+
int backwards = 0;
4478+
if (cmd_match(buf, "forwards"))
4479+
backwards = 0;
4480+
else if (cmd_match(buf, "backwards"))
4481+
backwards = 1;
4482+
else
4483+
return -EINVAL;
4484+
if (mddev->reshape_backwards == backwards)
4485+
return len;
4486+
4487+
/* check if we are allowed to change */
4488+
if (mddev->delta_disks)
4489+
return -EBUSY;
4490+
4491+
if (mddev->persistent &&
4492+
mddev->major_version == 0)
4493+
return -EINVAL;
4494+
4495+
mddev->reshape_backwards = backwards;
4496+
return len;
4497+
}
4498+
4499+
static struct md_sysfs_entry md_reshape_direction =
4500+
__ATTR(reshape_direction, S_IRUGO|S_IWUSR, reshape_direction_show,
4501+
reshape_direction_store);
4502+
44494503
static ssize_t
44504504
array_size_show(struct mddev *mddev, char *page)
44514505
{
@@ -4501,6 +4555,7 @@ static struct attribute *md_default_attrs[] = {
45014555
&md_safe_delay.attr,
45024556
&md_array_state.attr,
45034557
&md_reshape_position.attr,
4558+
&md_reshape_direction.attr,
45044559
&md_array_size.attr,
45054560
&max_corr_read_errors.attr,
45064561
NULL,
@@ -5064,6 +5119,7 @@ static void md_clean(struct mddev *mddev)
50645119
mddev->events = 0;
50655120
mddev->can_decrease_events = 0;
50665121
mddev->delta_disks = 0;
5122+
mddev->reshape_backwards = 0;
50675123
mddev->new_level = LEVEL_NONE;
50685124
mddev->new_layout = 0;
50695125
mddev->new_chunk_sectors = 0;
@@ -5888,6 +5944,7 @@ static int set_array_info(struct mddev * mddev, mdu_array_info_t *info)
58885944
mddev->new_chunk_sectors = mddev->chunk_sectors;
58895945
mddev->new_layout = mddev->layout;
58905946
mddev->delta_disks = 0;
5947+
mddev->reshape_backwards = 0;
58915948

58925949
return 0;
58935950
}
@@ -5953,10 +6010,16 @@ static int update_raid_disks(struct mddev *mddev, int raid_disks)
59536010
if (mddev->sync_thread || mddev->reshape_position != MaxSector)
59546011
return -EBUSY;
59556012
mddev->delta_disks = raid_disks - mddev->raid_disks;
6013+
if (mddev->delta_disks < 0)
6014+
mddev->reshape_backwards = 1;
6015+
else if (mddev->delta_disks > 0)
6016+
mddev->reshape_backwards = 0;
59566017

59576018
rv = mddev->pers->check_reshape(mddev);
5958-
if (rv < 0)
6019+
if (rv < 0) {
59596020
mddev->delta_disks = 0;
6021+
mddev->reshape_backwards = 0;
6022+
}
59606023
return rv;
59616024
}
59626025

drivers/md/md.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ struct mddev {
262262
sector_t reshape_position;
263263
int delta_disks, new_level, new_layout;
264264
int new_chunk_sectors;
265+
int reshape_backwards;
265266

266267
atomic_t plug_cnt; /* If device is expecting
267268
* more bios soon.

drivers/md/raid5.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3970,13 +3970,13 @@ static void make_request(struct mddev *mddev, struct bio * bi)
39703970
* to check again.
39713971
*/
39723972
spin_lock_irq(&conf->device_lock);
3973-
if (mddev->delta_disks < 0
3973+
if (mddev->reshape_backwards
39743974
? logical_sector < conf->reshape_progress
39753975
: logical_sector >= conf->reshape_progress) {
39763976
disks = conf->previous_raid_disks;
39773977
previous = 1;
39783978
} else {
3979-
if (mddev->delta_disks < 0
3979+
if (mddev->reshape_backwards
39803980
? logical_sector < conf->reshape_safe
39813981
: logical_sector >= conf->reshape_safe) {
39823982
spin_unlock_irq(&conf->device_lock);
@@ -4009,7 +4009,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
40094009
*/
40104010
int must_retry = 0;
40114011
spin_lock_irq(&conf->device_lock);
4012-
if (mddev->delta_disks < 0
4012+
if (mddev->reshape_backwards
40134013
? logical_sector >= conf->reshape_progress
40144014
: logical_sector < conf->reshape_progress)
40154015
/* mismatch, need to try again */
@@ -4108,11 +4108,11 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
41084108

41094109
if (sector_nr == 0) {
41104110
/* If restarting in the middle, skip the initial sectors */
4111-
if (mddev->delta_disks < 0 &&
4111+
if (mddev->reshape_backwards &&
41124112
conf->reshape_progress < raid5_size(mddev, 0, 0)) {
41134113
sector_nr = raid5_size(mddev, 0, 0)
41144114
- conf->reshape_progress;
4115-
} else if (mddev->delta_disks >= 0 &&
4115+
} else if (!mddev->reshape_backwards &&
41164116
conf->reshape_progress > 0)
41174117
sector_nr = conf->reshape_progress;
41184118
sector_div(sector_nr, new_data_disks);
@@ -4147,7 +4147,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
41474147
sector_div(readpos, data_disks);
41484148
safepos = conf->reshape_safe;
41494149
sector_div(safepos, data_disks);
4150-
if (mddev->delta_disks < 0) {
4150+
if (mddev->reshape_backwards) {
41514151
writepos -= min_t(sector_t, reshape_sectors, writepos);
41524152
readpos += reshape_sectors;
41534153
safepos += reshape_sectors;
@@ -4174,7 +4174,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
41744174
* Maybe that number should be configurable, but I'm not sure it is
41754175
* worth it.... maybe it could be a multiple of safemode_delay???
41764176
*/
4177-
if ((mddev->delta_disks < 0
4177+
if ((mddev->reshape_backwards
41784178
? (safepos > writepos && readpos < writepos)
41794179
: (safepos < writepos && readpos > writepos)) ||
41804180
time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) {
@@ -4195,7 +4195,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
41954195
sysfs_notify(&mddev->kobj, NULL, "sync_completed");
41964196
}
41974197

4198-
if (mddev->delta_disks < 0) {
4198+
if (mddev->reshape_backwards) {
41994199
BUG_ON(conf->reshape_progress == 0);
42004200
stripe_addr = writepos;
42014201
BUG_ON((mddev->dev_sectors &
@@ -4239,7 +4239,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
42394239
list_add(&sh->lru, &stripes);
42404240
}
42414241
spin_lock_irq(&conf->device_lock);
4242-
if (mddev->delta_disks < 0)
4242+
if (mddev->reshape_backwards)
42434243
conf->reshape_progress -= reshape_sectors * new_data_disks;
42444244
else
42454245
conf->reshape_progress += reshape_sectors * new_data_disks;
@@ -5008,7 +5008,7 @@ static int run(struct mddev *mddev)
50085008
mdname(mddev));
50095009
return -EINVAL;
50105010
}
5011-
} else if (mddev->delta_disks < 0
5011+
} else if (mddev->reshape_backwards
50125012
? (here_new * mddev->new_chunk_sectors <=
50135013
here_old * mddev->chunk_sectors)
50145014
: (here_new * mddev->new_chunk_sectors >=
@@ -5535,7 +5535,7 @@ static int raid5_start_reshape(struct mddev *mddev)
55355535
conf->chunk_sectors = mddev->new_chunk_sectors;
55365536
conf->prev_algo = conf->algorithm;
55375537
conf->algorithm = mddev->new_layout;
5538-
if (mddev->delta_disks < 0)
5538+
if (mddev->reshape_backwards)
55395539
conf->reshape_progress = raid5_size(mddev, 0, 0);
55405540
else
55415541
conf->reshape_progress = 0;
@@ -5663,6 +5663,7 @@ static void raid5_finish_reshape(struct mddev *mddev)
56635663
mddev->chunk_sectors = conf->chunk_sectors;
56645664
mddev->reshape_position = MaxSector;
56655665
mddev->delta_disks = 0;
5666+
mddev->reshape_backwards = 0;
56665667
}
56675668
}
56685669

include/linux/raid/md_p.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,15 @@ struct mdp_superblock_1 {
281281
* active device with same 'role'.
282282
* 'recovery_offset' is also set.
283283
*/
284+
#define MD_FEATURE_RESHAPE_BACKWARDS 32 /* Reshape doesn't change number
285+
* of devices, but is going
286+
* backwards anyway.
287+
*/
284288
#define MD_FEATURE_ALL (MD_FEATURE_BITMAP_OFFSET \
285289
|MD_FEATURE_RECOVERY_OFFSET \
286290
|MD_FEATURE_RESHAPE_ACTIVE \
287291
|MD_FEATURE_BAD_BLOCKS \
288-
|MD_FEATURE_REPLACEMENT)
292+
|MD_FEATURE_REPLACEMENT \
293+
|MD_FEATURE_RESHAPE_BACKWARDS)
289294

290295
#endif

0 commit comments

Comments
 (0)