From 15b7bc4067bf07e5b8fe9ce137785543076fe830 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Fri, 18 Sep 2026 09:18:53 +0900 Subject: [PATCH] ntfs: fix incorrect VCN units for index blocks in large clusters NTFS stores VCNs for index blocks smaller than their cluster in fixed 512-byte units, independent of logical sector size. Use correct block units when initializing and traversing these indexes so directory indexes are located correctly. Verified on a Windows-created 4Kn/32KB-cluster NTFS volume that when the index block is smaller than the cluster, the VCN unit is 512 bytes. Signed-off-by: Hyunchul Lee Reviewed-by: Baolin Liu Signed-off-by: Namjae Jeon --- fs/ntfs/index.c | 2 +- fs/ntfs/index.h | 2 +- fs/ntfs/inode.c | 8 ++++---- fs/ntfs/layout.h | 6 +++--- fs/ntfs/namei.c | 7 +++---- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c index 580998990bc9..4410df0a8f31 100644 --- a/fs/ntfs/index.c +++ b/fs/ntfs/index.c @@ -852,7 +852,7 @@ int ntfs_index_lookup(const void *key, const u32 key_len, struct ntfs_index_cont if (ni->vol->cluster_size <= icx->block_size) icx->vcn_size_bits = ni->vol->cluster_size_bits; else - icx->vcn_size_bits = ni->vol->sector_size_bits; + icx->vcn_size_bits = NTFS_BLOCK_SIZE_BITS; icx->cr = ir->collation_rule; if (!ntfs_is_collation_rule_supported(icx->cr)) { diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h index 9a03f53bba47..a898e348f2c9 100644 --- a/fs/ntfs/index.h +++ b/fs/ntfs/index.h @@ -37,7 +37,7 @@ * (maximum is MAX_PARENT_VCN) * @ib_dirty: true if the current index block (@ia/@ib) was modified * @block_size: size of index blocks in bytes (from $INDEX_ROOT or $Boot) - * @vcn_size_bits: log2(cluster size) + * @vcn_size_bits: log2 of the VCN unit size * @sync_write: true if synchronous writeback is requested for this context * * @idx_ni is the index inode this context belongs to. diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index b3c5219c7b77..111eff42870b 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -1021,8 +1021,8 @@ static int ntfs_read_locked_inode(struct inode *vi) ni->itype.index.vcn_size = vol->cluster_size; ni->itype.index.vcn_size_bits = vol->cluster_size_bits; } else { - ni->itype.index.vcn_size = vol->sector_size; - ni->itype.index.vcn_size_bits = vol->sector_size_bits; + ni->itype.index.vcn_size = NTFS_BLOCK_SIZE; + ni->itype.index.vcn_size_bits = NTFS_BLOCK_SIZE_BITS; } /* Setup the index allocation attribute, even if not present. */ @@ -1612,8 +1612,8 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) ni->itype.index.vcn_size = vol->cluster_size; ni->itype.index.vcn_size_bits = vol->cluster_size_bits; } else { - ni->itype.index.vcn_size = vol->sector_size; - ni->itype.index.vcn_size_bits = vol->sector_size_bits; + ni->itype.index.vcn_size = NTFS_BLOCK_SIZE; + ni->itype.index.vcn_size_bits = NTFS_BLOCK_SIZE_BITS; } /* Find index allocation attribute. */ diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h index 9438fd9b668e..8f5792139d71 100644 --- a/fs/ntfs/layout.h +++ b/fs/ntfs/layout.h @@ -1880,8 +1880,8 @@ struct index_header { * @index_block_size: Size of each index block in bytes * (in $INDEX_ALLOCATION). * @clusters_per_index_block: - * Clusters per index block (or log2(bytes) - * if < cluster). + * Clusters per index block, or 512-byte units when + * the index block is smaller than a cluster. * Power of 2; used for encoding block size. * @reserved: 3 bytes reserved/alignment (zero). * @index: Index header for root entries (entries follow @@ -1921,7 +1921,7 @@ struct index_root { * @lsn: Log sequence number of last modification. * @index_block_vcn: VCN of this index block. * Units: clusters if cluster_size <= index_block_size; - * sectors otherwise. + * 512-byte blocks otherwise. * @index: Index header describing entries in this block. * * When creating the index block, we place the update sequence array at this diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c index 3e572c00e102..2cde39da6bee 100644 --- a/fs/ntfs/namei.c +++ b/fs/ntfs/namei.c @@ -433,9 +433,8 @@ static struct ntfs_inode *__ntfs_create(const struct mnt_idmap *idmap, struct in ni->itype.index.vcn_size_bits = vol->cluster_size_bits; } else { - ni->itype.index.vcn_size = vol->sector_size; - ni->itype.index.vcn_size_bits = - vol->sector_size_bits; + ni->itype.index.vcn_size = NTFS_BLOCK_SIZE; + ni->itype.index.vcn_size_bits = NTFS_BLOCK_SIZE_BITS; } } @@ -569,7 +568,7 @@ static struct ntfs_inode *__ntfs_create(const struct mnt_idmap *idmap, struct in NTFS_B_TO_CLU(vol, ni->vol->index_record_size); else ir->clusters_per_index_block = - ni->vol->index_record_size >> ni->vol->sector_size_bits; + ni->vol->index_record_size >> NTFS_BLOCK_SIZE_BITS; ir->index.entries_offset = cpu_to_le32(sizeof(struct index_header)); ir->index.index_length = cpu_to_le32(index_len); ir->index.allocated_size = cpu_to_le32(index_len);