mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
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>
This commit is contained in:
parent
494dba7b27
commit
490d451fa5
@ -1698,11 +1698,16 @@ struct xfs_ino_geometry {
|
||||
/* Maximum inode count in this filesystem. */
|
||||
uint64_t maxicount;
|
||||
|
||||
/* Actual inode cluster buffer size, in bytes. */
|
||||
unsigned int inode_cluster_size;
|
||||
|
||||
/*
|
||||
* Desired inode cluster buffer size, in bytes. This value is not
|
||||
* rounded up to at least one filesystem block.
|
||||
* rounded up to at least one filesystem block, which is necessary for
|
||||
* the sole purpose of validating sb_spino_align. Runtime code must
|
||||
* only ever use inode_cluster_size.
|
||||
*/
|
||||
unsigned int inode_cluster_size;
|
||||
unsigned int inode_cluster_size_raw;
|
||||
|
||||
/* Inode cluster sizes, adjusted to be at least 1 fsb. */
|
||||
unsigned int inodes_per_cluster;
|
||||
|
@ -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. */
|
||||
|
@ -308,8 +308,7 @@ xfs_calc_iunlink_remove_reservation(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
|
||||
2 * max_t(uint, XFS_FSB_TO_B(mp, 1),
|
||||
M_IGEO(mp)->inode_cluster_size);
|
||||
2 * M_IGEO(mp)->inode_cluster_size;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -347,8 +346,7 @@ STATIC uint
|
||||
xfs_calc_iunlink_add_reservation(xfs_mount_t *mp)
|
||||
{
|
||||
return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
|
||||
max_t(uint, XFS_FSB_TO_B(mp, 1),
|
||||
M_IGEO(mp)->inode_cluster_size);
|
||||
M_IGEO(mp)->inode_cluster_size;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2893,8 +2893,7 @@ xlog_recover_buffer_pass2(
|
||||
*/
|
||||
if (XFS_DINODE_MAGIC ==
|
||||
be16_to_cpu(*((__be16 *)xfs_buf_offset(bp, 0))) &&
|
||||
(BBTOB(bp->b_io_length) != max(log->l_mp->m_sb.sb_blocksize,
|
||||
M_IGEO(log->l_mp)->inode_cluster_size))) {
|
||||
(BBTOB(bp->b_io_length) != M_IGEO(log->l_mp)->inode_cluster_size)) {
|
||||
xfs_buf_stale(bp);
|
||||
error = xfs_bwrite(bp);
|
||||
} else {
|
||||
|
@ -746,11 +746,11 @@ xfs_mountfs(
|
||||
*/
|
||||
if (xfs_sb_version_hassparseinodes(&mp->m_sb) &&
|
||||
mp->m_sb.sb_spino_align !=
|
||||
XFS_B_TO_FSBT(mp, igeo->inode_cluster_size)) {
|
||||
XFS_B_TO_FSBT(mp, igeo->inode_cluster_size_raw)) {
|
||||
xfs_warn(mp,
|
||||
"Sparse inode block alignment (%u) must match cluster size (%llu).",
|
||||
mp->m_sb.sb_spino_align,
|
||||
XFS_B_TO_FSBT(mp, igeo->inode_cluster_size));
|
||||
XFS_B_TO_FSBT(mp, igeo->inode_cluster_size_raw));
|
||||
error = -EINVAL;
|
||||
goto out_remove_uuid;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user