dm bufio: use the acquire memory barrier when testing for B_READING
The function test_bit doesn't provide any memory barrier. It may be possible that the read requests that follow test_bit(B_READING, &b->state) are reordered before the test, reading invalid data that existed before B_READING was cleared. Fix this bug by changing test_bit to test_bit_acquire. This is particularly important on arches with weak(er) memory ordering (e.g. arm64). Depends-On:8238b45798
("wait_on_bit: add an acquire memory barrier") Depends-On:d6ffe6067a
("provide arch_test_bit_acquire for architectures that define test_bit") Cc: stable@vger.kernel.org Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@kernel.org>
This commit is contained in:
parent
bb1a114646
commit
141b3523e9
|
@ -795,7 +795,8 @@ static void __make_buffer_clean(struct dm_buffer *b)
|
|||
{
|
||||
BUG_ON(b->hold_count);
|
||||
|
||||
if (!b->state) /* fast case */
|
||||
/* smp_load_acquire() pairs with read_endio()'s smp_mb__before_atomic() */
|
||||
if (!smp_load_acquire(&b->state)) /* fast case */
|
||||
return;
|
||||
|
||||
wait_on_bit_io(&b->state, B_READING, TASK_UNINTERRUPTIBLE);
|
||||
|
@ -816,7 +817,7 @@ static struct dm_buffer *__get_unclaimed_buffer(struct dm_bufio_client *c)
|
|||
BUG_ON(test_bit(B_DIRTY, &b->state));
|
||||
|
||||
if (static_branch_unlikely(&no_sleep_enabled) && c->no_sleep &&
|
||||
unlikely(test_bit(B_READING, &b->state)))
|
||||
unlikely(test_bit_acquire(B_READING, &b->state)))
|
||||
continue;
|
||||
|
||||
if (!b->hold_count) {
|
||||
|
@ -1058,7 +1059,7 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
|
|||
* If the user called both dm_bufio_prefetch and dm_bufio_get on
|
||||
* the same buffer, it would deadlock if we waited.
|
||||
*/
|
||||
if (nf == NF_GET && unlikely(test_bit(B_READING, &b->state)))
|
||||
if (nf == NF_GET && unlikely(test_bit_acquire(B_READING, &b->state)))
|
||||
return NULL;
|
||||
|
||||
b->hold_count++;
|
||||
|
@ -1218,7 +1219,7 @@ void dm_bufio_release(struct dm_buffer *b)
|
|||
* invalid buffer.
|
||||
*/
|
||||
if ((b->read_error || b->write_error) &&
|
||||
!test_bit(B_READING, &b->state) &&
|
||||
!test_bit_acquire(B_READING, &b->state) &&
|
||||
!test_bit(B_WRITING, &b->state) &&
|
||||
!test_bit(B_DIRTY, &b->state)) {
|
||||
__unlink_buffer(b);
|
||||
|
@ -1479,7 +1480,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_release_move);
|
|||
|
||||
static void forget_buffer_locked(struct dm_buffer *b)
|
||||
{
|
||||
if (likely(!b->hold_count) && likely(!b->state)) {
|
||||
if (likely(!b->hold_count) && likely(!smp_load_acquire(&b->state))) {
|
||||
__unlink_buffer(b);
|
||||
__free_buffer_wake(b);
|
||||
}
|
||||
|
@ -1639,7 +1640,7 @@ static bool __try_evict_buffer(struct dm_buffer *b, gfp_t gfp)
|
|||
{
|
||||
if (!(gfp & __GFP_FS) ||
|
||||
(static_branch_unlikely(&no_sleep_enabled) && b->c->no_sleep)) {
|
||||
if (test_bit(B_READING, &b->state) ||
|
||||
if (test_bit_acquire(B_READING, &b->state) ||
|
||||
test_bit(B_WRITING, &b->state) ||
|
||||
test_bit(B_DIRTY, &b->state))
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue