LCOV - code coverage report
Current view: top level - fs/xfs/scrub - rcbag.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-acha @ Mon Jul 31 20:08:06 PDT 2023 Lines: 107 177 60.5 %
Date: 2023-07-31 20:08:07 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       16691 : rcbag_init(
      33             :         struct xfs_mount        *mp,
      34             :         struct xfs_buftarg      *target,
      35             :         struct rcbag            **bagp)
      36             : {
      37       16691 :         struct rcbag            *bag;
      38       16691 :         int                     error;
      39             : 
      40       16691 :         bag = kmalloc(sizeof(struct rcbag), XCHK_GFP_FLAGS);
      41       16691 :         if (!bag)
      42             :                 return -ENOMEM;
      43             : 
      44       16691 :         bag->nr_items = 0;
      45       16691 :         bag->mp = mp;
      46             : 
      47       16691 :         error = rcbagbt_mem_create(mp, target, &bag->xfbtree);
      48       16691 :         if (error)
      49           0 :                 goto out_bag;
      50             : 
      51       16691 :         *bagp = bag;
      52       16691 :         return 0;
      53             : 
      54             : out_bag:
      55           0 :         kfree(bag);
      56           0 :         return error;
      57             : }
      58             : 
      59             : void
      60       16689 : rcbag_free(
      61             :         struct rcbag            **bagp)
      62             : {
      63       16689 :         struct rcbag            *bag = *bagp;
      64             : 
      65       16689 :         xfbtree_destroy(bag->xfbtree);
      66       16691 :         kfree(bag);
      67       16691 :         *bagp = NULL;
      68       16691 : }
      69             : 
      70             : /* Track an rmap in the refcount bag. */
      71             : int
      72   169211266 : rcbag_add(
      73             :         struct rcbag                    *bag,
      74             :         struct xfs_trans                *tp,
      75             :         const struct xfs_rmap_irec      *rmap)
      76             : {
      77   169211266 :         struct rcbag_rec                bagrec;
      78   169211266 :         struct xfs_mount                *mp = bag->mp;
      79   169211266 :         struct xfs_buf                  *head_bp;
      80   169211266 :         struct xfs_btree_cur            *cur;
      81   169211266 :         int                             has;
      82   169211266 :         int                             error;
      83             : 
      84   169211266 :         error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
      85   169211267 :         if (error)
      86             :                 return error;
      87             : 
      88   169211267 :         cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
      89   169211267 :         error = rcbagbt_lookup_eq(cur, rmap, &has);
      90   169211267 :         if (error)
      91           0 :                 goto out_cur;
      92             : 
      93   169211267 :         if (has) {
      94     5009736 :                 error = rcbagbt_get_rec(cur, &bagrec, &has);
      95     5009736 :                 if (error)
      96           0 :                         goto out_cur;
      97     5009736 :                 if (!has) {
      98           0 :                         error = -EFSCORRUPTED;
      99           0 :                         goto out_cur;
     100             :                 }
     101             : 
     102     5009736 :                 bagrec.rbg_refcount++;
     103     5009736 :                 error = rcbagbt_update(cur, &bagrec);
     104     5009736 :                 if (error)
     105           0 :                         goto out_cur;
     106             :         } else {
     107   164201531 :                 bagrec.rbg_startblock = rmap->rm_startblock;
     108   164201531 :                 bagrec.rbg_blockcount = rmap->rm_blockcount;
     109   164201531 :                 bagrec.rbg_refcount = 1;
     110             : 
     111   164201531 :                 error = rcbagbt_insert(cur, &bagrec, &has);
     112   164201531 :                 if (error)
     113           0 :                         goto out_cur;
     114   164201531 :                 if (!has) {
     115           0 :                         error = -EFSCORRUPTED;
     116           0 :                         goto out_cur;
     117             :                 }
     118             :         }
     119             : 
     120   169211267 :         xfs_btree_del_cursor(cur, 0);
     121   169211267 :         xfs_trans_brelse(tp, head_bp);
     122             : 
     123   169211267 :         error = xfbtree_trans_commit(bag->xfbtree, tp);
     124   169211267 :         if (error)
     125             :                 return error;
     126             : 
     127   169211267 :         bag->nr_items++;
     128   169211267 :         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   657575337 : rcbag_count(
     139             :         const struct rcbag      *rcbag)
     140             : {
     141   657575337 :         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   164389697 : 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   164389697 :         struct rcbag_rec                bagrec;
     159   164389697 :         struct xfs_mount                *mp = bag->mp;
     160   164389697 :         struct xfs_buf                  *head_bp;
     161   164389697 :         struct xfs_btree_cur            *cur;
     162   164389697 :         uint32_t                        next_bno = NULLAGBLOCK;
     163   164389697 :         int                             has;
     164   164389697 :         int                             error;
     165             : 
     166   164389697 :         if (next_valid)
     167   164375293 :                 next_bno = next_rmap->rm_startblock;
     168             : 
     169   164389697 :         error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
     170   164389698 :         if (error)
     171             :                 return error;
     172             : 
     173   164389698 :         cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
     174   164389698 :         error = xfs_btree_goto_left_edge(cur);
     175   164389698 :         if (error)
     176           0 :                 goto out_cur;
     177             : 
     178   495769932 :         while (true) {
     179   330079815 :                 error = xfs_btree_increment(cur, 0, &has);
     180   330079815 :                 if (error)
     181           0 :                         goto out_cur;
     182   330079815 :                 if (!has)
     183             :                         break;
     184             : 
     185   165690117 :                 error = rcbagbt_get_rec(cur, &bagrec, &has);
     186   165690117 :                 if (error)
     187           0 :                         goto out_cur;
     188   165690117 :                 if (!has) {
     189           0 :                         error = -EFSCORRUPTED;
     190           0 :                         goto out_cur;
     191             :                 }
     192             : 
     193   165690117 :                 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   164389698 :         if (next_bno == NULLAGBLOCK) {
     203           0 :                 error = -EFSCORRUPTED;
     204           0 :                 goto out_cur;
     205             :         }
     206             : 
     207   164389698 :         xfs_btree_del_cursor(cur, 0);
     208   164389698 :         xfs_trans_brelse(tp, head_bp);
     209             : 
     210   164389698 :         *next_bnop = next_bno;
     211   164389698 :         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   164389698 : rcbag_remove_ending_at(
     222             :         struct rcbag            *bag,
     223             :         struct xfs_trans        *tp,
     224             :         uint32_t                next_bno)
     225             : {
     226   164389698 :         struct rcbag_rec        bagrec;
     227   164389698 :         struct xfs_mount        *mp = bag->mp;
     228   164389698 :         struct xfs_buf          *head_bp;
     229   164389698 :         struct xfs_btree_cur    *cur;
     230   164389698 :         int                     has;
     231   164389698 :         int                     error;
     232             : 
     233   164389698 :         error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
     234   164389698 :         if (error)
     235             :                 return error;
     236             : 
     237             :         /* go to the right edge of the tree */
     238   164389698 :         cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
     239   164389698 :         memset(&cur->bc_rec, 0xFF, sizeof(cur->bc_rec));
     240   164389698 :         error = xfs_btree_lookup(cur, XFS_LOOKUP_GE, &has);
     241   164389698 :         if (error)
     242           0 :                 goto out_cur;
     243             : 
     244   330079815 :         while (true) {
     245   330079815 :                 error = xfs_btree_decrement(cur, 0, &has);
     246   330079815 :                 if (error)
     247           0 :                         goto out_cur;
     248   330079815 :                 if (!has)
     249             :                         break;
     250             : 
     251   165690117 :                 error = rcbagbt_get_rec(cur, &bagrec, &has);
     252   165690116 :                 if (error)
     253           0 :                         goto out_cur;
     254   165690116 :                 if (!has) {
     255           0 :                         error = -EFSCORRUPTED;
     256           0 :                         goto out_cur;
     257             :                 }
     258             : 
     259   165690116 :                 if (BAGREC_NEXT(&bagrec) != next_bno)
     260     1488587 :                         continue;
     261             : 
     262   164201529 :                 error = xfs_btree_delete(cur, &has);
     263   164201530 :                 if (error)
     264           0 :                         goto out_cur;
     265   164201530 :                 if (!has) {
     266           0 :                         error = -EFSCORRUPTED;
     267           0 :                         goto out_cur;
     268             :                 }
     269             : 
     270   164201530 :                 bag->nr_items -= bagrec.rbg_refcount;
     271             :         }
     272             : 
     273   164389698 :         xfs_btree_del_cursor(cur, 0);
     274   164389698 :         xfs_trans_brelse(tp, head_bp);
     275   164389698 :         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