Skip to content

Commit e5d1802

Browse files
author
Darrick J. Wong
committed
xfs: fix a bug in the online fsck directory leaf1 bestcount check
When xfs_scrub encounters a directory with a leaf1 block, it tries to validate that the leaf1 block's bestcount (aka the best free count of each directory data block) is the correct size. Previously, this author believed that comparing bestcount to the directory isize (since directory data blocks are under isize, and leaf/bestfree blocks are above it) was sufficient. Unfortunately during testing of online repair, it was discovered that it is possible to create a directory with a hole between the last directory block and isize. The directory code seems to handle this situation just fine and xfs_repair doesn't complain, which effectively makes this quirk part of the disk format. Fix the check to work properly. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Dave Chinner <[email protected]>
1 parent 7993f1a commit e5d1802

File tree

1 file changed

+11
-4
lines changed

1 file changed

+11
-4
lines changed

fs/xfs/scrub/dir.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ STATIC int
497497
xchk_directory_leaf1_bestfree(
498498
struct xfs_scrub *sc,
499499
struct xfs_da_args *args,
500+
xfs_dir2_db_t last_data_db,
500501
xfs_dablk_t lblk)
501502
{
502503
struct xfs_dir3_icleaf_hdr leafhdr;
@@ -534,10 +535,14 @@ xchk_directory_leaf1_bestfree(
534535
}
535536

536537
/*
537-
* There should be as many bestfree slots as there are dir data
538-
* blocks that can fit under i_size.
538+
* There must be enough bestfree slots to cover all the directory data
539+
* blocks that we scanned. It is possible for there to be a hole
540+
* between the last data block and i_disk_size. This seems like an
541+
* oversight to the scrub author, but as we have been writing out
542+
* directories like this (and xfs_repair doesn't mind them) for years,
543+
* that's what we have to check.
539544
*/
540-
if (bestcount != xfs_dir2_byte_to_db(geo, sc->ip->i_disk_size)) {
545+
if (bestcount != last_data_db + 1) {
541546
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
542547
goto out;
543548
}
@@ -669,6 +674,7 @@ xchk_directory_blocks(
669674
xfs_fileoff_t lblk;
670675
struct xfs_iext_cursor icur;
671676
xfs_dablk_t dabno;
677+
xfs_dir2_db_t last_data_db = 0;
672678
bool found;
673679
int is_block = 0;
674680
int error;
@@ -712,6 +718,7 @@ xchk_directory_blocks(
712718
args.geo->fsbcount);
713719
lblk < got.br_startoff + got.br_blockcount;
714720
lblk += args.geo->fsbcount) {
721+
last_data_db = xfs_dir2_da_to_db(args.geo, lblk);
715722
error = xchk_directory_data_bestfree(sc, lblk,
716723
is_block);
717724
if (error)
@@ -734,7 +741,7 @@ xchk_directory_blocks(
734741
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
735742
goto out;
736743
}
737-
error = xchk_directory_leaf1_bestfree(sc, &args,
744+
error = xchk_directory_leaf1_bestfree(sc, &args, last_data_db,
738745
leaf_lblk);
739746
if (error)
740747
goto out;

0 commit comments

Comments
 (0)