Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/mason/linux-btrfs

Pull btrfs deadlock fix from Chris Mason:
 "This has a fix for a long standing deadlock that we've been trying to
  nail down for a while.  It ended up being a bad interaction with the
  fair reader/writer locks and the order btrfs reacquires locks in the
  btree"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  btrfs: fix lockups from btrfs_clear_path_blocking
  • Loading branch information
Linus Torvalds committed Nov 23, 2014
2 parents cb95413 + f82c458 commit d038a63
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 15 deletions.
14 changes: 2 additions & 12 deletions fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,6 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
{
int i;

#ifdef CONFIG_DEBUG_LOCK_ALLOC
/* lockdep really cares that we take all of these spinlocks
* in the right order. If any of the locks in the path are not
* currently blocking, it is going to complain. So, make really
* really sure by forcing the path to blocking before we clear
* the path blocking.
*/
if (held) {
btrfs_set_lock_blocking_rw(held, held_rw);
if (held_rw == BTRFS_WRITE_LOCK)
Expand All @@ -95,7 +88,6 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
held_rw = BTRFS_READ_LOCK_BLOCKING;
}
btrfs_set_path_blocking(p);
#endif

for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) {
if (p->nodes[i] && p->locks[i]) {
Expand All @@ -107,10 +99,8 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
}
}

#ifdef CONFIG_DEBUG_LOCK_ALLOC
if (held)
btrfs_clear_lock_blocking_rw(held, held_rw);
#endif
}

/* this also releases the path */
Expand Down Expand Up @@ -2893,7 +2883,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
}
p->locks[level] = BTRFS_WRITE_LOCK;
} else {
err = btrfs_try_tree_read_lock(b);
err = btrfs_tree_read_lock_atomic(b);
if (!err) {
btrfs_set_path_blocking(p);
btrfs_tree_read_lock(b);
Expand Down Expand Up @@ -3025,7 +3015,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
}

level = btrfs_header_level(b);
err = btrfs_try_tree_read_lock(b);
err = btrfs_tree_read_lock_atomic(b);
if (!err) {
btrfs_set_path_blocking(p);
btrfs_tree_read_lock(b);
Expand Down
24 changes: 21 additions & 3 deletions fs/btrfs/locking.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,26 @@ void btrfs_tree_read_lock(struct extent_buffer *eb)
atomic_inc(&eb->spinning_readers);
}

/*
* take a spinning read lock.
* returns 1 if we get the read lock and 0 if we don't
* this won't wait for blocking writers
*/
int btrfs_tree_read_lock_atomic(struct extent_buffer *eb)
{
if (atomic_read(&eb->blocking_writers))
return 0;

read_lock(&eb->lock);
if (atomic_read(&eb->blocking_writers)) {
read_unlock(&eb->lock);
return 0;
}
atomic_inc(&eb->read_locks);
atomic_inc(&eb->spinning_readers);
return 1;
}

/*
* returns 1 if we get the read lock and 0 if we don't
* this won't wait for blocking writers
Expand Down Expand Up @@ -158,9 +178,7 @@ int btrfs_try_tree_write_lock(struct extent_buffer *eb)
atomic_read(&eb->blocking_readers))
return 0;

if (!write_trylock(&eb->lock))
return 0;

write_lock(&eb->lock);
if (atomic_read(&eb->blocking_writers) ||
atomic_read(&eb->blocking_readers)) {
write_unlock(&eb->lock);
Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/locking.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down

0 comments on commit d038a63

Please sign in to comment.