From 3581ef455875aead551f9b92fd1e82c8e6fe3fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Weso=C5=82owski?= Date: Tue, 15 Sep 2026 09:47:22 +0200 Subject: [PATCH] ntfs: fix directory lookup on large-page systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ntfs_lookup_inode_by_name() copies PAGE_SIZE bytes from the index allocation mapping and applies MST fixups to that entire buffer before selecting the requested INDX block. When PAGE_SIZE is larger than the NTFS index block size, the USA count belongs to the smaller INDX block. post_read_mst_fixup() therefore treats the PAGE_SIZE call as not applicable and leaves the update sequence words in place. A directory entry crossing a sector boundary can then be returned by readdir but missed by lookup. Select the INDX block first, apply the fixup using its actual block size, and propagate fixup failures before validating the block. Report fixup failures through ntfs_error() so the configured errors= policy is applied. Return -EIO when post_read_mst_fixup() detects an incomplete multi sector transfer, since this indicates an on-disk metadata integrity error. Reproduced on arm64 with 16 KiB pages and 4 KiB NTFS index blocks. The affected entry was visible in readdir but stat returned ENOENT. Both exact and case-insensitive lookup succeed after this change. Fixes: 0a8ac0c1fa0b ("ntfs: update directory operations") Signed-off-by: Marek WesoĊ‚owski Reviewed-by: Baolin Liu Reviewed-by: Hyunchul Lee Signed-off-by: Namjae Jeon --- fs/ntfs/dir.c | 9 ++++++++- fs/ntfs/mst.c | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index 54b706d807b4..c2b48bc696bf 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c @@ -331,7 +331,6 @@ u64 ntfs_lookup_inode_by_name(struct ntfs_inode *dir_ni, const __le16 *uname, } memcpy_from_folio(kaddr, folio, 0, PAGE_SIZE); - post_read_mst_fixup((struct ntfs_record *)kaddr, PAGE_SIZE); folio_unlock(folio); folio_put(folio); fast_descend_into_child_node: @@ -352,6 +351,14 @@ u64 ntfs_lookup_inode_by_name(struct ntfs_inode *dir_ni, const __le16 *uname, vcn, dir_ni->mft_no); goto unm_err_out; } + err = post_read_mst_fixup((struct ntfs_record *)ia, + dir_ni->itype.index.block_size); + if (err) { + ntfs_error(sb, + "MST fixup failed for index block vcn %lld in directory inode 0x%llx.", + vcn, dir_ni->mft_no); + goto unm_err_out; + } err = ntfs_index_block_inconsistent(vol, ia, dir_ni->itype.index.block_size, vcn, COLLATION_FILE_NAME, diff --git a/fs/ntfs/mst.c b/fs/ntfs/mst.c index 7f9faad924ad..cc6363413449 100644 --- a/fs/ntfs/mst.c +++ b/fs/ntfs/mst.c @@ -19,7 +19,7 @@ * magic of the ntfs record header being processed with "BAAD" (in memory only!) * and abort processing. * - * Return 0 on success and -EINVAL on error ("BAAD" magic will be present). + * Return 0 on success and -EIO on error ("BAAD" magic will be present). * * NOTE: We consider the absence / invalidity of an update sequence array to * mean that the structure is not protected at all and hence doesn't need to @@ -71,7 +71,7 @@ int post_read_mst_fixup(struct ntfs_record *b, const u32 size) * Note that magic_BAAD is already converted to le32. */ b->magic = magic_BAAD; - return -EINVAL; + return -EIO; } data_pos += NTFS_BLOCK_SIZE / sizeof(u16); }