hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/fs/xfs/scrub/bmap.c
....@@ -9,27 +9,19 @@
99 #include "xfs_format.h"
1010 #include "xfs_trans_resv.h"
1111 #include "xfs_mount.h"
12
-#include "xfs_defer.h"
1312 #include "xfs_btree.h"
1413 #include "xfs_bit.h"
1514 #include "xfs_log_format.h"
1615 #include "xfs_trans.h"
17
-#include "xfs_sb.h"
1816 #include "xfs_inode.h"
19
-#include "xfs_inode_fork.h"
2017 #include "xfs_alloc.h"
21
-#include "xfs_rtalloc.h"
2218 #include "xfs_bmap.h"
23
-#include "xfs_bmap_util.h"
2419 #include "xfs_bmap_btree.h"
2520 #include "xfs_rmap.h"
2621 #include "xfs_rmap_btree.h"
27
-#include "xfs_refcount.h"
28
-#include "scrub/xfs_scrub.h"
2922 #include "scrub/scrub.h"
3023 #include "scrub/common.h"
3124 #include "scrub/btree.h"
32
-#include "scrub/trace.h"
3325
3426 /* Set us up with an inode's bmap. */
3527 int
....@@ -101,6 +93,7 @@
10193 xfs_fileoff_t lastoff;
10294 bool is_rt;
10395 bool is_shared;
96
+ bool was_loaded;
10497 int whichfork;
10598 };
10699
....@@ -241,25 +234,20 @@
241234
242235 /* Cross-reference a single rtdev extent record. */
243236 STATIC void
244
-xchk_bmap_rt_extent_xref(
245
- struct xchk_bmap_info *info,
237
+xchk_bmap_rt_iextent_xref(
246238 struct xfs_inode *ip,
247
- struct xfs_btree_cur *cur,
239
+ struct xchk_bmap_info *info,
248240 struct xfs_bmbt_irec *irec)
249241 {
250
- if (info->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
251
- return;
252
-
253242 xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
254243 irec->br_blockcount);
255244 }
256245
257246 /* Cross-reference a single datadev extent record. */
258247 STATIC void
259
-xchk_bmap_extent_xref(
260
- struct xchk_bmap_info *info,
248
+xchk_bmap_iextent_xref(
261249 struct xfs_inode *ip,
262
- struct xfs_btree_cur *cur,
250
+ struct xchk_bmap_info *info,
263251 struct xfs_bmbt_irec *irec)
264252 {
265253 struct xfs_mount *mp = info->sc->mp;
....@@ -267,9 +255,6 @@
267255 xfs_agblock_t agbno;
268256 xfs_extlen_t len;
269257 int error;
270
-
271
- if (info->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
272
- return;
273258
274259 agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
275260 agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
....@@ -301,21 +286,41 @@
301286 xchk_ag_free(info->sc, &info->sc->sa);
302287 }
303288
289
+/*
290
+ * Directories and attr forks should never have blocks that can't be addressed
291
+ * by a xfs_dablk_t.
292
+ */
293
+STATIC void
294
+xchk_bmap_dirattr_extent(
295
+ struct xfs_inode *ip,
296
+ struct xchk_bmap_info *info,
297
+ struct xfs_bmbt_irec *irec)
298
+{
299
+ struct xfs_mount *mp = ip->i_mount;
300
+ xfs_fileoff_t off;
301
+
302
+ if (!S_ISDIR(VFS_I(ip)->i_mode) && info->whichfork != XFS_ATTR_FORK)
303
+ return;
304
+
305
+ if (!xfs_verify_dablk(mp, irec->br_startoff))
306
+ xchk_fblock_set_corrupt(info->sc, info->whichfork,
307
+ irec->br_startoff);
308
+
309
+ off = irec->br_startoff + irec->br_blockcount - 1;
310
+ if (!xfs_verify_dablk(mp, off))
311
+ xchk_fblock_set_corrupt(info->sc, info->whichfork, off);
312
+}
313
+
304314 /* Scrub a single extent record. */
305315 STATIC int
306
-xchk_bmap_extent(
316
+xchk_bmap_iextent(
307317 struct xfs_inode *ip,
308
- struct xfs_btree_cur *cur,
309318 struct xchk_bmap_info *info,
310319 struct xfs_bmbt_irec *irec)
311320 {
312321 struct xfs_mount *mp = info->sc->mp;
313
- struct xfs_buf *bp = NULL;
314322 xfs_filblks_t end;
315323 int error = 0;
316
-
317
- if (cur)
318
- xfs_btree_get_block(cur, 0, &bp);
319324
320325 /*
321326 * Check for out-of-order extents. This record could have come
....@@ -324,6 +329,8 @@
324329 if (irec->br_startoff < info->lastoff)
325330 xchk_fblock_set_corrupt(info->sc, info->whichfork,
326331 irec->br_startoff);
332
+
333
+ xchk_bmap_dirattr_extent(ip, info, irec);
327334
328335 /* There should never be a "hole" extent in either extent list. */
329336 if (irec->br_startblock == HOLESTARTBLOCK)
....@@ -365,10 +372,13 @@
365372 xchk_fblock_set_corrupt(info->sc, info->whichfork,
366373 irec->br_startoff);
367374
375
+ if (info->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
376
+ return 0;
377
+
368378 if (info->is_rt)
369
- xchk_bmap_rt_extent_xref(info, ip, cur, irec);
379
+ xchk_bmap_rt_iextent_xref(ip, info, irec);
370380 else
371
- xchk_bmap_extent_xref(info, ip, cur, irec);
381
+ xchk_bmap_iextent_xref(ip, info, irec);
372382
373383 info->lastoff = irec->br_startoff + irec->br_blockcount;
374384 return error;
....@@ -381,10 +391,13 @@
381391 union xfs_btree_rec *rec)
382392 {
383393 struct xfs_bmbt_irec irec;
394
+ struct xfs_bmbt_irec iext_irec;
395
+ struct xfs_iext_cursor icur;
384396 struct xchk_bmap_info *info = bs->private;
385
- struct xfs_inode *ip = bs->cur->bc_private.b.ip;
397
+ struct xfs_inode *ip = bs->cur->bc_ino.ip;
386398 struct xfs_buf *bp = NULL;
387399 struct xfs_btree_block *block;
400
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, info->whichfork);
388401 uint64_t owner;
389402 int i;
390403
....@@ -403,9 +416,26 @@
403416 }
404417 }
405418
406
- /* Set up the in-core record and scrub it. */
419
+ /*
420
+ * Check that the incore extent tree contains an extent that matches
421
+ * this one exactly. We validate those cached bmaps later, so we don't
422
+ * need to check them here. If the incore extent tree was just loaded
423
+ * from disk by the scrubber, we assume that its contents match what's
424
+ * on disk (we still hold the ILOCK) and skip the equivalence check.
425
+ */
426
+ if (!info->was_loaded)
427
+ return 0;
428
+
407429 xfs_bmbt_disk_get_all(&rec->bmbt, &irec);
408
- return xchk_bmap_extent(ip, bs->cur, info, &irec);
430
+ if (!xfs_iext_lookup_extent(ip, ifp, irec.br_startoff, &icur,
431
+ &iext_irec) ||
432
+ irec.br_startoff != iext_irec.br_startoff ||
433
+ irec.br_startblock != iext_irec.br_startblock ||
434
+ irec.br_blockcount != iext_irec.br_blockcount ||
435
+ irec.br_state != iext_irec.br_state)
436
+ xchk_fblock_set_corrupt(bs->sc, info->whichfork,
437
+ irec.br_startoff);
438
+ return 0;
409439 }
410440
411441 /* Scan the btree records. */
....@@ -416,15 +446,26 @@
416446 struct xchk_bmap_info *info)
417447 {
418448 struct xfs_owner_info oinfo;
449
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(sc->ip, whichfork);
419450 struct xfs_mount *mp = sc->mp;
420451 struct xfs_inode *ip = sc->ip;
421452 struct xfs_btree_cur *cur;
422453 int error;
423454
455
+ /* Load the incore bmap cache if it's not loaded. */
456
+ info->was_loaded = ifp->if_flags & XFS_IFEXTENTS;
457
+ if (!info->was_loaded) {
458
+ error = xfs_iread_extents(sc->tp, ip, whichfork);
459
+ if (!xchk_fblock_process_error(sc, whichfork, 0, &error))
460
+ goto out;
461
+ }
462
+
463
+ /* Check the btree structure. */
424464 cur = xfs_bmbt_init_cursor(mp, sc->tp, ip, whichfork);
425465 xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork);
426466 error = xchk_btree(sc, cur, xchk_bmapbt_rec, &oinfo, info);
427467 xfs_btree_del_cursor(cur, error);
468
+out:
428469 return error;
429470 }
430471
....@@ -480,7 +521,7 @@
480521 xchk_fblock_set_corrupt(sc, sbcri->whichfork,
481522 rec->rm_offset);
482523 if (irec.br_startblock != XFS_AGB_TO_FSB(sc->mp,
483
- cur->bc_private.a.agno, rec->rm_startblock))
524
+ cur->bc_ag.agno, rec->rm_startblock))
484525 xchk_fblock_set_corrupt(sc, sbcri->whichfork,
485526 rec->rm_offset);
486527 if (irec.br_blockcount > rec->rm_blockcount)
....@@ -501,7 +542,7 @@
501542
502543 out:
503544 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
504
- return XFS_BTREE_QUERY_RANGE_ABORT;
545
+ return -ECANCELED;
505546 return 0;
506547 }
507548
....@@ -530,7 +571,7 @@
530571 sbcri.sc = sc;
531572 sbcri.whichfork = whichfork;
532573 error = xfs_rmap_query_all(cur, xchk_bmap_check_rmap, &sbcri);
533
- if (error == XFS_BTREE_QUERY_RANGE_ABORT)
574
+ if (error == -ECANCELED)
534575 error = 0;
535576
536577 xfs_btree_del_cursor(cur, error);
....@@ -545,8 +586,9 @@
545586 struct xfs_scrub *sc,
546587 int whichfork)
547588 {
548
- loff_t size;
589
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(sc->ip, whichfork);
549590 xfs_agnumber_t agno;
591
+ bool zero_size;
550592 int error;
551593
552594 if (!xfs_sb_version_hasrmapbt(&sc->mp->m_sb) ||
....@@ -558,6 +600,8 @@
558600 if (XFS_IS_REALTIME_INODE(sc->ip) && whichfork == XFS_DATA_FORK)
559601 return 0;
560602
603
+ ASSERT(XFS_IFORK_PTR(sc->ip, whichfork) != NULL);
604
+
561605 /*
562606 * Only do this for complex maps that are in btree format, or for
563607 * situations where we would seem to have a size but zero extents.
....@@ -565,19 +609,14 @@
565609 * to flag this bmap as corrupt if there are rmaps that need to be
566610 * reattached.
567611 */
568
- switch (whichfork) {
569
- case XFS_DATA_FORK:
570
- size = i_size_read(VFS_I(sc->ip));
571
- break;
572
- case XFS_ATTR_FORK:
573
- size = XFS_IFORK_Q(sc->ip);
574
- break;
575
- default:
576
- size = 0;
577
- break;
578
- }
579
- if (XFS_IFORK_FORMAT(sc->ip, whichfork) != XFS_DINODE_FMT_BTREE &&
580
- (size == 0 || XFS_IFORK_NEXTENTS(sc->ip, whichfork) > 0))
612
+
613
+ if (whichfork == XFS_DATA_FORK)
614
+ zero_size = i_size_read(VFS_I(sc->ip)) == 0;
615
+ else
616
+ zero_size = false;
617
+
618
+ if (ifp->if_format != XFS_DINODE_FMT_BTREE &&
619
+ (zero_size || ifp->if_nextents > 0))
581620 return 0;
582621
583622 for (agno = 0; agno < sc->mp->m_sb.sb_agcount; agno++) {
....@@ -606,12 +645,14 @@
606645 struct xchk_bmap_info info = { NULL };
607646 struct xfs_mount *mp = sc->mp;
608647 struct xfs_inode *ip = sc->ip;
609
- struct xfs_ifork *ifp;
648
+ struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
610649 xfs_fileoff_t endoff;
611650 struct xfs_iext_cursor icur;
612651 int error = 0;
613652
614
- ifp = XFS_IFORK_PTR(ip, whichfork);
653
+ /* Non-existent forks can be ignored. */
654
+ if (!ifp)
655
+ goto out;
615656
616657 info.is_rt = whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip);
617658 info.whichfork = whichfork;
....@@ -620,9 +661,6 @@
620661
621662 switch (whichfork) {
622663 case XFS_COW_FORK:
623
- /* Non-existent CoW forks are ignorable. */
624
- if (!ifp)
625
- goto out;
626664 /* No CoW forks on non-reflink inodes/filesystems. */
627665 if (!xfs_is_reflink_inode(ip)) {
628666 xchk_ino_set_corrupt(sc, sc->ip->i_ino);
....@@ -630,8 +668,6 @@
630668 }
631669 break;
632670 case XFS_ATTR_FORK:
633
- if (!ifp)
634
- goto out_check_rmap;
635671 if (!xfs_sb_version_hasattr(&mp->m_sb) &&
636672 !xfs_sb_version_hasattr2(&mp->m_sb))
637673 xchk_ino_set_corrupt(sc, sc->ip->i_ino);
....@@ -642,7 +678,7 @@
642678 }
643679
644680 /* Check the fork values */
645
- switch (XFS_IFORK_FORMAT(ip, whichfork)) {
681
+ switch (ifp->if_format) {
646682 case XFS_DINODE_FMT_UUID:
647683 case XFS_DINODE_FMT_DEV:
648684 case XFS_DINODE_FMT_LOCAL:
....@@ -672,13 +708,6 @@
672708 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
673709 goto out;
674710
675
- /* Now try to scrub the in-memory extent list. */
676
- if (!(ifp->if_flags & XFS_IFEXTENTS)) {
677
- error = xfs_iread_extents(sc->tp, ip, whichfork);
678
- if (!xchk_fblock_process_error(sc, whichfork, 0, &error))
679
- goto out;
680
- }
681
-
682711 /* Find the offset of the last extent in the mapping. */
683712 error = xfs_bmap_last_offset(ip, &endoff, whichfork);
684713 if (!xchk_fblock_process_error(sc, whichfork, 0, &error))
....@@ -690,7 +719,7 @@
690719 for_each_xfs_iext(ifp, &icur, &irec) {
691720 if (xchk_should_terminate(sc, &error) ||
692721 (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
693
- break;
722
+ goto out;
694723 if (isnullstartblock(irec.br_startblock))
695724 continue;
696725 if (irec.br_startoff >= endoff) {
....@@ -698,12 +727,11 @@
698727 irec.br_startoff);
699728 goto out;
700729 }
701
- error = xchk_bmap_extent(ip, NULL, &info, &irec);
730
+ error = xchk_bmap_iextent(ip, &info, &irec);
702731 if (error)
703732 goto out;
704733 }
705734
706
-out_check_rmap:
707735 error = xchk_bmap_check_rmaps(sc, whichfork);
708736 if (!xchk_fblock_xref_process_error(sc, whichfork, 0, &error))
709737 goto out;