Received: by 2002:ac0:bc90:0:0:0:0:0 with SMTP id a16csp671131img; Fri, 22 Mar 2019 06:17:49 -0700 (PDT) X-Google-Smtp-Source: APXvYqzwQ3ylSEC9V0Z0RsAylCLlueXxunG2ZKBWNM8BdRcBNM9B5vRpeozwRhQ4+1kTlAF/ASk2 X-Received: by 2002:a65:63c1:: with SMTP id n1mr8787106pgv.339.1553260669891; Fri, 22 Mar 2019 06:17:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1553260669; cv=none; d=google.com; s=arc-20160816; b=ro5IL1Tg4Mv5iYN4BfGj+NbNDvPQQdKM5D37ssZFBTFBspyB665L4k5VCbIQM3K6UP 1S02b+WnlE6ExQULUwQ4rII9w8Ge+QhUpB4RdavxvHabeZ4rR+zOQ9Umnmq6VH4LF8Jk PtAvd+xT+6iJZDa63T9HDz3Cc/RYqNtS3ugbyWhg+VvlNHS96LVbqo7Mbn3faRI6V0lw s40oXsnUP9XLG4O6ZlI3ajCSm+OZLJ+P19uEw2tqFCmwgQ7FL8eBV5J74kSSL7VbwjfV /Mpught9AsDwmc1EtPFiV6WDV+StrVEcB1obTrNdYvXT9ku6rqk7E2Y19dOzRTXwroSN 1VYA== 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=u7tKICnFseLyV8EWfeWrwWpNRMGve+mEhY2YswjIbVM=; b=aBu3YNZsEdOzFgAFSia2/OMA2bnj2t4DE6pH7vvDgt2Stsa65jTx1Wj6beap7F4783 0wDDPS+lMdcNeZyFwH4ehlVv8T3fpypgFx5QNVd7QK7JOr5ZsEs89roiYjVfWpdW83E7 hBmE4wYo62ZwwoH6KlGvTiif9aABS6mA/29W9JqOq03uBUp2CQ5jieVq5ltL6vOtxvYt J16eH/7s+R0v/YeCyJs2bFamFbdejx2yJ5X01XCcQc1GLQSUHQt9XskP2vSVlHuJPaSF cTBIdvDefky/GqBGorKHmc4/4XgpFvADrrTq9z/JQoymL8U9CC4WPko+dYmEQVzdw8i9 tOTQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=Z7Ru8NMb; 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 n34si7319231pld.163.2019.03.22.06.17.31; Fri, 22 Mar 2019 06:17:49 -0700 (PDT) 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=Z7Ru8NMb; 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 S1729388AbfCVNQx (ORCPT + 99 others); Fri, 22 Mar 2019 09:16:53 -0400 Received: from mail.kernel.org ([198.145.29.99]:54112 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729404AbfCVL0W (ORCPT ); Fri, 22 Mar 2019 07:26:22 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (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 E1B88218A2; Fri, 22 Mar 2019 11:26:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1553253981; bh=fXCo4vyolS/9x/BdqIaLR+J8wmBy/BWnU37fEBIGd6g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Z7Ru8NMbum4XPSG8QTwTOfM7Njag5Y6MuFhxhEqSacmwys7HInKVd+OTcsctexL+l ryuXFkQthoq7R7139naSe/zHmEgGndR5pF9Vaokzpp3O7nDSGP/RWAaI7zeOBJL8yu 23e1kKdT5tcE3mRTdN6zZCtTu3d9cB3+jGdmFB88= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Zygo Blaxell , Filipe Manana , David Sterba Subject: [PATCH 3.18 115/134] Btrfs: fix corruption reading shared and compressed extents after hole punching Date: Fri, 22 Mar 2019 12:15:28 +0100 Message-Id: <20190322111218.644491941@linuxfoundation.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190322111210.465931067@linuxfoundation.org> References: <20190322111210.465931067@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review X-Patchwork-Hint: ignore 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 3.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Filipe Manana commit 8e928218780e2f1cf2f5891c7575e8f0b284fcce upstream. In the past we had data corruption when reading compressed extents that are shared within the same file and they are consecutive, this got fixed by commit 005efedf2c7d0 ("Btrfs: fix read corruption of compressed and shared extents") and by commit 808f80b46790f ("Btrfs: update fix for read corruption of compressed and shared extents"). However there was a case that was missing in those fixes, which is when the shared and compressed extents are referenced with a non-zero offset. The following shell script creates a reproducer for this issue: #!/bin/bash mkfs.btrfs -f /dev/sdc &> /dev/null mount -o compress /dev/sdc /mnt/sdc # Create a file with 3 consecutive compressed extents, each has an # uncompressed size of 128Kb and a compressed size of 4Kb. for ((i = 1; i <= 3; i++)); do head -c 4096 /dev/zero for ((j = 1; j <= 31; j++)); do head -c 4096 /dev/zero | tr '\0' "\377" done done > /mnt/sdc/foobar sync echo "Digest after file creation: $(md5sum /mnt/sdc/foobar)" # Clone the first extent into offsets 128K and 256K. xfs_io -c "reflink /mnt/sdc/foobar 0 128K 128K" /mnt/sdc/foobar xfs_io -c "reflink /mnt/sdc/foobar 0 256K 128K" /mnt/sdc/foobar sync echo "Digest after cloning: $(md5sum /mnt/sdc/foobar)" # Punch holes into the regions that are already full of zeroes. xfs_io -c "fpunch 0 4K" /mnt/sdc/foobar xfs_io -c "fpunch 128K 4K" /mnt/sdc/foobar xfs_io -c "fpunch 256K 4K" /mnt/sdc/foobar sync echo "Digest after hole punching: $(md5sum /mnt/sdc/foobar)" echo "Dropping page cache..." sysctl -q vm.drop_caches=1 echo "Digest after hole punching: $(md5sum /mnt/sdc/foobar)" umount /dev/sdc When running the script we get the following output: Digest after file creation: 5a0888d80d7ab1fd31c229f83a3bbcc8 /mnt/sdc/foobar linked 131072/131072 bytes at offset 131072 128 KiB, 1 ops; 0.0033 sec (36.960 MiB/sec and 295.6830 ops/sec) linked 131072/131072 bytes at offset 262144 128 KiB, 1 ops; 0.0015 sec (78.567 MiB/sec and 628.5355 ops/sec) Digest after cloning: 5a0888d80d7ab1fd31c229f83a3bbcc8 /mnt/sdc/foobar Digest after hole punching: 5a0888d80d7ab1fd31c229f83a3bbcc8 /mnt/sdc/foobar Dropping page cache... Digest after hole punching: fba694ae8664ed0c2e9ff8937e7f1484 /mnt/sdc/foobar This happens because after reading all the pages of the extent in the range from 128K to 256K for example, we read the hole at offset 256K and then when reading the page at offset 260K we don't submit the existing bio, which is responsible for filling all the page in the range 128K to 256K only, therefore adding the pages from range 260K to 384K to the existing bio and submitting it after iterating over the entire range. Once the bio completes, the uncompressed data fills only the pages in the range 128K to 256K because there's no more data read from disk, leaving the pages in the range 260K to 384K unfilled. It is just a slightly different variant of what was solved by commit 005efedf2c7d0 ("Btrfs: fix read corruption of compressed and shared extents"). Fix this by forcing a bio submit, during readpages(), whenever we find a compressed extent map for a page that is different from the extent map for the previous page or has a different starting offset (in case it's the same compressed extent), instead of the extent map's original start offset. A test case for fstests follows soon. Reported-by: Zygo Blaxell Fixes: 808f80b46790f ("Btrfs: update fix for read corruption of compressed and shared extents") Fixes: 005efedf2c7d0 ("Btrfs: fix read corruption of compressed and shared extents") Cc: stable@vger.kernel.org # 4.3+ Tested-by: Zygo Blaxell Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/extent_io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -3015,11 +3015,11 @@ static int __do_readpage(struct extent_i */ if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags) && prev_em_start && *prev_em_start != (u64)-1 && - *prev_em_start != em->orig_start) + *prev_em_start != em->start) force_bio_submit = true; if (prev_em_start) - *prev_em_start = em->orig_start; + *prev_em_start = em->start; free_extent_map(em); em = NULL;