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>
This commit is contained in:
parent
594831c4b2
commit
51561ffec9
@ -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)) {
|
if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
|
||||||
set_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
|
set_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
|
||||||
|
spin_unlock(&eb->refs_lock);
|
||||||
btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
|
btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
|
||||||
spin_lock(&fs_info->delalloc_lock);
|
spin_lock(&fs_info->delalloc_lock);
|
||||||
if (fs_info->dirty_metadata_bytes >= eb->len)
|
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);
|
WARN_ON(1);
|
||||||
spin_unlock(&fs_info->delalloc_lock);
|
spin_unlock(&fs_info->delalloc_lock);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
} else {
|
||||||
|
spin_unlock(&eb->refs_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_tree_unlock(eb);
|
btrfs_tree_unlock(eb);
|
||||||
|
Loading…
Reference in New Issue
Block a user