]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: collect reverse-mapping data for refcount/rmap tree rebuilding
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 19 Aug 2016 00:05:56 +0000 (10:05 +1000)
committerDave Chinner <david@fromorbit.com>
Fri, 19 Aug 2016 00:05:56 +0000 (10:05 +1000)
Collect reverse-mapping data for the entire filesystem so that we can
later check and rebuild the reference count tree and the reverse mapping
tree.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
repair/Makefile
repair/dinode.c
repair/phase4.c
repair/rmap.c [new file with mode: 0644]
repair/rmap.h [new file with mode: 0644]
repair/xfs_repair.c

index d76c9188feababffaedac7adf48c7a7df7d3553c..b7e8fd5c8aa4cc47c259b8df1c07ce0457de46bb 100644 (file)
@@ -11,13 +11,13 @@ LTCOMMAND = xfs_repair
 
 HFILES = agheader.h attr_repair.h avl.h avl64.h bmap.h btree.h \
        da_util.h dinode.h dir2.h err_protos.h globals.h incore.h protos.h \
-       rt.h progress.h scan.h versions.h prefetch.h slab.h threads.h
+       rt.h progress.h scan.h versions.h prefetch.h rmap.h slab.h threads.h
 
 CFILES = agheader.c attr_repair.c avl.c avl64.c bmap.c btree.c \
        da_util.c dino_chunks.c dinode.c dir2.c globals.c incore.c \
        incore_bmc.c init.c incore_ext.c incore_ino.c phase1.c \
        phase2.c phase3.c phase4.c phase5.c phase6.c phase7.c \
-       progress.c prefetch.c rt.c sb.c scan.c slab.c threads.c \
+       progress.c prefetch.c rmap.c rt.c sb.c scan.c slab.c threads.c \
        versions.c xfs_repair.c
 
 LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBXCMD) $(LIBUUID) \
index c1e60ffa84148b39ff73a9393a6550526554fe29..89163b1ed0637c3f370f71de4899f7bf8b5c6155 100644 (file)
@@ -30,6 +30,8 @@
 #include "attr_repair.h"
 #include "bmap.h"
 #include "threads.h"
+#include "slab.h"
+#include "rmap.h"
 
 /*
  * gettext lookups for translations of strings use mutexes internally to
@@ -779,6 +781,13 @@ _("illegal state %d in block map %" PRIu64 "\n"),
                                        state, b);
                        }
                }
+               if (collect_rmaps) { /* && !check_dups */
+                       error = add_rmap(mp, ino, whichfork, &irec);
+                       if (error)
+                               do_error(
+_("couldn't add reverse mapping\n")
+                                       );
+               }
                *tot += irec.br_blockcount;
        }
        error = 0;
index 1a7d7b5f57b96ff312955fc2ec2adcba1384391c..b4264df95883ecbb0e063854dc3ef8f01f2ba6ca 100644 (file)
 #include "versions.h"
 #include "dir2.h"
 #include "progress.h"
+#include "slab.h"
+#include "rmap.h"
 
