Skip to content

Commit

Permalink
btrfs: Fix deadlock caused by missing memory barrier
Browse files Browse the repository at this point in the history
Commit 06297d8 ("btrfs: switch extent_buffer blocking_writers from
atomic to int") changed the type of blocking_writers but forgot to
adjust relevant code in btrfs_tree_unlock by converting the
smp_mb__after_atomic to smp_mb.  This opened up the possibility of a
deadlock due to re-ordering of setting blocking_writers and
checking/waking up the waiter. This particular lockup is explained in a
comment above waitqueue_active() function.

Fix it by converting the memory barrier to a full smp_mb, accounting
for the fact that blocking_writers is a simple integer.

Fixes: 06297d8 ("btrfs: switch extent_buffer blocking_writers from atomic to int")
Tested-by: Johannes Thumshirn <jthumshirn@suse.com>
Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
  • Loading branch information
Nikolay Borisov authored and David Sterba committed Jul 25, 2019
1 parent 373c3b8 commit 6e7ca09
Showing 1 changed file with 6 additions and 3 deletions.
9 changes: 6 additions & 3 deletions fs/btrfs/locking.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,12 @@ void btrfs_tree_unlock(struct extent_buffer *eb)
if (blockers) {
btrfs_assert_no_spinning_writers(eb);
eb->blocking_writers--;
/* Use the lighter barrier after atomic */
smp_mb__after_atomic();
cond_wake_up_nomb(&eb->write_lock_wq);
/*
* We need to order modifying blocking_writers above with
* actually waking up the sleepers to ensure they see the
* updated value of blocking_writers
*/
cond_wake_up(&eb->write_lock_wq);
} else {
btrfs_assert_spinning_writers_put(eb);
write_unlock(&eb->lock);
Expand Down

0 comments on commit 6e7ca09

Please sign in to comment.