]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_repair: find and mark the rtrefcountbt inode
authorDarrick J. Wong <djwong@kernel.org>
Wed, 3 Jul 2024 21:22:34 +0000 (14:22 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 16 Jul 2024 22:49:24 +0000 (15:49 -0700)
Make sure that we find the realtime refcountbt inode and mark it
appropriately, just in case we find a rogue inode claiming to
be an rtrefcount, or just plain garbage in the superblock field.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
repair/dino_chunks.c
repair/dinode.c
repair/dir2.c
repair/incore.h
repair/rmap.c
repair/rmap.h
repair/scan.c

index fc882a49b94957a5fc55962b01923bda65e5e32a..6d612a91e8bca3334ef3cf1e9cc623af25e28914 100644 (file)
@@ -1016,6 +1016,17 @@ next_readbuf:
        _("would clear realtime rmap inode %" PRIu64 "\n"),
                                                ino);
                                }
+                       } else if (is_rtrefcount_ino(ino)) {
+                               refcount_avoid_check(mp);
+                               if (!no_modify)  {
+                                       do_warn(
+       _("cleared realtime refcount inode %" PRIu64 "\n"),
+                                               ino);
+                               } else  {
+                                       do_warn(
+       _("would clear realtime refcount inode %" PRIu64 "\n"),
+                                               ino);
+                               }
                        } else if (!no_modify)  {
                                do_warn(_("cleared inode %" PRIu64 "\n"),
                                        ino);
index 696c234fcb159d085fef5ec3a62addf3f13cbf74..ae5f242794996d5bb1fd18754e373b57da295335 100644 (file)
@@ -156,6 +156,9 @@ clear_dinode(xfs_mount_t *mp, struct xfs_dinode *dino, xfs_ino_t ino_num)
        if (is_rtrmap_inode(ino_num))
                rmap_avoid_check(mp);
 
+       if (is_rtrefcount_ino(ino_num))
+               refcount_avoid_check(mp);
+
        /* and clear the forks */
        memset(XFS_DFORK_DPTR(dino), 0, XFS_LITINO(mp));
        return;
@@ -1076,6 +1079,12 @@ _("rtrefcount inode %" PRIu64 " not flagged as metadata\n"),
                        lino);
                return 1;
        }
+       if (type != XR_INO_RTREFC) {
+               do_warn(
+_("rtrefcount inode %" PRIu64 " was not found in the metadata directory tree\n"),
+                       lino);
+               return 1;
+       }
 
        priv.rgno = rtgroup_for_rtrefcount_inode(mp, lino);
        if (priv.rgno == NULLRGNUMBER) {
@@ -1116,7 +1125,7 @@ _("computed size of rtrefcountbt root (%zu bytes) is greater than space in "
                error = process_rtrefc_reclist(mp, rp, numrecs,
                                &priv, "rtrefcountbt root");
                if (error) {
-                       refcount_avoid_check();
+                       refcount_avoid_check(mp);
                        return 1;
                }
                return 0;
@@ -2074,6 +2083,9 @@ process_check_sb_inodes(
        if (is_rtrmap_inode(lino))
                return process_check_rt_inode(mp, dinoc, lino, type, dirty,
                                XR_INO_RTRMAP, _("realtime rmap btree"));
+       if (is_rtrefcount_ino(lino))
+               return process_check_rt_inode(mp, dinoc, lino, type, dirty,
+                               XR_INO_RTREFC, _("realtime refcount btree"));
        return 0;
 }
 
@@ -2183,6 +2195,18 @@ _("found inode %" PRIu64 " claiming to be a rtrmapbt file, but rmapbt is disable
                }
                break;
 
+       case XR_INO_RTREFC:
+               /*
+                * if we have no refcountbt, any inode claiming
+                * to be a real-time file is bogus
+                */
+               if (!xfs_has_reflink(mp)) {
+                       do_warn(
+_("found inode %" PRIu64 " claiming to be a rtrefcountbt file, but reflink is disabled\n"), lino);
+                       return 1;
+               }
+               break;
+
        default:
                break;
        }
@@ -2212,6 +2236,7 @@ _("bad attr fork offset %d in dev inode %" PRIu64 ", should be %d\n"),
                }
                break;
        case XFS_DINODE_FMT_RMAP:
