• Josef Bacik's avatar
    btrfs: unlock locked extent area if we have contention · 9e769bd7
    Josef Bacik authored
    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: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    9e769bd7
extent-io-tree.c 42.5 KB