ntfs: fix directory lookup on large-page systems

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: 0a8ac0c1fa ("ntfs: update directory operations")
Signed-off-by: Marek Wesołowski <marek@wesolowski.eu.org>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Marek Wesołowski 2026-09-15 09:47:22 +02:00 committed by Namjae Jeon
parent 351bdddcc0
commit 3581ef4558
2 changed files with 10 additions and 3 deletions

View File

@ -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,

View File

@ -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);
}