diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
| -rw-r--r-- | fs/btrfs/transaction.c | 15 | 
1 files changed, 14 insertions, 1 deletions
| diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 18329ebcb1cb..b8d5b1fa9a03 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -2035,7 +2035,20 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, int err)  	if (current->journal_info == trans)  		current->journal_info = NULL; -	btrfs_scrub_cancel(fs_info); + +	/* +	 * If relocation is running, we can't cancel scrub because that will +	 * result in a deadlock. Before relocating a block group, relocation +	 * pauses scrub, then starts and commits a transaction before unpausing +	 * scrub. If the transaction commit is being done by the relocation +	 * task or triggered by another task and the relocation task is waiting +	 * for the commit, and we end up here due to an error in the commit +	 * path, then calling btrfs_scrub_cancel() will deadlock, as we are +	 * asking for scrub to stop while having it asked to be paused higher +	 * above in relocation code. +	 */ +	if (!test_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags)) +		btrfs_scrub_cancel(fs_info);  	kmem_cache_free(btrfs_trans_handle_cachep, trans);  } |