]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: add fixed-location per-AG rmaps
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 19 Aug 2016 00:20:03 +0000 (10:20 +1000)
committerDave Chinner <david@fromorbit.com>
Fri, 19 Aug 2016 00:20:03 +0000 (10:20 +1000)
Add reverse-mappings for fixed-location per-AG metadata such as inode
chunks, superblocks, and the log to the raw rmap list, then merge the
raw rmap data (which also has the BMBT data) into the main rmap list.

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/phase4.c
repair/rmap.c
repair/rmap.h

index b4264df95883ecbb0e063854dc3ef8f01f2ba6ca..8880c91400cfccc48fdbc459119542991ace6fe5 100644 (file)
@@ -157,6 +157,40 @@ process_ags(
        do_inode_prefetch(mp, ag_stride, process_ag_func, true, false);
 }
 
+static void
+check_rmap_btrees(
+       work_queue_t    *wq,
+       xfs_agnumber_t  agno,
+       void            *arg)
+{
+       int             error;
+
+       error = add_fixed_ag_rmap_data(wq->mp, agno);
+       if (error)
+               do_error(
+_("unable to add AG %u metadata reverse-mapping data.\n"), agno);
+
+       error = fold_raw_rmaps(wq->mp, agno);
+       if (error)
+               do_error(
+_("unable to merge AG %u metadata reverse-mapping data.\n"), agno);
+}
+
+static void
+process_rmap_data(
+       struct xfs_mount        *mp)
+{
+       struct work_queue       wq;
+       xfs_agnumber_t          i;
+
+       if (!needs_rmap_work(mp))
+               return;
+
+       create_work_queue(&wq, mp, libxfs_nproc());
+       for (i = 0; i < mp->m_sb.sb_agcount; i++)
+               queue_work(&wq, check_rmap_btrees, i, NULL);
+       destroy_work_queue(&wq);
+}
 
 void
 phase4(xfs_mount_t *mp)
@@ -306,6 +340,13 @@ phase4(xfs_mount_t *mp)
         * already in phase 3.
         */
        process_ags(mp);
+
+       /*
+        * Process all the reverse-mapping data that we collected.  This
+        * involves checking the rmap data against the btree.
+        */
+       process_rmap_data(mp);
+
        print_final_rpt();
 
        /*
index e30e99b3561782c80ee8c6fc414fa610b1d3ca83..8f532fb6eb6b23fa736bc05050fb207df062a236 100644 (file)
@@ -331,6 +331,98 @@ err:
        return error;
 }
 
+static int
+find_first_zero_bit(
+       __uint64_t      mask)
+{
+       int             n;
+       int             b = 0;
+
+       for (n = 0; n < sizeof(mask) * NBBY && (mask & 1); n++, mask >>= 1)
+               b++;
+
+       return b;
+}
+
+static int
+popcnt(
+       __uint64_t      mask)
+{
+       int             n;
+       int             b = 0;
+
+       if (mask == 0)
+               return 0;
+
+       for (n = 0; n < sizeof(mask) * NBBY; n++, mask >>= 1)
+               if (mask & 1)
+                       b++;
+
+       return b;
+}
+
+/*
+ * Add an allocation group's fixed metadata to the rmap list.  This includes
+ * sb/agi/agf/agfl headers, inode chunks, and the log.
+ */
+int
+add_fixed_ag_rmap_data(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          agno)
+{
+       xfs_fsblock_t           fsbno;
+       xfs_agblock_t           agbno;
+       ino_tree_node_t         *ino_rec;
+       xfs_agino_t             agino;
+       int                     error;
+       int                     startidx;
+       int                     nr;
+
+       if (!needs_rmap_work(mp))
+               return 0;
+
+       /* sb/agi/agf/agfl headers */
+       error = add_ag_rmap(mp, agno, 0, XFS_BNO_BLOCK(mp),
+                       XFS_RMAP_OWN_FS);
+       if (error)
+               goto out;
+
+       /* inodes */
+       ino_rec = findfirst_inode_rec(agno);
+       for (; ino_rec != NULL; ino_rec = next_ino_rec(ino_rec)) {
+               if (xfs_sb_version_hassparseinodes(&mp->m_sb)) {
+                       startidx = find_first_zero_bit(ino_rec->ir_sparse);
+                       nr = XFS_INODES_PER_CHUNK - popcnt(ino_rec->ir_sparse);
+               } else {
+                       startidx = 0;
+                       nr = XFS_INODES_PER_CHUNK;
+               }
+               nr /= mp->m_sb.sb_inopblock;
+               if (nr == 0)
+                       nr = 1;
+               agino = ino_rec->ino_startnum + startidx;
+               agbno = XFS_AGINO_TO_AGBNO(mp, agino);
+               if (XFS_AGINO_TO_OFFSET(mp, agino) == 0) {
+                       error = add_ag_rmap(mp, agno, agbno, nr,
+                                       XFS_RMAP_OWN_INODES);
+                       if (error)
+                               goto out;
+               }
+       }
+
+       /* log */
+       fsbno = mp->m_sb.sb_logstart;
+       if (fsbno && XFS_FSB_TO_AGNO(mp, fsbno) == agno) {
+               agbno = XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart);
+               error = add_ag_rmap(mp, agno, agbno, mp->m_sb.sb_logblocks,
+                               XFS_RMAP_OWN_LOG);
+               if (error)
+                       goto out;
+       }
+out:
+       return error;
+}
+
 #ifdef RMAP_DEBUG
 static void
 dump_rmap(
index 6a3a0a43af360b6ea5c2c1ad8497206873b17aa5..f948f25d4f2c5fa62c6b459e354ed12cf05e2c19 100644 (file)
@@ -34,4 +34,6 @@ extern int add_bmbt_rmap(struct xfs_mount *, xfs_ino_t, int, xfs_fsblock_t);
 extern int fold_raw_rmaps(struct xfs_mount *mp, xfs_agnumber_t agno);
 extern bool mergeable_rmaps(struct xfs_rmap_irec *r1, struct xfs_rmap_irec *r2);
 
+extern int add_fixed_ag_rmap_data(struct xfs_mount *, xfs_agnumber_t);
+
 #endif /* RMAP_H_ */