]> rtime.felk.cvut.cz Git - linux-imx.git/commitdiff
Btrfs: lock the transition from dirty to writeback for an eb
authorJosef Bacik <jbacik@fusionio.com>
Fri, 20 Jul 2012 20:25:24 +0000 (16:25 -0400)
committerChris Mason <chris.mason@fusionio.com>
Mon, 23 Jul 2012 20:28:09 +0000 (16:28 -0400)
There is a small window where an eb can have no IO bits set on it, which
could potentially result in extent_buffer_under_io() returning false when we
want it to return true, which could result in not fun things happening.  So
in order to protect this case we need to hold the refs_lock when we make
this transition to make sure we get reliable results out of
extent_buffer_udner_io().  Thanks,

Signed-off-by: Josef Bacik <jbacik@fusionio.com>
fs/btrfs/extent_io.c

index e1939a6c747867dd353830f915b85d605e7c8918..97efc2f22597ab4d1e23d6d182b135469ef45243 100644 (file)
@@ -3077,8 +3077,15 @@ static int lock_extent_buffer_for_io(struct extent_buffer *eb,
                }
        }
 
+       /*
+        * We need to do this to prevent races in people who check if the eb is
+        * under IO since we can end up having no IO bits set for a short period
+        * of time.
+        */
+       spin_lock(&eb->refs_lock);
        if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
                set_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
+               spin_unlock(&eb->refs_lock);
                btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
                spin_lock(&fs_info->delalloc_lock);
                if (fs_info->dirty_metadata_bytes >= eb->len)
@@ -3087,6 +3094,8 @@ static int lock_extent_buffer_for_io(struct extent_buffer *eb,
                        WARN_ON(1);
                spin_unlock(&fs_info->delalloc_lock);
                ret = 1;
+       } else {
+               spin_unlock(&eb->refs_lock);
        }
 
        btrfs_tree_unlock(eb);