Skip to content

Commit 4f5b1b3

Browse files
committed
xfs: split the sunit parameter update into two parts
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 <[email protected]> Reviewed-by: Brian Foster <[email protected]>
1 parent 1cac233 commit 4f5b1b3

File tree

1 file changed

+72
-51
lines changed

1 file changed

+72
-51
lines changed

fs/xfs/xfs_mount.c

Lines changed: 72 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -360,66 +360,76 @@ xfs_readsb(
360360
}
361361

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

370-
if (mp->m_dalign) {
375+
/*
376+
* If stripe unit and stripe width are not multiples
377+
* of the fs blocksize turn off alignment.
378+
*/
379+
if ((BBTOB(mp->m_dalign) & mp->m_blockmask) ||
380+
(BBTOB(mp->m_swidth) & mp->m_blockmask)) {
381+
xfs_warn(mp,
382+
"alignment check failed: sunit/swidth vs. blocksize(%d)",
383+
mp->m_sb.sb_blocksize);
384+
return -EINVAL;
385+
} else {
371386
/*
372-
* If stripe unit and stripe width are not multiples
373-
* of the fs blocksize turn off alignment.
387+
* Convert the stripe unit and width to FSBs.
374388
*/
375-
if ((BBTOB(mp->m_dalign) & mp->m_blockmask) ||
376-
(BBTOB(mp->m_swidth) & mp->m_blockmask)) {
389+
mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign);
390+
if (mp->m_dalign && (mp->m_sb.sb_agblocks % mp->m_dalign)) {
377391
xfs_warn(mp,
378-
"alignment check failed: sunit/swidth vs. blocksize(%d)",
379-
sbp->sb_blocksize);
392+
"alignment check failed: sunit/swidth vs. agsize(%d)",
393+
mp->m_sb.sb_agblocks);
380394
return -EINVAL;
381-
} else {
382-
/*
383-
* Convert the stripe unit and width to FSBs.
384-
*/
385-
mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign);
386-
if (mp->m_dalign && (sbp->sb_agblocks % mp->m_dalign)) {
387-
xfs_warn(mp,
388-
"alignment check failed: sunit/swidth vs. agsize(%d)",
389-
sbp->sb_agblocks);
390-
return -EINVAL;
391-
} else if (mp->m_dalign) {
392-
mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth);
393-
} else {
394-
xfs_warn(mp,
395-
"alignment check failed: sunit(%d) less than bsize(%d)",
396-
mp->m_dalign, sbp->sb_blocksize);
397-
return -EINVAL;
398-
}
399-
}
400-
401-
/*
402-
* Update superblock with new values
403-
* and log changes
404-
*/
405-
if (xfs_sb_version_hasdalign(sbp)) {
406-
if (sbp->sb_unit != mp->m_dalign) {
407-
sbp->sb_unit = mp->m_dalign;
408-
mp->m_update_sb = true;
409-
}
410-
if (sbp->sb_width != mp->m_swidth) {
411-
sbp->sb_width = mp->m_swidth;
412-
mp->m_update_sb = true;
413-
}
395+
} else if (mp->m_dalign) {
396+
mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth);
414397
} else {
415398
xfs_warn(mp,
416-
"cannot change alignment: superblock does not support data alignment");
399+
"alignment check failed: sunit(%d) less than bsize(%d)",
400+
mp->m_dalign, mp->m_sb.sb_blocksize);
417401
return -EINVAL;
418402
}
403+
}
404+
405+
if (!xfs_sb_version_hasdalign(&mp->m_sb)) {
406+
xfs_warn(mp,
407+
"cannot change alignment: superblock does not support data alignment");
408+
return -EINVAL;
409+
}
410+
411+
return 0;
412+
}
413+
414+
/* Update alignment values based on mount options and sb values. */
415+
STATIC int
416+
xfs_update_alignment(
417+
struct xfs_mount *mp)
418+
{
419+
struct xfs_sb *sbp = &mp->m_sb;
420+
421+
if (mp->m_dalign) {
422+
if (sbp->sb_unit == mp->m_dalign &&
423+
sbp->sb_width == mp->m_swidth)
424+
return 0;
425+
426+
sbp->sb_unit = mp->m_dalign;
427+
sbp->sb_width = mp->m_swidth;
428+
mp->m_update_sb = true;
419429
} else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN &&
420430
xfs_sb_version_hasdalign(&mp->m_sb)) {
421-
mp->m_dalign = sbp->sb_unit;
422-
mp->m_swidth = sbp->sb_width;
431+
mp->m_dalign = sbp->sb_unit;
432+
mp->m_swidth = sbp->sb_width;
423433
}
424434

425435
return 0;
@@ -648,12 +658,12 @@ xfs_mountfs(
648658
}
649659

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

@@ -664,6 +674,17 @@ xfs_mountfs(
664674
xfs_rmapbt_compute_maxlevels(mp);
665675
xfs_refcountbt_compute_maxlevels(mp);
666676

677+
/*
678+
* Check if sb_agblocks is aligned at stripe boundary. If sb_agblocks
679+
* is NOT aligned turn off m_dalign since allocator alignment is within
680+
* an ag, therefore ag has to be aligned at stripe boundary. Note that
681+
* we must compute the free space and rmap btree geometry before doing
682+
* this.
683+
*/
684+
error = xfs_update_alignment(mp);
685+
if (error)
686+
goto out;
687+
667688
/* enable fail_at_unmount as default */
668689
mp->m_fail_unmount = true;
669690

0 commit comments

Comments
 (0)