+       case XFS_DINODE_FMT_REFCOUNT:
                if (!(xfs_has_metadir(mp) && xfs_has_parent(mp))) {
                        do_warn(
 _("metadata inode %" PRIu64 " type %d cannot have attr fork\n"),
@@ -3355,6 +3380,8 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"),
                        type = XR_INO_PQUOTA;
                else if (is_rtrmap_inode(lino))
                        type = XR_INO_RTRMAP;
+               else if (is_rtrefcount_ino(lino))
+                       type = XR_INO_RTREFC;
                else
                        type = XR_INO_DATA;
                break;
@@ -3462,6 +3489,7 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "),
                case XR_INO_GQUOTA:
                case XR_INO_PQUOTA:
                case XR_INO_RTRMAP:
+               case XR_INO_RTREFC:
                        /*
                         * This inode was recognized as being filesystem
                         * metadata, so preserve the inode and its contents for
index e5f643bb7260d0a7336b0ab2fad9398a12ac7e85..efd9fef0dfd514e8301fd28860b86bbf61d28db4 100644 (file)
@@ -279,6 +279,9 @@ process_sf_dir2(
                } else if (is_rtrmap_inode(lino)) {
                        junkit = 1;
                        junkreason = _("realtime rmap");
+               } else if (is_rtrefcount_ino(lino)) {
+                       junkit = 1;
+                       junkreason = _("realtime refcount");
                } else if ((irec_p = find_inode_rec(mp,
                                        XFS_INO_TO_AGNO(mp, lino),
                                        XFS_INO_TO_AGINO(mp, lino))) != NULL) {
@@ -756,6 +759,8 @@ process_dir2_data(
                        clearreason = _("metadata directory root");
                } else if (is_rtrmap_inode(ent_ino)) {
                        clearreason = _("realtime rmap");
+               } else if (is_rtrefcount_ino(ent_ino)) {
+                       clearreason = _("realtime refcount");
                } else {
                        irec_p = find_inode_rec(mp,
                                                XFS_INO_TO_AGNO(mp, ent_ino),
index 6ee7a6629307c78971687afc587afda5a1b3e42a..5014a2d303cbf6ef68e6d7fbd61ae391a093eaa3 100644 (file)
@@ -222,6 +222,7 @@ int         count_bcnt_extents(xfs_agnumber_t);
 #define XR_INO_GQUOTA  13              /* group quota inode */
 #define XR_INO_PQUOTA  14              /* project quota inode */
 #define XR_INO_RTRMAP  15              /* realtime rmap */
+#define XR_INO_RTREFC  16              /* realtime refcount */
 
 /* inode allocation tree */
 
index ac1e0a3f3b3d6c739397b99520bcb0b3e298d5b7..ac4ed4bcffd5c0ba50fdf99ae75830cb2680be20 100644 (file)
@@ -44,6 +44,12 @@ struct xfs_ag_rmap {
         */
        xfs_ino_t               rg_rmap_ino;
 
+       /*
+        * inumber of the refcount btree for this rtgroup.  This can be set to
+        * NULLFSINO to signal to phase 6 to link a new inode into the metadir.
+        */
+       xfs_ino_t               rg_refcount_ino;
+
        /* agfl entries from leftover agbt allocations */
        int                     ar_flcount;
 };
@@ -56,6 +62,9 @@ static bool refcbt_suspect;
 /* Bitmap of rt group rmap inodes reachable via /realtime/$rgno.rmap. */
 static struct bitmap   *rmap_inodes;
 
+/* Bitmap of rt group refcount inodes reachable via /realtime/$rgno.refcount. */
+static struct bitmap   *refcount_inodes;
+
 static struct xfs_ag_rmap *rmaps_for_group(bool isrt, unsigned int group)
 {
        if (isrt)
@@ -134,6 +143,7 @@ rmaps_init_rt(
                goto nomem;
 
        ag_rmap->rg_rmap_ino = NULLFSINO;
+       ag_rmap->rg_refcount_ino = NULLFSINO;
        return;
 nomem:
        do_error(
@@ -242,6 +252,51 @@ out_path:
        return error;
 }
 
+static inline int
+set_rtgroup_refcount_inode(
+       struct xfs_mount        *mp,
+       xfs_rgnumber_t          rgno)
+{
+       struct xfs_imeta_path   *path;
+       struct xfs_ag_rmap      *ar = rmaps_for_group(true, rgno);
+       struct xfs_trans        *tp;
+       xfs_ino_t               ino;
+       int                     error;
+
+       if (!xfs_has_rtreflink(mp))
+               return 0;
+
+       path = xfs_rtrefcountbt_create_path(mp, rgno);
+       if (!path)
+               return ENOMEM;
+
+       error = -libxfs_trans_alloc_empty(mp, &tp);
+       if (error)
+               goto out_path;
+
+       error = -libxfs_imeta_lookup(tp, path, &ino);
+       if (error)
+               goto out_trans;
+
+       if (!libxfs_verify_ino(mp, ino) ||
+           bitmap_test(refcount_inodes, ino, 1)) {
+               error = EFSCORRUPTED;
+               goto out_trans;
+       }
+
+       error = bitmap_set(refcount_inodes, ino, 1);
+       if (error)
+               goto out_trans;
+
+       ar->rg_refcount_ino = ino;
+
+out_trans:
+       libxfs_trans_cancel(tp);
+out_path:
+       libxfs_imeta_free_path(path);
+       return error;
+}
+
 static void
 discover_rtgroup_inodes(
        struct xfs_mount        *mp)
@@ -253,10 +308,20 @@ discover_rtgroup_inodes(
        if (error)
                goto out;
 
+       error = bitmap_alloc(&refcount_inodes);
+       if (error) {
+               bitmap_free(&rmap_inodes);
+               goto out;
+       }
+
        for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
                int err2 = set_rtgroup_rmap_inode(mp, rgno);
                if (err2 && !error)
                        error = err2;
+
+               err2 = set_rtgroup_refcount_inode(mp, rgno);
+               if (err2 && !error)
+                       error = err2;
        }
 
 out:
@@ -272,6 +337,7 @@ out:
 static inline void
 free_rtmeta_inode_bitmaps(void)
 {
+       bitmap_free(&refcount_inodes);
        bitmap_free(&rmap_inodes);
 }
 
@@ -287,10 +353,28 @@ rtgroup_for_rtrefcount_inode(
        struct xfs_mount        *mp,
        xfs_ino_t               ino)
 {
-       /* This will be implemented later. */
+       xfs_rgnumber_t          rgno;
+
+       if (!refcount_inodes)
+               return NULLRGNUMBER;
+
+       for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
+               if (rg_rmaps[rgno].rg_refcount_ino == ino)
+                       return rgno;
+       }
+
        return NULLRGNUMBER;
 }
 
+bool
+is_rtrefcount_ino(
+       xfs_ino_t               ino)
+{
+       if (!refcount_inodes)
+               return false;
+       return bitmap_test(refcount_inodes, ino, 1);
+}
+
 /*
  * Initialize per-AG reverse map data.
  */
@@ -1870,8 +1954,19 @@ init_refcount_cursor(
  * Disable the refcount btree check.
  */
 void
-refcount_avoid_check(void)
+refcount_avoid_check(
+       struct xfs_mount        *mp)
 {
+       struct xfs_rtgroup      *rtg;
+       xfs_rgnumber_t          rgno;
+
+       for_each_rtgroup(mp, rgno, rtg) {
+               struct xfs_ag_rmap *ar = rmaps_for_group(true, rtg->rtg_rgno);
+
+               ar->rg_refcount_ino = NULLFSINO;
+       }
+
+       bitmap_clear(refcount_inodes, 0, XFS_MAXINUMBER);
        refcbt_suspect = true;
 }
 
index c4e3b7f3a1b8523651ac2fa28eb4eb7dd8594086..75974fccb41cd49b63d8f519966f413840b25e17 100644 (file)
@@ -41,7 +41,7 @@ extern void rmap_high_key_from_rec(struct xfs_rmap_irec *rec,
 extern int compute_refcounts(struct xfs_mount *, xfs_agnumber_t);
 uint64_t refcount_record_count(struct xfs_mount *mp, xfs_agnumber_t agno);
 extern int init_refcount_cursor(xfs_agnumber_t, struct xfs_slab_cursor **);
-extern void refcount_avoid_check(void);
+extern void refcount_avoid_check(struct xfs_mount *mp);
 void check_refcounts(struct xfs_mount *mp, xfs_agnumber_t agno);
 
 extern void record_inode_reflink_flag(struct xfs_mount *, struct xfs_dinode *,
@@ -67,5 +67,6 @@ xfs_filblks_t estimate_rtrmapbt_blocks(struct xfs_rtgroup *rtg);
 
 xfs_rgnumber_t rtgroup_for_rtrefcount_inode(struct xfs_mount *mp,
                xfs_ino_t ino);
+bool is_rtrefcount_ino(xfs_ino_t ino);
 
 #endif /* RMAP_H_ */
index 0811a7e212f14555638f7d6116c61adc6cf05f32..c469f60c4035ae53c73a4234e225a3bc0dc153e6 100644 (file)
@@ -1987,7 +1987,7 @@ _("extent (%u/%u) len %u claimed, state is %d\n"),
        libxfs_perag_put(pag);
 out:
        if (suspect)
-               refcount_avoid_check();
+               refcount_avoid_check(mp);
        return;
 }
 
@@ -2277,7 +2277,7 @@ _("%s btree block claimed (state %d), agno %d, agbno %d, suspect %d\n"),
        }
 out:
        if (suspect) {
-               refcount_avoid_check();
+               refcount_avoid_check(mp);
                return 1;
        }
 
@@ -3140,7 +3140,7 @@ validate_agf(
                if (levels == 0 || levels > mp->m_refc_maxlevels) {
                        do_warn(_("bad levels %u for refcountbt root, agno %d\n"),
                                levels, agno);
-                       refcount_avoid_check();
+                       refcount_avoid_check(mp);
                }
 
                bno = be32_to_cpu(agf->agf_refcount_root);
@@ -3158,7 +3158,7 @@ validate_agf(
                } else {
                        do_warn(_("bad agbno %u for refcntbt root, agno %d\n"),
                                bno, agno);
-                       refcount_avoid_check();
+                       refcount_avoid_check(mp);
                }
        }