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=1794590811; b=PIJ460RkKE0aUFWqVkmw8lmLpxgml5SsDvCXdAhzQXnMvQ2YFqDpL3s290L8AmN61t7j S1hcgdD7yICoxkCVqxz0jBr3VhauUkmUubjth6RmT1FPEeSH6Yka3m9JQxU3WlFX+OgZM Ap2l/b0qeA7c3T0YYJI7N9alLWkfhfmXoMHaNGoPuucN7BlAOlk3fC2+dxZSg3WCHtj/4 gefkFoOkeP6RCcTIv0vH/1N0rljbmwl9cayPAxrR+v9kFxPwc2AlkycVVEcb+3pXTx+g8 W0FIj8MIP9riialhJRqjVCE8zO5m45mqVlRq/JcLyUbPT+Lmepr3DUWL23GaHW88Opg== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794590811; 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=7xmC4WEGQGqj3NRE2AUnOJS/7y6wI1jX3z25MzWLpIw=; b=0/SGnyIXLP/bt+OjOonsm324PgSW/+kcnleX/iK6DksaEFhvH+0SN73Bq/muoKpU7tM8 5BEoFvqePeBBaDYFX24KkFuMe/ETlDsh095OnKbwAY4spEJVQA3skDugxeRdbU/lsEvwt ZCGNcyrlL68FM8MeM0h+ATDH/qlJTBiWTwg3e0pf3UXXtfmt+BGpf9llwxU80IHUJz/2g eT4IHQtkX/ZrFsmhcEnlHEQU1sSV4BbvNkl3kQ+a4wSDSkVJ3AlYQy98n+PENqh9j6orS JFOxtH1rcV9ufzLIWLHrkqMxk+e/ggQeEdTmI55Izu5d8ToNjb9h6tJoXWNLYQIQ10g== 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=m3Ij+26P; 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 5E817606D481; Fri, 13 Nov 2026 17:26:51 +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=m3Ij+26P Received: by smtp.kernel.org (Postfix) with ESMTPSA id C31421F000C5; Fri, 13 Nov 2026 17:26:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794590811; bh=7xmC4WEGQGqj3NRE2AUnOJS/7y6wI1jX3z25MzWLpIw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=m3Ij+26PWxNt3uvcPmA7zJMeLnlkChudmYQahzTEfvHF/oygqyzpHNEuCe0HLKJFW POMEJ2p+xJ4m40/b9HkCm7jzwGHR4EVI9XEZTyJhCcRC8Os9J60ggbwckXptTVbyxM 0QGBE8DGQiJc41eERUYHFEjhyv7dgMA4Cw1xH05Q= 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 6.12 020/670] xfs: refactor directory data block walking loops in scrub Date: Fri, 13 Nov 2026 10:43:04 -0500 Message-ID: <20261113153811.872009812@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261113153811.177190860@linuxfoundation.org> References: <20261113153811.177190860@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 6.12-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 284f72ef2b584..7928dbe221d58 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -305,6 +305,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( @@ -381,21 +420,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 2bc2354cd85d4..4c565f7bcd290 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -456,6 +456,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( @@ -477,33 +523,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