+bool collect_rmaps;
 
 /*
  * null out quota inode fields in sb if they point to non-existent inodes.
@@ -170,6 +173,8 @@ phase4(xfs_mount_t *mp)
        int                     ag_hdr_block;
        int                     bstate;
 
+       if (needs_rmap_work(mp))
+               collect_rmaps = true;
        ag_hdr_block = howmany(ag_hdr_len, mp->m_sb.sb_blocksize);
 
        do_log(_("Phase 4 - check for duplicate blocks...\n"));
diff --git a/repair/rmap.c b/repair/rmap.c
new file mode 100644 (file)
index 0000000..e78115e
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2016 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ */
+#include <libxfs.h>
+#include "btree.h"
+#include "err_protos.h"
+#include "libxlog.h"
+#include "incore.h"
+#include "globals.h"
+#include "dinode.h"
+#include "slab.h"
+#include "rmap.h"
+
+#undef RMAP_DEBUG
+
+#ifdef RMAP_DEBUG
+# define dbg_printf(f, a...)  do {printf(f, ## a); fflush(stdout); } while (0)
+#else
+# define dbg_printf(f, a...)
+#endif
+
+/* per-AG rmap object anchor */
+struct xfs_ag_rmap {
+       struct xfs_slab *ar_rmaps;              /* rmap observations, p4 */
+};
+
+static struct xfs_ag_rmap *ag_rmaps;
+
+/*
+ * Compare rmap observations for array sorting.
+ */
+static int
+rmap_compare(
+       const void              *a,
+       const void              *b)
+{
+       const struct xfs_rmap_irec      *pa;
+       const struct xfs_rmap_irec      *pb;
+       __u64                   oa;
+       __u64                   ob;
+
+       pa = a; pb = b;
+       oa = xfs_rmap_irec_offset_pack(pa);
+       ob = xfs_rmap_irec_offset_pack(pb);
+
+       if (pa->rm_startblock < pb->rm_startblock)
+               return -1;
+       else if (pa->rm_startblock > pb->rm_startblock)
+               return 1;
+       else if (pa->rm_owner < pb->rm_owner)
+               return -1;
+       else if (pa->rm_owner > pb->rm_owner)
+               return 1;
+       else if (oa < ob)
+               return -1;
+       else if (oa > ob)
+               return 1;
+       else
+               return 0;
+}
+
+/*
+ * Returns true if we must reconstruct either the reference count or reverse
+ * mapping trees.
+ */
+bool
+needs_rmap_work(
+       struct xfs_mount        *mp)
+{
+       return xfs_sb_version_hasrmapbt(&mp->m_sb);
+}
+
+/*
+ * Initialize per-AG reverse map data.
+ */
+void
+init_rmaps(
+       struct xfs_mount        *mp)
+{
+       xfs_agnumber_t          i;
+       int                     error;
+
+       if (!needs_rmap_work(mp))
+               return;
+
+       ag_rmaps = calloc(mp->m_sb.sb_agcount, sizeof(struct xfs_ag_rmap));
+       if (!ag_rmaps)
+               do_error(_("couldn't allocate per-AG reverse map roots\n"));
+
+       for (i = 0; i < mp->m_sb.sb_agcount; i++) {
+               error = init_slab(&ag_rmaps[i].ar_rmaps,
+                               sizeof(struct xfs_rmap_irec));
+               if (error)
+                       do_error(
+_("Insufficient memory while allocating reverse mapping slabs."));
+       }
+}
+
+/*
+ * Free the per-AG reverse-mapping data.
+ */
+void
+free_rmaps(
+       struct xfs_mount        *mp)
+{
+       xfs_agnumber_t          i;
+
+       if (!needs_rmap_work(mp))
+               return;
+
+       for (i = 0; i < mp->m_sb.sb_agcount; i++)
+               free_slab(&ag_rmaps[i].ar_rmaps);
+       free(ag_rmaps);
+       ag_rmaps = NULL;
+}
+
+/*
+ * Add an observation about a block mapping in an inode's data or attribute
+ * fork for later btree reconstruction.
+ */
+int
+add_rmap(
+       struct xfs_mount        *mp,
+       xfs_ino_t               ino,
+       int                     whichfork,
+       struct xfs_bmbt_irec    *irec)
+{
+       struct xfs_slab         *rmaps;
+       struct xfs_rmap_irec    rmap;
+       xfs_agnumber_t          agno;
+       xfs_agblock_t           agbno;
+
+       if (!needs_rmap_work(mp))
+               return 0;
+
+       agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
+       agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
+       ASSERT(agno != NULLAGNUMBER);
+       ASSERT(agno < mp->m_sb.sb_agcount);
+       ASSERT(agbno + irec->br_blockcount <= mp->m_sb.sb_agblocks);
+       ASSERT(ino != NULLFSINO);
+       ASSERT(whichfork == XFS_DATA_FORK || whichfork == XFS_ATTR_FORK);
+
+       rmaps = ag_rmaps[agno].ar_rmaps;
+       rmap.rm_owner = ino;
+       rmap.rm_offset = irec->br_startoff;
+       rmap.rm_flags = 0;
+       if (whichfork == XFS_ATTR_FORK)
+               rmap.rm_flags |= XFS_RMAP_ATTR_FORK;
+       rmap.rm_startblock = agbno;
+       rmap.rm_blockcount = irec->br_blockcount;
+       if (irec->br_state == XFS_EXT_UNWRITTEN)
+               rmap.rm_flags |= XFS_RMAP_UNWRITTEN;
+       return slab_add(rmaps, &rmap);
+}
+
+#ifdef RMAP_DEBUG
+static void
+dump_rmap(
+       const char              *msg,
+       xfs_agnumber_t          agno,
+       struct xfs_rmap_irec    *rmap)
+{
+       printf("%s: %p agno=%u pblk=%llu own=%lld lblk=%llu len=%u flags=0x%x\n",
+               msg, rmap,
+               (unsigned int)agno,
+               (unsigned long long)rmap->rm_startblock,
+               (unsigned long long)rmap->rm_owner,
+               (unsigned long long)rmap->rm_offset,
+               (unsigned int)rmap->rm_blockcount,
+               (unsigned int)rmap->rm_flags);
+}
+#else
+# define dump_rmap(m, a, r)
+#endif
diff --git a/repair/rmap.h b/repair/rmap.h
new file mode 100644 (file)
index 0000000..0832790
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 Oracle.  All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ */
+#ifndef RMAP_H_
+#define RMAP_H_
+
+extern bool collect_rmaps;
+
+extern bool needs_rmap_work(struct xfs_mount *);
+
+extern void init_rmaps(struct xfs_mount *);
+extern void free_rmaps(struct xfs_mount *);
+
+extern int add_rmap(struct xfs_mount *, xfs_ino_t, int, struct xfs_bmbt_irec *);
+
+#endif /* RMAP_H_ */
index a635ea8918ee3dab10d16453cfcb71f1f07cf3b9..3040c4676751717f2cb9563e293b0b275d0a1957 100644 (file)
@@ -32,6 +32,8 @@
 #include "threads.h"
 #include "progress.h"
 #include "dinode.h"
+#include "slab.h"
+#include "rmap.h"
 
 #define        rounddown(x, y) (((x)/(y))*(y))
 
@@ -898,6 +900,7 @@ main(int argc, char **argv)
        init_bmaps(mp);
        incore_ino_init(mp);
        incore_ext_init(mp);
+       init_rmaps(mp);
 
        /* initialize random globals now that we know the fs geometry */
        inodes_per_block = mp->m_sb.sb_inopblock;
@@ -931,6 +934,7 @@ main(int argc, char **argv)
        /*
         * Done with the block usage maps, toss them...
         */
+       free_rmaps(mp);
        free_bmaps(mp);
 
        if (!bad_ino_btree)  {