aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
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/md/md.c
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/md/md.c')
-rw-r--r--drivers/md/md.c67
1 files changed, 65 insertions, 2 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 2b30ffdb81b..44bb1d52dd4 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