Commit 141b3523 authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Mike Snitzer

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: 8238b457 ("wait_on_bit: add an acquire memory barrier")
Depends-On: d6ffe606 ("provide arch_test_bit_acquire for architectures that define test_bit")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@kernel.org>
parent bb1a1146
...@@ -795,7 +795,8 @@ static void __make_buffer_clean(struct dm_buffer *b) ...@@ -795,7 +795,8 @@ static void __make_buffer_clean(struct dm_buffer *b)
{ {
BUG_ON(b->hold_count); 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; return;
wait_on_bit_io(&b->state, B_READING, TASK_UNINTERRUPTIBLE); 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) ...@@ -816,7 +817,7 @@ static struct dm_buffer *__get_unclaimed_buffer(struct dm_bufio_client *c)
BUG_ON(test_bit(B_DIRTY, &b->state)); BUG_ON(test_bit(B_DIRTY, &b->state));
if (static_branch_unlikely(&no_sleep_enabled) && c->no_sleep && 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; continue;
if (!b->hold_count) { if (!b->hold_count) {
...@@ -1058,7 +1059,7 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block, ...@@ -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 * If the user called both dm_bufio_prefetch and dm_bufio_get on
* the same buffer, it would deadlock if we waited. * 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; return NULL;
b->hold_count++; b->hold_count++;
...@@ -1218,7 +1219,7 @@ void dm_bufio_release(struct dm_buffer *b) ...@@ -1218,7 +1219,7 @@ void dm_bufio_release(struct dm_buffer *b)
* invalid buffer. * invalid buffer.
*/ */
if ((b->read_error || b->write_error) && 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_WRITING, &b->state) &&
!test_bit(B_DIRTY, &b->state)) { !test_bit(B_DIRTY, &b->state)) {
__unlink_buffer(b); __unlink_buffer(b);
...@@ -1479,7 +1480,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_release_move); ...@@ -1479,7 +1480,7 @@ EXPORT_SYMBOL_GPL(dm_bufio_release_move);
static void forget_buffer_locked(struct dm_buffer *b) 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); __unlink_buffer(b);
__free_buffer_wake(b); __free_buffer_wake(b);
} }
...@@ -1639,7 +1640,7 @@ static bool __try_evict_buffer(struct dm_buffer *b, gfp_t gfp) ...@@ -1639,7 +1640,7 @@ static bool __try_evict_buffer(struct dm_buffer *b, gfp_t gfp)
{ {
if (!(gfp & __GFP_FS) || if (!(gfp & __GFP_FS) ||
(static_branch_unlikely(&no_sleep_enabled) && b->c->no_sleep)) { (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_WRITING, &b->state) ||
test_bit(B_DIRTY, &b->state)) test_bit(B_DIRTY, &b->state))
return false; return false;
......
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