From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794585286; b=HayEbUZtgsmkGNEjub3EwVnnGD3rZCO8m5IfYz8yMUNKArpn7F0ViQO25q0ZyDsDjWxh Y7bsisCSxGn0JZe3u49djqGjIjoNPiECTyTKgvKcSXw9qLSPj27N0aXoGRzJq9AE8ihLh OzlGRNSwSAOpKM43/4Pt/QAMLTnu7qAOQyp3u65xgBufuJI3zAbv0Qd1wrk50ODFcbiBp r6jpYePmdkKGYcg0ITGWDkncitudRP4+ixcyHrF38Fq9PBtQ7XqlpHENjOTLL1h54yHs4 CF3Dtkd4YnLZmd5EiNBOqZvo+FPa5CW8iI49mNeobUOdA2859EizX0Bg7cMX6P0K/eQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794585286; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Transfer-Encoding; bh=LM4IO3HaYt5e1cmI4XddTOdwTyR8x2tSGqK6mTX8/rc=; b=xz6JmJCHJyDo4IZoqWAIKHGFRYgKwGbp/Ji1xCYqLkBNmKJcXFM9Xeftxq7C+q+edEVt 7RbsdlYzmFGiZasdgspTEVtxlqtJ3OME1zahtL9GUFO3XxpQcyHPep1ee1SLGpScY2nis oehGHLUl96IbXUV/R1+gi/kMWnNXnZDmAxNxiRLCNcxI+c6rIjqY/y9EZtBe4yVDPT5E3 BlDYBdGRltNFQ+KYcXYKwqP9v3jorNP2jmAAbJszFFt3NPs+lW5vW4Yjgka+yxLELbKCq OSjIuuJA7j6H9J5YXNtVW+Atj/KfJFOrkG7n6x+oucbYBWd31tdnbehZ74R1abkdVUQ== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=R+G+8szB; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 62773606A331; Fri, 13 Nov 2026 15:54:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=R+G+8szB Received: by smtp.kernel.org (Postfix) with ESMTPSA id A88201F000C4; Fri, 13 Nov 2026 15:54:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794585285; bh=LM4IO3HaYt5e1cmI4XddTOdwTyR8x2tSGqK6mTX8/rc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=R+G+8szBMQ88bf/Sx2Fse/XoyGbD5Cu499QHa2BhvW3wXYwWWBEFtfULT41c8zysr 5cU1Sf3ZGXAP7q2jSYKnmfrUHPG+eM+Thf5ZnVsxqw3rArvv3lMkh3oOEnk5Q5MRTz 7ppNbYgBZhvKz6IS0ddoh36gCA2v4Fvk3Rt0Hw4g= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, "Darrick J. Wong" , Christoph Hellwig , Carlos Maiolino , Sasha Levin Subject: [PATCH 7.3 008/507] xfs: refactor directory data block walking loops in scrub Date: Fri, 13 Nov 2026 10:45:12 -0500 Message-ID: <20261113153753.662192675@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261113153753.358973689@linuxfoundation.org> References: <20261113153753.358973689@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: patches@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Darrick J. Wong [ Upstream commit 19b5653cc870788df71e7fcf2dd7b6131d8868dc ] Hoist the inner loop code of the directory data block walking code in the directory scrub and repair code to separate functions in preparation for strengthening the validation in a subsequent patch. Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Signed-off-by: Carlos Maiolino Stable-dep-of: 5d470234d04d ("xfs: improve dirent bounds checking in scrub and repair") Signed-off-by: Sasha Levin --- fs/xfs/scrub/dir.c | 56 ++++++++++++++++++++++++++---- fs/xfs/scrub/dir_repair.c | 73 ++++++++++++++++++++++++++++----------- 2 files changed, 102 insertions(+), 27 deletions(-) diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index 4ab7e64692482..e35631e00ddec 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -313,6 +313,45 @@ xchk_dir_actor( return error; } +/* + * Deal with an unused directory entry. Returns a positive number of bytes to + * advance in the directory block, zero to stop processing, or -1 if corruption + * was found. + */ +static int +xchk_dir_check_unused( + struct xchk_da_btree *ds, + struct xfs_buf *bp, + unsigned int iter_off, + unsigned int end) +{ + struct xfs_dir2_data_unused *dup = bp->b_addr + iter_off; + + return be16_to_cpu(dup->length); +} + +/* + * Check a directory entry. Returns a positive number of bytes to advance + * in the directory block, zero to stop processing, or -1 if corruption was + * found. + */ +static int +xchk_dir_check_entry( + struct xchk_da_btree *ds, + struct xfs_buf *bp, + unsigned int iter_off, + unsigned int end, + struct xfs_dir2_data_entry *dent) +{ + struct xfs_dir2_data_entry *dep = bp->b_addr + iter_off; + struct xfs_mount *mp = ds->state->mp; + + if (dep == dent) + return 0; + + return xfs_dir2_data_entsize(mp, dep->namelen); +} + /* Scrub a directory btree record. */ STATIC int xchk_dir_rec( @@ -389,21 +428,24 @@ xchk_dir_rec( goto out_relse; } for (;;) { - struct xfs_dir2_data_entry *dep = bp->b_addr + iter_off; struct xfs_dir2_data_unused *dup = bp->b_addr + iter_off; + int advance; if (iter_off >= end) { xchk_fblock_set_corrupt(ds->sc, XFS_DATA_FORK, rec_bno); goto out_relse; } - if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { - iter_off += be16_to_cpu(dup->length); - continue; - } - if (dep == dent) + if (dup->freetag == cpu_to_be16(XFS_DIR2_DATA_FREE_TAG)) + advance = xchk_dir_check_unused(ds, bp, iter_off, end); + else + advance = xchk_dir_check_entry(ds, bp, iter_off, end, + dent); + if (advance < 0) + goto out_relse; + if (!advance) break; - iter_off += xfs_dir2_data_entsize(mp, dep->namelen); + iter_off += advance; } /* Retrieve the entry, sanity check it, and compare hashes. */ diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index bb3f2f462bde5..1169a2ad26876 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -462,6 +462,52 @@ xrep_dir_salvage_data_entry( return xrep_dir_salvage_entry(rd, dep->name, dep->namelen, ino); } +/* + * Deal with an unused directory entry. Returns a positive number of bytes to + * advance in the directory block, or zero to stop processing. + */ +static int +xrep_dir_recover_unused( + struct xfs_buf *bp, + unsigned int offset, + unsigned int end) +{ + struct xfs_dir2_data_unused *dup = bp->b_addr + offset; + + return be16_to_cpu(dup->length); +} + +/* + * Salvage a directory entry. Returns a positive number of bytes to advance + * in the directory block, zero to stop processing, or a negative errno. + */ +static int +xrep_dir_recover_entry( + struct xrep_dir *rd, + struct xfs_buf *bp, + unsigned int offset, + unsigned int end) +{ + struct xfs_dir2_data_entry *dep = bp->b_addr + offset; + unsigned int advance; + int error; + + /* Don't walk off the end of the block. */ + advance = xfs_dir2_data_entsize(rd->sc->mp, dep->namelen); + if (!advance) + return 0; + if (offset + advance > end) + return 0; + + /* Ok, let's save this entry. */ + error = xrep_dir_salvage_data_entry(rd, dep); + if (error < 0) + return error; + + return advance; +} + + /* Try to recover block/data format directory entries. */ STATIC int xrep_dir_recover_data( @@ -483,33 +529,20 @@ xrep_dir_recover_data( while (offset < end) { struct xfs_dir2_data_unused *dup = bp->b_addr + offset; - struct xfs_dir2_data_entry *dep = bp->b_addr + offset; - unsigned int advance; + int advance; if (xchk_should_terminate(rd->sc, &error)) return error; - /* Skip unused entries. */ - if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { - if (!dup->length) - break; - offset += be16_to_cpu(dup->length); - continue; - } - - /* Don't walk off the end of the block. */ - advance = xfs_dir2_data_entsize(rd->sc->mp, dep->namelen); + if (dup->freetag == cpu_to_be16(XFS_DIR2_DATA_FREE_TAG)) + advance = xrep_dir_recover_unused(bp, offset, end); + else + advance = xrep_dir_recover_entry(rd, bp, offset, end); + if (advance < 0) + return advance; if (!advance) break; offset += advance; - if (offset > end) - break; - - /* Ok, let's save this entry. */ - error = xrep_dir_salvage_data_entry(rd, dep); - if (error) - return error; - } return 0; -- 2.53.0