xfs: fix the minrecs logic when dealing with inode root child blocks
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.
Fixes: 08a3a692ef
("xfs: btree scrub should check minrecs")
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Chandan Babu R <chandanrlinux@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
2bd3fa793a
commit
e95b6c3ef1
|
@ -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)
|
||||
return;
|
||||
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;
|
||||
|
||||
xchk_btree_set_corrupt(bs->sc, bs->cur, level);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue