]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: reserve enough blocks to handle btree splits when remapping
authorDarrick J. Wong <darrick.wong@oracle.com>
Thu, 11 May 2017 19:01:09 +0000 (14:01 -0500)
committerEric Sandeen <sandeen@redhat.com>
Thu, 11 May 2017 19:01:09 +0000 (14:01 -0500)
Source kernel commit: fe0be23e68200573de027de9b8cc2b27e7fce35e

In xfs_reflink_end_cow, we erroneously reserve only enough blocks to
handle adding 1 extent.  This is problematic if we fragment free space,
have to do CoW, and then have to perform multiple bmap btree expansions.
Furthermore, the BUI recovery routine doesn't reserve /any/ blocks to
handle btree splits, so log recovery fails after our first error causes
the filesystem to go down.

Therefore, refactor the transaction block reservation macros until we
have a macro that works for our deferred (re)mapping activities, and fix
both problems by using that macro.

With 1k blocks we can hit this fairly often in g/187 if the scratch fs
is big enough.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
libxfs/xfs_trans_space.h

index 7917f6e44286a4591e9109138a7be07dc1a18eb1..d787c677d2a3201cc62d042fbee55415923934f6 100644 (file)
 /*
  * Components of space reservations.
  */
+
+/* Worst case number of rmaps that can be held in a block. */
 #define XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp)    \
                (((mp)->m_rmap_mxr[0]) - ((mp)->m_rmap_mnr[0]))
+
+/* Adding one rmap could split every level up to the top of the tree. */
+#define XFS_RMAPADD_SPACE_RES(mp) ((mp)->m_rmap_maxlevels)
+
+/* Blocks we might need to add "b" rmaps to a tree. */
+#define XFS_NRMAPADD_SPACE_RES(mp, b)\
+       (((b + XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp) - 1) / \
+         XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp)) * \
+         XFS_RMAPADD_SPACE_RES(mp))
+
 #define XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)    \
                (((mp)->m_alloc_mxr[0]) - ((mp)->m_alloc_mnr[0]))
 #define        XFS_EXTENTADD_SPACE_RES(mp,w)   (XFS_BM_MAXLEVELS(mp,w) - 1)
        (((b + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) - 1) / \
          XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)) * \
          XFS_EXTENTADD_SPACE_RES(mp,w))
+
+/* Blocks we might need to add "b" mappings & rmappings to a file. */
 #define XFS_SWAP_RMAP_SPACE_RES(mp,b,w)\
-       (((b + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) - 1) / \
-         XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)) * \
-         XFS_EXTENTADD_SPACE_RES(mp,w) + \
-        ((b + XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp) - 1) / \
-         XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp)) * \
-         (mp)->m_rmap_maxlevels)
+       (XFS_NEXTENTADD_SPACE_RES((mp), (b), (w)) + \
+        XFS_NRMAPADD_SPACE_RES((mp), (b)))
+
 #define        XFS_DAENTER_1B(mp,w)    \
        ((w) == XFS_DATA_FORK ? (mp)->m_dir_geo->fsbcount : 1)
 #define        XFS_DAENTER_DBS(mp,w)   \