mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 01:04:08 +08:00
md/raid5: fix newly-broken locking in get_active_stripe.
commit566c09c534
raid5: relieve lock contention in get_active_stripe() modified the locking in get_active_stripe() reducing the range protected by the (highly contended) device_lock. Unfortunately it reduced the range too much opening up some races. One race can occur if get_priority_stripe runs between the test on sh->count and device_lock being taken. This will mean that sh->lru is not empty while get_active_stripe thinks ->count is zero resulting in a 'BUG' firing. Another race happens if __release_stripe is called immediately after sh->count is tested and found to be non-zero. If STRIPE_HANDLE is not set, get_active_stripe should increment ->active_stripes when it increments ->count from 0, but as it didn't think it was 0, it doesn't. Extending device_lock to cover the test on sh->count close these races. While we are here, fix the two BUG tests: -If count is zero, then lru really must not be empty, or we've lock the stripe_head somehow - no other tests are relevant. -STRIPE_ON_RELEASE_LIST is completely independent of ->lru so testing it is pointless. Reported-and-tested-by: Brassow Jonathan <jbrassow@redhat.com> Reviewed-by: Shaohua Li <shli@kernel.org> Fixes:566c09c534
Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
parent
142d44c310
commit
6d183de407
@ -678,26 +678,23 @@ get_active_stripe(struct r5conf *conf, sector_t sector,
|
|||||||
} else
|
} else
|
||||||
init_stripe(sh, sector, previous);
|
init_stripe(sh, sector, previous);
|
||||||
} else {
|
} else {
|
||||||
|
spin_lock(&conf->device_lock);
|
||||||
if (atomic_read(&sh->count)) {
|
if (atomic_read(&sh->count)) {
|
||||||
BUG_ON(!list_empty(&sh->lru)
|
BUG_ON(!list_empty(&sh->lru)
|
||||||
&& !test_bit(STRIPE_EXPANDING, &sh->state)
|
&& !test_bit(STRIPE_EXPANDING, &sh->state)
|
||||||
&& !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)
|
&& !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)
|
||||||
&& !test_bit(STRIPE_ON_RELEASE_LIST, &sh->state));
|
);
|
||||||
} else {
|
} else {
|
||||||
spin_lock(&conf->device_lock);
|
|
||||||
if (!test_bit(STRIPE_HANDLE, &sh->state))
|
if (!test_bit(STRIPE_HANDLE, &sh->state))
|
||||||
atomic_inc(&conf->active_stripes);
|
atomic_inc(&conf->active_stripes);
|
||||||
if (list_empty(&sh->lru) &&
|
BUG_ON(list_empty(&sh->lru));
|
||||||
!test_bit(STRIPE_ON_RELEASE_LIST, &sh->state) &&
|
|
||||||
!test_bit(STRIPE_EXPANDING, &sh->state))
|
|
||||||
BUG();
|
|
||||||
list_del_init(&sh->lru);
|
list_del_init(&sh->lru);
|
||||||
if (sh->group) {
|
if (sh->group) {
|
||||||
sh->group->stripes_cnt--;
|
sh->group->stripes_cnt--;
|
||||||
sh->group = NULL;
|
sh->group = NULL;
|
||||||
}
|
}
|
||||||
spin_unlock(&conf->device_lock);
|
|
||||||
}
|
}
|
||||||
|
spin_unlock(&conf->device_lock);
|
||||||
}
|
}
|
||||||
} while (sh == NULL);
|
} while (sh == NULL);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user