Skip to content

Commit 8e698ee

Browse files
Darrick J. Wongdgchinner
authored andcommitted
xfs: set bnobt/cntbt numrecs correctly when formatting new AGs
Through generic/300, I discovered that mkfs.xfs creates corrupt filesystems when given these parameters: # mkfs.xfs -d size=512M /dev/sda -f -d su=128k,sw=4 --unsupported Filesystems formatted with --unsupported are not supported!! meta-data=/dev/sda isize=512 agcount=8, agsize=16352 blks = sectsz=512 attr=2, projid32bit=1 = crc=1 finobt=1, sparse=1, rmapbt=1 = reflink=1 bigtime=1 inobtcount=1 nrext64=1 data = bsize=4096 blocks=130816, imaxpct=25 = sunit=32 swidth=128 blks naming =version 2 bsize=4096 ascii-ci=0, ftype=1 log =internal log bsize=4096 blocks=8192, version=2 = sectsz=512 sunit=32 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 = rgcount=0 rgsize=0 blks Discarding blocks...Done. # xfs_repair -n /dev/sda Phase 1 - find and verify superblock... - reporting progress in intervals of 15 minutes Phase 2 - using internal log - zero log... - 16:30:50: zeroing log - 16320 of 16320 blocks done - scan filesystem freespace and inode maps... agf_freeblks 25, counted 0 in ag 4 sb_fdblocks 8823, counted 8798 The root cause of this problem is the numrecs handling in xfs_freesp_init_recs, which is used to initialize a new AG. Prior to calling the function, we set up the new bnobt block with numrecs == 1 and rely on _freesp_init_recs to format that new record. If the last record created has a blockcount of zero, then it sets numrecs = 0. That last bit isn't correct if the AG contains the log, the start of the log is not immediately after the initial blocks due to stripe alignment, and the end of the log is perfectly aligned with the end of the AG. For this case, we actually formatted a single bnobt record to handle the free space before the start of the (stripe aligned) log, and incremented arec to try to format a second record. That second record turned out to be unnecessary, so what we really want is to leave numrecs at 1. The numrecs handling itself is overly complicated because a different function sets numrecs == 1. Change the bnobt creation code to start with numrecs set to zero and only increment it after successfully formatting a free space extent into the btree block. Fixes: f327a00 ("xfs: account for log space when formatting new AGs") Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
1 parent b82a5c4 commit 8e698ee

1 file changed

Lines changed: 9 additions & 10 deletions

File tree

fs/xfs/libxfs/xfs_ag.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -495,10 +495,12 @@ xfs_freesp_init_recs(
495495
ASSERT(start >= mp->m_ag_prealloc_blocks);
496496
if (start != mp->m_ag_prealloc_blocks) {
497497
/*
498-
* Modify first record to pad stripe align of log
498+
* Modify first record to pad stripe align of log and
499+
* bump the record count.
499500
*/
500501
arec->ar_blockcount = cpu_to_be32(start -
501502
mp->m_ag_prealloc_blocks);
503+
be16_add_cpu(&block->bb_numrecs, 1);
502504
nrec = arec + 1;
503505

504506
/*
@@ -509,7 +511,6 @@ xfs_freesp_init_recs(
509511
be32_to_cpu(arec->ar_startblock) +
510512
be32_to_cpu(arec->ar_blockcount));
511513
arec = nrec;
512-
be16_add_cpu(&block->bb_numrecs, 1);
513514
}
514515
/*
515516
* Change record start to after the internal log
@@ -518,15 +519,13 @@ xfs_freesp_init_recs(
518519
}
519520

520521
/*
521-
* Calculate the record block count and check for the case where
522-
* the log might have consumed all available space in the AG. If
523-
* so, reset the record count to 0 to avoid exposure of an invalid
524-
* record start block.
522+
* Calculate the block count of this record; if it is nonzero,
523+
* increment the record count.
525524
*/
526525
arec->ar_blockcount = cpu_to_be32(id->agsize -
527526
be32_to_cpu(arec->ar_startblock));
528-
if (!arec->ar_blockcount)
529-
block->bb_numrecs = 0;
527+
if (arec->ar_blockcount)
528+
be16_add_cpu(&block->bb_numrecs, 1);
530529
}
531530

532531
/*
@@ -538,7 +537,7 @@ xfs_bnoroot_init(
538537
struct xfs_buf *bp,
539538
struct aghdr_init_data *id)
540539
{
541-
xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 1, id->agno);
540+
xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 0, id->agno);
542541
xfs_freesp_init_recs(mp, bp, id);
543542
}
544543

@@ -548,7 +547,7 @@ xfs_cntroot_init(
548547
struct xfs_buf *bp,
549548
struct aghdr_init_data *id)
550549
{
551-
xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 1, id->agno);
550+
xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 0, id->agno);
552551
xfs_freesp_init_recs(mp, bp, id);
553552
}
554553

0 commit comments

Comments
 (0)