From: Darrick J. Wong <djwong@xxxxxxxxxx> Currently, one can feed mkfs a combination of options like this: $ truncate -s 6366g /tmp/a ; mkfs.xfs -f /tmp/a -d agcount=3200 -d su=256k,sw=4 meta-data=/tmp/a isize=512 agcount=3200, agsize=521536 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=1, sparse=1, rmapbt=0 = reflink=1 bigtime=0 inobtcount=0 data = bsize=4096 blocks=1668808704, imaxpct=5 = sunit=64 swidth=256 blks naming =version 2 bsize=4096 ascii-ci=0, ftype=1 log =internal log bsize=4096 blocks=521536, version=2 = sectsz=512 sunit=64 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 Metadata corruption detected at 0x55e88052c6b6, xfs_agf block 0x1/0x200 libxfs_bwrite: write verifier failed on xfs_agf bno 0x1/0x1 mkfs.xfs: writing AG headers failed, err=117 The format fails because the internal log size sizing algorithm specifies a log size of 521492 blocks to avoid taking all the space in the AG, but align_log_size sees the stripe unit and rounds that up to the next stripe unit, which is 521536 blocks. Fix this problem by rounding the log size down if rounding up would result in a log that consumes more space in the AG than we allow. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> --- mkfs/xfs_mkfs.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c index e11b39d7..eb4d7fa9 100644 --- a/mkfs/xfs_mkfs.c +++ b/mkfs/xfs_mkfs.c @@ -3180,9 +3180,10 @@ sb_set_features( static void align_log_size( struct mkfs_params *cfg, - int sunit) + int sunit, + int max_logblocks) { - uint64_t tmp_logblocks; + uint64_t tmp_logblocks; /* nothing to do if it's already aligned. */ if ((cfg->logblocks % sunit) == 0) @@ -3199,7 +3200,8 @@ _("log size %lld is not a multiple of the log stripe unit %d\n"), /* If the log is too large, round down instead of round up */ if ((tmp_logblocks > XFS_MAX_LOG_BLOCKS) || - ((tmp_logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES)) { + ((tmp_logblocks << cfg->blocklog) > XFS_MAX_LOG_BYTES) || + tmp_logblocks > max_logblocks) { tmp_logblocks = (cfg->logblocks / sunit) * sunit; } cfg->logblocks = tmp_logblocks; @@ -3213,7 +3215,8 @@ static void align_internal_log( struct mkfs_params *cfg, struct xfs_mount *mp, - int sunit) + int sunit, + int max_logblocks) { uint64_t logend; @@ -3231,7 +3234,7 @@ _("Due to stripe alignment, the internal log start (%lld) cannot be aligned\n" } /* round up/down the log size now */ - align_log_size(cfg, sunit); + align_log_size(cfg, sunit, max_logblocks); /* check the aligned log still starts and ends in the same AG. */ logend = cfg->logstart + cfg->logblocks - 1; @@ -3309,7 +3312,7 @@ _("external log device size %lld blocks too small, must be at least %lld blocks\ cfg->logstart = 0; cfg->logagno = 0; if (cfg->lsunit) - align_log_size(cfg, cfg->lsunit); + align_log_size(cfg, cfg->lsunit, XFS_MAX_LOG_BLOCKS); validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); return; @@ -3386,9 +3389,9 @@ _("log ag number %lld too large, must be less than %lld\n"), * Align the logstart at stripe unit boundary. */ if (cfg->lsunit) { - align_internal_log(cfg, mp, cfg->lsunit); + align_internal_log(cfg, mp, cfg->lsunit, max_logblocks); } else if (cfg->dsunit) { - align_internal_log(cfg, mp, cfg->dsunit); + align_internal_log(cfg, mp, cfg->dsunit, max_logblocks); } validate_log_size(cfg->logblocks, cfg->blocklog, min_logblocks); }