| From 82577093fbdfd55bff5d56bd526aeb9c67509e49 Mon Sep 17 00:00:00 2001 |
| From: Heinz Mauelshagen <heinzm@redhat.com> |
| Date: Tue, 28 Feb 2017 19:17:49 +0100 |
| Subject: [PATCH] dm raid: fix data corruption on reshape request |
| |
| commit d36a19541fe8f392778ac137d60f9be8dfdd8f9d upstream. |
| |
| The lvm2 sequence to manage dm-raid constructor flags that trigger a |
| rebuild or a reshape is defined as: |
| |
| 1) load table with flags (e.g. rebuild/delta_disks/data_offset) |
| 2) clear out the flags in lvm2 metadata |
| 3) store the lvm2 metadata, reload the table to reset the flags |
| previously established during the initial load (1) -- in order to |
| prevent repeatedly requesting a rebuild or a reshape on activation |
| |
| Currently, loading an inactive table with rebuild/reshape flags |
| specified will cause dm-raid to rebuild/reshape on resume and thus start |
| updating the raid metadata (about the progress). When the second table |
| reload, to reset the flags, occurs the constructor accesses the volatile |
| progress state kept in the raid superblocks. Because the active mapping |
| is still processing the rebuild/reshape, that position will be stale by |
| the time the device is resumed. |
| |
| In the reshape case, this causes data corruption by processing already |
| reshaped stripes again. In the rebuild case, it does _not_ cause data |
| corruption but instead involves superfluous rebuilds. |
| |
| Fix by keeping the raid set frozen during the first resume and then |
| allow the rebuild/reshape during the second resume. |
| |
| Fixes: 9dbd1aa3a ("dm raid: add reshaping support to the target") |
| Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com> |
| Signed-off-by: Mike Snitzer <snitzer@redhat.com> |
| Cc: stable@vger.kernel.org # 4.8+ |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c |
| index af2d79b52484..15daa36fcea6 100644 |
| --- a/drivers/md/dm-raid.c |
| +++ b/drivers/md/dm-raid.c |
| @@ -3621,6 +3621,8 @@ static int raid_preresume(struct dm_target *ti) |
| return r; |
| } |
| |
| +#define RESUME_STAY_FROZEN_FLAGS (CTR_FLAG_DELTA_DISKS | CTR_FLAG_DATA_OFFSET) |
| + |
| static void raid_resume(struct dm_target *ti) |
| { |
| struct raid_set *rs = ti->private; |
| @@ -3638,7 +3640,15 @@ static void raid_resume(struct dm_target *ti) |
| mddev->ro = 0; |
| mddev->in_sync = 0; |
| |
| - clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); |
| + /* |
| + * Keep the RAID set frozen if reshape/rebuild flags are set. |
| + * The RAID set is unfrozen once the next table load/resume, |
| + * which clears the reshape/rebuild flags, occurs. |
| + * This ensures that the constructor for the inactive table |
| + * retrieves an up-to-date reshape_position. |
| + */ |
| + if (!(rs->ctr_flags & RESUME_STAY_FROZEN_FLAGS)) |
| + clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); |
| |
| if (mddev->suspended) |
| mddev_resume(mddev); |
| -- |
| 2.12.0 |
| |