summaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-raid.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-raid.c')
-rw-r--r--drivers/md/dm-raid.c34
1 files changed, 19 insertions, 15 deletions
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 1ff469f14ff2..846c58d2bcf9 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -2682,6 +2682,7 @@ static void configure_discard_support(struct raid_set *rs)
static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
{
int r;
+ bool resize = false;
struct raid_type *rt;
unsigned num_raid_params, num_raid_devs;
sector_t calculated_dev_sectors;
@@ -2760,7 +2761,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
if (r)
goto bad;
- rs_setup_recovery(rs, calculated_dev_sectors);
+ resize = calculated_dev_sectors != rs->dev[0].rdev.sectors;
INIT_WORK(&rs->md.event_work, do_table_event);
ti->private = rs;
@@ -2770,8 +2771,6 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
rs_config_restore(rs, &rs_layout);
if (test_bit(MD_ARRAY_FIRST_USE, &rs->md.flags)) {
- set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags);
- rs_set_new(rs);
/* A new raid6 set has to be recovered to ensure proper parity and Q-Syndrome */
if (rs_is_raid6(rs) &&
test_bit(__CTR_FLAG_NOSYNC, &rs->ctr_flags)) {
@@ -2780,16 +2779,18 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad;
}
rs_setup_recovery(rs, 0);
- } else if (rs_is_recovering(rs) || rs_is_reshaping(rs)) {
- /* Have to reject size change request during recovery/reshape */
- if (calculated_dev_sectors != rs->dev[0].rdev.sectors) {
- ti->error = rs_is_recovering(rs) ?
- "Can't resize a recovering raid set" :
- "Can't resize a reshaping raid set";
+ set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags);
+ rs_set_new(rs);
+ } else if (rs_is_recovering(rs)) {
+ ; /* skip setup rs */
+ } else if (rs_is_reshaping(rs)) {
+ /* Have to reject size change request during reshape */
+ if (resize) {
+ ti->error = "Can't resize a reshaping raid set";
r = -EPERM;
goto bad;
}
- /* skip setup rs */
+ ; /* skip setup rs */
} else if (rs_takeover_requested(rs)) {
if (rs_is_reshaping(rs)) {
ti->error = "Can't takeover a reshaping raid set";
@@ -2799,8 +2800,9 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
/*
* If a takeover is needed, userspace sets any additional
- * devices to rebuild, so just set the level to the new
- * requested one and allow the raid set to run
+ * devices to rebuild, so set the level to the new requested
+ * one, prohibit requesting recovery, allow the raid
+ * set to run and store superblocks during resume.
*/
r = rs_check_takeover(rs);
if (r)
@@ -2812,6 +2814,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags);
set_bit(RT_FLAG_KEEP_RS_FROZEN, &rs->runtime_flags);
+ rs_setup_recovery(rs, MaxSector);
rs_set_new(rs);
} else if (rs_reshape_requested(rs)) {
if (rs_is_reshaping(rs)) {
@@ -2868,16 +2871,17 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
if (rs->md.raid_disks < rs->raid_disks)
set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags);
- rs_set_cur(rs);
rs_setup_recovery(rs, MaxSector);
- } else {
rs_set_cur(rs);
+ } else {
+ /* May not set recovery when a device rebuild is requested */
if (test_bit(__CTR_FLAG_REBUILD, &rs->ctr_flags)) {
rs_setup_recovery(rs, MaxSector);
set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags);
} else
rs_setup_recovery(rs, test_bit(__CTR_FLAG_SYNC, &rs->ctr_flags) ?
- 0 : calculated_dev_sectors);
+ 0 : (resize ? calculated_dev_sectors : MaxSector));
+ rs_set_cur(rs);
}
/* If constructor requested it, change data and new_data offsets */