Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp1770128ybl; Sat, 11 Jan 2020 02:28:08 -0800 (PST) X-Google-Smtp-Source: APXvYqziX8TLPrffRS+9wqBqoa2TAFgxIk5wK8LwqSyCTcQkBafQ2IkwzjVFp5/jLDXOCTaIKT+X X-Received: by 2002:a05:6830:10a:: with SMTP id i10mr6037579otp.365.1578738488770; Sat, 11 Jan 2020 02:28:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1578738488; cv=none; d=google.com; s=arc-20160816; b=nRGUBv5As/qD2rCsh+cTuBDXY4R/jXk2KnlL/SIrbw7F+qvqNrd+BtrFOOgP56FMUD GKc0jelr7zToR+szPHftwBSEjWAonf2qWYXQnxkh+3TKWRyBI0fe8s3z0pI+4wI+BA8y 5Cp3LeYen4CRwZJ2qMySdtwm7wUlJ+VC0YxHAyaYGhnZe/ZOC0+JU2pTm8YNojwOSCIf BlG9t6NkCuSrU8nG7uoBKTmbbOxwYLe87xSE840SFrLLtSq/4ZtpjELfvhLiOVNepBIH qgQKo+KkiqD2YtofHztFdxjyDoQd+fT54pwjqlEwAo+XymAEel0gH4ibvemYfWWtG+Jh AWCA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=0MIg2ObOTmSNs0HSRwpYIuBnhkyoznNedMY+lqZlytw=; b=RruF5oJjAoRdgmBc6QgOqgL35ys4EYiWaZXcMEVpiWylcmofcu9evfxxanrUW3VTIW pUC+f48aijPFjlcpreLUZT4NdjJ/cKbeRbuTd/ron5GiNBDKrfZBuXO80UHI/dcxIDrE zqp8t+PD2ZRieMRoMlOb/TOUZCu/+fBFR3K2U1qaC8oSr9nctcHVcy8VdrPNdSO5aaKQ 58/wnFiKyMglMQw71X8Y0yP5Yl5GJBgwnRa4/S1icql5pUFIphIEszHhCwHqkNSwDLIu 7B+BKMZ1F4GFyA+kjLUnseRwlTBlkI47hfHTNFoZxX1R1pojHfJyfPRiNqaMEZGeMqrE MJNw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=fpMaJPZf; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 10si2752633ois.76.2020.01.11.02.27.57; Sat, 11 Jan 2020 02:28:08 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=fpMaJPZf; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731165AbgAKK1I (ORCPT + 99 others); Sat, 11 Jan 2020 05:27:08 -0500 Received: from mail.kernel.org ([198.145.29.99]:60654 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729122AbgAKK1G (ORCPT ); Sat, 11 Jan 2020 05:27:06 -0500 Received: from localhost (unknown [62.119.166.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 2DBD320842; Sat, 11 Jan 2020 10:27:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1578738425; bh=mm4956ygG+jablg48bigObr7P6aCT2lVITov/2olgyg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fpMaJPZfXOj1rsT+Gy1uSB4jKyiscnrdTo3TBsyjvGDq5Er2t21BKJS0AbGb0qBLU tl9k3Q2RKWfcZrqND6pdfVAT4fQvwyr8UUqAq8PvJDMbcRFMQZc8F1CLeRcDdKOeP6 HS2Iabk5/i/eJcduMaMv7AJiKhI8XdKU04C9x88s= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Filipe Manana , David Sterba , Sasha Levin Subject: [PATCH 5.4 074/165] Btrfs: fix cloning range with a hole when using the NO_HOLES feature Date: Sat, 11 Jan 2020 10:49:53 +0100 Message-Id: <20200111094927.367746025@linuxfoundation.org> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200111094921.347491861@linuxfoundation.org> References: <20200111094921.347491861@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Filipe Manana [ Upstream commit fcb970581dd900675c4371c2b688a57924a8368c ] When using the NO_HOLES feature if we clone a range that contains a hole and a temporary ENOSPC happens while dropping extents from the target inode's range, we can end up failing and aborting the transaction with -EEXIST or with a corrupt file extent item, that has a length greater than it should and overlaps with other extents. For example when cloning the following range from inode A to inode B: Inode A: extent A1 extent A2 [ ----------- ] [ hole, implicit, 4MB length ] [ ------------- ] 0 1MB 5MB 6MB Range to clone: [1MB, 6MB) Inode B: extent B1 extent B2 extent B3 extent B4 [ ---------- ] [ --------- ] [ ---------- ] [ ---------- ] 0 1MB 1MB 2MB 2MB 5MB 5MB 6MB Target range: [1MB, 6MB) (same as source, to make it easier to explain) The following can happen: 1) btrfs_punch_hole_range() gets -ENOSPC from __btrfs_drop_extents(); 2) At that point, 'cur_offset' is set to 1MB and __btrfs_drop_extents() set 'drop_end' to 2MB, meaning it was able to drop only extent B2; 3) We then compute 'clone_len' as 'drop_end' - 'cur_offset' = 2MB - 1MB = 1MB; 4) We then attempt to insert a file extent item at inode B with a file offset of 5MB, which is the value of clone_info->file_offset. This fails with error -EEXIST because there's already an extent at that offset (extent B4); 5) We abort the current transaction with -EEXIST and return that error to user space as well. Another example, for extent corruption: Inode A: extent A1 extent A2 [ ----------- ] [ hole, implicit, 10MB length ] [ ------------- ] 0 1MB 11MB 12MB Inode B: extent B1 extent B2 [ ----------- ] [ --------- ] [ ----------------------------- ] 0 1MB 1MB 5MB 5MB 12MB Target range: [1MB, 12MB) (same as source, to make it easier to explain) 1) btrfs_punch_hole_range() gets -ENOSPC from __btrfs_drop_extents(); 2) At that point, 'cur_offset' is set to 1MB and __btrfs_drop_extents() set 'drop_end' to 5MB, meaning it was able to drop only extent B2; 3) We then compute 'clone_len' as 'drop_end' - 'cur_offset' = 5MB - 1MB = 4MB; 4) We then insert a file extent item at inode B with a file offset of 11MB which is the value of clone_info->file_offset, and a length of 4MB (the value of 'clone_len'). So we get 2 extents items with ranges that overlap and an extent length of 4MB, larger then the extent A2 from inode A (1MB length); 5) After that we end the transaction, balance the btree dirty pages and then start another or join the previous transaction. It might happen that the transaction which inserted the incorrect extent was committed by another task so we end up with extent corruption if a power failure happens. So fix this by making sure we attempt to insert the extent to clone at the destination inode only if we are past dropping the sub-range that corresponds to a hole. Fixes: 690a5dbfc51315 ("Btrfs: fix ENOSPC errors, leading to transaction aborts, when cloning extents") Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index c332968f9056..eaafd00f93d4 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2601,8 +2601,8 @@ int btrfs_punch_hole_range(struct inode *inode, struct btrfs_path *path, } } - if (clone_info) { - u64 clone_len = drop_end - cur_offset; + if (clone_info && drop_end > clone_info->file_offset) { + u64 clone_len = drop_end - clone_info->file_offset; ret = btrfs_insert_clone_extent(trans, inode, path, clone_info, clone_len); -- 2.20.1