|
@@ -1700,16 +1700,30 @@ static bool rs_takeover_requested(struct raid_set *rs)
|
|
|
/* True if @rs is requested to reshape by ctr */
|
|
|
static bool rs_reshape_requested(struct raid_set *rs)
|
|
|
{
|
|
|
+ bool change;
|
|
|
struct mddev *mddev = &rs->md;
|
|
|
|
|
|
+ if (rs_takeover_requested(rs))
|
|
|
+ return false;
|
|
|
+
|
|
|
if (!mddev->level)
|
|
|
return false;
|
|
|
|
|
|
- return !__is_raid10_far(mddev->new_layout) &&
|
|
|
- mddev->new_level == mddev->level &&
|
|
|
- (mddev->new_layout != mddev->layout ||
|
|
|
- mddev->new_chunk_sectors != mddev->chunk_sectors ||
|
|
|
- rs->raid_disks + rs->delta_disks != mddev->raid_disks);
|
|
|
+ change = mddev->new_layout != mddev->layout ||
|
|
|
+ mddev->new_chunk_sectors != mddev->chunk_sectors ||
|
|
|
+ rs->delta_disks;
|
|
|
+
|
|
|
+ /* Historical case to support raid1 reshape without delta disks */
|
|
|
+ if (mddev->level == 1)
|
|
|
+ return !change &&
|
|
|
+ mddev->raid_disks != rs->raid_disks;
|
|
|
+
|
|
|
+ if (mddev->level == 10)
|
|
|
+ return change &&
|
|
|
+ !__is_raid10_far(mddev->new_layout) &&
|
|
|
+ rs->delta_disks >= 0;
|
|
|
+
|
|
|
+ return change;
|
|
|
}
|
|
|
|
|
|
/* Features */
|
|
@@ -1821,7 +1835,7 @@ static int rs_check_reshape(struct raid_set *rs)
|
|
|
rs->ti->error = "Can't reshape degraded raid set";
|
|
|
else if (rs_is_recovering(rs))
|
|
|
rs->ti->error = "Convert request on recovering raid set prohibited";
|
|
|
- else if (mddev->reshape_position && rs_is_reshaping(rs))
|
|
|
+ else if (rs_is_reshaping(rs))
|
|
|
rs->ti->error = "raid set already reshaping!";
|
|
|
else if (!(rs_is_raid10(rs) || rs_is_raid456(rs)))
|
|
|
rs->ti->error = "Reshaping only supported for raid4/5/6/10";
|
|
@@ -2518,6 +2532,69 @@ static int rs_setup_takeover(struct raid_set *rs)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* Prepare @rs for reshape */
|
|
|
+static int rs_prepare_reshape(struct raid_set *rs)
|
|
|
+{
|
|
|
+ bool reshape;
|
|
|
+ struct mddev *mddev = &rs->md;
|
|
|
+
|
|
|
+ if (rs_is_raid10(rs)) {
|
|
|
+ if (rs->raid_disks != mddev->raid_disks &&
|
|
|
+ __is_raid10_near(mddev->layout) &&
|
|
|
+ rs->raid10_copies &&
|
|
|
+ rs->raid10_copies != __raid10_near_copies(mddev->layout)) {
|
|
|
+ /*
|
|
|
+ * raid disk have to be multiple of data copies to allow this conversion,
|
|
|
+ *
|
|
|
+ * This is actually not a reshape it is a
|
|
|
+ * rebuild of any additional mirrors per group
|
|
|
+ */
|
|
|
+ if (rs->raid_disks % rs->raid10_copies) {
|
|
|
+ rs->ti->error = "Can't reshape raid10 mirror groups";
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Userpace reordered disks to add/remove mirrors -> adjust raid_disk indexes */
|
|
|
+ __reorder_raid_disk_indexes(rs);
|
|
|
+ mddev->layout = raid10_format_to_md_layout(rs, ALGORITHM_RAID10_NEAR,
|
|
|
+ rs->raid10_copies);
|
|
|
+ mddev->new_layout = mddev->layout;
|
|
|
+ reshape = false;
|
|
|
+ } else
|
|
|
+ reshape = true;
|
|
|
+
|
|
|
+ } else if (rs_is_raid456(rs))
|
|
|
+ reshape = true;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * HM FIXME: process raid1 via delta_disks as well?
|
|
|
+ * Would cause allocations in raid1->check_reshape
|
|
|
+ * though, thus more issues with potential failures
|
|
|
+ */
|
|
|
+ else if (rs_is_raid1(rs)) {
|
|
|
+ set_bit(RT_FLAG_KEEP_RS_FROZEN, &rs->runtime_flags);
|
|
|
+ mddev->raid_disks = rs->raid_disks;
|
|
|
+ reshape = false;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ rs->ti->error = "Called with bogus raid type";
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (reshape) {
|
|
|
+ set_bit(RT_FLAG_RESHAPE_RS, &rs->runtime_flags);
|
|
|
+ set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags);
|
|
|
+ set_bit(RT_FLAG_KEEP_RS_FROZEN, &rs->runtime_flags);
|
|
|
+ }
|
|
|
+ /* Create new superblocks and bitmaps, if any */
|
|
|
+ if (mddev->raid_disks < rs->raid_disks) {
|
|
|
+ set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags);
|
|
|
+ rs_set_cur(rs);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
*
|
|
|
* - change raid layout
|
|
@@ -2682,7 +2759,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;
|
|
|
+ bool resize;
|
|
|
struct raid_type *rt;
|
|
|
unsigned num_raid_params, num_raid_devs;
|
|
|
sector_t calculated_dev_sectors;
|
|
@@ -2770,6 +2847,12 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|
|
/* Restore any requested new layout for conversion decision */
|
|
|
rs_config_restore(rs, &rs_layout);
|
|
|
|
|
|
+ /*
|
|
|
+ * Now that we have any superblock metadata available,
|
|
|
+ * check for new, recovering, reshaping, to be taken over,
|
|
|
+ * to be reshaped or an existing, unchanged raid set to
|
|
|
+ * run in sequence.
|
|
|
+ */
|
|
|
if (test_bit(MD_ARRAY_FIRST_USE, &rs->md.flags)) {
|
|
|
/* A new raid6 set has to be recovered to ensure proper parity and Q-Syndrome */
|
|
|
if (rs_is_raid6(rs) &&
|
|
@@ -2782,6 +2865,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|
|
set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags);
|
|
|
rs_set_new(rs);
|
|
|
} else if (rs_is_recovering(rs)) {
|
|
|
+ /* A recovering raid set may be resized */
|
|
|
; /* skip setup rs */
|
|
|
} else if (rs_is_reshaping(rs)) {
|
|
|
/* Have to reject size change request during reshape */
|
|
@@ -2790,7 +2874,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|
|
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";
|
|
@@ -2800,7 +2884,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 set the level to the new requested
|
|
|
+ * devices to rebuild and we can check for a valid request here.
|
|
|
+ *
|
|
|
+ * If acceptible, set the level to the new requested
|
|
|
* one, prohibit requesting recovery, allow the raid
|
|
|
* set to run and store superblocks during resume.
|
|
|
*/
|
|
@@ -2814,63 +2900,22 @@ 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);
|
|
|
+ /* Takeover ain't recovery, so disable recovery */
|
|
|
rs_setup_recovery(rs, MaxSector);
|
|
|
rs_set_new(rs);
|
|
|
} else if (rs_reshape_requested(rs)) {
|
|
|
- if (rs_is_reshaping(rs)) {
|
|
|
- ti->error = "raid set already reshaping!";
|
|
|
- r = -EPERM;
|
|
|
- goto bad;
|
|
|
- }
|
|
|
-
|
|
|
- if (rs_is_raid10(rs)) {
|
|
|
- if (rs->raid_disks != rs->md.raid_disks &&
|
|
|
- __is_raid10_near(rs->md.layout) &&
|
|
|
- rs->raid10_copies &&
|
|
|
- rs->raid10_copies != __raid10_near_copies(rs->md.layout)) {
|
|
|
- /*
|
|
|
- * raid disk have to be multiple of data copies to allow this conversion,
|
|
|
- *
|
|
|
- * This is actually not a reshape it is a
|
|
|
- * rebuild of any additional mirrors per group
|
|
|
- */
|
|
|
- if (rs->raid_disks % rs->raid10_copies) {
|
|
|
- ti->error = "Can't reshape raid10 mirror groups";
|
|
|
- r = -EINVAL;
|
|
|
- goto bad;
|
|
|
- }
|
|
|
-
|
|
|
- /* Userpace reordered disks to add/remove mirrors -> adjust raid_disk indexes */
|
|
|
- __reorder_raid_disk_indexes(rs);
|
|
|
- rs->md.layout = raid10_format_to_md_layout(rs, ALGORITHM_RAID10_NEAR,
|
|
|
- rs->raid10_copies);
|
|
|
- rs->md.new_layout = rs->md.layout;
|
|
|
-
|
|
|
- } else
|
|
|
- set_bit(RT_FLAG_RESHAPE_RS, &rs->runtime_flags);
|
|
|
-
|
|
|
- } else if (rs_is_raid456(rs))
|
|
|
- set_bit(RT_FLAG_RESHAPE_RS, &rs->runtime_flags);
|
|
|
-
|
|
|
/*
|
|
|
- * HM FIXME: process raid1 via delta_disks as well?
|
|
|
- * Would cause allocations in raid1->check_reshape
|
|
|
- * though, thus more issues with potential failures
|
|
|
- */
|
|
|
- else if (rs_is_raid1(rs)) {
|
|
|
- set_bit(RT_FLAG_KEEP_RS_FROZEN, &rs->runtime_flags);
|
|
|
- rs->md.raid_disks = rs->raid_disks;
|
|
|
- }
|
|
|
-
|
|
|
- if (test_bit(RT_FLAG_RESHAPE_RS, &rs->runtime_flags)) {
|
|
|
- set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags);
|
|
|
- set_bit(RT_FLAG_KEEP_RS_FROZEN, &rs->runtime_flags);
|
|
|
- }
|
|
|
-
|
|
|
- /* Create new superblocks and bitmaps, if any */
|
|
|
- if (rs->md.raid_disks < rs->raid_disks)
|
|
|
- set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags);
|
|
|
+ * We can only prepare for a reshape here, because the
|
|
|
+ * raid set needs to run to provide the repective reshape
|
|
|
+ * check functions via its MD personality instance.
|
|
|
+ *
|
|
|
+ * So do the reshape check after md_run() succeeded.
|
|
|
+ */
|
|
|
+ r = rs_prepare_reshape(rs);
|
|
|
+ if (r)
|
|
|
+ return r;
|
|
|
|
|
|
+ /* Reshaping ain't recovery, so disable recovery */
|
|
|
rs_setup_recovery(rs, MaxSector);
|
|
|
rs_set_cur(rs);
|
|
|
} else {
|