On Monday 9 November 2020 11:47:45 PM IST Darrick J. Wong wrote: > From: Darrick J. Wong <darrick.wong@xxxxxxxxxx> > > The comment and logic in xchk_btree_check_minrecs for dealing with > inode-rooted btrees isn't quite correct. While the direct children of > the inode root are allowed to have fewer records than what would > normally be allowed for a regular ondisk btree block, this is only true > if there is only one child block and the number of records don't fit in > the inode root. > The code changes are consistent with rules provided in the comments. Reviewed-by: Chandan Babu R <chandanrlinux@xxxxxxxxx> > Fixes: 08a3a692ef58 ("xfs: btree scrub should check minrecs") > Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> > --- > fs/xfs/scrub/btree.c | 45 +++++++++++++++++++++++++++------------------ > 1 file changed, 27 insertions(+), 18 deletions(-) > > > diff --git a/fs/xfs/scrub/btree.c b/fs/xfs/scrub/btree.c > index f52a7b8256f9..debf392e0515 100644 > --- a/fs/xfs/scrub/btree.c > +++ b/fs/xfs/scrub/btree.c > @@ -452,32 +452,41 @@ xchk_btree_check_minrecs( > int level, > struct xfs_btree_block *block) > { > - unsigned int numrecs; > - int ok_level; > - > - numrecs = be16_to_cpu(block->bb_numrecs); > + struct xfs_btree_cur *cur = bs->cur; > + unsigned int root_level = cur->bc_nlevels - 1; > + unsigned int numrecs = be16_to_cpu(block->bb_numrecs); > > /* More records than minrecs means the block is ok. */ > - if (numrecs >= bs->cur->bc_ops->get_minrecs(bs->cur, level)) > + if (numrecs >= cur->bc_ops->get_minrecs(cur, level)) > return; > > /* > - * Certain btree blocks /can/ have fewer than minrecs records. Any > - * level greater than or equal to the level of the highest dedicated > - * btree block are allowed to violate this constraint. > - * > - * For a btree rooted in a block, the btree root can have fewer than > - * minrecs records. If the btree is rooted in an inode and does not > - * store records in the root, the direct children of the root and the > - * root itself can have fewer than minrecs records. > + * For btrees rooted in the inode, it's possible that the root block > + * contents spilled into a regular ondisk block because there wasn't > + * enough space in the inode root. The number of records in that > + * child block might be less than the standard minrecs, but that's ok > + * provided that there's only one direct child of the root. > */ > - ok_level = bs->cur->bc_nlevels - 1; > - if (bs->cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) > - ok_level--; > - if (level >= ok_level) > + if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && > + level == cur->bc_nlevels - 2) { > + struct xfs_btree_block *root_block; > + struct xfs_buf *root_bp; > + int root_maxrecs; > + > + root_block = xfs_btree_get_block(cur, root_level, &root_bp); > + root_maxrecs = cur->bc_ops->get_dmaxrecs(cur, root_level); > + if (be16_to_cpu(root_block->bb_numrecs) != 1 || > + numrecs <= root_maxrecs) > + xchk_btree_set_corrupt(bs->sc, cur, level); > return; > + } > > - xchk_btree_set_corrupt(bs->sc, bs->cur, level); > + /* > + * Otherwise, only the root level is allowed to have fewer than minrecs > + * records or keyptrs. > + */ > + if (level < root_level) > + xchk_btree_set_corrupt(bs->sc, cur, level); > } > > /* > > -- chandan