btrfs: qgroup: don't try to wait flushing if we're already holding a transaction
authorQu Wenruo <wqu@suse.com>
Fri, 4 Dec 2020 01:24:47 +0000 (09:24 +0800)
committerDavid Sterba <dsterba@suse.com>
Fri, 18 Dec 2020 13:50:07 +0000 (14:50 +0100)
commitae5e070eaca9dbebde3459dd8f4c2756f8c097d0
treef50431f9404ecd29a263188a4c0b579404fd497a
parent9a664971569daf68254928149f580b4f5856d274
btrfs: qgroup: don't try to wait flushing if we're already holding a transaction

There is a chance of racing for qgroup flushing which may lead to
deadlock:

Thread A | Thread B
   (not holding trans handle) |  (holding a trans handle)
--------------------------------+--------------------------------
__btrfs_qgroup_reserve_meta()   | __btrfs_qgroup_reserve_meta()
|- try_flush_qgroup() | |- try_flush_qgroup()
   |- QGROUP_FLUSHING bit set   |    |
   | |    |- test_and_set_bit()
   | |    |- wait_event()
   |- btrfs_join_transaction() |
   |- btrfs_commit_transaction()|

!!! DEAD LOCK !!!

Since thread A wants to commit transaction, but thread B is holding a
transaction handle, blocking the commit.
At the same time, thread B is waiting for thread A to finish its commit.

This is just a hot fix, and would lead to more EDQUOT when we're near
the qgroup limit.

The proper fix would be to make all metadata/data reservations happen
without holding a transaction handle.

CC: stable@vger.kernel.org # 5.9+
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/qgroup.c