Skip to content

Commit

Permalink
xfs: split the sunit parameter update into two parts
Browse files Browse the repository at this point in the history
If the administrator provided a sunit= mount option, we need to validate
the raw parameter, convert the mount option units (512b blocks) into the
internal unit (fs blocks), and then validate that the (now cooked)
parameter doesn't screw anything up on disk.  The incore inode geometry
computation can depend on the new sunit option, but a subsequent patch
will make validating the cooked value depends on the computed inode
geometry, so break the sunit update into two steps.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
  • Loading branch information
Darrick J. Wong committed Dec 19, 2019
1 parent 1cac233 commit 4f5b1b3
Showing 1 changed file with 72 additions and 51 deletions.
123 changes: 72 additions & 51 deletions fs/xfs/xfs_mount.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,66 +360,76 @@ xfs_readsb(
}

/*
* Update alignment values based on mount options and sb values
* If we were provided with new sunit/swidth values as mount options, make sure
* that they pass basic alignment and superblock feature checks, and convert
* them into the same units (FSB) that everything else expects. This step
* /must/ be done before computing the inode geometry.
*/
STATIC int
xfs_update_alignment(xfs_mount_t *mp)
xfs_validate_new_dalign(
struct xfs_mount *mp)
{
xfs_sb_t *sbp = &(mp->m_sb);
if (mp->m_dalign == 0)
return 0;

if (mp->m_dalign) {
/*
* If stripe unit and stripe width are not multiples
* of the fs blocksize turn off alignment.
*/
if ((BBTOB(mp->m_dalign) & mp->m_blockmask) ||
(BBTOB(mp->m_swidth) & mp->m_blockmask)) {
xfs_warn(mp,
"alignment check failed: sunit/swidth vs. blocksize(%d)",
mp->m_sb.sb_blocksize);
return -EINVAL;
} else {
/*
* If stripe unit and stripe width are not multiples
* of the fs blocksize turn off alignment.
* Convert the stripe unit and width to FSBs.
*/
if ((BBTOB(mp->m_dalign) & mp->m_blockmask) ||
(BBTOB(mp->m_swidth) & mp->m_blockmask)) {
mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign);
if (mp->m_dalign && (mp->m_sb.sb_agblocks % mp->m_dalign)) {
xfs_warn(mp,
"alignment check failed: sunit/swidth vs. blocksize(%d)",
sbp->sb_blocksize);
"alignment check failed: sunit/swidth vs. agsize(%d)",
mp->m_sb.sb_agblocks);
return -EINVAL;
} else {
/*
* Convert the stripe unit and width to FSBs.
*/
mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign);
if (mp->m_dalign && (sbp->sb_agblocks % mp->m_dalign)) {
xfs_warn(mp,
"alignment check failed: sunit/swidth vs. agsize(%d)",
sbp->sb_agblocks);
return -EINVAL;
} else if (mp->m_dalign) {
mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth);
} else {
xfs_warn(mp,
"alignment check failed: sunit(%d) less than bsize(%d)",
mp->m_dalign, sbp->sb_blocksize);
return -EINVAL;
}
}

/*
* Update superblock with new values
* and log changes
*/
if (xfs_sb_version_hasdalign(sbp)) {
if (sbp->sb_unit != mp->m_dalign) {
sbp->sb_unit = mp->m_dalign;
mp->m_update_sb = true;
}
if (sbp->sb_width != mp->m_swidth) {
sbp->sb_width = mp->m_swidth;
mp->m_update_sb = true;
}
} else if (mp->m_dalign) {
mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth);
} else {
xfs_warn(mp,
"cannot change alignment: superblock does not support data alignment");
"alignment check failed: sunit(%d) less than bsize(%d)",
mp->m_dalign, mp->m_sb.sb_blocksize);
return -EINVAL;
}
}

if (!xfs_sb_version_hasdalign(&mp->m_sb)) {
xfs_warn(mp,
"cannot change alignment: superblock does not support data alignment");
return -EINVAL;
}

return 0;
}

/* Update alignment values based on mount options and sb values. */
STATIC int
xfs_update_alignment(
struct xfs_mount *mp)
{
struct xfs_sb *sbp = &mp->m_sb;

if (mp->m_dalign) {
if (sbp->sb_unit == mp->m_dalign &&
sbp->sb_width == mp->m_swidth)
return 0;

sbp->sb_unit = mp->m_dalign;
sbp->sb_width = mp->m_swidth;
mp->m_update_sb = true;
} else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN &&
xfs_sb_version_hasdalign(&mp->m_sb)) {
mp->m_dalign = sbp->sb_unit;
mp->m_swidth = sbp->sb_width;
mp->m_dalign = sbp->sb_unit;
mp->m_swidth = sbp->sb_width;
}

return 0;
Expand Down Expand Up @@ -648,12 +658,12 @@ xfs_mountfs(
}

/*
* Check if sb_agblocks is aligned at stripe boundary
* If sb_agblocks is NOT aligned turn off m_dalign since
* allocator alignment is within an ag, therefore ag has
* to be aligned at stripe boundary.
* If we were given new sunit/swidth options, do some basic validation
* checks and convert the incore dalign and swidth values to the
* same units (FSB) that everything else uses. This /must/ happen
* before computing the inode geometry.
*/
error = xfs_update_alignment(mp);
error = xfs_validate_new_dalign(mp);
if (error)
goto out;

Expand All @@ -664,6 +674,17 @@ xfs_mountfs(
xfs_rmapbt_compute_maxlevels(mp);
xfs_refcountbt_compute_maxlevels(mp);

/*
* Check if sb_agblocks is aligned at stripe boundary. If sb_agblocks
* is NOT aligned turn off m_dalign since allocator alignment is within
* an ag, therefore ag has to be aligned at stripe boundary. Note that
* we must compute the free space and rmap btree geometry before doing
* this.
*/
error = xfs_update_alignment(mp);
if (error)
goto out;

/* enable fail_at_unmount as default */
mp->m_fail_unmount = true;

Expand Down

0 comments on commit 4f5b1b3

Please sign in to comment.