From nobody Mon Sep 28 16:23:31 2026 Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com [209.85.214.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 556F41D5146 for ; Thu, 20 Aug 2026 00:22:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787185321; cv=none; b=B7IuzPxKDZo/FBprMjPTsig5t7yuMbKPINe2VOhnUZUP9Y1eXHb4om9Ca0naKMbO5Mw4RcdU/7QVo+JzL6wu1+82hhcSDhL35T3B93c81rvquYEYxt7uLuNQSrsYwuPIpbc2Zs9hbXppJGIGkPRMpCmsjJfPI+mt6T3Hj+w9I7g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787185321; c=relaxed/simple; bh=vaY0P3hjZGMlXKCzaJyIxaJwtL7yg0HdeDCgjEEBY0c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=rJkfLxf31eJRIfZ6tNcMjClAPnu+8voDL11NVY1T1sQjXyCla/gNxu+pj5AxWVbufcm93EJSlwLaYNFV6nnyO4huzjWYYRSQU70cHH6VQS1bgR7ZmHcvFSLmnHzV7cJ2+4WvuOoWC6okxcBW7/tm6OMBuRBBaYfy4iqa10DtetA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=anthonyvardaro.com; spf=none smtp.mailfrom=anthonyvardaro.com; dkim=pass (2048-bit key) header.d=anthonyvardaro-com.20251104.gappssmtp.com header.i=@anthonyvardaro-com.20251104.gappssmtp.com header.b=XrH5T264; arc=none smtp.client-ip=209.85.214.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=anthonyvardaro.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=anthonyvardaro.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=anthonyvardaro-com.20251104.gappssmtp.com header.i=@anthonyvardaro-com.20251104.gappssmtp.com header.b="XrH5T264" Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-2cf6d65d8a7so18910125ad.0 for ; Wed, 19 Aug 2026 17:22:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=anthonyvardaro-com.20251104.gappssmtp.com; s=20251104; t=1787185319; x=1787790119; darn=vger.kernel.org; h=cc:to:message-id:content-transfer-encoding:content-type :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=APwF6PUHOqN1JhIA+m2g5MAL7aCXBL5aOcOFSVNm7oo=; b=XrH5T264dJm0XaXbJGaXsNYcFq/7v5oGusxGeo9UgbTB19fx+DZpltZKLeSuMHST6k O7dyntksTMVC070VSKrBnMBuW3Mcy5dX5Xwcqrhx0UdvCCR4OQBAPvjF31gZEdqrTDKW I+DA/XWN3dV2SiCT3PaRbsbP5gEr6EFerlbc6Kl220N52QcuvBXyugsOTzQgl7l1KtWA HJCOcG8FUk0anqjYWQ/s4/qoi2W3Hz4WwZveULAjbDwRH6R3tDx3FeLbn8ATt2f+ay1W G8P0Pmnly2q7D3OUjwwzsYko77Lz4Fp0MlsiLXsvEi+7WdDqfEWtrN2LVejiJc5eODx/ 9vbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787185319; x=1787790119; h=cc:to:message-id:content-transfer-encoding:content-type :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=APwF6PUHOqN1JhIA+m2g5MAL7aCXBL5aOcOFSVNm7oo=; b=NrVQs9OXOi64DRfGxXXrB5xD8nmeO1+wVEha9AqZXJjdm5OpfO+G07+QVK1jkxPZBy EBdDFDt5IN2UPi9RDa1c38zk4OAQf7loVjEkbl5LHcBz9FrQ9taAVc6toBUPUQxWx4a7 y0B6j2ynbWahHJXuU1X3l/DfkCbRwhWfugO6vY6zqGAmssgjVUv0EkYvLbjWm1Y+fXh3 B7SBUNcMSACpW1WWDVN/zj5Ho1ii8dPHmUeJk8eB1zZWOLANwOvmCM+IH21k9DJMbVoH Ek61Rf7f7ZpTcwRdL0pCry2O0eHTqw88eC+QPCB2yEP5rzmmstFODYcgcwQ16yvk/tiK P0SA== X-Forwarded-Encrypted: i=1; AHgh+RqWWocPZPnvhBnf6GFVqjwe4biGoGVdyDoN8x2bQUxwQEo1O0P8LjdwkZpxAa9zObxse065pWCrweOcHnw=@vger.kernel.org X-Gm-Message-State: AFuF++nwL9eYIiaIJ7ZuBSPsjacVTe62gySN1McQZoHzCIbEibPaSs4V TeMFJJN0bTbAydzHc4/LYsP171MSfw/Wk/oIBrl+rhkLDTFYmXZFMfOeiN2D9W8yrzM= X-Gm-Gg: AR+sD11L4KHf5ljy1i++d1qzQm6siWh4AOPNHGZU5afFZ4YrUTwk7tSih3m35ooamqQ 8HafLhdqT5VhKUrjH2SAnpwxmf+v5XDCNQfkI1JHG27avbMfWSUKlSTzWgdCBU5v2mN5pBTTxzI AmgEPogM1+2HwKq3yT4o2Z6jtordTfaT3KYDYnLMlqk28QXrTW9Jbm1UvWtXdPFjdxDTmRR6iT2 bXfapsm1+3tYNCR/TfOeYtcOfdLLsxJjE309/tED5MkBAq7g1Xwrc+0pNmOIaYmkUX/fdZ+XdXN 7WCMUQybeXm1lbPRGAgVhSn1VLvnpvRWeM9g5F5FJow6+4wn2EETOiigaaRm7eeur2rrKoSJODt GzAVyBnvNIbxyNULk36SR1m1fabF6Dg4lu7FXp1Y5upfo15hBvTs/Gvs69QlApTkbkgr9FIRzC9 bkv3SbhXonhoU1QRx7/2bIzmkqOh0cYf2nPIgsvJOmzbBvub5q2fqUNK/XlDTMo89fpAaqNQWJS gy2iPo2Og/LUnces4PnH0Wd1HCbRc1qMVvJnMr/sw3cgs3cIEwQQ/MntJ0OA+Wz2MIc3qzLMlUe SByWXbWmNJHkT0lp+p87URMFkW5yQk4fV33yu8fhgysreuSOY57VxkdgpyNNeyumVzvJzm3jGA6 eExzgrKhMDavD90b3bAFd5oA= X-Received: by 2002:a17:902:c950:b0:2d6:2901:6265 with SMTP id d9443c01a7336-2d629016342mr11412075ad.2.1787185319472; Wed, 19 Aug 2026 17:21:59 -0700 (PDT) Received: from coder-vardaro-vardaro-2-0.coder-vardaro-vardaro-2.remote-dev.svc.cluster.local (ec2-16-145-69-213.us-west-2.compute.amazonaws.com. [16.145.69.213]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d62e3d27basm229915ad.79.2026.08.19.17.21.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Aug 2026 17:21:58 -0700 (PDT) From: "Anthony Vardaro (Anthropic)" Date: Thu, 20 Aug 2026 00:21:38 +0000 Subject: [PATCH] xfs: revalidate cached COW fork mappings during writeback Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260820-b4-xfs-cow-wb-revalidate-v1-1-8a19080799ea@anthonyvardaro.com> X-B4-Tracking: v=1; b=H4sIAJFIhmoC/22Nyw6DIBBFf8XMuhMBjTb9lcYFj6HSGjBgq4nx3 wt22+WZO/fcHRJFRwlu1Q6RPi654DPwSwV6lP5B6ExmEEx07MobVC1uNqEOK64Kc0VOzsiFkLW iN9yqpjM95PocybrtVN+HH6e3epJeiq98KJkIVZRej+U0zXW2hviiWJ/R3x04ji90XxSgtQAAA A== X-Change-ID: 20260813-b4-xfs-cow-wb-revalidate-0427d1fb36d7 To: Carlos Maiolino Cc: linux-xfs@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, "Anthony Vardaro (Anthropic)" X-Mailer: b4 0.15.2 Writeback can write a folio through a cached COW fork mapping after the blocks behind it have been freed. Since commit d9252d526ba6 ("xfs: validate writeback mapping using data fork seq counter") a cached data fork mapping is dropped when the fork changes, but a COW fork mapping is accepted on range alone, and since commit 3b3508980730 ("xfs: remove superfluous writeback mapping eof trimming") nothing trims it to EOF. So when close() or truncate frees the post-EOF COW blocks and the file is then appended, the same writeback pass writes the new folio into blocks the inode no longer owns. fsync() returns 0 and the range reads back as zeroes, or the data lands in another file. Check cow_seq against the COW fork if_seq for COW mappings as well, and only sample cow_seq where the mapping is built so a failed conversion cannot pair a stale mapping with a fresh sequence number. This costs one extent lookup and one cancelled transaction per invalidation: about 5% more fsync time on random 4k overwrites of a reflinked file, nothing measurable on sequential writeback. Fixes: d9252d526ba6 ("xfs: validate writeback mapping using data fork seq c= ounter") Cc: stable@vger.kernel.org # v5.1 Assisted-by: Claude:unspecified Signed-off-by: Anthony Vardaro (Anthropic) --- An fstests case for this, using the wb_delay_ms error injection knob, follows separately. Backport note: kernels before v6.2 do not have trace_xfs_wb_cow_iomap_invalid() (added by commit c2beff99eb03), so drop that call there. Kernels before v5.5 test wpc->fork =3D=3D XFS_COW_FORK instead of IOMAP_F_SHARED and have no XFS_WPC(). --- fs/xfs/xfs_aops.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 2a0c54256..c043e5bad 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -304,12 +304,22 @@ xfs_imap_valid( offset >=3D wpc->iomap.offset + wpc->iomap.length) return false; /* - * If this is a COW mapping, it is sufficient to check that the mapping - * covers the offset. Be careful to check this first because the caller - * can revalidate a COW mapping without updating the data seqno. + * A COW mapping is only valid while the COW fork is unchanged. After a + * change, the blocks behind the mapping can already be freed, for + * example by the post-EOF trim on close. Do this check before the + * data fork check, because the caller can revalidate a COW mapping + * without updating the data seqno. */ - if (wpc->iomap.flags & IOMAP_F_SHARED) + if (wpc->iomap.flags & IOMAP_F_SHARED) { + if (!ip->i_cowfp) + return false; + if (XFS_WPC(wpc)->cow_seq !=3D READ_ONCE(ip->i_cowfp->if_seq)) { + trace_xfs_wb_cow_iomap_invalid(ip, &wpc->iomap, + XFS_WPC(wpc)->cow_seq, XFS_COW_FORK); + return false; + } return true; + } =20 /* * This is not a COW mapping. Check the sequence number of the data fork @@ -359,9 +369,8 @@ xfs_map_blocks( /* * COW fork blocks can overlap data fork blocks even if the blocks * aren't shared. COW I/O always takes precedent, so we must always - * check for overlap on reflink inodes unless the mapping is already a - * COW one, or the COW fork hasn't changed from the last time we looked - * at it. + * check for overlap on reflink inodes unless the COW fork hasn't + * changed from the last time we looked at it. * * It's safe to check the COW fork if_seq here without the ILOCK because * we've indirectly protected against concurrent updates: writeback has @@ -394,16 +403,14 @@ xfs_map_blocks( xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb, &icur, &imap)) cow_fsb =3D imap.br_startoff; if (cow_fsb !=3D NULLFILEOFF && cow_fsb <=3D offset_fsb) { - XFS_WPC(wpc)->cow_seq =3D READ_ONCE(ip->i_cowfp->if_seq); xfs_iunlock(ip, XFS_ILOCK_SHARED); - whichfork =3D XFS_COW_FORK; goto allocate_blocks; } =20 /* - * No COW extent overlap. Revalidate now that we may have updated - * ->cow_seq. If the data mapping is still valid, we're done. + * No COW extent overlap. If the data mapping is still valid, we're + * done. */ if (xfs_imap_valid(wpc, ip, offset)) { xfs_iunlock(ip, XFS_ILOCK_SHARED); --- base-commit: 0877338ade31b825884a744e03f27c8de300f101 change-id: 20260813-b4-xfs-cow-wb-revalidate-0427d1fb36d7 Best regards, -- =20 Anthony Vardaro (Anthropic)