Commit c7af5eb4 authored by NeilBrown's avatar NeilBrown Committed by Jiri Slaby

md/raid10: always set reshape_safe when initializing reshape_position.

commit 299b0685 upstream.

'reshape_position' tracks where in the reshape we have reached.
'reshape_safe' tracks where in the reshape we have safely recorded
in the metadata.

These are compared to determine when to update the metadata.
So it is important that reshape_safe is initialised properly.
Currently it isn't.  When starting a reshape from the beginning
it usually has the correct value by luck.  But when reducing the
number of devices in a RAID10, it has the wrong value and this leads
to the metadata not being updated correctly.
This can lead to corruption if the reshape is not allowed to complete.

This patch is suitable for any -stable kernel which supports RAID10
reshape, which is 3.5 and later.

Fixes: 3ea7daa5 ("md/raid10: add reshape support")
Signed-off-by: default avatarNeilBrown <neilb@suse.com>
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
parent cefcb16c
...@@ -3599,6 +3599,7 @@ static struct r10conf *setup_conf(struct mddev *mddev) ...@@ -3599,6 +3599,7 @@ static struct r10conf *setup_conf(struct mddev *mddev)
/* far_copies must be 1 */ /* far_copies must be 1 */
conf->prev.stride = conf->dev_sectors; conf->prev.stride = conf->dev_sectors;
} }
conf->reshape_safe = conf->reshape_progress;
spin_lock_init(&conf->device_lock); spin_lock_init(&conf->device_lock);
INIT_LIST_HEAD(&conf->retry_list); INIT_LIST_HEAD(&conf->retry_list);
...@@ -3806,7 +3807,6 @@ static int run(struct mddev *mddev) ...@@ -3806,7 +3807,6 @@ static int run(struct mddev *mddev)
} }
conf->offset_diff = min_offset_diff; conf->offset_diff = min_offset_diff;
conf->reshape_safe = conf->reshape_progress;
clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
...@@ -4151,6 +4151,7 @@ static int raid10_start_reshape(struct mddev *mddev) ...@@ -4151,6 +4151,7 @@ static int raid10_start_reshape(struct mddev *mddev)
conf->reshape_progress = size; conf->reshape_progress = size;
} else } else
conf->reshape_progress = 0; conf->reshape_progress = 0;
conf->reshape_safe = conf->reshape_progress;
spin_unlock_irq(&conf->device_lock); spin_unlock_irq(&conf->device_lock);
if (mddev->delta_disks && mddev->bitmap) { if (mddev->delta_disks && mddev->bitmap) {
...@@ -4217,6 +4218,7 @@ static int raid10_start_reshape(struct mddev *mddev) ...@@ -4217,6 +4218,7 @@ static int raid10_start_reshape(struct mddev *mddev)
rdev->new_data_offset = rdev->data_offset; rdev->new_data_offset = rdev->data_offset;
smp_wmb(); smp_wmb();
conf->reshape_progress = MaxSector; conf->reshape_progress = MaxSector;
conf->reshape_safe = MaxSector;
mddev->reshape_position = MaxSector; mddev->reshape_position = MaxSector;
spin_unlock_irq(&conf->device_lock); spin_unlock_irq(&conf->device_lock);
return ret; return ret;
...@@ -4564,6 +4566,7 @@ static void end_reshape(struct r10conf *conf) ...@@ -4564,6 +4566,7 @@ static void end_reshape(struct r10conf *conf)
md_finish_reshape(conf->mddev); md_finish_reshape(conf->mddev);
smp_wmb(); smp_wmb();
conf->reshape_progress = MaxSector; conf->reshape_progress = MaxSector;
conf->reshape_safe = MaxSector;
spin_unlock_irq(&conf->device_lock); spin_unlock_irq(&conf->device_lock);
/* read-ahead size must cover two whole stripes, which is /* read-ahead size must cover two whole stripes, which is
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment