]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - repair/incore.h
xfs_{copy,db,logprint,repair}: pass xfs_mount pointers instead of xfs_sb pointers
[thirdparty/xfsprogs-dev.git] / repair / incore.h
index eef8f6cd6894eee5d9fd932e6eeceab83e90300e..d64315fd25853709a202452358faebe064b44423 100644 (file)
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
  * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-/*
- * contains definition information.  implementation (code)
- * is spread out in separate files.
- */
-
-/*
- * block allocation lists
  */
-typedef struct ba_rec  {
-       void            *addr;
-       struct ba_rec   *next;
-} ba_rec_t;
-
-void                   record_allocation(ba_rec_t *addr, ba_rec_t *list);
-void                   free_allocations(ba_rec_t *list);
 
-/*
- * block bit map defs -- track state of each filesystem block.
- * ba_bmap is an array of bitstrings declared in the globals.h file.
- * the bitstrings are broken up into 64-bit chunks.  one bitstring per AG.
- */
-#define BA_BMAP_SIZE(x)                (howmany(x, 4))
+#ifndef XFS_REPAIR_INCORE_H
+#define XFS_REPAIR_INCORE_H
 
-void                   set_bmap_rt(xfs_drfsbno_t numblocks);
-void                   set_bmap_log(xfs_mount_t *mp);
-void                   set_bmap_fs(xfs_mount_t *mp);
-void                   teardown_bmap(xfs_mount_t *mp);
+#include "avl.h"
 
-void                   teardown_rt_bmap(xfs_mount_t *mp);
-void                   teardown_ag_bmap(xfs_mount_t *mp, xfs_agnumber_t agno);
-void                   teardown_bmap_finish(xfs_mount_t *mp);
-
-/* blocks are numbered from zero */
-
-/* block records fit into __uint64_t's units */
-
-#define XR_BB_UNIT     64                      /* number of bits/unit */
-#define XR_BB          4                       /* bits per block record */
-#define XR_BB_NUM      (XR_BB_UNIT/XR_BB)      /* number of records per unit */
-#define XR_BB_MASK     0xF                     /* block record mask */
 
 /*
- * bitstring ops -- set/get block states, either in filesystem
- * bno's or in agbno's.  turns out that fsbno addressing is
- * more convenient when dealing with bmap extracted addresses
- * and agbno addressing is more convenient when dealing with
- * meta-data extracted addresses.  So the fsbno versions use
- * mtype (which can be one of the block map types above) to
- * set the correct block map while the agbno versions assume
- * you want to use the regular block map.
- */
-
-#if defined(XR_BMAP_TRACE) || defined(XR_BMAP_DBG)
-/*
- * implemented as functions for debugging purposes
+ * contains definition information.  implementation (code)
+ * is spread out in separate files.
  */
-int get_agbno_state(xfs_mount_t *mp, xfs_agnumber_t agno,
-       xfs_agblock_t ag_blockno);
-void set_agbno_state(xfs_mount_t *mp, xfs_agnumber_t agno,
-       xfs_agblock_t ag_blockno, int state);
 
-int get_fsbno_state(xfs_mount_t *mp, xfs_dfsbno_t blockno);
-void set_fsbno_state(xfs_mount_t *mp, xfs_dfsbno_t blockno, int state);
-#else
 /*
- * implemented as macros for performance purposes
+ * block map -- track state of each filesystem block.
  */
 
-#define get_agbno_state(mp, agno, ag_blockno) \
-                       ((int) (*(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM) \
-                                >> (((ag_blockno)%XR_BB_NUM)*XR_BB)) \
-                               & XR_BB_MASK)
-#define set_agbno_state(mp, agno, ag_blockno, state) \
-       *(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM) = \
-               ((*(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM) & \
-         (~((__uint64_t) XR_BB_MASK << (((ag_blockno)%XR_BB_NUM)*XR_BB)))) | \
-        (((__uint64_t) (state)) << (((ag_blockno)%XR_BB_NUM)*XR_BB)))
+void           init_bmaps(xfs_mount_t *mp);
+void           reset_bmaps(xfs_mount_t *mp);
+void           free_bmaps(xfs_mount_t *mp);
 
