]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
metadump: refactor inode processing
authorChristoph Hellwig <hch@lst.de>
Tue, 16 Jul 2024 12:35:56 +0000 (14:35 +0200)
committerChristoph Hellwig <hch@lst.de>
Thu, 18 Jul 2024 06:44:27 +0000 (08:44 +0200)
The code to dump inodes in metadump is rather convoluted because it tries
to determine the inode "type" early and pass it down, which also leads to
dumping the metadata inodes twice as we only determine their actual type
in the second pass and not as part of the AGI scan.

Switch to passing down the mount and dinode as far as possible, and then
use a helper to determine the type only when it actually is needed.  With
that we can simply add the data for dump for the metadata inodes to the
normal AGI scan and remove the second pass.

Signed-off-by: Christoph Hellwig <hch@lst.de>
db/metadump.c

index 212bcad6f6b3bb00e20da43f8ffbe4c898f6b48f..f16383c7fa6595e9438e0d41f1eb8cf4832296dc 100644 (file)
@@ -1155,6 +1155,15 @@ add_remap:
                free(orig_name);
 }
 
+static inline bool
+is_metadir_ino(
+       struct xfs_dinode       *dip)
+{
+       if (!xfs_has_metadir(mp) || dip->di_version < 3)
+               return false;
+       return dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADIR);
+}
+
 static inline bool
 want_obfuscate_dirents(bool is_meta)
 {
@@ -1163,9 +1172,9 @@ want_obfuscate_dirents(bool is_meta)
 
 static void
 process_sf_dir(
-       struct xfs_dinode       *dip,
-       bool                    is_meta)
+       struct xfs_dinode       *dip)
 {
+       bool                    is_meta = is_metadir_ino(dip);
        struct xfs_dir2_sf_hdr  *sfp;
        xfs_dir2_sf_entry_t     *sfep;
        uint64_t                ino_dir_size;
@@ -1397,16 +1406,15 @@ want_obfuscate_attr(
        return true;
 }
 
+/*
+ * Obfuscate the attr names and fill the actual values with 'v' (to see a valid
+ * string length, as opposed to NULLs).
+ */
 static void
 process_sf_attr(
-       struct xfs_dinode               *dip,
-       bool                            is_meta)
+       struct xfs_dinode               *dip)
 {
-       /*
-        * with extended attributes, obfuscate the names and fill the actual
-        * values with 'v' (to see a valid string length, as opposed to NULLs)
-        */
-
+       bool                            is_meta = is_metadir_ino(dip);
        struct xfs_attr_sf_hdr          *hdr = XFS_DFORK_APTR(dip);
        struct xfs_attr_sf_entry        *asfep = libxfs_attr_sf_firstentry(hdr);
        int                             ino_attr_size;
@@ -2079,6 +2087,38 @@ out_pop:
        return rval;
 }
 
