diff options
author | Josef Bacik <jbacik@fusionio.com> | 2012-07-20 16:25:24 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2012-07-23 16:28:09 -0400 |
commit | 51561ffec9614618f3da362f9d1b03a95b717484 (patch) | |
tree | 0698cb8f1e7de2217b3060866b91a5bd7faa8411 /fs/btrfs | |
parent | 594831c4b232b094d645503ecedec2e35dcebdf3 (diff) |
Btrfs: lock the transition from dirty to writeback for an eb
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>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/extent_io.c | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index e1939a6c7478..97efc2f22597 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -3077,8 +3077,15 @@ static int lock_extent_buffer_for_io(struct extent_buffer *eb, | |||
3077 | } | 3077 | } |
3078 | } | 3078 | } |
3079 | 3079 | ||
3080 | /* | ||
3081 | * We need to do this to prevent races in people who check if the eb is | ||
3082 | * under IO since we can end up having no IO bits set for a short period | ||
3083 | * of time. | ||
3084 | */ | ||
3085 | spin_lock(&eb->refs_lock); | ||
3080 | if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { | 3086 | if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { |
3081 | set_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags); | 3087 | set_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags); |
3088 | spin_unlock(&eb->refs_lock); | ||
3082 | btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); | 3089 | btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); |
3083 | spin_lock(&fs_info->delalloc_lock); | 3090 | spin_lock(&fs_info->delalloc_lock); |
3084 | if (fs_info->dirty_metadata_bytes >= eb->len) | 3091 | if (fs_info->dirty_metadata_bytes >= eb->len) |
@@ -3087,6 +3094,8 @@ static int lock_extent_buffer_for_io(struct extent_buffer *eb, | |||
3087 | WARN_ON(1); | 3094 | WARN_ON(1); |
3088 | spin_unlock(&fs_info->delalloc_lock); | 3095 | spin_unlock(&fs_info->delalloc_lock); |
3089 | ret = 1; | 3096 | ret = 1; |
3097 | } else { | ||
3098 | spin_unlock(&eb->refs_lock); | ||
3090 | } | 3099 | } |
3091 | 3100 | ||
3092 | btrfs_tree_unlock(eb); | 3101 | btrfs_tree_unlock(eb); |