LCOV - code coverage report
Current view: top level - fs/xfs - xfs_fsrefs.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsx @ Mon Jul 31 20:08:34 PDT 2023 Lines: 390 400 97.5 %
Date: 2023-07-31 20:08:34 Functions: 16 16 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (C) 2021-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_resv.h"
      12             : #include "xfs_mount.h"
      13             : #include "xfs_inode.h"
      14             : #include "xfs_trans.h"
      15             : #include "xfs_btree.h"
      16             : #include "xfs_trace.h"
      17             : #include "xfs_alloc.h"
      18             : #include "xfs_bit.h"
      19             : #include "xfs_fsrefs.h"
      20             : #include "xfs_refcount.h"
      21             : #include "xfs_refcount_btree.h"
      22             : #include "xfs_alloc_btree.h"
      23             : #include "xfs_rtalloc.h"
      24             : #include "xfs_rtrefcount_btree.h"
      25             : #include "xfs_ag.h"
      26             : #include "xfs_rtbitmap.h"
      27             : #include "xfs_rtgroup.h"
      28             : 
      29             : /* getfsrefs query state */
      30             : struct xfs_fsrefs_info {
      31             :         struct xfs_fsrefs_head  *head;
      32             :         struct xfs_getfsrefs    *fsrefs_recs;   /* mapping records */
      33             : 
      34             :         struct xfs_btree_cur    *refc_cur;      /* refcount btree cursor */
      35             :         struct xfs_btree_cur    *bno_cur;       /* bnobt btree cursor */
      36             : 
      37             :         struct xfs_buf          *agf_bp;        /* AGF, for refcount queries */
      38             :         struct xfs_perag        *pag;           /* perag structure */
      39             :         struct xfs_rtgroup      *rtg;
      40             : 
      41             :         xfs_daddr_t             next_daddr;     /* next daddr we expect */
      42             :         /* daddr of low fsmap key when we're using the rtbitmap */
      43             :         xfs_daddr_t             low_daddr;
      44             : 
      45             :         /*
      46             :          * Low refcount key for the query.  If low.rc_blockcount is nonzero,
      47             :          * this is the second (or later) call to retrieve the recordset in
      48             :          * pieces.  xfs_getfsrefs_rec_before_start will compare all records
      49             :          * retrieved by the refcountbt query to filter out any records that
      50             :          * start before the last record.
      51             :          */
      52             :         struct xfs_refcount_irec low;
      53             :         struct xfs_refcount_irec high;          /* high refcount key */
      54             : 
      55             :         u32                     dev;            /* device id */
      56             :         bool                    last;           /* last extent? */
      57             : };
      58             : 
      59             : /* Associate a device with a getfsrefs handler. */
      60             : struct xfs_fsrefs_dev {
      61             :         u32                     dev;
      62             :         int                     (*fn)(struct xfs_trans *tp,
      63             :                                       const struct xfs_fsrefs *keys,
      64             :                                       struct xfs_fsrefs_info *info);
      65             : };
      66             : 
      67             : /* Convert an xfs_fsrefs to an fsrefs. */
      68             : static void
      69             : xfs_fsrefs_from_internal(
      70             :         struct xfs_getfsrefs    *dest,
      71             :         struct xfs_fsrefs       *src)
      72             : {
      73       36143 :         dest->fcr_device = src->fcr_device;
      74       36143 :         dest->fcr_flags = src->fcr_flags;
      75       36143 :         dest->fcr_physical = BBTOB(src->fcr_physical);
      76       36143 :         dest->fcr_owners = src->fcr_owners;
      77       36143 :         dest->fcr_length = BBTOB(src->fcr_length);
      78       36143 :         dest->fcr_reserved[0] = 0;
      79       36143 :         dest->fcr_reserved[1] = 0;
      80       36143 :         dest->fcr_reserved[2] = 0;
      81       36143 :         dest->fcr_reserved[3] = 0;
      82             : }
      83             : 
      84             : /* Convert an fsrefs to an xfs_fsrefs. */
      85             : void
      86       24837 : xfs_fsrefs_to_internal(
      87             :         struct xfs_fsrefs       *dest,
      88             :         struct xfs_getfsrefs    *src)
      89             : {
      90       24837 :         dest->fcr_device = src->fcr_device;
      91       24837 :         dest->fcr_flags = src->fcr_flags;
      92       24837 :         dest->fcr_physical = BTOBBT(src->fcr_physical);
      93       24837 :         dest->fcr_owners = src->fcr_owners;
      94       24837 :         dest->fcr_length = BTOBBT(src->fcr_length);
      95       24837 : }
      96             : 
      97             : /* Compare two getfsrefs device handlers. */
      98             : static int
      99       24837 : xfs_fsrefs_dev_compare(
     100             :         const void                      *p1,
     101             :         const void                      *p2)
     102             : {
     103       24837 :         const struct xfs_fsrefs_dev     *d1 = p1;
     104       24837 :         const struct xfs_fsrefs_dev     *d2 = p2;
     105             : 
     106       24837 :         return d1->dev - d2->dev;
     107             : }
     108             : 
     109             : static inline bool
     110             : xfs_fsrefs_rec_before_start(
     111             :         struct xfs_fsrefs_info          *info,
     112             :         const struct xfs_refcount_irec  *rec,
     113             :         xfs_daddr_t                     rec_daddr)
     114             : {
     115       51130 :         if (info->low_daddr != -1ULL)
     116        4045 :                 return rec_daddr < info->low_daddr;
     117       47085 :         if (info->low.rc_blockcount)
     118       22669 :                 return rec->rc_startblock < info->low.rc_startblock;
     119             :         return false;
     120             : }
     121             : 
     122             : /*
     123             :  * Format a refcount record for fsrefs, having translated rc_startblock into
     124             :  * the appropriate daddr units.
     125             :  */
     126             : STATIC int
     127       51130 : xfs_fsrefs_helper(
     128             :         struct xfs_trans                *tp,
     129             :         struct xfs_fsrefs_info          *info,
     130             :         const struct xfs_refcount_irec  *rec,
     131             :         xfs_daddr_t                     rec_daddr,
     132             :         xfs_daddr_t                     len_daddr)
     133             : {
     134       51130 :         struct xfs_fsrefs               fcr;
     135       51130 :         struct xfs_getfsrefs            *row;
     136       51130 :         struct xfs_mount                *mp = tp->t_mountp;
     137             : 
     138       51130 :         if (fatal_signal_pending(current))
     139             :                 return -EINTR;
     140             : 
     141       51130 :         if (len_daddr == 0)
     142       38090 :                 len_daddr = XFS_FSB_TO_BB(mp, rec->rc_blockcount);
     143             : 
     144             :         /*
     145             :          * Filter out records that start before our startpoint, if the
     146             :          * caller requested that.
     147             :          */
     148       77844 :         if (xfs_fsrefs_rec_before_start(info, rec, rec_daddr))
     149             :                 return 0;
     150             : 
     151             :         /* Are we just counting mappings? */
     152       51130 :         if (info->head->fch_count == 0) {
     153           0 :                 if (info->head->fch_entries == UINT_MAX)
     154             :                         return -ECANCELED;
     155             : 
     156           0 :                 info->head->fch_entries++;
     157           0 :                 return 0;
     158             :         }
     159             : 
     160             :         /* Fill out the extent we found */
     161       51130 :         if (info->head->fch_entries >= info->head->fch_count)
     162             :                 return -ECANCELED;
     163             : 
     164       36143 :         if (info->pag)
     165       23888 :                 trace_xfs_fsrefs_mapping(mp, info->dev, info->pag->pag_agno,
     166             :                                 rec);
     167       12255 :         else if (info->rtg)
     168        6152 :                 trace_xfs_fsrefs_mapping(mp, info->dev, info->rtg->rtg_rgno,
     169             :                                 rec);
     170             :         else
     171        6103 :                 trace_xfs_fsrefs_mapping(mp, info->dev, NULLAGNUMBER, rec);
     172             : 
     173       36143 :         fcr.fcr_device = info->dev;
     174       36143 :         fcr.fcr_flags = 0;
     175       36143 :         fcr.fcr_physical = rec_daddr;
     176       36143 :         fcr.fcr_owners = rec->rc_refcount;
     177       36143 :         fcr.fcr_length = len_daddr;
     178             : 
     179       36143 :         trace_xfs_getfsrefs_mapping(mp, &fcr);
     180             : 
     181       36143 :         row = &info->fsrefs_recs[info->head->fch_entries++];
     182       36143 :         xfs_fsrefs_from_internal(row, &fcr);
     183       36143 :         return 0;
     184             : }
     185             : 
     186             : /* Synthesize fsrefs records from free space data. */
     187             : STATIC int
     188       42643 : xfs_fsrefs_ddev_bnobt_helper(
     189             :         struct xfs_btree_cur            *cur,
     190             :         const struct xfs_alloc_rec_incore *rec,
     191             :         void                            *priv)
     192             : {
     193       42643 :         struct xfs_refcount_irec        irec;
     194       42643 :         struct xfs_mount                *mp = cur->bc_mp;
     195       42643 :         struct xfs_fsrefs_info          *info = priv;
     196       42643 :         xfs_agnumber_t                  next_agno;
     197       42643 :         xfs_agblock_t                   next_agbno;
     198       42643 :         xfs_daddr_t                     rec_daddr;
     199             : 
     200             :         /*
     201             :          * Figure out if there's a gap between the last fsrefs record we
     202             :          * emitted and this free extent.  If there is, report the gap as a
     203             :          * refcount==1 record.
     204             :          */
     205       42643 :         next_agno = xfs_daddr_to_agno(mp, info->next_daddr);
     206       42643 :         next_agbno = xfs_daddr_to_agbno(mp, info->next_daddr);
     207             : 
     208       42643 :         ASSERT(next_agno >= cur->bc_ag.pag->pag_agno);
     209       42643 :         ASSERT(rec->ar_startblock >= next_agbno);
     210             : 
     211             :         /*
     212             :          * If we've already moved on to the next AG, we don't have any fsrefs
     213             :          * records to synthesize.
     214             :          */
     215       42643 :         if (next_agno > cur->bc_ag.pag->pag_agno)
     216             :                 return 0;
     217             : 
     218       42424 :         info->next_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
     219             :                         rec->ar_startblock + rec->ar_blockcount);
     220             : 
     221       42424 :         if (rec->ar_startblock == next_agbno)
     222             :                 return 0;
     223             : 
     224             :         /* Emit a record for the in-use space */
     225       35528 :         irec.rc_startblock = next_agbno;
     226       35528 :         irec.rc_blockcount = rec->ar_startblock - next_agbno;
     227       35528 :         irec.rc_refcount = 1;
     228       35528 :         irec.rc_domain = XFS_REFC_DOMAIN_SHARED;
     229       35528 :         rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
     230             :                         irec.rc_startblock);
     231             : 
     232       35528 :         return xfs_fsrefs_helper(cur->bc_tp, info, &irec, rec_daddr, 0);
     233             : }
     234             : 
     235             : /* Emit records to fill a gap in the refcount btree with singly-owned blocks. */
     236             : STATIC int
     237       14797 : xfs_fsrefs_ddev_fill_refcount_gap(
     238             :         struct xfs_trans                *tp,
     239             :         struct xfs_fsrefs_info          *info,
     240             :         xfs_agblock_t                   agbno)
     241             : {
     242       14797 :         struct xfs_alloc_rec_incore     low = {0};
     243       14797 :         struct xfs_alloc_rec_incore     high = {0};
     244       14797 :         struct xfs_mount                *mp = tp->t_mountp;
     245       14797 :         struct xfs_btree_cur            *cur = info->bno_cur;
     246       14797 :         struct xfs_agf                  *agf;
     247       14797 :         int                             error;
     248             : 
     249       14797 :         ASSERT(xfs_daddr_to_agno(mp, info->next_daddr) ==
     250             :                         cur->bc_ag.pag->pag_agno);
     251             : 
     252       14797 :         low.ar_startblock = xfs_daddr_to_agbno(mp, info->next_daddr);
     253       14797 :         if (low.ar_startblock >= agbno)
     254             :                 return 0;
     255             : 
     256       13891 :         high.ar_startblock = agbno;
     257       13891 :         error = xfs_alloc_query_range(cur, &low, &high,
     258             :                         xfs_fsrefs_ddev_bnobt_helper, info);
     259       13891 :         if (error)
     260             :                 return error;
     261             : 
     262             :         /*
     263             :          * Synthesize records for single-owner extents between the last
     264             :          * fsrefcount record emitted and the end of the query range.
     265             :          */
     266        1395 :         agf = cur->bc_ag.agbp->b_addr;
     267        1395 :         low.ar_startblock = min_t(xfs_agblock_t, agbno,
     268             :                                   be32_to_cpu(agf->agf_length));
     269        1395 :         if (xfs_daddr_to_agbno(mp, info->next_daddr) > low.ar_startblock)
     270             :                 return 0;
     271             : 
     272        1395 :         info->last = true;
     273        1395 :         return xfs_fsrefs_ddev_bnobt_helper(cur, &low, info);
     274             : }
     275             : 
     276             : /* Transform a refcountbt irec into a fsrefs */
     277             : STATIC int
     278        7086 : xfs_fsrefs_ddev_refcountbt_helper(
     279             :         struct xfs_btree_cur            *cur,
     280             :         const struct xfs_refcount_irec  *rec,
     281             :         void                            *priv)
     282             : {
     283        7086 :         struct xfs_mount                *mp = cur->bc_mp;
     284        7086 :         struct xfs_fsrefs_info          *info = priv;
     285        7086 :         xfs_daddr_t                     rec_daddr;
     286        7086 :         int                             error;
     287             : 
     288             :         /*
     289             :          * Stop once we get to the CoW staging extents; they're all shoved to
     290             :          * the right side of the btree and were already covered by the bnobt
     291             :          * scan.
     292             :          */
     293        7086 :         if (rec->rc_domain != XFS_REFC_DOMAIN_SHARED)
     294             :                 return -ECANCELED;
     295             : 
     296             :         /* Report on any gaps first */
     297        7086 :         error = xfs_fsrefs_ddev_fill_refcount_gap(cur->bc_tp, info,
     298        7086 :                         rec->rc_startblock);
     299        7086 :         if (error)
     300             :                 return error;
     301             : 
     302        1756 :         rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
     303             :                         rec->rc_startblock);
     304        1756 :         info->next_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
     305             :                         rec->rc_startblock + rec->rc_blockcount);
     306             : 
     307        1756 :         return xfs_fsrefs_helper(cur->bc_tp, info, rec, rec_daddr, 0);
     308             : }
     309             : 
     310             : /* Execute a getfsrefs query against the regular data device. */
     311             : STATIC int
     312        7531 : xfs_fsrefs_ddev(
     313             :         struct xfs_trans        *tp,
     314             :         const struct xfs_fsrefs *keys,
     315             :         struct xfs_fsrefs_info  *info)
     316             : {
     317        7531 :         struct xfs_mount        *mp = tp->t_mountp;
     318        7531 :         struct xfs_buf          *agf_bp = NULL;
     319        7531 :         struct xfs_perag        *pag = NULL;
     320        7531 :         xfs_fsblock_t           start_fsb;
     321        7531 :         xfs_fsblock_t           end_fsb;
     322        7531 :         xfs_agnumber_t          start_ag;
     323        7531 :         xfs_agnumber_t          end_ag;
     324        7531 :         xfs_agnumber_t          agno;
     325        7531 :         uint64_t                eofs;
     326        7531 :         int                     error = 0;
     327             : 
     328        7531 :         eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
     329        7531 :         if (keys[0].fcr_physical >= eofs)
     330             :                 return 0;
     331        7531 :         start_fsb = XFS_DADDR_TO_FSB(mp, keys[0].fcr_physical);
     332        7531 :         end_fsb = XFS_DADDR_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
     333             : 
     334        7531 :         info->refc_cur = info->bno_cur = NULL;
     335             : 
     336             :         /*
     337             :          * Convert the fsrefs low/high keys to AG based keys.  Initialize
     338             :          * low to the fsrefs low key and max out the high key to the end
     339             :          * of the AG.
     340             :          */
     341        7531 :         info->low.rc_startblock = XFS_FSB_TO_AGBNO(mp, start_fsb);
     342        7531 :         info->low.rc_blockcount = XFS_BB_TO_FSBT(mp, keys[0].fcr_length);
     343        7531 :         info->low.rc_refcount = 0;
     344        7531 :         info->low.rc_domain = XFS_REFC_DOMAIN_SHARED;
     345             : 
     346             :         /* Adjust the low key if we are continuing from where we left off. */
     347        7531 :         if (info->low.rc_blockcount > 0) {
     348        7498 :                 info->low.rc_startblock += info->low.rc_blockcount;
     349             : 
     350        7498 :                 start_fsb += info->low.rc_blockcount;
     351        7498 :                 if (XFS_FSB_TO_DADDR(mp, start_fsb) >= eofs)
     352             :                         return 0;
     353             :         }
     354             : 
     355        7531 :         info->high.rc_startblock = -1U;
     356        7531 :         info->high.rc_blockcount = 0;
     357        7531 :         info->high.rc_refcount = 0;
     358        7531 :         info->high.rc_domain = XFS_REFC_DOMAIN_SHARED;
     359             : 
     360        7531 :         start_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
     361        7531 :         end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
     362             : 
     363             :         /* Query each AG */
     364        7531 :         agno = start_ag;
     365        7750 :         for_each_perag_range(mp, agno, end_ag, pag) {
     366             :                 /*
     367             :                  * Set the AG high key from the fsrefs high key if this
     368             :                  * is the last AG that we're querying.
     369             :                  */
     370        7711 :                 info->pag = pag;
     371        7711 :                 if (pag->pag_agno == end_ag)
     372        1625 :                         info->high.rc_startblock = XFS_FSB_TO_AGBNO(mp,
     373             :                                         end_fsb);
     374             : 
     375        7711 :                 if (info->refc_cur) {
     376         168 :                         xfs_btree_del_cursor(info->refc_cur, XFS_BTREE_NOERROR);
     377         168 :                         info->refc_cur = NULL;
     378             :                 }
     379        7711 :                 if (info->bno_cur) {
     380         180 :                         xfs_btree_del_cursor(info->bno_cur, XFS_BTREE_NOERROR);
     381         180 :                         info->bno_cur = NULL;
     382             :                 }
     383        7711 :                 if (agf_bp) {
     384         180 :                         xfs_trans_brelse(tp, agf_bp);
     385         180 :                         agf_bp = NULL;
     386             :                 }
     387             : 
     388        7711 :                 error = xfs_alloc_read_agf(pag, tp, 0, &agf_bp);
     389        7711 :                 if (error)
     390             :                         break;
     391             : 
     392        7711 :                 trace_xfs_fsrefs_low_key(mp, info->dev, pag->pag_agno,
     393        7711 :                                 &info->low);
     394        7711 :                 trace_xfs_fsrefs_high_key(mp, info->dev, pag->pag_agno,
     395        7711 :                                 &info->high);
     396             : 
     397        7711 :                 info->bno_cur = xfs_allocbt_init_cursor(mp, tp, agf_bp, pag,
     398             :                                                 XFS_BTNUM_BNO);
     399             : 
     400        7711 :                 if (xfs_has_reflink(mp)) {
     401        7678 :                         info->refc_cur = xfs_refcountbt_init_cursor(mp, tp,
     402             :                                                         agf_bp, pag);
     403             : 
     404             :                         /*
     405             :                          * Fill the query with refcount records and synthesize
     406             :                          * singly-owned block records from free space data.
     407             :                          */
     408        7678 :                         error = xfs_refcount_query_range(info->refc_cur,
     409             :                                         &info->low, &info->high,
     410             :                                         xfs_fsrefs_ddev_refcountbt_helper,
     411             :                                         info);
     412        7678 :                         if (error && error != -ECANCELED)
     413             :                                 break;
     414             :                 }
     415             : 
     416             :                 /*
     417             :                  * Synthesize refcount==1 records from the free space data
     418             :                  * between the end of the last fsrefs record reported and the
     419             :                  * end of the range.  If we don't have refcount support, the
     420             :                  * starting point will be the start of the query range.
     421             :                  */
     422        7711 :                 error = xfs_fsrefs_ddev_fill_refcount_gap(tp, info,
     423             :                                 info->high.rc_startblock);
     424        7711 :                 if (error)
     425             :                         break;
     426             : 
     427             :                 /*
     428             :                  * Set the AG low key to the start of the AG prior to
     429             :                  * moving on to the next AG.
     430             :                  */
     431         219 :                 if (pag->pag_agno == start_ag)
     432         252 :                         memset(&info->low, 0, sizeof(info->low));
     433             : 
     434         219 :                 info->pag = NULL;
     435             :         }
     436             : 
     437        7531 :         if (info->refc_cur) {
     438        7510 :                 xfs_btree_del_cursor(info->refc_cur, error);
     439        7510 :                 info->refc_cur = NULL;
     440             :         }
     441        7531 :         if (info->bno_cur) {
     442        7531 :                 xfs_btree_del_cursor(info->bno_cur, error);
     443        7531 :                 info->bno_cur = NULL;
     444             :         }
     445        7531 :         if (agf_bp)
     446        7531 :                 xfs_trans_brelse(tp, agf_bp);
     447        7531 :         if (info->pag) {
     448        7492 :                 xfs_perag_rele(info->pag);
     449        7492 :                 info->pag = NULL;
     450          39 :         } else if (pag) {
     451             :                 /* loop termination case */
     452           0 :                 xfs_perag_rele(pag);
     453             :         }
     454             : 
     455             :         return error;
     456             : }
     457             : 
     458             : /* Execute a getfsrefs query against the log device. */
     459             : STATIC int
     460          24 : xfs_fsrefs_logdev(
     461             :         struct xfs_trans                *tp,
     462             :         const struct xfs_fsrefs         *keys,
     463             :         struct xfs_fsrefs_info          *info)
     464             : {
     465          24 :         struct xfs_mount                *mp = tp->t_mountp;
     466          24 :         struct xfs_refcount_irec        refc;
     467          24 :         xfs_daddr_t                     rec_daddr, len_daddr;
     468          24 :         xfs_fsblock_t                   start_fsb, end_fsb;
     469          24 :         uint64_t                        eofs;
     470             : 
     471          24 :         eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
     472          24 :         if (keys[0].fcr_physical >= eofs)
     473             :                 return 0;
     474          24 :         start_fsb = XFS_BB_TO_FSBT(mp,
     475             :                                 keys[0].fcr_physical + keys[0].fcr_length);
     476          24 :         end_fsb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
     477             : 
     478             :         /* Adjust the low key if we are continuing from where we left off. */
     479          24 :         if (keys[0].fcr_length > 0)
     480           4 :                 info->low_daddr = XFS_FSB_TO_BB(mp, start_fsb);
     481             : 
     482          24 :         trace_xfs_fsrefs_low_key_linear(mp, info->dev, start_fsb);
     483          24 :         trace_xfs_fsrefs_high_key_linear(mp, info->dev, end_fsb);
     484             : 
     485          24 :         if (start_fsb > 0)
     486             :                 return 0;
     487             : 
     488             :         /* Fabricate an refc entry for the external log device. */
     489          20 :         refc.rc_startblock = 0;
     490          20 :         refc.rc_blockcount = mp->m_sb.sb_logblocks;
     491          20 :         refc.rc_refcount = 1;
     492          20 :         refc.rc_domain = XFS_REFC_DOMAIN_SHARED;
     493             : 
     494          20 :         rec_daddr = XFS_FSB_TO_BB(mp, refc.rc_startblock);
     495          20 :         len_daddr = XFS_FSB_TO_BB(mp, refc.rc_blockcount);
     496          20 :         return xfs_fsrefs_helper(tp, info, &refc, rec_daddr, len_daddr);
     497             : }
     498             : 
     499             : #ifdef CONFIG_XFS_RT
     500             : /* Synthesize fsrefs records from rtbitmap records. */
     501             : STATIC int
     502       13736 : xfs_fsrefs_rtdev_bitmap_helper(
     503             :         struct xfs_mount                *mp,
     504             :         struct xfs_trans                *tp,
     505             :         const struct xfs_rtalloc_rec    *rec,
     506             :         void                            *priv)
     507             : {
     508       13736 :         struct xfs_refcount_irec        irec;
     509       13736 :         struct xfs_fsrefs_info          *info = priv;
     510       13736 :         xfs_rtblock_t                   rt_startblock;
     511       13736 :         xfs_rtblock_t                   rec_rtlen;
     512       13736 :         xfs_rtblock_t                   next_rtbno;
     513       13736 :         xfs_daddr_t                     rec_daddr, len_daddr;
     514             : 
     515             :         /*
     516             :          * Figure out if there's a gap between the last fsrefs record we
     517             :          * emitted and this free extent.  If there is, report the gap as a
     518             :          * refcount==1 record.
     519             :          */
     520       13736 :         next_rtbno = XFS_BB_TO_FSBT(mp, info->next_daddr);
     521       13736 :         rec_daddr = XFS_FSB_TO_BB(mp, next_rtbno);
     522       13736 :         irec.rc_startblock = next_rtbno;
     523             : 
     524       13736 :         rt_startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
     525       13736 :         rec_rtlen = xfs_rtx_to_rtb(mp, rec->ar_extcount);
     526             : 
     527       13736 :         ASSERT(rt_startblock >= next_rtbno);
     528             : 
     529       13736 :         info->next_daddr = XFS_FSB_TO_BB(mp, rt_startblock + rec_rtlen);
     530             : 
     531       13736 :         if (rt_startblock == next_rtbno)
     532             :                 return 0;
     533             : 
     534             :         /* Emit a record for the in-use space */
     535       13020 :         irec.rc_blockcount = rt_startblock - next_rtbno;
     536       13020 :         len_daddr = XFS_FSB_TO_BB(mp, rt_startblock - next_rtbno);
     537             : 
     538       13020 :         irec.rc_refcount = 1;
     539       13020 :         irec.rc_domain = XFS_REFC_DOMAIN_SHARED;
     540             : 
     541       13020 :         return xfs_fsrefs_helper(tp, info, &irec, rec_daddr, len_daddr);
     542             : }
     543             : 
     544             : /* Emit records to fill a gap in the refcount btree with singly-owned blocks. */
     545             : STATIC int
     546        2141 : xfs_fsrefs_rtdev_fill_refcount_gap(
     547             :         struct xfs_trans        *tp,
     548             :         struct xfs_fsrefs_info  *info,
     549             :         xfs_rtblock_t           start_rtb,
     550             :         xfs_rtblock_t           end_rtb)
     551             : {
     552        2141 :         struct xfs_rtalloc_rec  low = { 0 };
     553        2141 :         struct xfs_rtalloc_rec  high = { 0 };
     554        2141 :         struct xfs_mount        *mp = tp->t_mountp;
     555        2141 :         xfs_daddr_t             rec_daddr;
     556        2141 :         xfs_extlen_t            mod;
     557        2141 :         int                     error;
     558             : 
     559             :         /*
     560             :          * Set up query parameters to return free extents covering the range we
     561             :          * want.
     562             :          */
     563        2141 :         low.ar_startext = xfs_rtb_to_rtxt(mp, start_rtb);
     564        2141 :         high.ar_startext = xfs_rtb_to_rtx(mp, end_rtb, &mod);
     565        2141 :         if (mod)
     566           0 :                 high.ar_startext++;
     567             : 
     568        2141 :         error = xfs_rtalloc_query_range(mp, tp, &low, &high,
     569             :                         xfs_fsrefs_rtdev_bitmap_helper, info);
     570        2141 :         if (error)
     571             :                 return error;
     572             : 
     573             :         /*
     574             :          * Synthesize records for single-owner extents between the last
     575             :          * fsrefcount record emitted and the end of the query range.
     576             :          */
     577        1033 :         high.ar_startext = min(mp->m_sb.sb_rextents, high.ar_startext);
     578        1033 :         rec_daddr = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, high.ar_startext));
     579        1033 :         if (info->next_daddr > rec_daddr)
     580             :                 return 0;
     581             : 
     582        1033 :         info->last = true;
     583        1033 :         return xfs_fsrefs_rtdev_bitmap_helper(mp, tp, &high, info);
     584             : }
     585             : 
     586             : /* Transform a absolute-startblock refcount (rtdev, logdev) into a fsrefs */
     587             : STATIC int
     588        1377 : xfs_fsrefs_rtdev_refcountbt_helper(
     589             :         struct xfs_btree_cur            *cur,
     590             :         const struct xfs_refcount_irec  *rec,
     591             :         void                            *priv)
     592             : {
     593        1377 :         struct xfs_mount                *mp = cur->bc_mp;
     594        1377 :         struct xfs_fsrefs_info          *info = priv;
     595        1377 :         xfs_rtblock_t                   rec_rtbno, next_rtbno;
     596        1377 :         int                             error;
     597             : 
     598             :         /*
     599             :          * Stop once we get to the CoW staging extents; they're all shoved to
     600             :          * the right side of the btree and were already covered by the rtbitmap
     601             :          * scan.
     602             :          */
     603        1377 :         if (rec->rc_domain != XFS_REFC_DOMAIN_SHARED)
     604             :                 return -ECANCELED;
     605             : 
     606             :         /* Report on any gaps first */
     607        1377 :         rec_rtbno = xfs_rgbno_to_rtb(mp, cur->bc_ino.rtg->rtg_rgno,
     608        1377 :                         rec->rc_startblock);
     609        1377 :         next_rtbno = XFS_BB_TO_FSBT(mp, info->next_daddr);
     610        1377 :         error = xfs_fsrefs_rtdev_fill_refcount_gap(cur->bc_tp, info,
     611             :                         next_rtbno, rec_rtbno);
     612        1377 :         if (error)
     613             :                 return error;
     614             : 
     615             :         /* Report this refcount extent. */
     616         806 :         info->next_daddr = XFS_FSB_TO_BB(mp, rec_rtbno + rec->rc_blockcount);
     617        1612 :         return xfs_fsrefs_helper(cur->bc_tp, info, rec,
     618         806 :                         XFS_FSB_TO_BB(mp, rec_rtbno), 0);
     619             : }
     620             : 
     621             : /* Execute a getfsrefs query against the realtime bitmap. */
     622             : STATIC int
     623          11 : xfs_fsrefs_rtdev_rtbitmap(
     624             :         struct xfs_trans        *tp,
     625             :         const struct xfs_fsrefs *keys,
     626             :         struct xfs_fsrefs_info  *info)
     627             : {
     628          11 :         struct xfs_mount        *mp = tp->t_mountp;
     629          11 :         xfs_rtblock_t           start_rtb;
     630          11 :         xfs_rtblock_t           end_rtb;
     631          11 :         uint64_t                eofs;
     632          11 :         int                     error;
     633             : 
     634          11 :         eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
     635          11 :         if (keys[0].fcr_physical >= eofs)
     636             :                 return 0;
     637          11 :         start_rtb = XFS_BB_TO_FSBT(mp,
     638             :                                 keys[0].fcr_physical + keys[0].fcr_length);
     639          11 :         end_rtb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
     640             : 
     641          11 :         info->refc_cur = NULL;
     642             : 
     643             :         /* Adjust the low key if we are continuing from where we left off. */
     644          11 :         if (keys[0].fcr_length > 0) {
     645           7 :                 info->low_daddr = XFS_FSB_TO_BB(mp, start_rtb);
     646           7 :                 if (info->low_daddr >= eofs)
     647             :                         return 0;
     648             :         }
     649             : 
     650          11 :         trace_xfs_fsrefs_low_key_linear(mp, info->dev, start_rtb);
     651          11 :         trace_xfs_fsrefs_high_key_linear(mp, info->dev, end_rtb);
     652             : 
     653             :         /* Synthesize refcount==1 records from the free space data. */
     654          11 :         xfs_rtbitmap_lock_shared(mp, XFS_RBMLOCK_BITMAP);
     655          11 :         error = xfs_fsrefs_rtdev_fill_refcount_gap(tp, info, start_rtb,
     656             :                         end_rtb);
     657          11 :         xfs_rtbitmap_unlock_shared(mp, XFS_RBMLOCK_BITMAP);
     658          11 :         return error;
     659             : }
     660             : 
     661             : #define XFS_RTGLOCK_FSREFS      (XFS_RTGLOCK_BITMAP_SHARED | \
     662             :                                  XFS_RTGLOCK_REFCOUNT)
     663             : 
     664             : /* Execute a getfsrefs query against the realtime device. */
     665             : STATIC int
     666         753 : xfs_fsrefs_rtdev(
     667             :         struct xfs_trans        *tp,
     668             :         const struct xfs_fsrefs *keys,
     669             :         struct xfs_fsrefs_info  *info)
     670             : {
     671         753 :         struct xfs_mount        *mp = tp->t_mountp;
     672         753 :         struct xfs_rtgroup      *rtg;
     673         753 :         xfs_rtblock_t           start_rtb;
     674         753 :         xfs_rtblock_t           end_rtb;
     675         753 :         uint64_t                eofs;
     676         753 :         xfs_rgnumber_t          start_rg, end_rg;
     677         753 :         int                     error = 0;
     678             : 
     679         753 :         eofs = XFS_FSB_TO_BB(mp, xfs_rtx_to_rtb(mp, mp->m_sb.sb_rextents));
     680         753 :         if (keys[0].fcr_physical >= eofs)
     681             :                 return 0;
     682         753 :         start_rtb = XFS_BB_TO_FSBT(mp, keys[0].fcr_physical);
     683         753 :         end_rtb = XFS_BB_TO_FSB(mp, min(eofs - 1, keys[1].fcr_physical));
     684             : 
     685         753 :         info->refc_cur = NULL;
     686             : 
     687             :         /*
     688             :          * Convert the fsrefs low/high keys to rtgroup based keys.  Initialize
     689             :          * low to the fsrefs low key and max out the high key to the end of the
     690             :          * rtgroup.
     691             :          */
     692         753 :         info->low.rc_startblock = xfs_rtb_to_rgbno(mp, start_rtb, &start_rg);
     693         753 :         info->low.rc_blockcount = XFS_BB_TO_FSBT(mp, keys[0].fcr_length);
     694         753 :         info->low.rc_refcount = 0;
     695         753 :         info->low.rc_domain = XFS_REFC_DOMAIN_SHARED;
     696             : 
     697             :         /* Adjust the low key if we are continuing from where we left off. */
     698         753 :         if (info->low.rc_blockcount > 0) {
     699         737 :                 info->low.rc_startblock += info->low.rc_blockcount;
     700             : 
     701         737 :                 start_rtb += info->low.rc_blockcount;
     702         737 :                 if (xfs_rtb_to_daddr(mp, start_rtb) >= eofs)
     703             :                         return 0;
     704             :         }
     705             : 
     706         753 :         info->high.rc_startblock = -1U;
     707         753 :         info->high.rc_blockcount = 0;
     708         753 :         info->high.rc_refcount = 0;
     709         753 :         info->high.rc_domain = XFS_REFC_DOMAIN_SHARED;
     710             : 
     711         753 :         end_rg = xfs_rtb_to_rgno(mp, end_rtb);
     712             : 
     713        1520 :         for_each_rtgroup_range(mp, start_rg, end_rg, rtg) {
     714             :                 /*
     715             :                  * Set the rtgroup high key from the fsrefs high key if this
     716             :                  * is the last rtgroup that we're querying.
     717             :                  */
     718        1508 :                 info->rtg = rtg;
     719        1508 :                 if (rtg->rtg_rgno == end_rg) {
     720         753 :                         xfs_rgnumber_t  junk;
     721             : 
     722         753 :                         info->high.rc_startblock = xfs_rtb_to_rgbno(mp,
     723             :                                         end_rtb, &junk);
     724             :                 }
     725             : 
     726        1508 :                 if (info->refc_cur) {
     727         755 :                         xfs_rtgroup_unlock(info->refc_cur->bc_ino.rtg,
     728             :                                         XFS_RTGLOCK_FSREFS);
     729         755 :                         xfs_btree_del_cursor(info->refc_cur, XFS_BTREE_NOERROR);
     730         755 :                         info->refc_cur = NULL;
     731             :                 }
     732             : 
     733        1508 :                 trace_xfs_fsrefs_low_key(mp, info->dev, rtg->rtg_rgno,
     734        1508 :                                 &info->low);
     735        1508 :                 trace_xfs_fsrefs_high_key(mp, info->dev, rtg->rtg_rgno,
     736        1508 :                                 &info->high);
     737             : 
     738        1508 :                 xfs_rtgroup_lock(NULL, rtg, XFS_RTGLOCK_FSREFS);
     739        1508 :                 info->refc_cur = xfs_rtrefcountbt_init_cursor(mp, tp, rtg,
     740             :                                                 rtg->rtg_refcountip);
     741             : 
     742             :                 /*
     743             :                  * Fill the query with refcount records and synthesize
     744             :                  * singly-owned block records from free space data.
     745             :                  */
     746        1508 :                 error = xfs_refcount_query_range(info->refc_cur,
     747             :                                 &info->low, &info->high,
     748             :                                 xfs_fsrefs_rtdev_refcountbt_helper, info);
     749        1508 :                 if (error && error != -ECANCELED)
     750             :                         break;
     751             : 
     752             :                 /*
     753             :                  * Set the rtgroup low key to the start of the rtgroup prior to
     754             :                  * moving on to the next rtgroup.
     755             :                  */
     756        1508 :                 if (rtg->rtg_rgno == start_rg)
     757        3016 :                         memset(&info->low, 0, sizeof(info->low));
     758             : 
     759             :                 /*
     760             :                  * If this is the last rtgroup, report any gap at the end of it
     761             :                  * before we drop the reference to the perag when the loop
     762             :                  * terminates.
     763             :                  */
     764        1508 :                 if (rtg->rtg_rgno == end_rg) {
     765         753 :                         xfs_rtblock_t   next_rtbno;
     766             : 
     767         753 :                         info->last = true;
     768         753 :                         next_rtbno = XFS_BB_TO_FSBT(mp, info->next_daddr);
     769         753 :                         error = xfs_fsrefs_rtdev_fill_refcount_gap(tp, info,
     770             :                                         next_rtbno, end_rtb);
     771         753 :                         if (error)
     772             :                                 break;
     773             :                 }
     774         767 :                 info->rtg = NULL;
     775             :         }
     776             : 
     777         753 :         if (info->refc_cur) {
     778         753 :                 xfs_rtgroup_unlock(info->refc_cur->bc_ino.rtg,
     779             :                                 XFS_RTGLOCK_FSREFS);
     780         753 :                 xfs_btree_del_cursor(info->refc_cur, error);
     781         753 :                 info->refc_cur = NULL;
     782             :         }
     783         753 :         if (info->rtg) {
     784         741 :                 xfs_rtgroup_rele(info->rtg);
     785         741 :                 info->rtg = NULL;
     786          12 :         } else if (rtg) {
     787             :                 /* loop termination case */
     788           0 :                 xfs_rtgroup_rele(rtg);
     789             :         }
     790             : 
     791             :         return error;
     792             : }
     793             : #endif
     794             : 
     795             : /* Do we recognize the device? */
     796             : STATIC bool
     797       16558 : xfs_fsrefs_is_valid_device(
     798             :         struct xfs_mount        *mp,
     799             :         struct xfs_fsrefs       *fcr)
     800             : {
     801       16558 :         if (fcr->fcr_device == 0 || fcr->fcr_device == UINT_MAX ||
     802        8246 :             fcr->fcr_device == new_encode_dev(mp->m_ddev_targp->bt_dev))
     803             :                 return true;
     804         748 :         if (mp->m_logdev_targp &&
     805         748 :             fcr->fcr_device == new_encode_dev(mp->m_logdev_targp->bt_dev))
     806             :                 return true;
     807         744 :         if (mp->m_rtdev_targp &&
     808         744 :             fcr->fcr_device == new_encode_dev(mp->m_rtdev_targp->bt_dev))
     809         744 :                 return true;
     810             :         return false;
     811             : }
     812             : 
     813             : /* Ensure that the low key is less than the high key. */
     814             : STATIC bool
     815        8279 : xfs_fsrefs_check_keys(
     816             :         struct xfs_fsrefs       *low_key,
     817             :         struct xfs_fsrefs       *high_key)
     818             : {
     819        8279 :         if (low_key->fcr_device > high_key->fcr_device)
     820             :                 return false;
     821        8279 :         if (low_key->fcr_device < high_key->fcr_device)
     822             :                 return true;
     823             : 
     824           0 :         if (low_key->fcr_physical > high_key->fcr_physical)
     825             :                 return false;
     826           0 :         if (low_key->fcr_physical < high_key->fcr_physical)
     827           0 :                 return true;
     828             : 
     829             :         return false;
     830             : }
     831             : 
     832             : /*
     833             :  * There are only two devices if we didn't configure RT devices at build time.
     834             :  */
     835             : #ifdef CONFIG_XFS_RT
     836             : #define XFS_GETFSREFS_DEVS      3
     837             : #else
     838             : #define XFS_GETFSREFS_DEVS      2
     839             : #endif /* CONFIG_XFS_RT */
     840             : 
     841             : /*
     842             :  * Get filesystem's extent refcounts as described in head, and format for
     843             :  * output. Fills in the supplied records array until there are no more reverse
     844             :  * mappings to return or head.fch_entries == head.fch_count.  In the second
     845             :  * case, this function returns -ECANCELED to indicate that more records would
     846             :  * have been returned.
     847             :  *
     848             :  * Key to Confusion
     849             :  * ----------------
     850             :  * There are multiple levels of keys and counters at work here:
     851             :  * xfs_fsrefs_head.fch_keys     -- low and high fsrefs keys passed in;
     852             :  *                                 these reflect fs-wide sector addrs.
     853             :  * dkeys                        -- fch_keys used to query each device;
     854             :  *                                 these are fch_keys but w/ the low key
     855             :  *                                 bumped up by fcr_length.
     856             :  * xfs_fsrefs_info.next_daddr-- next disk addr we expect to see; this
     857             :  *                                 is how we detect gaps in the fsrefs
     858             :  *                                 records and report them.
     859             :  * xfs_fsrefs_info.low/high     -- per-AG low/high keys computed from
     860             :  *                                 dkeys; used to query the metadata.
     861             :  */
     862             : int
     863        8279 : xfs_getfsrefs(
     864             :         struct xfs_mount        *mp,
     865             :         struct xfs_fsrefs_head  *head,
     866             :         struct xfs_getfsrefs    *fsrefs_recs)
     867             : {
     868        8279 :         struct xfs_trans        *tp = NULL;
     869        8279 :         struct xfs_fsrefs       dkeys[2];       /* per-dev keys */
     870        8279 :         struct xfs_fsrefs_dev   handlers[XFS_GETFSREFS_DEVS];
     871        8279 :         struct xfs_fsrefs_info  info = { NULL };
     872        8279 :         int                     i;
     873        8279 :         int                     error = 0;
     874             : 
     875        8279 :         if (head->fch_iflags & ~FCH_IF_VALID)
     876             :                 return -EINVAL;
     877        8279 :         if (!xfs_fsrefs_is_valid_device(mp, &head->fch_keys[0]) ||
     878        8279 :             !xfs_fsrefs_is_valid_device(mp, &head->fch_keys[1]))
     879             :                 return -EINVAL;
     880        8279 :         if (!xfs_fsrefs_check_keys(&head->fch_keys[0], &head->fch_keys[1]))
     881             :                 return -EINVAL;
     882             : 
     883        8279 :         head->fch_entries = 0;
     884             : 
     885             :         /* Set up our device handlers. */
     886        8279 :         memset(handlers, 0, sizeof(handlers));
     887        8279 :         handlers[0].dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
     888        8279 :         handlers[0].fn = xfs_fsrefs_ddev;
     889        8279 :         if (mp->m_logdev_targp != mp->m_ddev_targp) {
     890        1931 :                 handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev);
     891        1931 :                 handlers[1].fn = xfs_fsrefs_logdev;
     892             :         }
     893             : #ifdef CONFIG_XFS_RT
     894        8279 :         if (mp->m_rtdev_targp) {
     895         823 :                 handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);
     896         823 :                 if (xfs_has_rtreflink(mp))
     897         795 :                         handlers[2].fn = xfs_fsrefs_rtdev;
     898             :                 else
     899          28 :                         handlers[2].fn = xfs_fsrefs_rtdev_rtbitmap;
     900             :         }
     901             : #endif /* CONFIG_XFS_RT */
     902             : 
     903        8279 :         xfs_sort(handlers, XFS_GETFSREFS_DEVS, sizeof(struct xfs_fsrefs_dev),
     904             :                         xfs_fsrefs_dev_compare);
     905             : 
     906             :         /*
     907             :          * To continue where we left off, we allow userspace to use the last
     908             :          * mapping from a previous call as the low key of the next.  This is
     909             :          * identified by a non-zero length in the low key. We have to increment
     910             :          * the low key in this scenario to ensure we don't return the same
     911             :          * mapping again, and instead return the very next mapping.  Bump the
     912             :          * physical offset as there can be no other mapping for the same
     913             :          * physical block range.
     914             :          *
     915             :          * Each fsrefs backend is responsible for making this adjustment as
     916             :          * appropriate for the backend.
     917             :          */
     918        8279 :         dkeys[0] = head->fch_keys[0];
     919        8279 :         memset(&dkeys[1], 0xFF, sizeof(struct xfs_fsrefs));
     920             : 
     921        8279 :         info.next_daddr = head->fch_keys[0].fcr_physical +
     922        8279 :                           head->fch_keys[0].fcr_length;
     923        8279 :         info.fsrefs_recs = fsrefs_recs;
     924        8279 :         info.head = head;
     925             : 
     926             :         /* For each device we support... */
     927       23641 :         for (i = 0; i < XFS_GETFSREFS_DEVS; i++) {
     928             :                 /* Is this device within the range the user asked for? */
     929       23608 :                 if (!handlers[i].fn)
     930       13804 :                         continue;
     931        9804 :                 if (head->fch_keys[0].fcr_device > handlers[i].dev)
     932        1485 :                         continue;
     933        8319 :                 if (head->fch_keys[1].fcr_device < handlers[i].dev)
     934             :                         break;
     935             : 
     936             :                 /*
     937             :                  * If this device number matches the high key, we have to pass
     938             :                  * the high key to the handler to limit the query results.  If
     939             :                  * the device number exceeds the low key, zero out the low key
     940             :                  * so that we get everything from the beginning.
     941             :                  */
     942        8319 :                 if (handlers[i].dev == head->fch_keys[1].fcr_device)
     943           0 :                         dkeys[1] = head->fch_keys[1];
     944        8319 :                 if (handlers[i].dev > head->fch_keys[0].fcr_device)
     945          73 :                         memset(&dkeys[0], 0, sizeof(struct xfs_fsrefs));
     946             : 
     947             :                 /*
     948             :                  * Grab an empty transaction so that we can use its recursive
     949             :                  * buffer locking abilities to detect cycles in the refcountbt
     950             :                  * without deadlocking.
     951             :                  */
     952        8319 :                 error = xfs_trans_alloc_empty(mp, &tp);
     953        8319 :                 if (error)
     954             :                         break;
     955             : 
     956        8319 :                 info.dev = handlers[i].dev;
     957        8319 :                 info.last = false;
     958        8319 :                 info.pag = NULL;
     959        8319 :                 info.rtg = NULL;
     960        8319 :                 info.low_daddr = -1ULL;
     961        8319 :                 info.low.rc_blockcount = 0;
     962        8319 :                 error = handlers[i].fn(tp, dkeys, &info);
     963        8319 :                 if (error)
     964             :                         break;
     965          73 :                 xfs_trans_cancel(tp);
     966          73 :                 tp = NULL;
     967          73 :                 info.next_daddr = 0;
     968             :         }
     969             : 
     970        8279 :         if (tp)
     971        8246 :                 xfs_trans_cancel(tp);
     972        8279 :         head->fch_oflags = FCH_OF_DEV_T;
     973        8279 :         return error;
     974             : }

Generated by: LCOV version 1.14