summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_ialloc.c
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2019-06-05 21:19:35 +0300
committerDarrick J. Wong <darrick.wong@oracle.com>2019-06-12 18:37:40 +0300
commit490d451fa5188975c21246f7f8f4914cd3f2d6f2 (patch)
tree334d0a26f447c2e594aa18fe5336487e4801bf9e /fs/xfs/libxfs/xfs_ialloc.c
parent494dba7b276e12bc3f6ff2b9b584b6e9f693af45 (diff)
downloadlinux-490d451fa5188975c21246f7f8f4914cd3f2d6f2.tar.xz
xfs: fix inode_cluster_size rounding mayhem
inode_cluster_size is supposed to represent the size (in bytes) of an inode cluster buffer. We avoid having to handle multiple clusters per filesystem block on filesystems with large blocks by openly rounding this value up to 1 FSB when necessary. However, we never reset inode_cluster_size to reflect this new rounded value, which adds to the potential for mistakes in calculating geometries. Fix this by setting inode_cluster_size to reflect the rounded-up size if needed, and special-case the few places in the sparse inodes code where we actually need the smaller value to validate on-disk metadata. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com>
Diffstat (limited to 'fs/xfs/libxfs/xfs_ialloc.c')
-rw-r--r--fs/xfs/libxfs/xfs_ialloc.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index fdfcc03a35b9..0f5ff2a4b0b8 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -2805,21 +2805,32 @@ xfs_ialloc_setup_geometry(
igeo->maxicount = 0;
}
- igeo->inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE;
+ /*
+ * Compute the desired size of an inode cluster buffer size, which
+ * starts at 8K and (on v5 filesystems) scales up with larger inode
+ * sizes.
+ *
+ * Preserve the desired inode cluster size because the sparse inodes
+ * feature uses that desired size (not the actual size) to compute the
+ * sparse inode alignment. The mount code validates this value, so we
+ * cannot change the behavior.
+ */
+ igeo->inode_cluster_size_raw = XFS_INODE_BIG_CLUSTER_SIZE;
if (xfs_sb_version_hascrc(&mp->m_sb)) {
- int new_size = igeo->inode_cluster_size;
+ int new_size = igeo->inode_cluster_size_raw;
new_size *= mp->m_sb.sb_inodesize / XFS_DINODE_MIN_SIZE;
if (mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, new_size))
- igeo->inode_cluster_size = new_size;
+ igeo->inode_cluster_size_raw = new_size;
}
/* Calculate inode cluster ratios. */
- if (igeo->inode_cluster_size > mp->m_sb.sb_blocksize)
+ if (igeo->inode_cluster_size_raw > mp->m_sb.sb_blocksize)
igeo->blocks_per_cluster = XFS_B_TO_FSBT(mp,
- igeo->inode_cluster_size);
+ igeo->inode_cluster_size_raw);
else
igeo->blocks_per_cluster = 1;
+ igeo->inode_cluster_size = XFS_FSB_TO_B(mp, igeo->blocks_per_cluster);
igeo->inodes_per_cluster = XFS_FSB_TO_INO(mp, igeo->blocks_per_cluster);
/* Calculate inode cluster alignment. */