diff options
author | Chris Mason <clm@fb.com> | 2014-11-19 21:25:09 +0300 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-11-19 21:34:35 +0300 |
commit | f82c458a2c3ffb94b431fc6ad791a79df1b3713e (patch) | |
tree | 0eca3f95f74d1cde140366002b3cd794ce96f67c /fs/btrfs/locking.h | |
parent | 6e5aafb27419f32575b27ef9d6a31e5d54661aca (diff) | |
download | linux-f82c458a2c3ffb94b431fc6ad791a79df1b3713e.tar.xz |
btrfs: fix lockups from btrfs_clear_path_blocking
The fair reader/writer locks mean that btrfs_clear_path_blocking needs
to strictly follow lock ordering rules even when we already have
blocking locks on a given path.
Before we can clear a blocking lock on the path, we need to make sure
all of the locks have been converted to blocking. This will remove lock
inversions against anyone spinning in write_lock() against the buffers
we're trying to get read locks on. These inversions didn't exist before
the fair read/writer locks, but now we need to be more careful.
We papered over this deadlock in the past by changing
btrfs_try_read_lock() to be a true trylock against both the spinlock and
the blocking lock. This was slower, and not sufficient to fix all the
deadlocks. This patch adds a btrfs_tree_read_lock_atomic(), which
basically means get the spinlock but trylock on the blocking lock.
Signed-off-by: Chris Mason <clm@fb.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
Reported-by: Patrick Schmid <schmid@phys.ethz.ch>
cc: stable@vger.kernel.org #v3.15+
Diffstat (limited to 'fs/btrfs/locking.h')
-rw-r--r-- | fs/btrfs/locking.h | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/fs/btrfs/locking.h b/fs/btrfs/locking.h index b81e0e9a4894..c44a9d5f5362 100644 --- a/fs/btrfs/locking.h +++ b/fs/btrfs/locking.h @@ -35,6 +35,8 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw); void btrfs_assert_tree_locked(struct extent_buffer *eb); int btrfs_try_tree_read_lock(struct extent_buffer *eb); int btrfs_try_tree_write_lock(struct extent_buffer *eb); +int btrfs_tree_read_lock_atomic(struct extent_buffer *eb); + static inline void btrfs_tree_unlock_rw(struct extent_buffer *eb, int rw) { |