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.

Signed-off-by: Mikulas Patocka <[email protected]>
Cc: [email protected]

---
 drivers/md/dm-bufio.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

Index: linux-2.6/drivers/md/dm-bufio.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-bufio.c
+++ linux-2.6/drivers/md/dm-bufio.c
@@ -795,7 +795,7 @@ static void __make_buffer_clean(struct d
 {
        BUG_ON(b->hold_count);
 
-       if (!b->state)  /* fast case */
+       if (!smp_load_acquire(&b->state))       /* fast case */
                return;
 
        wait_on_bit_io(&b->state, B_READING, TASK_UNINTERRUPTIBLE);
@@ -816,7 +816,7 @@ static struct dm_buffer *__get_unclaimed
                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 +1058,7 @@ found_buffer:
         * 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 +1218,7 @@ void dm_bufio_release(struct dm_buffer *
                 * 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 +1479,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 +1639,7 @@ static bool __try_evict_buffer(struct dm
 {
        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;
--
dm-devel mailing list
[email protected]
https://listman.redhat.com/mailman/listinfo/dm-devel

Reply via email to