]> www.infradead.org Git - linux-platform-drivers-x86.git/commitdiff
xfs: directory scrub should check the null bestfree entries too
authorDarrick J. Wong <darrick.wong@oracle.com>
Mon, 9 Nov 2020 00:32:42 +0000 (16:32 -0800)
committerDarrick J. Wong <darrick.wong@oracle.com>
Wed, 18 Nov 2020 17:23:50 +0000 (09:23 -0800)
Teach the directory scrubber to check all the bestfree entries,
including the null ones.  We want to be able to detect the case where
the entry is null but there actually /is/ a directory data block.

Found by fuzzing lbests[0] = ones in xfs/391.

Fixes: df481968f33b ("xfs: scrub directory freespace")
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>
fs/xfs/scrub/dir.c

index 7c432997edade4ee1356449e47aeb32cf38346ec..b045e95c2ea734a2f9e41e42cfbadd1d8495d4be 100644 (file)
@@ -558,14 +558,27 @@ xchk_directory_leaf1_bestfree(
        /* Check all the bestfree entries. */
        for (i = 0; i < bestcount; i++, bestp++) {
                best = be16_to_cpu(*bestp);
-               if (best == NULLDATAOFF)
-                       continue;
                error = xfs_dir3_data_read(sc->tp, sc->ip,
-                               i * args->geo->fsbcount, 0, &dbp);
+                               xfs_dir2_db_to_da(args->geo, i),
+                               XFS_DABUF_MAP_HOLE_OK,
+                               &dbp);
                if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk,
                                &error))
                        break;
-               xchk_directory_check_freesp(sc, lblk, dbp, best);
+
+               if (!dbp) {
+                       if (best != NULLDATAOFF) {
+                               xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
+                                               lblk);
+                               break;
+                       }
+                       continue;
+               }
+
+               if (best == NULLDATAOFF)
+                       xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, lblk);
+               else
+                       xchk_directory_check_freesp(sc, lblk, dbp, best);
                xfs_trans_brelse(sc->tp, dbp);
                if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
                        break;