Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Btrfs: fix deadlock when throttling transactions

Hit this nice little deadlock. What happens is this

__btrfs_end_transaction with throttle set, --use_count so it equals 0
btrfs_commit_transaction
<somebody else actually manages to start the commit>
btrfs_end_transaction --use_count so now its -1 <== BAD
we just return and wait on the transaction

This is bad because we just return after our use_count is -1 and don't let go
of our num_writer count on the transaction, so the guy committing the
transaction just sits there forever. Fix this by inc'ing our use_count if we're
going to call commit_transaction so that if we call btrfs_end_transaction it's
valid. Thanks,

Signed-off-by: Josef Bacik <josef@redhat.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>

authored by

Josef Bacik and committed by
Chris Mason
81317fde a6591715

+9 -2
+9 -2
fs/btrfs/transaction.c
··· 497 497 } 498 498 499 499 if (lock && cur_trans->blocked && !cur_trans->in_commit) { 500 - if (throttle) 500 + if (throttle) { 501 + /* 502 + * We may race with somebody else here so end up having 503 + * to call end_transaction on ourselves again, so inc 504 + * our use_count. 505 + */ 506 + trans->use_count++; 501 507 return btrfs_commit_transaction(trans, root); 502 - else 508 + } else { 503 509 wake_up_process(info->transaction_kthread); 510 + } 504 511 } 505 512 506 513 WARN_ON(cur_trans != info->running_transaction);