aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2022-05-17 22:48:12 -0400
committerEric Sandeen <sandeen@sandeen.net>2022-05-17 22:48:12 -0400
commit8d1bff2be3360572fbee9ed83e0d1c86af1614c5 (patch)
tree86e0bab3b82f29c38c010d64eb25877ed1d4f26c
parentaba6743c5893e9a4bfe88aefecef08eb3069b336 (diff)
downloadxfsprogs-dev-8d1bff2be3360572fbee9ed83e0d1c86af1614c5.tar.gz
mkfs: reduce internal log size when log stripe units are in play
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@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
-rw-r--r--mkfs/xfs_mkfs.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index e11b39d777..eb4d7fa9ce 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);
}