Skip to content

Commit 9e769bd

Browse files
josefbacikkdave
authored andcommitted
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: [email protected] # 5.15+ Reviewed-by: Filipe Manana <[email protected]> Signed-off-by: Josef Bacik <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent c86eab8 commit 9e769bd

File tree

1 file changed

+8
-7
lines changed

1 file changed

+8
-7
lines changed

fs/btrfs/extent-io-tree.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,16 +1641,17 @@ int lock_extent(struct extent_io_tree *tree, u64 start, u64 end,
16411641
int err;
16421642
u64 failed_start;
16431643

1644-
while (1) {
1644+
err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, &failed_start,
1645+
cached_state, NULL, GFP_NOFS);
1646+
while (err == -EEXIST) {
1647+
if (failed_start != start)
1648+
clear_extent_bit(tree, start, failed_start - 1,
1649+
EXTENT_LOCKED, cached_state);
1650+
1651+
wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED);
16451652
err = __set_extent_bit(tree, start, end, EXTENT_LOCKED,
16461653
&failed_start, cached_state, NULL,
16471654
GFP_NOFS);
1648-
if (err == -EEXIST) {
1649-
wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED);
1650-
start = failed_start;
1651-
} else
1652-
break;
1653-
WARN_ON(start > end);
16541655
}
16551656
return err;
16561657
}

0 commit comments

Comments
 (0)