aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-05-20 19:27:00 -0400
committerNeilBrown <neilb@suse.de>2012-05-20 19:27:00 -0400
commit2c810cddc44d6f95cef75df3f07fc0850ff92417 (patch)
tree185b35ce06656a53327dd66343f0926aa5a910d7 /drivers
parentb5e1b8cee7ad58a15d2fa79bcd7946acb592602d (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/md.c67
-rw-r--r--drivers/md/md.h1
-rw-r--r--drivers/md/raid5.c23
3 files changed, 78 insertions, 13 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 2b30ffdb81b2..44bb1d52dd4c 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -607,6 +607,7 @@ void mddev_init(struct mddev *mddev)
607 init_waitqueue_head(&mddev->sb_wait); 607 init_waitqueue_head(&mddev->sb_wait);
608 init_waitqueue_head(&mddev->recovery_wait); 608 init_waitqueue_head(&mddev->recovery_wait);
609 mddev->reshape_position = MaxSector; 609 mddev->reshape_position = MaxSector;
610 mddev->reshape_backwards = 0;
610 mddev->resync_min = 0; 611 mddev->resync_min = 0;
611 mddev->resync_max = MaxSector; 612 mddev->resync_max = MaxSector;
612 mddev->level = LEVEL_NONE; 613 mddev->level = LEVEL_NONE;
@@ -1185,6 +1186,7 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
1185 mddev->events = ev1; 1186 mddev->events = ev1;
1186 mddev->bitmap_info.offset = 0; 1187 mddev->bitmap_info.offset = 0;
1187 mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9; 1188 mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
1189 mddev->reshape_backwards = 0;
1188 1190
1189 if (mddev->minor_version >= 91) { 1191 if (mddev->minor_version >= 91) {
1190 mddev->reshape_position = sb->reshape_position; 1192 mddev->reshape_position = sb->reshape_position;
@@ -1192,6 +1194,8 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
1192 mddev->new_level = sb->new_level; 1194 mddev->new_level = sb->new_level;
1193 mddev->new_layout = sb->new_layout; 1195 mddev->new_layout = sb->new_layout;
1194 mddev->new_chunk_sectors = sb->new_chunk >> 9; 1196 mddev->new_chunk_sectors = sb->new_chunk >> 9;
1197 if (mddev->delta_disks < 0)
1198 mddev->reshape_backwards = 1;
1195 } else { 1199 } else {
1196 mddev->reshape_position = MaxSector; 1200 mddev->reshape_position = MaxSector;
1197 mddev->delta_disks = 0; 1201 mddev->delta_disks = 0;
@@ -1645,7 +1649,8 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
1645 mddev->events = ev1; 1649 mddev->events = ev1;
1646 mddev->bitmap_info.offset = 0; 1650 mddev->bitmap_info.offset = 0;
1647 mddev->bitmap_info.default_offset = 1024 >> 9; 1651 mddev->bitmap_info.default_offset = 1024 >> 9;
1648 1652 mddev->reshape_backwards = 0;
1653
1649 mddev->recovery_cp = le64_to_cpu(sb->resync_offset); 1654 mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
1650 memcpy(mddev->uuid, sb->set_uuid, 16); 1655 memcpy(mddev->uuid, sb->set_uuid, 16);
1651 1656
@@ -1662,6 +1667,11 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
1662 mddev->new_level = le32_to_cpu(sb->new_level); 1667 mddev->new_level = le32_to_cpu(sb->new_level);
1663 mddev->new_layout = le32_to_cpu(sb->new_layout); 1668 mddev->new_layout = le32_to_cpu(sb->new_layout);
1664 mddev->new_chunk_sectors = le32_to_cpu(sb->new_chunk); 1669 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;
1665 } else { 1675 } else {
1666 mddev->reshape_position = MaxSector; 1676 mddev->reshape_position = MaxSector;
1667 mddev->delta_disks = 0; 1677 mddev->delta_disks = 0;
@@ -1781,6 +1791,10 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
1781 sb->delta_disks = cpu_to_le32(mddev->delta_disks); 1791 sb->delta_disks = cpu_to_le32(mddev->delta_disks);
1782 sb->new_level = cpu_to_le32(mddev->new_level); 1792 sb->new_level = cpu_to_le32(mddev->new_level);
1783 sb->new_chunk = cpu_to_le32(mddev->new_chunk_sectors); 1793 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);
1784 } 1798 }
1785 1799
1786 if (rdev->badblocks.count == 0) 1800 if (rdev->badblocks.count == 0)
@@ -3419,6 +3433,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
3419 mddev->new_chunk_sectors = mddev->chunk_sectors; 3433 mddev->new_chunk_sectors = mddev->chunk_sectors;
3420 mddev->raid_disks -= mddev->delta_disks; 3434 mddev->raid_disks -= mddev->delta_disks;
3421 mddev->delta_disks = 0; 3435 mddev->delta_disks = 0;
3436 mddev->reshape_backwards = 0;
3422 module_put(pers->owner); 3437 module_put(pers->owner);
3423 printk(KERN_WARNING "md: %s: %s would not accept array\n", 3438 printk(KERN_WARNING "md: %s: %s would not accept array\n",
3424 mdname(mddev), clevel); 3439 mdname(mddev), clevel);
@@ -3492,6 +3507,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
3492 mddev->layout = mddev->new_layout; 3507 mddev->layout = mddev->new_layout;
3493 mddev->chunk_sectors = mddev->new_chunk_sectors; 3508 mddev->chunk_sectors = mddev->new_chunk_sectors;
3494 mddev->delta_disks = 0; 3509 mddev->delta_disks = 0;
3510 mddev->reshape_backwards = 0;
3495 mddev->degraded = 0; 3511 mddev->degraded = 0;
3496 if (mddev->pers->sync_request == NULL) { 3512 if (mddev->pers->sync_request == NULL) {
3497 /* this is now an array without redundancy, so 3513 /* this is now an array without redundancy, so
@@ -3585,6 +3601,7 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
3585 int olddisks = mddev->raid_disks - mddev->delta_disks; 3601 int olddisks = mddev->raid_disks - mddev->delta_disks;
3586 mddev->delta_disks = n - olddisks; 3602 mddev->delta_disks = n - olddisks;
3587 mddev->raid_disks = n; 3603 mddev->raid_disks = n;
3604 mddev->reshape_backwards = (mddev->delta_disks < 0);
3588 } else 3605 } else
3589 mddev->raid_disks = n; 3606 mddev->raid_disks = n;
3590 return rv ? rv : len; 3607 return rv ? rv : len;
@@ -4436,6 +4453,7 @@ reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
4436 return -EINVAL; 4453 return -EINVAL;
4437 mddev->reshape_position = new; 4454 mddev->reshape_position = new;
4438 mddev->delta_disks = 0; 4455 mddev->delta_disks = 0;
4456 mddev->reshape_backwards = 0;
4439 mddev->new_level = mddev->level; 4457 mddev->new_level = mddev->level;
4440 mddev->new_layout = mddev->layout; 4458 mddev->new_layout = mddev->layout;
4441 mddev->new_chunk_sectors = mddev->chunk_sectors; 4459 mddev->new_chunk_sectors = mddev->chunk_sectors;
@@ -4447,6 +4465,42 @@ __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
4447 reshape_position_store); 4465 reshape_position_store);
4448 4466
4449static ssize_t 4467static ssize_t
4468reshape_direction_show(struct mddev *mddev, char *page)
4469{
4470 return sprintf(page, "%s\n",
4471 mddev->reshape_backwards ? "backwards" : "forwards");
4472}
4473
4474static ssize_t
4475reshape_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
4499static struct md_sysfs_entry md_reshape_direction =
4500__ATTR(reshape_direction, S_IRUGO|S_IWUSR, reshape_direction_show,
4501 reshape_direction_store);
4502
4503static ssize_t
4450array_size_show(struct mddev *mddev, char *page) 4504array_size_show(struct mddev *mddev, char *page)
4451{ 4505{
4452 if (mddev->external_size) 4506 if (mddev->external_size)
@@ -4501,6 +4555,7 @@ static struct attribute *md_default_attrs[] = {
4501 &md_safe_delay.attr, 4555 &md_safe_delay.attr,
4502 &md_array_state.attr, 4556 &md_array_state.attr,
4503 &md_reshape_position.attr, 4557 &md_reshape_position.attr,
4558 &md_reshape_direction.attr,
4504 &md_array_size.attr, 4559 &md_array_size.attr,
4505 &max_corr_read_errors.attr, 4560 &max_corr_read_errors.attr,
4506 NULL, 4561 NULL,
@@ -5064,6 +5119,7 @@ static void md_clean(struct mddev *mddev)
5064 mddev->events = 0; 5119 mddev->events = 0;
5065 mddev->can_decrease_events = 0; 5120 mddev->can_decrease_events = 0;
5066 mddev->delta_disks = 0; 5121 mddev->delta_disks = 0;
5122 mddev->reshape_backwards = 0;
5067 mddev->new_level = LEVEL_NONE; 5123 mddev->new_level = LEVEL_NONE;
5068 mddev->new_layout = 0; 5124 mddev->new_layout = 0;
5069 mddev->new_chunk_sectors = 0; 5125 mddev->new_chunk_sectors = 0;
@@ -5888,6 +5944,7 @@ static int set_array_info(struct mddev * mddev, mdu_array_info_t *info)
5888 mddev->new_chunk_sectors = mddev->chunk_sectors; 5944 mddev->new_chunk_sectors = mddev->chunk_sectors;
5889 mddev->new_layout = mddev->layout; 5945 mddev->new_layout = mddev->layout;
5890 mddev->delta_disks = 0; 5946 mddev->delta_disks = 0;
5947 mddev->reshape_backwards = 0;
5891 5948
5892 return 0; 5949 return 0;
5893} 5950}
@@ -5953,10 +6010,16 @@ static int update_raid_disks(struct mddev *mddev, int raid_disks)
5953 if (mddev->sync_thread || mddev->reshape_position != MaxSector) 6010 if (mddev->sync_thread || mddev->reshape_position != MaxSector)
5954 return -EBUSY; 6011 return -EBUSY;
5955 mddev->delta_disks = raid_disks - mddev->raid_disks; 6012 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;
5956 6017
5957 rv = mddev->pers->check_reshape(mddev); 6018 rv = mddev->pers->check_reshape(mddev);
5958 if (rv < 0) 6019 if (rv < 0) {
5959 mddev->delta_disks = 0; 6020 mddev->delta_disks = 0;
6021 mddev->reshape_backwards = 0;
6022 }
5960 return rv; 6023 return rv;
5961} 6024}
5962 6025
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 1c2063ccf48e..d51c0ca37777 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -262,6 +262,7 @@ struct mddev {
262 sector_t reshape_position; 262 sector_t reshape_position;
263 int delta_disks, new_level, new_layout; 263 int delta_disks, new_level, new_layout;
264 int new_chunk_sectors; 264 int new_chunk_sectors;
265 int reshape_backwards;
265 266
266 atomic_t plug_cnt; /* If device is expecting 267 atomic_t plug_cnt; /* If device is expecting
267 * more bios soon. 268 * more bios soon.
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index f351422938e0..0abbd3447cfb 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3970,13 +3970,13 @@ static void make_request(struct mddev *mddev, struct bio * bi)
3970 * to check again. 3970 * to check again.
3971 */ 3971 */
3972 spin_lock_irq(&conf->device_lock); 3972 spin_lock_irq(&conf->device_lock);
3973 if (mddev->delta_disks < 0 3973 if (mddev->reshape_backwards
3974 ? logical_sector < conf->reshape_progress 3974 ? logical_sector < conf->reshape_progress
3975 : logical_sector >= conf->reshape_progress) { 3975 : logical_sector >= conf->reshape_progress) {
3976 disks = conf->previous_raid_disks; 3976 disks = conf->previous_raid_disks;
3977 previous = 1; 3977 previous = 1;
3978 } else { 3978 } else {
3979 if (mddev->delta_disks < 0 3979 if (mddev->reshape_backwards
3980 ? logical_sector < conf->reshape_safe 3980 ? logical_sector < conf->reshape_safe
3981 : logical_sector >= conf->reshape_safe) { 3981 : logical_sector >= conf->reshape_safe) {
3982 spin_unlock_irq(&conf->device_lock); 3982 spin_unlock_irq(&conf->device_lock);
@@ -4009,7 +4009,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
4009 */ 4009 */
4010 int must_retry = 0; 4010 int must_retry = 0;
4011 spin_lock_irq(&conf->device_lock); 4011 spin_lock_irq(&conf->device_lock);
4012 if (mddev->delta_disks < 0 4012 if (mddev->reshape_backwards
4013 ? logical_sector >= conf->reshape_progress 4013 ? logical_sector >= conf->reshape_progress
4014 : logical_sector < conf->reshape_progress) 4014 : logical_sector < conf->reshape_progress)
4015 /* mismatch, need to try again */ 4015 /* mismatch, need to try again */
@@ -4108,11 +4108,11 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
4108 4108
4109 if (sector_nr == 0) { 4109 if (sector_nr == 0) {
4110 /* If restarting in the middle, skip the initial sectors */ 4110 /* If restarting in the middle, skip the initial sectors */
4111 if (mddev->delta_disks < 0 && 4111 if (mddev->reshape_backwards &&
4112 conf->reshape_progress < raid5_size(mddev, 0, 0)) { 4112 conf->reshape_progress < raid5_size(mddev, 0, 0)) {
4113 sector_nr = raid5_size(mddev, 0, 0) 4113 sector_nr = raid5_size(mddev, 0, 0)
4114 - conf->reshape_progress; 4114 - conf->reshape_progress;
4115 } else if (mddev->delta_disks >= 0 && 4115 } else if (!mddev->reshape_backwards &&
4116 conf->reshape_progress > 0) 4116 conf->reshape_progress > 0)
4117 sector_nr = conf->reshape_progress; 4117 sector_nr = conf->reshape_progress;
4118 sector_div(sector_nr, new_data_disks); 4118 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
4147 sector_div(readpos, data_disks); 4147 sector_div(readpos, data_disks);
4148 safepos = conf->reshape_safe; 4148 safepos = conf->reshape_safe;
4149 sector_div(safepos, data_disks); 4149 sector_div(safepos, data_disks);
4150 if (mddev->delta_disks < 0) { 4150 if (mddev->reshape_backwards) {
4151 writepos -= min_t(sector_t, reshape_sectors, writepos); 4151 writepos -= min_t(sector_t, reshape_sectors, writepos);
4152 readpos += reshape_sectors; 4152 readpos += reshape_sectors;
4153 safepos += reshape_sectors; 4153 safepos += reshape_sectors;
@@ -4174,7 +4174,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
4174 * Maybe that number should be configurable, but I'm not sure it is 4174 * Maybe that number should be configurable, but I'm not sure it is
4175 * worth it.... maybe it could be a multiple of safemode_delay??? 4175 * worth it.... maybe it could be a multiple of safemode_delay???
4176 */ 4176 */
4177 if ((mddev->delta_disks < 0 4177 if ((mddev->reshape_backwards
4178 ? (safepos > writepos && readpos < writepos) 4178 ? (safepos > writepos && readpos < writepos)
4179 : (safepos < writepos && readpos > writepos)) || 4179 : (safepos < writepos && readpos > writepos)) ||
4180 time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) { 4180 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
4195 sysfs_notify(&mddev->kobj, NULL, "sync_completed"); 4195 sysfs_notify(&mddev->kobj, NULL, "sync_completed");
4196 } 4196 }
4197 4197
4198 if (mddev->delta_disks < 0) { 4198 if (mddev->reshape_backwards) {
4199 BUG_ON(conf->reshape_progress == 0); 4199 BUG_ON(conf->reshape_progress == 0);
4200 stripe_addr = writepos; 4200 stripe_addr = writepos;
4201 BUG_ON((mddev->dev_sectors & 4201 BUG_ON((mddev->dev_sectors &
@@ -4239,7 +4239,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
4239 list_add(&sh->lru, &stripes); 4239 list_add(&sh->lru, &stripes);
4240 } 4240 }
4241 spin_lock_irq(&conf->device_lock); 4241 spin_lock_irq(&conf->device_lock);
4242 if (mddev->delta_disks < 0) 4242 if (mddev->reshape_backwards)
4243 conf->reshape_progress -= reshape_sectors * new_data_disks; 4243 conf->reshape_progress -= reshape_sectors * new_data_disks;
4244 else 4244 else
4245 conf->reshape_progress += reshape_sectors * new_data_disks; 4245 conf->reshape_progress += reshape_sectors * new_data_disks;
@@ -5008,7 +5008,7 @@ static int run(struct mddev *mddev)
5008 mdname(mddev)); 5008 mdname(mddev));
5009 return -EINVAL; 5009 return -EINVAL;
5010 } 5010 }
5011 } else if (mddev->delta_disks < 0 5011 } else if (mddev->reshape_backwards
5012 ? (here_new * mddev->new_chunk_sectors <= 5012 ? (here_new * mddev->new_chunk_sectors <=
5013 here_old * mddev->chunk_sectors) 5013 here_old * mddev->chunk_sectors)
5014 : (here_new * mddev->new_chunk_sectors >= 5014 : (here_new * mddev->new_chunk_sectors >=
@@ -5535,7 +5535,7 @@ static int raid5_start_reshape(struct mddev *mddev)
5535 conf->chunk_sectors = mddev->new_chunk_sectors; 5535 conf->chunk_sectors = mddev->new_chunk_sectors;
5536 conf->prev_algo = conf->algorithm; 5536 conf->prev_algo = conf->algorithm;
5537 conf->algorithm = mddev->new_layout; 5537 conf->algorithm = mddev->new_layout;
5538 if (mddev->delta_disks < 0) 5538 if (mddev->reshape_backwards)
5539 conf->reshape_progress = raid5_size(mddev, 0, 0); 5539 conf->reshape_progress = raid5_size(mddev, 0, 0);
5540 else 5540 else
5541 conf->reshape_progress = 0; 5541 conf->reshape_progress = 0;
@@ -5663,6 +5663,7 @@ static void raid5_finish_reshape(struct mddev *mddev)
5663 mddev->chunk_sectors = conf->chunk_sectors; 5663 mddev->chunk_sectors = conf->chunk_sectors;
5664 mddev->reshape_position = MaxSector; 5664 mddev->reshape_position = MaxSector;
5665 mddev->delta_disks = 0; 5665 mddev->delta_disks = 0;
5666 mddev->reshape_backwards = 0;
5666 } 5667 }
5667} 5668}
5668 5669