xfs: don't update rmapbt when fixing agfl
authorDarrick J. Wong <darrick.wong@oracle.com>
Wed, 3 Aug 2016 02:19:53 +0000 (12:19 +1000)
committerDave Chinner <david@fromorbit.com>
Wed, 3 Aug 2016 02:19:53 +0000 (12:19 +1000)
Allow a caller of xfs_alloc_fix_freelist to disable rmapbt updates
when fixing the AG freelist.  xfs_repair needs this during phase 5
to be able to adjust the freelist while it's reconstructing the rmap
btree; the missing entries will be added back at the very end of
phase 5 once the AGFL contents settle down.

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>
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_alloc.h

index 73ab1ea1270d6f730f47368b8a3823d03c7bd257..a0dc2999778d3093e0bd417eb58197a9c4682352 100644 (file)
@@ -2090,9 +2090,21 @@ xfs_alloc_fix_freelist(
         * anything other than extra overhead when we need to put more blocks
         * back on the free list? Maybe we should only do this when space is
         * getting low or the AGFL is more than half full?
+        *
+        * The NOSHRINK flag prevents the AGFL from being shrunk if it's too
+        * big; the NORMAP flag prevents AGFL expand/shrink operations from
+        * updating the rmapbt.  Both flags are used in xfs_repair while we're
+        * rebuilding the rmapbt, and neither are used by the kernel.  They're
+        * both required to ensure that rmaps are correctly recorded for the
+        * regenerated AGFL, bnobt, and cntbt.  See repair/phase5.c and
+        * repair/rmap.c in xfsprogs for details.
         */
-       xfs_rmap_ag_owner(&targs.oinfo, XFS_RMAP_OWN_AG);
-       while (pag->pagf_flcount > need) {
+       memset(&targs, 0, sizeof(targs));
+       if (flags & XFS_ALLOC_FLAG_NORMAP)
+               xfs_rmap_skip_owner_update(&targs.oinfo);
+       else
+               xfs_rmap_ag_owner(&targs.oinfo, XFS_RMAP_OWN_AG);
+       while (!(flags & XFS_ALLOC_FLAG_NOSHRINK) && pag->pagf_flcount > need) {
                struct xfs_buf  *bp;
 
                error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);
@@ -2106,10 +2118,8 @@ xfs_alloc_fix_freelist(
                xfs_trans_binval(tp, bp);
        }
 
-       memset(&targs, 0, sizeof(targs));
        targs.tp = tp;
        targs.mp = mp;
-       xfs_rmap_ag_owner(&targs.oinfo, XFS_RMAP_OWN_AG);
        targs.agbp = agbp;
        targs.agno = args->agno;
        targs.alignment = targs.minlen = targs.prod = targs.isfl = 1;
index 360f9e42553612867cfe7f196c33a50a6959292c..6fe2d6b7cfe93e6ed87f999438877e28ebad3ef6 100644 (file)
@@ -54,6 +54,9 @@ typedef unsigned int xfs_alloctype_t;
  */
 #define        XFS_ALLOC_FLAG_TRYLOCK  0x00000001  /* use trylock for buffer locking */
 #define        XFS_ALLOC_FLAG_FREEING  0x00000002  /* indicate caller is freeing extents*/
+#define        XFS_ALLOC_FLAG_NORMAP   0x00000004  /* don't modify the rmapbt */
+#define        XFS_ALLOC_FLAG_NOSHRINK 0x00000008  /* don't shrink the freelist */
+
 
 /*
  * Argument structure for xfs_alloc routines.