Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp4775075pxj; Wed, 9 Jun 2021 01:17:39 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz6RRglIE+ZeQgEfBA22BzrsuMGOZKUzCcgb8uHLSkLkC4V4cDhWd7PkOVO2pDcZwO3CDyU X-Received: by 2002:a17:906:b06:: with SMTP id u6mr28353117ejg.199.1623226658967; Wed, 09 Jun 2021 01:17:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1623226658; cv=none; d=google.com; s=arc-20160816; b=INJUfWFwfEICzbSwK1JbpnmNM3JCub7njzGzXb4X7zB8MzpqA+XnetLGK0jrM777fF jR5YmO8tva0sKxzdJeVNILyq8Nc5R1vOkME45msPZQ/npcqlkmu7LXElFSMexvRXz59E bqUmC3b8PVraSFpprRu/NUAzX7h6V3WRJh4Cb2h84nlf0We6Pp5M+deLdoErhd6d+gjb q33re7yjtnHxcaWIh7avUeeHji8AxHVLK3jWzqgKVGnTzfyPgl5XldcGpo/Z1lRQ9JtT MG8SMbGHM/36ZjfGcsIyeG3rm5T4o5iUbUewJxICJChxqus9dS7SR2CTHXrdcuuzrgew Y9lQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=dPaEIwvmFu1o8lEZQpqd3CRtUVHBJs8ScedgBYiqZSw=; b=JRWZO7AuWpjspUMS+L/fSCX5VJfVpgY5kQgwsuMryL39RKV+qWGChnXQ2XEfBnRCZf JcZmvTrz5CAwMkdO+RIw8FCxIc+2CJoHB12HzxEvFKZjraPiJYk1I4m7iIT1+IkKM0qs 7TdkmH9FqxZs4ZWqn9HcmjgeQnkHe/eidgRfQ4hILFp3+IoBAUeRBddAgvL5qfAHLE7p 9vqFY2bcanwxjdLy1+QfKWdw05oHkEJ7z7g9g2m7VQPQQ/3K9UWppWYREdTvJKqcBgX1 1LHNjwhPZoTvfw4u9H4tESUR49IKQJGcYAZOJ3GkCHO/FrVtn/V6hdpjr01ET0c4QSmr S5Ew== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=nFXTGbBh; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id c14si2142425edr.0.2021.06.09.01.17.15; Wed, 09 Jun 2021 01:17:38 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=nFXTGbBh; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238329AbhFHTdF (ORCPT + 99 others); Tue, 8 Jun 2021 15:33:05 -0400 Received: from mail.kernel.org ([198.145.29.99]:39586 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237855AbhFHTSC (ORCPT ); Tue, 8 Jun 2021 15:18:02 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id D985B61978; Tue, 8 Jun 2021 18:51:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1623178290; bh=n7pG4w/2rTfxpet/fCl9Stkv5gQqX6+XHsU/tbXwW+w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nFXTGbBhwZap9hVJeRrtjzb6nQkqas08XJ9dP5HsQQQxsNf9Pt9s0kS/LK60RYSfp LhOune/hpUQppWUaMOiVEu8YMMR20OlVlr0o/nP9fHscOztKI34TmSgzem/IvSiQMW vi5CTWtKBNptKEOH+HGcnO8cOK3BN3LQyRRWkdFU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Filipe Manana , David Sterba Subject: [PATCH 5.12 147/161] btrfs: fix deadlock when cloning inline extents and low on available space Date: Tue, 8 Jun 2021 20:27:57 +0200 Message-Id: <20210608175950.415896811@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210608175945.476074951@linuxfoundation.org> References: <20210608175945.476074951@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Filipe Manana commit 76a6d5cd74479e7ec8a7f9a29bce63d5549b6b2e upstream. There are a few cases where cloning an inline extent requires copying data into a page of the destination inode. For these cases we are allocating the required data and metadata space while holding a leaf locked. This can result in a deadlock when we are low on available space because allocating the space may flush delalloc and two deadlock scenarios can happen: 1) When starting writeback for an inode with a very small dirty range that fits in an inline extent, we deadlock during the writeback when trying to insert the inline extent, at cow_file_range_inline(), if the extent is going to be located in the leaf for which we are already holding a read lock; 2) After successfully starting writeback, for non-inline extent cases, the async reclaim thread will hang waiting for an ordered extent to complete if the ordered extent completion needs to modify the leaf for which the clone task is holding a read lock (for adding or replacing file extent items). So the cloning task will wait forever on the async reclaim thread to make progress, which in turn is waiting for the ordered extent completion which in turn is waiting to acquire a write lock on the same leaf. So fix this by making sure we release the path (and therefore the leaf) every time we need to copy the inline extent's data into a page of the destination inode, as by that time we do not need to have the leaf locked. Fixes: 05a5a7621ce66c ("Btrfs: implement full reflink support for inline extents") CC: stable@vger.kernel.org # 5.10+ Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/reflink.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -207,10 +207,7 @@ static int clone_copy_inline_extent(stru * inline extent's data to the page. */ ASSERT(key.offset > 0); - ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset, - inline_data, size, datal, - comp_type); - goto out; + goto copy_to_page; } } else if (i_size_read(dst) <= datal) { struct btrfs_file_extent_item *ei; @@ -226,13 +223,10 @@ static int clone_copy_inline_extent(stru BTRFS_FILE_EXTENT_INLINE) goto copy_inline_extent; - ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset, - inline_data, size, datal, comp_type); - goto out; + goto copy_to_page; } copy_inline_extent: - ret = 0; /* * We have no extent items, or we have an extent at offset 0 which may * or may not be inlined. All these cases are dealt the same way. @@ -244,11 +238,13 @@ copy_inline_extent: * clone. Deal with all these cases by copying the inline extent * data into the respective page at the destination inode. */ - ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset, - inline_data, size, datal, comp_type); - goto out; + goto copy_to_page; } + /* + * Release path before starting a new transaction so we don't hold locks + * that would confuse lockdep. + */ btrfs_release_path(path); /* * If we end up here it means were copy the inline extent into a leaf @@ -286,11 +282,6 @@ copy_inline_extent: out: if (!ret && !trans) { /* - * Release path before starting a new transaction so we don't - * hold locks that would confuse lockdep. - */ - btrfs_release_path(path); - /* * No transaction here means we copied the inline extent into a * page of the destination inode. * @@ -310,6 +301,21 @@ out: *trans_out = trans; return ret; + +copy_to_page: + /* + * Release our path because we don't need it anymore and also because + * copy_inline_to_page() needs to reserve data and metadata, which may + * need to flush delalloc when we are low on available space and + * therefore cause a deadlock if writeback of an inline extent needs to + * write to the same leaf or an ordered extent completion needs to write + * to the same leaf. + */ + btrfs_release_path(path); + + ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset, + inline_data, size, datal, comp_type); + goto out; } /**