+static typnm_t
+ifork_data_type(
+       struct xfs_dinode       *dip,
+       int                     whichfork)
+{
+       xfs_ino_t               ino = be64_to_cpu(dip->di_ino);
+
+       if (whichfork == XFS_ATTR_FORK)
+               return TYP_ATTR;
+
+       switch (be16_to_cpu(dip->di_mode) & S_IFMT) {
+       case S_IFDIR:
+               return TYP_DIR2;
+       case S_IFLNK:
+               return TYP_SYMLINK;
+       case S_IFREG:
+               if (ino == mp->m_sb.sb_rbmino)
+                       return TYP_RTBITMAP;
+               if (ino == mp->m_sb.sb_rsumino)
+                       return TYP_RTSUMMARY;
+               if (ino == mp->m_sb.sb_uquotino)
+                       return TYP_DQBLK;
+               if (ino == mp->m_sb.sb_gquotino)
+                       return TYP_DQBLK;
+               if (ino == mp->m_sb.sb_pquotino)
+                       return TYP_DQBLK;
+               return TYP_DATA;
+       default:
+               return TYP_NONE;
+       }
+}
+
 static bool
 is_multi_fsb_object(
        struct xfs_mount        *mp,
@@ -2114,11 +2154,13 @@ process_multi_fsb_objects(
 /* inode copy routines */
 static int
 process_bmbt_reclist(
-       xfs_bmbt_rec_t          *rp,
-       int                     numrecs,
-       typnm_t                 btype,
-       bool                    is_meta)
+       struct xfs_dinode       *dip,
+       int                     whichfork,
+       struct xfs_bmbt_rec     *rp,
+       int                     numrecs)
 {
+       bool                    is_meta = is_metadir_ino(dip);
+       typnm_t                 btype = ifork_data_type(dip, whichfork);
        int                     i;
        xfs_fileoff_t           o, op = NULLFILEOFF;
        xfs_fsblock_t           s;
@@ -2127,7 +2169,6 @@ process_bmbt_reclist(
        xfs_fileoff_t           last;
        xfs_agnumber_t          agno;
        xfs_agblock_t           agbno;
-       bool                    is_multi_fsb = is_multi_fsb_object(mp, btype);
        int                     rval = 1;
 
        if (btype == TYP_DATA)
@@ -2195,7 +2236,7 @@ process_bmbt_reclist(
                }
 
                /* multi-extent blocks require special handling */
-               if (is_multi_fsb)
+               if (is_multi_fsb_object(mp, btype))
                        rval = process_multi_fsb_objects(o, s, c, btype,
                                        last, is_meta);
                else
@@ -2209,8 +2250,8 @@ process_bmbt_reclist(
 }
 
 struct scan_bmap {
-       enum typnm      typ;
-       bool            is_meta;
+       struct xfs_dinode *dip;
+       int             whichfork;
 };
 
 static int
@@ -2220,7 +2261,7 @@ scanfunc_bmap(
        xfs_agblock_t           agbno,
        int                     level,
        typnm_t                 btype,
-       void                    *arg)   /* ptr to itype */
+       void                    *arg)
 {
        struct scan_bmap        *sbm = arg;
        int                     i;
@@ -2237,8 +2278,8 @@ scanfunc_bmap(
                                        typtab[btype].name, agno, agbno);
                        return 1;
                }
-               return process_bmbt_reclist(xfs_bmbt_rec_addr(mp, block, 1),
-                                           nrecs, sbm->typ, sbm->is_meta);
+               return process_bmbt_reclist(sbm->dip, sbm->whichfork,
+                               xfs_bmbt_rec_addr(mp, block, 1), nrecs);
        }
 
        if (nrecs > mp->m_bmap_dmxr[1]) {
@@ -2270,36 +2311,20 @@ scanfunc_bmap(
        return 1;
 }
 
-static inline bool
-is_metadata_ino(
-       struct xfs_dinode       *dip)
-{
-       return xfs_has_metadir(mp) &&
-                       dip->di_version >= 3 &&
-                       (dip->di_flags2 & cpu_to_be64(XFS_DIFLAG2_METADIR));
-}
-
 static int
 process_btinode(
        struct xfs_dinode       *dip,
-       typnm_t                 itype)
+       int                     whichfork)
 {
-       xfs_bmdr_block_t        *dib;
-       int                     i;
-       xfs_bmbt_ptr_t          *pp;
-       int                     level;
-       int                     nrecs;
+       struct xfs_bmdr_block   *dib =
+               (struct xfs_bmdr_block *)XFS_DFORK_PTR(dip, whichfork);
+       int                     level = be16_to_cpu(dib->bb_level);
+       int                     nrecs = be16_to_cpu(dib->bb_numrecs);
        int                     maxrecs;
-       int                     whichfork;
-       typnm_t                 btype;
-       bool                    is_meta = is_metadata_ino(dip);
-
-       whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK;
-       btype = (itype == TYP_ATTR) ? TYP_BMAPBTA : TYP_BMAPBTD;
-
-       dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
-       level = be16_to_cpu(dib->bb_level);
-       nrecs = be16_to_cpu(dib->bb_numrecs);
+       typnm_t                 btype = (whichfork == XFS_ATTR_FORK) ?
+               TYP_BMAPBTA : TYP_BMAPBTD;
+       xfs_bmbt_ptr_t          *pp;
+       int                     i;
 
        if (level > XFS_BM_MAXLEVELS(mp, whichfork)) {
                if (metadump.show_warnings)
@@ -2310,8 +2335,9 @@ process_btinode(
        }
 
        if (level == 0) {
-               return process_bmbt_reclist(xfs_bmdr_rec_addr(dib, 1),
-                                           nrecs, itype, is_meta);
+               return process_bmbt_reclist(dip, whichfork,
+                               xfs_bmdr_rec_addr(dib, 1),
+                               nrecs);
        }
 
        maxrecs = libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0);
@@ -2339,8 +2365,8 @@ process_btinode(
 
        for (i = 0; i < nrecs; i++) {
                struct scan_bmap        sbm = {
-                       .typ = itype,
-                       .is_meta = is_meta,
+                       .dip = dip,
+                       .whichfork = whichfork,
                };
                xfs_agnumber_t  ag;
                xfs_agblock_t   bno;
@@ -2367,20 +2393,13 @@ process_btinode(
 static int
 process_exinode(
        struct xfs_dinode       *dip,
-       typnm_t                 itype)
+       int                     whichfork)
 {
-       int                     whichfork;
-       int                     used;
-       xfs_extnum_t            nex, max_nex;
-       bool                    is_meta = is_metadata_ino(dip);
-
-       whichfork = (itype == TYP_ATTR) ? XFS_ATTR_FORK : XFS_DATA_FORK;
+       xfs_extnum_t            max_nex = xfs_iext_max_nextents(
+                       xfs_dinode_has_large_extent_counts(dip), whichfork);
+       xfs_extnum_t            nex = xfs_dfork_nextents(dip, whichfork);
+       int                     used = nex * sizeof(struct xfs_bmbt_rec);
 
-       nex = xfs_dfork_nextents(dip, whichfork);
-       max_nex = xfs_iext_max_nextents(
-                       xfs_dinode_has_large_extent_counts(dip),
-                       whichfork);
-       used = nex * sizeof(xfs_bmbt_rec_t);
        if (nex > max_nex || used > XFS_DFORK_SIZE(dip, mp, whichfork)) {
                if (metadump.show_warnings)
                        print_warning("bad number of extents %llu in inode %lld",
@@ -2396,36 +2415,24 @@ process_exinode(
                       XFS_DFORK_SIZE(dip, mp, whichfork) - used);
 
 
-       return process_bmbt_reclist((xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip,
-                                       whichfork), nex, itype, is_meta);
+       return process_bmbt_reclist(dip, whichfork,
+                       (struct xfs_bmbt_rec *)XFS_DFORK_PTR(dip, whichfork),
+                       nex);
 }
 
 static int
 process_rtrmap(
-       struct xfs_dinode       *dip,
-       typnm_t                 itype)
+       struct xfs_dinode       *dip)
 {
-       struct xfs_rtrmap_root  *dib;
-       int                     i;
-       xfs_rtrmap_ptr_t        *pp;
-       int                     level;
-       int                     nrecs;
+       int                     whichfork = XFS_DATA_FORK;
+       struct xfs_rtrmap_root  *dib =
+               (struct xfs_rtrmap_root *)XFS_DFORK_PTR(dip, whichfork);
+       int                     level = be16_to_cpu(dib->bb_level);
+       int                     nrecs = be16_to_cpu(dib->bb_numrecs);
+       typnm_t                 btype = TYP_RTRMAPBT;
        int                     maxrecs;
-       int                     whichfork;
-       typnm_t                 btype;
-
-       if (itype == TYP_ATTR && metadump.show_warnings) {
-               print_warning("ignoring rtrmapbt root in inode %llu attr fork",
-                               (unsigned long long)metadump.cur_ino);
-               return 1;
-       }
-
-       whichfork = XFS_DATA_FORK;
-       btype = TYP_RTRMAPBT;
-
-       dib = (struct xfs_rtrmap_root *)XFS_DFORK_PTR(dip, whichfork);
-       level = be16_to_cpu(dib->bb_level);
-       nrecs = be16_to_cpu(dib->bb_numrecs);
+       xfs_rtrmap_ptr_t        *pp;
+       int                     i;
 
        if (level > mp->m_rtrmap_maxlevels) {
                if (metadump.show_warnings)
@@ -2470,8 +2477,7 @@ process_rtrmap(
                        continue;
                }
 
-               if (!scan_btree(ag, bno, level, btype, &itype,
-                               scanfunc_rtrmapbt))
+               if (!scan_btree(ag, bno, level, btype, NULL, scanfunc_rtrmapbt))
                        return 0;
        }
        return 1;
@@ -2479,30 +2485,17 @@ process_rtrmap(
 
 static int
 process_rtrefc(
-       struct xfs_dinode       *dip,
-       typnm_t                 itype)
+       struct xfs_dinode       *dip)
 {
-       struct xfs_rtrefcount_root      *dib;
-       int                     i;
-       xfs_rtrefcount_ptr_t    *pp;
-       int                     level;
-       int                     nrecs;
+       int                     whichfork = XFS_DATA_FORK;
+       struct xfs_rtrefcount_root *dib =
+               (struct xfs_rtrefcount_root *)XFS_DFORK_PTR(dip, whichfork);
+       int                     level = be16_to_cpu(dib->bb_level);
+       int                     nrecs = be16_to_cpu(dib->bb_numrecs);
+       typnm_t                 btype = TYP_RTREFCBT;
        int                     maxrecs;
-       int                     whichfork;
-       typnm_t                 btype;
-
-       if (itype == TYP_ATTR && metadump.show_warnings) {
-               print_warning("ignoring rtrefcbt root in inode %llu attr fork",
-                               (unsigned long long)metadump.cur_ino);
-               return 1;
-       }
-
-       whichfork = XFS_DATA_FORK;
-       btype = TYP_RTREFCBT;
-
-       dib = (struct xfs_rtrefcount_root *)XFS_DFORK_PTR(dip, whichfork);
-       level = be16_to_cpu(dib->bb_level);
-       nrecs = be16_to_cpu(dib->bb_numrecs);
+       xfs_rtrefcount_ptr_t    *pp;
+       int                     i;
 
        if (level > mp->m_rtrefc_maxlevels) {
                if (metadump.show_warnings)
@@ -2547,8 +2540,7 @@ process_rtrefc(
                        continue;
                }
 
-               if (!scan_btree(ag, bno, level, btype, &itype,
-                               scanfunc_rtrefcbt))
+               if (!scan_btree(ag, bno, level, btype, NULL, scanfunc_rtrefcbt))
                        return 0;
        }
        return 1;
@@ -2556,54 +2548,45 @@ process_rtrefc(
 
 static int
 process_inode_data(
-       struct xfs_dinode       *dip,
-       typnm_t                 itype)
+       struct xfs_dinode       *dip)
 {
-       bool                    is_meta = is_metadata_ino(dip);
-
        switch (dip->di_format) {
-               case XFS_DINODE_FMT_LOCAL:
-                       if (!(metadump.obfuscate || metadump.zero_stale_data))
-                               break;
+       case XFS_DINODE_FMT_LOCAL:
+               if (!(metadump.obfuscate || metadump.zero_stale_data))
+                       break;
 
-                       /*
-                        * If the fork size is invalid, we can't safely do
-                        * anything with this fork. Leave it alone to preserve
-                        * the information for diagnostic purposes.
-                        */
-                       if (XFS_DFORK_DSIZE(dip, mp) > XFS_LITINO(mp)) {
-                               print_warning(
+               /*
+                * If the fork size is invalid, we can't safely do
+                * anything with this fork. Leave it alone to preserve
+                * the information for diagnostic purposes.
+                */
+               if (XFS_DFORK_DSIZE(dip, mp) > XFS_LITINO(mp)) {
+                       print_warning(
 "Invalid data fork size (%d) in inode %llu, preserving contents!",
-                                               XFS_DFORK_DSIZE(dip, mp),
-                                               (long long)metadump.cur_ino);
-                               break;
-                       }
-
-                       switch (itype) {
-                               case TYP_DIR2:
-                                       process_sf_dir(dip, is_meta);
-                                       break;
-
-                               case TYP_SYMLINK:
-                                       process_sf_symlink(dip);
-                                       break;
-
-                               default:
-                                       break;
-                       }
+                                       XFS_DFORK_DSIZE(dip, mp),
+                                       (long long)metadump.cur_ino);
                        break;
+               }
 
-               case XFS_DINODE_FMT_EXTENTS:
-                       return process_exinode(dip, itype);
-
-               case XFS_DINODE_FMT_BTREE:
-                       return process_btinode(dip, itype);
-
-               case XFS_DINODE_FMT_RMAP:
-                       return process_rtrmap(dip, itype);
-
-               case XFS_DINODE_FMT_REFCOUNT:
-                       return process_rtrefc(dip, itype);
+               switch (be16_to_cpu(dip->di_mode) & S_IFMT) {
+               case S_IFDIR:
+                       process_sf_dir(dip);
+                       break;
+               case S_IFLNK:
+                       process_sf_symlink(dip);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case XFS_DINODE_FMT_EXTENTS:
+               return process_exinode(dip, XFS_DATA_FORK);
+       case XFS_DINODE_FMT_BTREE:
+               return process_btinode(dip, XFS_DATA_FORK);
+       case XFS_DINODE_FMT_RMAP:
+               return process_rtrmap(dip);
+       case XFS_DINODE_FMT_REFCOUNT:
+               return process_rtrefc(dip);
        }
        return 1;
 }
@@ -2676,28 +2659,22 @@ process_inode(
 
        /* copy appropriate data fork metadata */
        switch (be16_to_cpu(dip->di_mode) & S_IFMT) {
-               case S_IFDIR:
-                       rval = process_inode_data(dip, TYP_DIR2);
-                       if (dip->di_format == XFS_DINODE_FMT_LOCAL)
-                               need_new_crc = true;
-                       break;
-               case S_IFLNK:
-                       rval = process_inode_data(dip, TYP_SYMLINK);
-                       if (dip->di_format == XFS_DINODE_FMT_LOCAL)
-                               need_new_crc = true;
-                       break;
-               case S_IFREG:
-                       rval = process_inode_data(dip, TYP_DATA);
-                       break;
-               case S_IFIFO:
-               case S_IFCHR:
-               case S_IFBLK:
-               case S_IFSOCK:
-                       process_dev_inode(dip);
+       case S_IFDIR:
+       case S_IFLNK:
+       case S_IFREG:
+               rval = process_inode_data(dip);
+               if (dip->di_format == XFS_DINODE_FMT_LOCAL)
                        need_new_crc = true;
-                       break;
-               default:
-                       break;
+               break;
+       case S_IFIFO:
+       case S_IFCHR:
+       case S_IFBLK:
+       case S_IFSOCK:
+               process_dev_inode(dip);
+               need_new_crc = true;
+               break;
+       default:
+               break;
        }
        nametable_clear();
        if (!rval)
@@ -2705,24 +2682,20 @@ process_inode(
 
        /* copy extended attributes if they exist and forkoff is valid */
        if (XFS_DFORK_DSIZE(dip, mp) < XFS_LITINO(mp)) {
-               bool    is_meta = is_metadata_ino(dip);
-
                attr_data.remote_val_count = 0;
                switch (dip->di_aformat) {
-                       case XFS_DINODE_FMT_LOCAL:
-                               need_new_crc = true;
-                               if (metadump.obfuscate ||
-                                   metadump.zero_stale_data)
-                                       process_sf_attr(dip, is_meta);
-                               break;
-
-                       case XFS_DINODE_FMT_EXTENTS:
-                               rval = process_exinode(dip, TYP_ATTR);
-                               break;
-
-                       case XFS_DINODE_FMT_BTREE:
-                               rval = process_btinode(dip, TYP_ATTR);
-                               break;
+               case XFS_DINODE_FMT_LOCAL:
+                       need_new_crc = true;
+                       if (metadump.obfuscate ||
+                           metadump.zero_stale_data)
+                               process_sf_attr(dip);
+                       break;
+               case XFS_DINODE_FMT_EXTENTS:
+                       rval = process_exinode(dip, XFS_ATTR_FORK);
+                       break;
+               case XFS_DINODE_FMT_BTREE:
+                       rval = process_btinode(dip, XFS_ATTR_FORK);
+                       break;
                }
                nametable_clear();
        }
@@ -3099,70 +3072,6 @@ pop_out:
        return rval;
 }
 
-static int
-copy_ino(
-       xfs_ino_t               ino,
-       typnm_t                 itype)
-{
-       xfs_agnumber_t          agno;
-       xfs_agblock_t           agbno;
-       xfs_agino_t             agino;
-       int                     offset;
-       int                     rval = 1;
-
-       if (ino == 0 || ino == NULLFSINO)
-               return 1;
-
-       agno = XFS_INO_TO_AGNO(mp, ino);
-       agino = XFS_INO_TO_AGINO(mp, ino);
-       agbno = XFS_AGINO_TO_AGBNO(mp, agino);
-       offset = XFS_AGINO_TO_OFFSET(mp, agino);
-
-       if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
-                       offset >= mp->m_sb.sb_inopblock) {
-               if (metadump.show_warnings)
-                       print_warning("invalid %s inode number (%lld)",
-                                       typtab[itype].name, (long long)ino);
-               return 1;
-       }
-
-       push_cur();
-       set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, agbno),
-                       blkbb, DB_RING_IGN, NULL);
-       if (iocur_top->data == NULL) {
-               print_warning("cannot read %s inode %lld",
-                               typtab[itype].name, (long long)ino);
-               rval = !metadump.stop_on_read_error;
-               goto pop_out;
-       }
-       off_cur(offset << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize);
-
-       metadump.cur_ino = ino;
-       rval = process_inode_data(iocur_top->data, itype);
-pop_out:
-       pop_cur();
-       return rval;
-}
-
-
-static int
-copy_sb_inodes(void)
-{
-       if (!copy_ino(mp->m_sb.sb_rbmino, TYP_RTBITMAP))
-               return 0;
-
-       if (!copy_ino(mp->m_sb.sb_rsumino, TYP_RTSUMMARY))
-               return 0;
-
-       if (!copy_ino(mp->m_sb.sb_uquotino, TYP_DQBLK))
-               return 0;
-
-       if (!copy_ino(mp->m_sb.sb_gquotino, TYP_DQBLK))
-               return 0;
-
-       return copy_ino(mp->m_sb.sb_pquotino, TYP_DQBLK);
-}
-
 static int
 copy_log(void)
 {
@@ -3644,10 +3553,6 @@ metadump_f(
                }
        }
 
-       /* copy realtime and quota inode contents */
-       if (!exitcode)
-               exitcode = !copy_sb_inodes();
-
        /* copy log */
        if (!exitcode && !(metadump.version == 1 && metadump.external_log))
                exitcode = !copy_log();