-#define get_fsbno_state(mp, blockno) \
-               get_agbno_state(mp, XFS_FSB_TO_AGNO(mp, (blockno)), \
-                               XFS_FSB_TO_AGBNO(mp, (blockno)))
-#define set_fsbno_state(mp, blockno, state) \
-               set_agbno_state(mp, XFS_FSB_TO_AGNO(mp, (blockno)), \
-                       XFS_FSB_TO_AGBNO(mp, (blockno)), (state))
+void           set_bmap_ext(xfs_agnumber_t agno, xfs_agblock_t agbno,
+                            xfs_extlen_t blen, int state);
+int            get_bmap_ext(xfs_agnumber_t agno, xfs_agblock_t agbno,
+                            xfs_agblock_t maxbno, xfs_extlen_t *blen);
 
+void           set_rtbmap(xfs_rtblock_t bno, int state);
+int            get_rtbmap(xfs_rtblock_t bno);
 
-#define get_agbno_rec(mp, agno, ag_blockno) \
-                       (*(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM))
-#endif /* XR_BMAP_TRACE */
-
-/*
- * these work in real-time extents (e.g. fsbno == rt extent number)
- */
-#define get_rtbno_state(mp, fsbno) \
-                       ((*(rt_ba_bmap + (fsbno)/XR_BB_NUM) >> \
-                       (((fsbno)%XR_BB_NUM)*XR_BB)) & XR_BB_MASK)
-#define set_rtbno_state(mp, fsbno, state) \
-       *(rt_ba_bmap + (fsbno)/XR_BB_NUM) = \
-        ((*(rt_ba_bmap + (fsbno)/XR_BB_NUM) & \
-         (~((__uint64_t) XR_BB_MASK << (((fsbno)%XR_BB_NUM)*XR_BB)))) | \
-        (((__uint64_t) (state)) << (((fsbno)%XR_BB_NUM)*XR_BB)))
+static inline void
+set_bmap(xfs_agnumber_t agno, xfs_agblock_t agbno, int state)
+{
+       set_bmap_ext(agno, agbno, 1, state);
+}
 
+static inline int
+get_bmap(xfs_agnumber_t agno, xfs_agblock_t agbno)
+{
+       return get_bmap_ext(agno, agbno, agbno + 1, NULL);
+}
 
 /*
  * extent tree definitions
@@ -137,6 +61,7 @@ typedef struct extent_tree_node  {
        extent_state_t          ex_state;       /* see state flags below */
 
        struct extent_tree_node         *next;  /* for bcnt extent lists */
+       struct extent_tree_node         *last;  /* for bcnt extent list anchors */
 #if 0
        xfs_ino_t               ex_inode;       /* owner, NULL if free or  */
                                                /*      multiply allocated */
