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=1794585983; b=y9ekEJLLFt9STNRMJxmJq6Hz1xXBHldaMrXg3+d7owC8AxsY5bs0/9AVloLqenCd7g9h uqxMq7qQu7Vfn+iFZqFR0IZOIlDaiSOdxh7nnziXu4Khsj2PGJC6Y6GR50Ms1OagAWmNO W9iLscWR63QX0LprS/tnTdFBAX6QeLqrGzXzhP28GkFi4C36NVGjtglZgdMA5zvcbM4SK DvcjRtyrR/2+A6jwd15Eit0LlmmgtKkRjfui+eevE9B2EGaVzsjd7w+7X9FRM+oVEqv6G xBzwax/6pIzleLK1wtoVPexCULnIeCncHjyMfTxQh4melNZoSC6tK+7NsSDJBInZ39Q== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794585983; 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=MukOkJgCl+DqphkB3vkrvYevxn6LI76HN8e1vXHaSng=; b=vZYbsiinksl2wLrbX7/eJmT+4Hl1bKA/pvs+TO7LwK54ThN+sYqvbLXjZ3IJ2HEdo3fx wsdE4QaO5SoB/Th4mtzqUkU/DWQgw7+vy/tK342NTXzHxFDfkvs1+vq2VppIelaTtZYuE vRif0U8wfqWg2iJe1FiUFs32iJmr1QhVPKBzwRod51IX4vFJaJs+d7cajVbAQKIllVILH WIIM08a1mY33VFs1P5Dc9xjsZouaCaLh2HgEOXP9+Hg1ylJtoOsp+9NsTceOxUjejTO2W wpSdUoS9KJZGEEqmlsK7o0I0UlPNc7SVkmQGVY3+ls6FwD0uJn2JCgpsfc99bCSyc8g== 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=y+TDMVm2; 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 558276072317; Fri, 13 Nov 2026 16:06:23 +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=y+TDMVm2 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 012701F000C4; Fri, 13 Nov 2026 16:06:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794585983; bh=MukOkJgCl+DqphkB3vkrvYevxn6LI76HN8e1vXHaSng=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=y+TDMVm24RIQ7qinYHrIs5qjm8d/MgXwW5N9MUUmKPswvTXKojATH1MTO9oeGaFWW 17Fl1Weu8gY/8jrm36SGHcQ9Pyl9FlNJ3mVqyXp8gxSpwpICItvQ3AUUGBopUpGPBr tIQQphv9lEQkqVcaXM1HfZSnZ54nKQMen8rUsV2A= 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.18 028/686] xfs: refactor directory data block walking loops in scrub Date: Fri, 13 Nov 2026 10:42:41 -0500 Message-ID: <20261113153821.940060138@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261113153820.902362109@linuxfoundation.org> References: <20261113153820.902362109@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.18-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 7b0a9d2aea3ec..2f73baee0f0b4 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 9aafe5c31cbe3..f8e88b638c43d 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