]> git.baikalelectronics.ru Git - kernel.git/commit
btrfs: unlock locked extent area if we have contention
authorJosef Bacik <josef@toxicpanda.com>
Fri, 30 Sep 2022 20:45:08 +0000 (16:45 -0400)
committerDavid Sterba <dsterba@suse.com>
Tue, 11 Oct 2022 12:47:06 +0000 (14:47 +0200)
commit9e769bd7e5db5e3bd76e7c67004c261f7fcaa8f1
tree3c079df3099eb2edb18a15e1ca9f4e92585af921
parentc86eab81a23f368d08efd3df96a95f3d0b471f85
btrfs: unlock locked extent area if we have contention

In production we hit the following deadlock

task 1 task 2 task 3
------ ------ ------
fiemap(file) falloc(file) fsync(file)
  write(0, 1MiB)
  btrfs_commit_transaction()
    wait_on(!pending_ordered)
  lock(512MiB, 1GiB)
  start_transaction
    wait_on_transaction

  lock(0, 1GiB)
    wait_extent_bit(512MiB)

task 4
------
finish_ordered_extent(0, 1MiB)
  lock(0, 1MiB)
  **DEADLOCK**

This occurs because when task 1 does it's lock, it locks everything from
0-512MiB, and then waits for the 512MiB chunk to unlock.  task 2 will
never unlock because it's waiting on the transaction commit to happen,
the transaction commit is waiting for the outstanding ordered extents,
and then the ordered extent thread is blocked waiting on the 0-1MiB
range to unlock.

To fix this we have to clear anything we've locked so far, wait for the
extent_state that we contended on, and then try to re-lock the entire
range again.

CC: stable@vger.kernel.org # 5.15+
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/extent-io-tree.c