dm raid: fix redundancy check and avoid frozen raid recovery
Subsystems (2)
cover dm raid: fix redundancy check and avoid frozen raid recovery
Patch 1 fixes validate_raid_redundancy() to check the current raid set level as stored in the superblock rather than the constructor requested one. In case of a raid0 to raid10 conversion, the related flaw caused a raid10 check on the given raid0 raid set leading to a divide error.
Patch 2 hardens raid resync/recover/reshape by retrieving any current related offsets from the active, uspended mapping thus avoiding frozen raid recovery across reloads altogether.
Patch 3 ensures 'a' chars during reshaping.
Patch 4 + 5 add simplification and cleanup without functional change.
This series presumes
https://www.redhat.com/archives/dm-devel/2017-December/msg00012.html
or
linux-dm.git, revision-range fbc7c07ec23c..b84cf26924cf respectively.
Heinz Mauelshagen (5):
dm raid: validate current raid sets redundancy dm raid: avoid keeping raid set frozen altogether dm raid: ensure 'a' chars during reshape dm raid: simplify rs_get_progress()
dm raid: use rs_is_raid*() / comment
Documentation/device-mapper/dm-raid.txt | 1 + drivers/md/dm-raid.c | 168 ++++++++++++++++++-------------- 2 files changed, 98 insertions(+), 71 deletions(-)
Signature · 1 line
2.13.6
PATCH 1/5 dm raid: validate current raid sets redundancy
Verifying the current raid sets redundancy based on retrieved superblock content has to use the raid level as of superblock content (e.g. raid0), not the constructor requested one (e.g. raid10).
Using the requested raid level of raid10 lead to a "divide error" on raid0 which defines data copies divided by to be zero.
Also check for bogus data copies.
--- drivers/md/dm-raid.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/md/dm-raid.c +6 -1
@@ -1007,7 +1007,7 @@ static int validate_raid_redundancy(struct raid_set *rs) !rs->dev[i].rdev.sb_page) rebuild_cnt++; -switch (rs->raid_type->level) { +switch (rs->md.level) {case 0 :break ;case 1 :
@@ -1022,6 +1022,11 @@ static int validate_raid_redundancy(struct raid_set *rs)break ;case 10 : copies =raid10_md_layout_to_copies (rs->md.new_layout); +if (copies <2 ) { +DMERR ("Bogus raid10 data copies < 2!" ); +return -EINVAL ; + } +if (rebuild_cnt < copies)break ;
Signature · 1 line
2.13.6
PATCH 2/5 dm raid: avoid keeping raid set frozen altogether
In reply to Heinz MauelshagenIn order to avoid redoing synchronization/recovery/reshape partially, the raid set got frozen until after all passed in table line flags had been cleared. The related table reload sequence had to be precisely followed, or reshaping may lead to data corruption caused by the active mapping carrying on with a reshape when the inactive mapping already had retrieved a stale reshape position.
Harden by retrieving the actual resync/recovery/reshape position during resume whilst the active table is suspended thus avoiding to keep the raid set frozen altogether. This prevents superfluous redoing of an already resynchronized or recovered segment and, most importantly, potential redoing of an already reshaped segment causing data corruption.
This is an enhancement to upstream commitd39f0010e40964d959c5157be02839da8a178015.
Bump target version to reflect these changes.
Also update Documentation respectively.
--- Documentation/device-mapper/dm-raid.txt | 1 + drivers/md/dm-raid.c | 109 ++++++++++++++++++++------------ 2 files changed, 71 insertions(+), 39 deletions(-)
Documentation/device-mapper/dm-raid.txt +1 -0
@@ -346,3 +346,4 @@ Version History 1.12.1 Fix for MD deadlock between mddev_suspend() and md_write_start() available 1.13.0 Fix dev_health status at end of "recover" (was 'a', now 'A') 1.13.1 Fix deadlock caused by early md_stop_writes() +1.13.2 Fix raid redundancy validation and avoid keeping raid set frozen
drivers/md/dm-raid.c +70 -39
199 lines not on this page · raw message
Signature · 1 line
2.13.6
PATCH 3/5 dm raid: ensure 'a' chars during reshape
In reply to Heinz MauelshagenDuring reshape, 'A' chars were reported in status rather than 'a'.
--- drivers/md/dm-raid.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/md/dm-raid.c +9 -0
@@ -3451,6 +3451,15 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery,*/ set_bit (RT_FLAG_RS_RESYNCING , &rs->runtime_flags); + }else if (test_bit (MD_RECOVERY_RESHAPE , &recovery) && + !test_bit (MD_RECOVERY_REQUESTED , &recovery)) { +/* +* If "reshape" is occurring, the raid set +* is or may be out of sync hence the health +* characters shall be 'a'. +*/ +set_bit (RT_FLAG_RS_RESYNCING , &rs->runtime_flags); + }else if (test_bit (MD_RECOVERY_REQUESTED , &recovery)) {/* * If "check" or "repair" is occurring, the raid set has
Signature · 1 line
2.13.6
PATCH 4/5 dm raid: simplify rs_get_progress()
In reply to Heinz MauelshagenNo need to calculate the reshaping progress because mddev->curr_resync_completed holds it.
--- drivers/md/dm-raid.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-)
drivers/md/dm-raid.c +3 -20
@@ -3399,26 +3399,9 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery,set_bit (RT_FLAG_RS_IN_SYNC , &rs->runtime_flags); }else { -/* Reshape is relative to the array size */ -if (test_bit (MD_RECOVERY_RESHAPE , &recovery)) { - r = mddev->reshape_position; -if (r != MaxSector) { -/* Got to reverse on backward reshape */ -if (mddev->reshape_backwards) - r = mddev->array_sectors - r; - -/* Divide by # of data stripes unless raid1 */ -if (!rs_is_raid1 (rs)) -sector_div (r,mddev_data_stripes (rs)); - } - -/* -* Sync/recover is relative to the component device size. -* -* MD_RECOVERY_NEEDED for https://bugzilla.redhat.com/show_bug.cgi?id=1508070 -*/ - }else if (test_bit (MD_RECOVERY_NEEDED , &recovery) || -test_bit (MD_RECOVERY_RUNNING , &recovery)) +if (test_bit (MD_RECOVERY_NEEDED , &recovery) || +test_bit (MD_RECOVERY_RESHAPE , &recovery) || +test_bit (MD_RECOVERY_RUNNING , &recovery)) r = mddev->curr_resync_completed;else r = mddev->recovery_cp;
Signature · 1 line
2.13.6
PATCH 5/5 dm raid: use rs_is_raid*() / comment
In reply to Heinz MauelshagenCleanup, no functional change.
--- drivers/md/dm-raid.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-)
drivers/md/dm-raid.c +9 -11
@@ -588,7 +588,7 @@ static const char *raid10_md_layout_to_format(int layout) }/* Return md raid10 algorithm for @name */ -static int raid10_name_to_format (const char *name) +static const int raid10_name_to_format (const char *name) {if (!strcasecmp (name,"near" ))return ALGORITHM_RAID10_NEAR ;
@@ -1913,7 +1913,7 @@ static bool rs_reshape_requested(struct raid_set *rs)if (rs_takeover_requested (rs))return false; -if (!mddev->level) +if (rs_is_raid0 (rs))return false; change = mddev->new_layout != mddev->layout ||
@@ -1921,7 +1921,7 @@ static bool rs_reshape_requested(struct raid_set *rs) rs->delta_disks;/* Historical case to support raid1 reshape without delta disks */ -if (mddev->level ==1 ) { +if (rs_is_raid1 (rs)) {if (rs->delta_disks)return !!rs->delta_disks;
@@ -1929,7 +1929,7 @@ static bool rs_reshape_requested(struct raid_set *rs) mddev->raid_disks != rs->raid_disks; } -if (mddev->level ==10 ) +if (rs_is_raid10 (rs))return change && !__is_raid10_far (mddev->new_layout) && rs->delta_disks >=0 ;
@@ -2742,14 +2742,14 @@ static int rs_setup_takeover(struct raid_set *rs)sector_t new_data_offset = rs->dev[0 ].rdev.data_offset ?0 : rs->data_offset;if (rt_is_raid10 (rs->raid_type)) { -if (mddev->level ==0 ) { +if (rs_is_raid0 (rs)) {/* Userpace reordered disks -> adjust raid_disk indexes */ __reorder_raid_disk_indexes (rs);/* raid0 -> raid10_far layout */ mddev->layout =raid10_format_to_md_layout (rs,ALGORITHM_RAID10_FAR , rs->raid10_copies); - }else if (mddev->level ==1 ) + }else if (rs_is_raid1 (rs))/* raid1 -> raid10_near layout */ mddev->layout =raid10_format_to_md_layout (rs,ALGORITHM_RAID10_NEAR , rs->raid_disks);
@@ -2974,10 +2974,8 @@ static void configure_discard_support(struct raid_set *rs)bool raid456;struct dm_target *ti = rs->ti; -/* -* XXX: RAID level 4,5,6 require zeroing for safety. -*/ - raid456 = (rs->md.level ==4 || rs->md.level ==5 || rs->md.level ==6 ); +/* RAID level 4,5,6 require discard_zeroes_data for data integrity! */ + raid456 =rs_is_raid456 (rs);for (i =0 ; i < rs->raid_disks; i++) {struct request_queue *q;
@@ -3002,7 +3000,7 @@ static void configure_discard_support(struct raid_set *rs)* RAID1 and RAID10 personalities require bio splitting, * RAID0/4/5/6 don't and process large discard bios properly. */ - ti->split_discard_bios = !!(rs->md.level ==1 || rs->md.level ==10 ); + ti->split_discard_bios = !!(rs_is_raid1 (rs) ||rs_is_raid10 (rs)); ti->num_discard_bios =1 ; }
Signature · 1 line
2.13.6