@@ -145,7 +70,7 @@ typedef struct extent_tree_node  {
 
 typedef struct rt_extent_tree_node  {
        avlnode_t               avl_node;
-       xfs_drtbno_t            rt_startblock;  /* starting realtime block */
+       xfs_rtblock_t           rt_startblock;  /* starting realtime block */
        xfs_extlen_t            rt_blockcount;  /* number of blocks in extent */
        extent_state_t          rt_state;       /* see state flags below */
 
@@ -165,13 +90,17 @@ typedef struct rt_extent_tree_node  {
 #define XR_E_MULT      5       /* extent is multiply referenced */
 #define XR_E_INO       6       /* extent used by inodes (inode blocks) */
 #define XR_E_FS_MAP    7       /* extent used by fs space/inode maps */
-#define XR_E_BAD_STATE 8
+#define XR_E_INUSE1    8       /* used block (marked by rmap btree) */
+#define XR_E_INUSE_FS1 9       /* used by fs ag header or log (rmap btree) */
+#define XR_E_INO1      10      /* used by inodes (marked by rmap btree) */
+#define XR_E_FS_MAP1   11      /* used by fs space/inode maps (rmap btree) */
+#define XR_E_REFC      12      /* used by fs ag reference count btree */
+#define XR_E_COW       13      /* leftover cow extent */
+#define XR_E_BAD_STATE 14
 
 /* separate state bit, OR'ed into high (4th) bit of ex_state field */
 
 #define XR_E_WRITTEN   0x8     /* extent has been written out, can't reclaim */
-#define good_state(state)      (((state) & (~XR_E_WRITTEN)) >= XR_E_UNKNOWN && \
-                               ((state) & (~XR_E_WRITTEN) < XF_E_BAD_STATE))
 #define written(state)         ((state) & XR_E_WRITTEN)
 #define set_written(state)     (state) &= XR_E_WRITTEN
 
@@ -223,19 +152,16 @@ get_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock,
 /*
  * duplicate extent tree functions
  */
-void           add_dup_extent(xfs_agnumber_t agno,
-                               xfs_agblock_t startblock,
-                               xfs_extlen_t blockcount);
 
-int            search_dup_extent(xfs_mount_t *mp,
-                               xfs_agnumber_t agno,
-                               xfs_agblock_t agbno);
-
-void           add_rt_dup_extent(xfs_drtbno_t  startblock,
+int            add_dup_extent(xfs_agnumber_t agno, xfs_agblock_t startblock,
+                       xfs_extlen_t blockcount);
+int            search_dup_extent(xfs_agnumber_t agno,
+                       xfs_agblock_t start_agbno, xfs_agblock_t end_agbno);
+void           add_rt_dup_extent(xfs_rtblock_t startblock,
                                xfs_extlen_t    blockcount);
 
 int            search_rt_dup_extent(xfs_mount_t        *mp,
-                                       xfs_drtbno_t    bno);
+                                       xfs_rtblock_t   bno);
 
 /*
  * extent/tree recyling and deletion routines
@@ -258,12 +184,18 @@ void              release_agbcnt_extent_tree(xfs_agnumber_t agno);
  */
 void           free_rt_dup_extent_tree(xfs_mount_t *mp);
 
+void           incore_ext_init(xfs_mount_t *);
 /*
  * per-AG extent trees shutdown routine -- all (bno, bcnt and dup)
  * at once.  this one actually frees the memory instead of just recyling
  * the nodes.
  */
 void           incore_ext_teardown(xfs_mount_t *mp);
+void           incore_ino_init(xfs_mount_t *);
+
+int            count_bno_extents(xfs_agnumber_t);
+int            count_bno_extents_blocks(xfs_agnumber_t, uint *);
+int            count_bcnt_extents(xfs_agnumber_t);
 
 /*
  * inode definitions
@@ -282,7 +214,9 @@ void                incore_ext_teardown(xfs_mount_t *mp);
 #define XR_INO_BLKDEV  8               /* block device */
 #define XR_INO_SOCK    9               /* socket */
 #define XR_INO_FIFO    10              /* fifo */
-#define XR_INO_MOUNTPOINT 11           /* mountpoint */
+#define XR_INO_UQUOTA  12              /* user quota inode */
+#define XR_INO_GQUOTA  13              /* group quota inode */
+#define XR_INO_PQUOTA  14              /* project quota inode */
 
 /* inode allocation tree */
 
@@ -308,35 +242,52 @@ void              incore_ext_teardown(xfs_mount_t *mp);
 
 typedef xfs_ino_t parent_entry_t;
 
+struct nlink_ops;
+
 typedef struct parent_list  {
-       __uint64_t              pmask;
+       uint64_t                pmask;
        parent_entry_t          *pentries;
 #ifdef DEBUG
        short                   cnt;
 #endif
 } parent_list_t;
 
-typedef struct backptrs  {
-       __uint64_t              ino_reached;    /* bit == 1 if reached */
-       __uint64_t              ino_processed;  /* reference checked bit mask */
-       __uint32_t              nlinks[XFS_INODES_PER_CHUNK];
+union ino_nlink {
+       uint8_t         *un8;
+       uint16_t        *un16;
+       uint32_t        *un32;
+};
+
+typedef struct ino_ex_data  {
+       uint64_t                ino_reached;    /* bit == 1 if reached */
+       uint64_t                ino_processed;  /* reference checked bit mask */
        parent_list_t           *parents;
-} backptrs_t;
+       union ino_nlink         counted_nlinks;/* counted nlinks in P6 */
+} ino_ex_data_t;
 
 typedef struct ino_tree_node  {
        avlnode_t               avl_node;
        xfs_agino_t             ino_startnum;   /* starting inode # */
        xfs_inofree_t           ir_free;        /* inode free bit mask */
-       __uint64_t              ino_confirmed;  /* confirmed bitmask */
-       __uint64_t              ino_isa_dir;    /* bit == 1 if a directory */
+       uint64_t                ir_sparse;      /* sparse inode bitmask */
+       uint64_t                ino_confirmed;  /* confirmed bitmask */
+       uint64_t                ino_isa_dir;    /* bit == 1 if a directory */
+       uint64_t                ino_was_rl;     /* bit == 1 if reflink flag set */
+       uint64_t                ino_is_rl;      /* bit == 1 if reflink flag should be set */
+       uint8_t                 nlink_size;
+       union ino_nlink         disk_nlinks;    /* on-disk nlinks, set in P3 */
        union  {
-               backptrs_t      *backptrs;
-               parent_list_t   *plist;
+               ino_ex_data_t   *ex_data;       /* phases 6,7 */
+               parent_list_t   *plist;         /* phases 2-5 */
        } ino_un;
+       uint8_t                 *ftypes;        /* phases 3,6 */
+       pthread_mutex_t         lock;
 } ino_tree_node_t;
 
-#define INOS_PER_IREC          (sizeof(__uint64_t) * NBBY)
-void                           add_ino_backptrs(xfs_mount_t *mp);
+#define INOS_PER_IREC  (sizeof(uint64_t) * NBBY)
+#define        IREC_MASK(i)    ((uint64_t)1 << (i))
+
+void           add_ino_ex_data(xfs_mount_t *mp);
 
 /*
  * return an inode record to the free inode record pool
@@ -346,11 +297,33 @@ void              free_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec);
 /*
  * get pulls the inode record from the good inode tree
  */
-void           get_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec);
-
-ino_tree_node_t *findfirst_inode_rec(xfs_agnumber_t agno);
-ino_tree_node_t *find_inode_rec(xfs_agnumber_t agno, xfs_agino_t ino);
-void           find_inode_rec_range(xfs_agnumber_t agno,
+void           get_inode_rec(struct xfs_mount *mp, xfs_agnumber_t agno,
+                             ino_tree_node_t *ino_rec);
+
+extern avltree_desc_t     **inode_tree_ptrs;
+
+static inline int
+get_inode_offset(struct xfs_mount *mp, xfs_ino_t ino, ino_tree_node_t *irec)
+{
+       return XFS_INO_TO_AGINO(mp, ino) - irec->ino_startnum;
+}
+static inline ino_tree_node_t *
+findfirst_inode_rec(xfs_agnumber_t agno)
+{
+       return((ino_tree_node_t *) inode_tree_ptrs[agno]->avl_firstino);
+}
+static inline ino_tree_node_t *
+find_inode_rec(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t ino)
+{
+       /*
+        * Is the AG inside the file system
+        */
+       if (agno >= mp->m_sb.sb_agcount)
+               return NULL;
+       return((ino_tree_node_t *)
+               avl_findrange(inode_tree_ptrs[agno], ino));
+}
+void           find_inode_rec_range(struct xfs_mount *mp, xfs_agnumber_t agno,
                        xfs_agino_t start_ino, xfs_agino_t end_ino,
                        ino_tree_node_t **first, ino_tree_node_t **last);
 
@@ -359,8 +332,10 @@ void               find_inode_rec_range(xfs_agnumber_t agno,
  * automatically marks it as "existing".  Note -- all the inode
  * add/set/get routines assume a valid inode number.
  */
-ino_tree_node_t        *set_inode_used_alloc(xfs_agnumber_t agno, xfs_agino_t ino);
-ino_tree_node_t        *set_inode_free_alloc(xfs_agnumber_t agno, xfs_agino_t ino);
+ino_tree_node_t        *set_inode_used_alloc(struct xfs_mount *mp, xfs_agnumber_t agno,
+                                     xfs_agino_t ino);
+ino_tree_node_t        *set_inode_free_alloc(struct xfs_mount *mp, xfs_agnumber_t agno,
+                                     xfs_agino_t ino);
 
 void           print_inode_list(xfs_agnumber_t agno);
 void           print_uncertain_inode_list(xfs_agnumber_t agno);
@@ -373,9 +348,11 @@ ino_tree_node_t            *find_uncertain_inode_rec(xfs_agnumber_t agno,
                                                xfs_agino_t ino);
 void                   add_inode_uncertain(xfs_mount_t *mp,
                                                xfs_ino_t ino, int free);
-void                   add_aginode_uncertain(xfs_agnumber_t agno,
+void                   add_aginode_uncertain(struct xfs_mount *mp,
+                                               xfs_agnumber_t agno,
                                                xfs_agino_t agino, int free);
-void                   get_uncertain_inode_rec(xfs_agnumber_t agno,
+void                   get_uncertain_inode_rec(struct xfs_mount *mp,
+                                               xfs_agnumber_t agno,
                                                ino_tree_node_t *ino_rec);
 void                   clear_uncertain_ino_cache(xfs_agnumber_t agno);
 
@@ -392,89 +369,177 @@ void                     clear_uncertain_ino_cache(xfs_agnumber_t agno);
                ((ino_tree_node_t *) ((ino_node_ptr)->avl_node.avl_forw))
 
 /*
- * Bit manipulations for processed field
+ * finobt helpers
  */
-#define        XFS_INOPROC_MASK(i)     ((__uint64_t)1 << (i))
-#define        XFS_INOPROC_MASKN(i,n)  ((__uint64_t)((1 << (n)) - 1) << (i))
 
-#define        XFS_INOPROC_IS_PROC(rp, i) \
-       (((rp)->ino_un.backptrs->ino_processed & XFS_INOPROC_MASK((i))) == 0LL \
-               ? 0 : 1)
-#define        XFS_INOPROC_SET_PROC(rp, i) \
-       ((rp)->ino_un.backptrs->ino_processed |= XFS_INOPROC_MASK((i)))
-/*
-#define        XFS_INOPROC_CLR_PROC(rp, i) \
-       ((rp)->ino_un.backptrs->ino_processed &= ~XFS_INOPROC_MASK((i)))
-*/
+static inline bool
+inode_rec_has_free(struct ino_tree_node *ino_rec)
+{
+       /* must have real, allocated inodes for finobt */
+       return ino_rec->ir_free & ~ino_rec->ir_sparse;
+}
+
+static inline ino_tree_node_t *
+findfirst_free_inode_rec(xfs_agnumber_t agno)
+{
+       ino_tree_node_t *ino_rec;
+
+       ino_rec = findfirst_inode_rec(agno);
+
+       while (ino_rec && !inode_rec_has_free(ino_rec))
+               ino_rec = next_ino_rec(ino_rec);
+
+       return ino_rec;
+}
+
+static inline ino_tree_node_t *
+next_free_ino_rec(ino_tree_node_t *ino_rec)
+{
+       ino_rec = next_ino_rec(ino_rec);
+
+       while (ino_rec && !inode_rec_has_free(ino_rec))
+               ino_rec = next_ino_rec(ino_rec);
+
+       return ino_rec;
+}
 
 /*
- * same for ir_confirmed.
+ * Has an inode been processed for phase 6 (reference count checking)?
+ *
+ * add_inode_refchecked() is set on an inode when it gets traversed
+ * during the reference count phase (6).  It's set so that if the inode
+ * is a directory, it's traversed (and it's links counted) only once.
  */
-#define        XFS_INOCF_MASK(i)       ((__uint64_t)1 << (i))
-#define        XFS_INOCF_MASKN(i,n)    ((__uint64_t)((1 << (n)) - 1) << (i))
+static inline void add_inode_refchecked(struct ino_tree_node *irec, int offset)
+{
+       pthread_mutex_lock(&irec->lock);
+       irec->ino_un.ex_data->ino_processed |= IREC_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+}
 
-#define        XFS_INOCF_IS_CF(rp, i) \
-               (((rp)->ino_confirmed & XFS_INOCF_MASK((i))) == 0LL \
-                       ? 0 : 1)
-#define        XFS_INOCF_SET_CF(rp, i) \
-                       ((rp)->ino_confirmed |= XFS_INOCF_MASK((i)))
-#define        XFS_INOCF_CLR_CF(rp, i) \
-                       ((rp)->ino_confirmed &= ~XFS_INOCF_MASK((i)))
+static inline int is_inode_refchecked(struct ino_tree_node *irec, int offset)
+{
+       return (irec->ino_un.ex_data->ino_processed & IREC_MASK(offset)) != 0;
+}
 
 /*
- * same for backptr->ino_reached
+ * set/test is inode known to be valid (although perhaps corrupt)
  */
-#define        XFS_INO_RCHD_MASK(i)    ((__uint64_t)1 << (i))
+static inline void set_inode_confirmed(struct ino_tree_node *irec, int offset)
+{
+       irec->ino_confirmed |= IREC_MASK(offset);
+}
+
+static inline int is_inode_confirmed(struct ino_tree_node *irec, int offset)
+{
+       return (irec->ino_confirmed & IREC_MASK(offset)) != 0;
+}
 
-#define        XFS_INO_RCHD_IS_RCHD(rp, i) \
-       (((rp)->ino_un.backptrs->ino_reached & XFS_INO_RCHD_MASK((i))) == 0LL \
-               ? 0 : 1)
-#define        XFS_INO_RCHD_SET_RCHD(rp, i) \
-               ((rp)->ino_un.backptrs->ino_reached |= XFS_INO_RCHD_MASK((i)))
-#define        XFS_INO_RCHD_CLR_RCHD(rp, i) \
-               ((rp)->ino_un.backptrs->ino_reached &= ~XFS_INO_RCHD_MASK((i)))
 /*
  * set/clear/test is inode a directory inode
  */
-#define        XFS_INO_ISADIR_MASK(i)  ((__uint64_t)1 << (i))
+static inline void set_inode_isadir(struct ino_tree_node *irec, int offset)
+{
+       pthread_mutex_lock(&irec->lock);
+       irec->ino_isa_dir |= IREC_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+}
 
-#define inode_isadir(ino_rec, ino_offset) \
-       (((ino_rec)->ino_isa_dir & XFS_INO_ISADIR_MASK((ino_offset))) == 0LL \
-               ? 0 : 1)
-#define set_inode_isadir(ino_rec, ino_offset) \
-               ((ino_rec)->ino_isa_dir |= XFS_INO_ISADIR_MASK((ino_offset)))
-#define clear_inode_isadir(ino_rec, ino_offset) \
-               ((ino_rec)->ino_isa_dir &= ~XFS_INO_ISADIR_MASK((ino_offset)))
+static inline void clear_inode_isadir(struct ino_tree_node *irec, int offset)
+{
+       pthread_mutex_lock(&irec->lock);
+       irec->ino_isa_dir &= ~IREC_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+}
 
+static inline int inode_isadir(struct ino_tree_node *irec, int offset)
+{
+       return (irec->ino_isa_dir & IREC_MASK(offset)) != 0;
+}
 
 /*
- * set/clear/test is inode known to be valid (although perhaps corrupt)
+ * set/clear/test is inode free or used
  */
-#define clear_inode_confirmed(ino_rec, ino_offset) \
-                       XFS_INOCF_CLR_CF((ino_rec), (ino_offset))
+static inline void set_inode_free(struct ino_tree_node *irec, int offset)
+{
+       pthread_mutex_lock(&irec->lock);
+       set_inode_confirmed(irec, offset);
+       irec->ir_free |= XFS_INOBT_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+
+}
 
-#define set_inode_confirmed(ino_rec, ino_offset) \
-                       XFS_INOCF_SET_CF((ino_rec), (ino_offset))
+static inline void set_inode_used(struct ino_tree_node *irec, int offset)
+{
+       pthread_mutex_lock(&irec->lock);
+       set_inode_confirmed(irec, offset);
+       irec->ir_free &= ~XFS_INOBT_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+}
 
-#define is_inode_confirmed(ino_rec, ino_offset) \
-                       XFS_INOCF_IS_CF(ino_rec, ino_offset)
+static inline int is_inode_free(struct ino_tree_node *irec, int offset)
+{
+       return (irec->ir_free & XFS_INOBT_MASK(offset)) != 0;
+}
 
 /*
- * set/clear/test is inode free or used
+ * set/test is inode sparse (not physically allocated)
  */
-#define set_inode_free(ino_rec, ino_offset) \
-       XFS_INOCF_SET_CF((ino_rec), (ino_offset)), \
-       XFS_INOBT_SET_FREE((ino_rec), (ino_offset))
+static inline void set_inode_sparse(struct ino_tree_node *irec, int offset)
+{
+       pthread_mutex_lock(&irec->lock);
+       irec->ir_sparse |= XFS_INOBT_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+}
 
-#define set_inode_used(ino_rec, ino_offset) \
-       XFS_INOCF_SET_CF((ino_rec), (ino_offset)), \
-       XFS_INOBT_CLR_FREE((ino_rec), (ino_offset))
+static inline bool is_inode_sparse(struct ino_tree_node *irec, int offset)
+{
+       return irec->ir_sparse & XFS_INOBT_MASK(offset);
+}
 
-#define is_inode_used(ino_rec, ino_offset)     \
-       !XFS_INOBT_IS_FREE((ino_rec), (ino_offset))
+/*
+ * set/clear/test was inode marked as reflinked
+ */
+static inline void set_inode_was_rl(struct ino_tree_node *irec, int offset)
+{
+       pthread_mutex_lock(&irec->lock);
+       irec->ino_was_rl |= IREC_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+}
+
+static inline void clear_inode_was_rl(struct ino_tree_node *irec, int offset)
+{
+       pthread_mutex_lock(&irec->lock);
+       irec->ino_was_rl &= ~IREC_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+}
 
-#define is_inode_free(ino_rec, ino_offset)     \
-       XFS_INOBT_IS_FREE((ino_rec), (ino_offset))
+static inline int inode_was_rl(struct ino_tree_node *irec, int offset)
+{
+       return (irec->ino_was_rl & IREC_MASK(offset)) != 0;
+}
+
+/*
+ * set/clear/test should inode be marked as reflinked
+ */
+static inline void set_inode_is_rl(struct ino_tree_node *irec, int offset)
+{
+       pthread_mutex_lock(&irec->lock);
+       irec->ino_is_rl |= IREC_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+}
+
+static inline void clear_inode_is_rl(struct ino_tree_node *irec, int offset)
+{
+       pthread_mutex_lock(&irec->lock);
+       irec->ino_is_rl &= ~IREC_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+}
+
+static inline int inode_is_rl(struct ino_tree_node *irec, int offset)
+{
+       return (irec->ino_is_rl & IREC_MASK(offset)) != 0;
+}
 
 /*
  * add_inode_reached() is set on inode I only if I has been reached
@@ -485,42 +550,62 @@ void                      clear_uncertain_ino_cache(xfs_agnumber_t agno);
  * detected and drop_inode_ref() is called every time a link to
  * an inode that we've counted is removed.
  */
-
-void           add_inode_reached(ino_tree_node_t *ino_rec, int ino_offset);
-void           add_inode_ref(ino_tree_node_t *ino_rec, int ino_offset);
-void           drop_inode_ref(ino_tree_node_t *ino_rec, int ino_offset);
-int            is_inode_reached(ino_tree_node_t *ino_rec, int ino_offset);
-int            is_inode_referenced(ino_tree_node_t *ino_rec, int ino_offset);
-__uint32_t     num_inode_references(ino_tree_node_t *ino_rec, int ino_offset);
-
-/*
- * has an inode been processed for phase 6 (reference count checking)?
- * add_inode_refchecked() is set on an inode when it gets traversed
- * during the reference count phase (6).  It's set so that if the inode
- * is a directory, it's traversed (and it's links counted) only once.
- */
-#ifndef XR_INO_REF_DEBUG
-#define add_inode_refchecked(ino, ino_rec, ino_offset) \
-               XFS_INOPROC_SET_PROC((ino_rec), (ino_offset))
-#define is_inode_refchecked(ino, ino_rec, ino_offset) \
-               (XFS_INOPROC_IS_PROC(ino_rec, ino_offset) == 0LL ? 0 : 1)
-#else
-void add_inode_refchecked(xfs_ino_t ino,
-                       ino_tree_node_t *ino_rec, int ino_offset);
-int is_inode_refchecked(xfs_ino_t ino,
-                       ino_tree_node_t *ino_rec, int ino_offset);
-#endif /* XR_INO_REF_DEBUG */
+void add_inode_ref(struct ino_tree_node *irec, int offset);
+void drop_inode_ref(struct ino_tree_node *irec, int offset);
+uint32_t num_inode_references(struct ino_tree_node *irec, int offset);
+
+void set_inode_disk_nlinks(struct ino_tree_node *irec, int offset, uint32_t nlinks);
+uint32_t get_inode_disk_nlinks(struct ino_tree_node *irec, int offset);
+
+static inline int is_inode_reached(struct ino_tree_node *irec, int offset)
+{
+       ASSERT(irec->ino_un.ex_data != NULL);
+       return (irec->ino_un.ex_data->ino_reached & IREC_MASK(offset)) != 0;
+}
+
+static inline void add_inode_reached(struct ino_tree_node *irec, int offset)
+{
+       add_inode_ref(irec, offset);
+       pthread_mutex_lock(&irec->lock);
+       irec->ino_un.ex_data->ino_reached |= IREC_MASK(offset);
+       pthread_mutex_unlock(&irec->lock);
+}
+
+/*
+ * get/set inode filetype. Only used if the superblock feature bit is set
+ * which allocates irec->ftypes.
+ */
+static inline void
+set_inode_ftype(struct ino_tree_node *irec,
+       int             ino_offset,
+       uint8_t         ftype)
+{
+       if (irec->ftypes)
+               irec->ftypes[ino_offset] = ftype;
+}
+
+static inline uint8_t
+get_inode_ftype(
+       struct ino_tree_node *irec,
+       int             ino_offset)
+{
+       if (!irec->ftypes)
+               return XFS_DIR3_FT_UNKNOWN;
+       return irec->ftypes[ino_offset];
+}
 
 /*
  * set/get inode number of parent -- works for directory inodes only
  */
 void           set_inode_parent(ino_tree_node_t *irec, int ino_offset,
                                        xfs_ino_t ino);
-#if 0
-void           clear_inode_parent(ino_tree_node_t *irec, int offset);
-#endif
 xfs_ino_t      get_inode_parent(ino_tree_node_t *irec, int ino_offset);
 
+/*
+ * Allocate extra inode data
+ */
+void           alloc_ex_data(ino_tree_node_t *irec);
+
 /*
  * bmap cursor for tracking and fixing bmap btrees.  All xfs btrees number
  * the levels with 0 being the leaf and every level up being 1 greater.
@@ -529,15 +614,15 @@ xfs_ino_t get_inode_parent(ino_tree_node_t *irec, int ino_offset);
 #define XR_MAX_BMLEVELS                10      /* XXX - rcc need to verify number */
 
 typedef struct bm_level_state  {
-       xfs_dfsbno_t            fsbno;
-       xfs_dfsbno_t            left_fsbno;
-       xfs_dfsbno_t            right_fsbno;
-       __uint64_t              first_key;
-       __uint64_t              last_key;
+       xfs_fsblock_t           fsbno;
+       xfs_fsblock_t           left_fsbno;
+       xfs_fsblock_t           right_fsbno;
+       uint64_t                first_key;
+       uint64_t                last_key;
 /*
        int                     level;
-       __uint64_t              prev_last_key;
-       xfs_buf_t               *bp;
+       uint64_t                prev_last_key;
+       struct xfs_buf          *bp;
        xfs_bmbt_block_t        *block;
 */
 } bm_level_state_t;
@@ -550,3 +635,33 @@ typedef struct bm_cursor  {
 } bmap_cursor_t;
 
 void init_bm_cursor(bmap_cursor_t *cursor, int num_level);
+
+/*
+ * On-disk inobt record helpers. The sparse inode record format has a single
+ * byte freecount. The older format has a 32-bit freecount and thus byte
+ * conversion is necessary.
+ */
+
+static inline int
+inorec_get_freecount(
+       struct xfs_mount        *mp,
+       struct xfs_inobt_rec    *rp)
+{
+       if (xfs_sb_version_hassparseinodes(&mp->m_sb))
+               return rp->ir_u.sp.ir_freecount;
+       return be32_to_cpu(rp->ir_u.f.ir_freecount);
+}
+
+static inline void
+inorec_set_freecount(
+       struct xfs_mount        *mp,
+       struct xfs_inobt_rec    *rp,
+       int                     freecount)
+{
+       if (xfs_sb_version_hassparseinodes(&mp->m_sb))
+               rp->ir_u.sp.ir_freecount = freecount;
+       else
+               rp->ir_u.f.ir_freecount = cpu_to_be32(freecount);
+}
+
+#endif /* XFS_REPAIR_INCORE_H */