| From 8313b8e57f55b15e5b7f7fc5d1630bbf686a9a97 Mon Sep 17 00:00:00 2001 |
| From: NeilBrown <neilb@suse.de> |
| Date: Thu, 12 Dec 2013 10:13:33 +1100 |
| Subject: md: fix problem when adding device to read-only array with bitmap. |
| |
| From: NeilBrown <neilb@suse.de> |
| |
| commit 8313b8e57f55b15e5b7f7fc5d1630bbf686a9a97 upstream. |
| |
| If an array is started degraded, and then the missing device |
| is found it can be re-added and a minimal bitmap-based recovery |
| will bring it fully up-to-date. |
| |
| If the array is read-only a recovery would not be allowed. |
| But also if the array is read-only and the missing device was |
| present very recently, then there could be no need for any |
| recovery at all, so we simply include the device in the read-only |
| array without any recovery. |
| |
| However... if the missing device was removed a little longer ago |
| it could be missing some updates, but if a bitmap is present it will |
| be conditionally accepted pending a bitmap-based update. We don't |
| currently detect this case properly and will include that old |
| device into the read-only array with no recovery even though it really |
| needs a recovery. |
| |
| This patch keeps track of whether a bitmap-based-recovery is really |
| needed or not in the new Bitmap_sync rdev flag. If that is set, |
| then the device will not be added to a read-only array. |
| |
| Cc: Andrei Warkentin <andreiw@vmware.com> |
| Fixes: d70ed2e4fafdbef0800e73942482bb075c21578b |
| Signed-off-by: NeilBrown <neilb@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/md/md.c | 18 +++++++++++++++--- |
| drivers/md/md.h | 3 +++ |
| 2 files changed, 18 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/md/md.c |
| +++ b/drivers/md/md.c |
| @@ -1119,6 +1119,7 @@ static int super_90_validate(struct mdde |
| rdev->raid_disk = -1; |
| clear_bit(Faulty, &rdev->flags); |
| clear_bit(In_sync, &rdev->flags); |
| + clear_bit(Bitmap_sync, &rdev->flags); |
| clear_bit(WriteMostly, &rdev->flags); |
| |
| if (mddev->raid_disks == 0) { |
| @@ -1197,6 +1198,8 @@ static int super_90_validate(struct mdde |
| */ |
| if (ev1 < mddev->bitmap->events_cleared) |
| return 0; |
| + if (ev1 < mddev->events) |
| + set_bit(Bitmap_sync, &rdev->flags); |
| } else { |
| if (ev1 < mddev->events) |
| /* just a hot-add of a new device, leave raid_disk at -1 */ |
| @@ -1605,6 +1608,7 @@ static int super_1_validate(struct mddev |
| rdev->raid_disk = -1; |
| clear_bit(Faulty, &rdev->flags); |
| clear_bit(In_sync, &rdev->flags); |
| + clear_bit(Bitmap_sync, &rdev->flags); |
| clear_bit(WriteMostly, &rdev->flags); |
| |
| if (mddev->raid_disks == 0) { |
| @@ -1687,6 +1691,8 @@ static int super_1_validate(struct mddev |
| */ |
| if (ev1 < mddev->bitmap->events_cleared) |
| return 0; |
| + if (ev1 < mddev->events) |
| + set_bit(Bitmap_sync, &rdev->flags); |
| } else { |
| if (ev1 < mddev->events) |
| /* just a hot-add of a new device, leave raid_disk at -1 */ |
| @@ -2830,6 +2836,7 @@ slot_store(struct md_rdev *rdev, const c |
| else |
| rdev->saved_raid_disk = -1; |
| clear_bit(In_sync, &rdev->flags); |
| + clear_bit(Bitmap_sync, &rdev->flags); |
| err = rdev->mddev->pers-> |
| hot_add_disk(rdev->mddev, rdev); |
| if (err) { |
| @@ -5773,6 +5780,7 @@ static int add_new_disk(struct mddev * m |
| info->raid_disk < mddev->raid_disks) { |
| rdev->raid_disk = info->raid_disk; |
| set_bit(In_sync, &rdev->flags); |
| + clear_bit(Bitmap_sync, &rdev->flags); |
| } else |
| rdev->raid_disk = -1; |
| } else |
| @@ -7731,7 +7739,8 @@ static int remove_and_add_spares(struct |
| if (test_bit(Faulty, &rdev->flags)) |
| continue; |
| if (mddev->ro && |
| - rdev->saved_raid_disk < 0) |
| + ! (rdev->saved_raid_disk >= 0 && |
| + !test_bit(Bitmap_sync, &rdev->flags))) |
| continue; |
| |
| rdev->recovery_offset = 0; |
| @@ -7812,9 +7821,12 @@ void md_check_recovery(struct mddev *mdd |
| * As we only add devices that are already in-sync, |
| * we can activate the spares immediately. |
| */ |
| - clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery); |
| remove_and_add_spares(mddev, NULL); |
| - mddev->pers->spare_active(mddev); |
| + /* There is no thread, but we need to call |
| + * ->spare_active and clear saved_raid_disk |
| + */ |
| + md_reap_sync_thread(mddev); |
| + clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery); |
| goto unlock; |
| } |
| |
| --- a/drivers/md/md.h |
| +++ b/drivers/md/md.h |
| @@ -129,6 +129,9 @@ struct md_rdev { |
| enum flag_bits { |
| Faulty, /* device is known to have a fault */ |
| In_sync, /* device is in_sync with rest of array */ |
| + Bitmap_sync, /* ..actually, not quite In_sync. Need a |
| + * bitmap-based recovery to get fully in sync |
| + */ |
| Unmerged, /* device is being added to array and should |
| * be considerred for bvec_merge_fn but not |
| * yet for actual IO |