LCOV - code coverage report
Current view: top level - fs/xfs/scrub - rcbag.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsx @ Mon Jul 31 20:08:34 PDT 2023 Lines: 107 177 60.5 %
Date: 2023-07-31 20:08:34 Functions: 6 7 85.7 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2022-2023 Oracle.  All Rights Reserved.
       4             :  * Author: Darrick J. Wong <djwong@kernel.org>
       5             :  */
       6             : #include "xfs.h"
       7             : #include "xfs_fs.h"
       8             : #include "xfs_shared.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_log_format.h"
      11             : #include "xfs_trans.h"
      12             : #include "xfs_trans_resv.h"
      13             : #include "xfs_mount.h"
      14             : #include "xfs_defer.h"
      15             : #include "xfs_btree.h"
      16             : #include "xfs_btree_mem.h"
      17             : #include "xfs_error.h"
      18             : #include "scrub/scrub.h"
      19             : #include "scrub/xfile.h"
      20             : #include "scrub/xfbtree.h"
      21             : #include "scrub/rcbag_btree.h"
      22             : #include "scrub/rcbag.h"
      23             : #include "scrub/trace.h"
      24             : 
      25             : struct rcbag {
      26             :         struct xfs_mount        *mp;
      27             :         struct xfbtree          *xfbtree;
      28             :         uint64_t                nr_items;
      29             : };
      30             : 
      31             : int
      32      120457 : rcbag_init(
      33             :         struct xfs_mount        *mp,
      34             :         struct xfs_buftarg      *target,
      35             :         struct rcbag            **bagp)
      36             : {
      37      120457 :         struct rcbag            *bag;
      38      120457 :         int                     error;
      39             : 
      40      120457 :         bag = kmalloc(sizeof(struct rcbag), XCHK_GFP_FLAGS);
      41      120446 :         if (!bag)
      42             :                 return -ENOMEM;
      43             : 
      44      120446 :         bag->nr_items = 0;
      45      120446 :         bag->mp = mp;
      46             : 
      47      120446 :         error = rcbagbt_mem_create(mp, target, &bag->xfbtree);
      48      120325 :         if (error)
      49           0 :                 goto out_bag;
      50             : 
      51      120325 :         *bagp = bag;
      52      120325 :         return 0;
      53             : 
      54             : out_bag:
      55           0 :         kfree(bag);
      56           0 :         return error;
      57             : }
      58             : 
      59             : void
      60      120103 : rcbag_free(
      61             :         struct rcbag            **bagp)
      62             : {
      63      120103 :         struct rcbag            *bag = *bagp;
      64             : 
      65      120103 :         xfbtree_destroy(bag->xfbtree);
      66      120361 :         kfree(bag);
      67      120275 :         *bagp = NULL;
      68      120275 : }
      69             : 
      70             : /* Track an rmap in the refcount bag. */
      71             : int
      72   352817417 : rcbag_add(
      73             :         struct rcbag                    *bag,
      74             :         struct xfs_trans                *tp,
      75             :         const struct xfs_rmap_irec      *rmap)
      76             : {
      77   352817417 :         struct rcbag_rec                bagrec;
      78   352817417 :         struct xfs_mount                *mp = bag->mp;
      79   352817417 :         struct xfs_buf                  *head_bp;
      80   352817417 :         struct xfs_btree_cur            *cur;
      81   352817417 :         int                             has;
      82   352817417 :         int                             error;
      83             : 
      84   352817417 :         error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
      85   352814759 :         if (error)
      86             :                 return error;
      87             : 
      88   352815169 :         cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
      89   352820544 :         error = rcbagbt_lookup_eq(cur, rmap, &has);
      90   352816939 :         if (error)
      91           0 :                 goto out_cur;
      92             : 
      93   352816939 :         if (has) {
      94    67704813 :                 error = rcbagbt_get_rec(cur, &bagrec, &has);
      95    67703737 :                 if (error)
      96           0 :                         goto out_cur;
      97    67703737 :                 if (!has) {
      98           0 :                         error = -EFSCORRUPTED;
      99           0 :                         goto out_cur;
     100             :                 }
     101             : 
     102    67703737 :                 bagrec.rbg_refcount++;
     103    67703737 :                 error = rcbagbt_update(cur, &bagrec);
     104    67704445 :                 if (error)
     105           0 :                         goto out_cur;
     106             :         } else {
     107   285112126 :                 bagrec.rbg_startblock = rmap->rm_startblock;
     108   285112126 :                 bagrec.rbg_blockcount = rmap->rm_blockcount;
     109   285112126 :                 bagrec.rbg_refcount = 1;
     110             : 
     111   285112126 :                 error = rcbagbt_insert(cur, &bagrec, &has);
     112   285107336 :                 if (error)
     113           0 :                         goto out_cur;
     114   285107336 :                 if (!has) {
     115           0 :                         error = -EFSCORRUPTED;
     116           0 :                         goto out_cur;
     117             :                 }
     118             :         }
     119             : 
     120   352811781 :         xfs_btree_del_cursor(cur, 0);
     121   352812939 :         xfs_trans_brelse(tp, head_bp);
     122             : 
     123   352817098 :         error = xfbtree_trans_commit(bag->xfbtree, tp);
     124   352815338 :         if (error)
     125             :                 return error;
     126             : 
     127   352815338 :         bag->nr_items++;
     128   352815338 :         return 0;
     129             : 
     130           0 : out_cur:
     131           0 :         xfs_btree_del_cursor(cur, error);
     132           0 :         xfs_trans_brelse(tp, head_bp);
     133           0 :         xfbtree_trans_cancel(bag->xfbtree, tp);
     134           0 :         return error;
     135             : }
     136             : 
     137             : uint64_t
     138  1133846718 : rcbag_count(
     139             :         const struct rcbag      *rcbag)
     140             : {
     141  1133846718 :         return rcbag->nr_items;
     142             : }
     143             : 
     144             : #define BAGREC_NEXT(r)  ((r)->rbg_startblock + (r)->rbg_blockcount)
     145             : 
     146             : /*
     147             :  * Find the next block where the refcount changes, given the next rmap we
     148             :  * looked at and the ones we're already tracking.
     149             :  */
     150             : int
     151   283432207 : rcbag_next_edge(
     152             :         struct rcbag                    *bag,
     153             :         struct xfs_trans                *tp,
     154             :         const struct xfs_rmap_irec      *next_rmap,
     155             :         bool                            next_valid,
     156             :         uint32_t                        *next_bnop)
     157             : {
     158   283432207 :         struct rcbag_rec                bagrec;
     159   283432207 :         struct xfs_mount                *mp = bag->mp;
     160   283432207 :         struct xfs_buf                  *head_bp;
     161   283432207 :         struct xfs_btree_cur            *cur;
     162   283432207 :         uint32_t                        next_bno = NULLAGBLOCK;
     163   283432207 :         int                             has;
     164   283432207 :         int                             error;
     165             : 
     166   283432207 :         if (next_valid)
     167   283339461 :                 next_bno = next_rmap->rm_startblock;
     168             : 
     169   283432207 :         error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
     170   283431857 :         if (error)
     171             :                 return error;
     172             : 
     173   283432214 :         cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
     174   283438330 :         error = xfs_btree_goto_left_edge(cur);
     175   283430817 :         if (error)
     176           0 :                 goto out_cur;
     177             : 
     178   909926433 :         while (true) {
     179   596678625 :                 error = xfs_btree_increment(cur, 0, &has);
     180   596673450 :                 if (error)
     181           0 :                         goto out_cur;
     182   596673450 :                 if (!has)
     183             :                         break;
     184             : 
     185   313249697 :                 error = rcbagbt_get_rec(cur, &bagrec, &has);
     186   313247808 :                 if (error)
     187           0 :                         goto out_cur;
     188   313247808 :                 if (!has) {
     189           0 :                         error = -EFSCORRUPTED;
     190           0 :                         goto out_cur;
     191             :                 }
     192             : 
     193   313247808 :                 next_bno = min(next_bno, BAGREC_NEXT(&bagrec));
     194             :         }
     195             : 
     196             :         /*
     197             :          * We should have found /something/ because either next_rrm is the next
     198             :          * interesting rmap to look at after emitting this refcount extent, or
     199             :          * there are other rmaps in rmap_bag contributing to the current
     200             :          * sharing count.  But if something is seriously wrong, bail out.
     201             :          */
     202   283423753 :         if (next_bno == NULLAGBLOCK) {
     203           0 :                 error = -EFSCORRUPTED;
     204           0 :                 goto out_cur;
     205             :         }
     206             : 
     207   283423753 :         xfs_btree_del_cursor(cur, 0);
     208   283433449 :         xfs_trans_brelse(tp, head_bp);
     209             : 
     210   283435977 :         *next_bnop = next_bno;
     211   283435977 :         return 0;
     212             : 
     213           0 : out_cur:
     214           0 :         xfs_btree_del_cursor(cur, error);
     215           0 :         xfs_trans_brelse(tp, head_bp);
     216           0 :         return error;
     217             : }
     218             : 
     219             : /* Pop all refcount bag records that end at next_bno */
     220             : int
     221   283435630 : rcbag_remove_ending_at(
     222             :         struct rcbag            *bag,
     223             :         struct xfs_trans        *tp,
     224             :         uint32_t                next_bno)
     225             : {
     226   283435630 :         struct rcbag_rec        bagrec;
     227   283435630 :         struct xfs_mount        *mp = bag->mp;
     228   283435630 :         struct xfs_buf          *head_bp;
     229   283435630 :         struct xfs_btree_cur    *cur;
     230   283435630 :         int                     has;
     231   283435630 :         int                     error;
     232             : 
     233   283435630 :         error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
     234   283431540 :         if (error)
     235             :                 return error;
     236             : 
     237             :         /* go to the right edge of the tree */
     238   283431794 :         cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
     239   283438219 :         memset(&cur->bc_rec, 0xFF, sizeof(cur->bc_rec));
     240   283438219 :         error = xfs_btree_lookup(cur, XFS_LOOKUP_GE, &has);
     241   283427686 :         if (error)
     242           0 :                 goto out_cur;
     243             : 
     244   596682092 :         while (true) {
     245   596682092 :                 error = xfs_btree_decrement(cur, 0, &has);
     246   596682948 :                 if (error)
     247           0 :                         goto out_cur;
     248   596682948 :                 if (!has)
     249             :                         break;
     250             : 
     251   313251676 :                 error = rcbagbt_get_rec(cur, &bagrec, &has);
     252   313251547 :                 if (error)
     253           0 :                         goto out_cur;
     254   313251547 :                 if (!has) {
     255           0 :                         error = -EFSCORRUPTED;
     256           0 :                         goto out_cur;
     257             :                 }
     258             : 
     259   313251547 :                 if (BAGREC_NEXT(&bagrec) != next_bno)
     260    28143707 :                         continue;
     261             : 
     262   285107840 :                 error = xfs_btree_delete(cur, &has);
     263   285110699 :                 if (error)
     264           0 :                         goto out_cur;
     265   285110699 :                 if (!has) {
     266           0 :                         error = -EFSCORRUPTED;
     267           0 :                         goto out_cur;
     268             :                 }
     269             : 
     270   285110699 :                 bag->nr_items -= bagrec.rbg_refcount;
     271             :         }
     272             : 
     273   283431272 :         xfs_btree_del_cursor(cur, 0);
     274   283432417 :         xfs_trans_brelse(tp, head_bp);
     275   283435585 :         return xfbtree_trans_commit(bag->xfbtree, tp);
     276           0 : out_cur:
     277           0 :         xfs_btree_del_cursor(cur, error);
     278           0 :         xfs_trans_brelse(tp, head_bp);
     279           0 :         xfbtree_trans_cancel(bag->xfbtree, tp);
     280           0 :         return error;
     281             : }
     282             : 
     283             : /* Dump the rcbag. */
     284             : void
     285           0 : rcbag_dump(
     286             :         struct rcbag                    *bag,
     287             :         struct xfs_trans                *tp)
     288             : {
     289           0 :         struct rcbag_rec                bagrec;
     290           0 :         struct xfs_mount                *mp = bag->mp;
     291           0 :         struct xfs_buf                  *head_bp;
     292           0 :         struct xfs_btree_cur            *cur;
     293           0 :         unsigned long long              nr = 0;
     294           0 :         int                             has;
     295           0 :         int                             error;
     296             : 
     297           0 :         error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
     298           0 :         if (error)
     299           0 :                 return;
     300             : 
     301           0 :         cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
     302           0 :         error = xfs_btree_goto_left_edge(cur);
     303           0 :         if (error)
     304           0 :                 goto out_cur;
     305             : 
     306           0 :         while (true) {
     307           0 :                 error = xfs_btree_increment(cur, 0, &has);
     308           0 :                 if (error)
     309           0 :                         goto out_cur;
     310           0 :                 if (!has)
     311             :                         break;
     312             : 
     313           0 :                 error = rcbagbt_get_rec(cur, &bagrec, &has);
     314           0 :                 if (error)
     315           0 :                         goto out_cur;
     316           0 :                 if (!has) {
     317           0 :                         error = -EFSCORRUPTED;
     318           0 :                         goto out_cur;
     319             :                 }
     320             : 
     321           0 :                 xfs_err(bag->mp, "[%llu]: bno 0x%x fsbcount 0x%x refcount 0x%llx\n",
     322             :                                 nr++,
     323             :                                 (unsigned int)bagrec.rbg_startblock,
     324             :                                 (unsigned int)bagrec.rbg_blockcount,
     325             :                                 (unsigned long long)bagrec.rbg_refcount);
     326             :         }
     327             : 
     328           0 : out_cur:
     329           0 :         xfs_btree_del_cursor(cur, error);
     330           0 :         xfs_trans_brelse(tp, head_bp);
     331             : }

Generated by: LCOV version 1.14