Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
[cascardo/linux.git] / fs / xfs / libxfs / xfs_bmap_btree.c
index cd85274..8007d2b 100644 (file)
@@ -453,6 +453,7 @@ xfs_bmbt_alloc_block(
 
        if (args.fsbno == NULLFSBLOCK) {
                args.fsbno = be64_to_cpu(start->l);
+try_another_ag:
                args.type = XFS_ALLOCTYPE_START_BNO;
                /*
                 * Make sure there is sufficient room left in the AG to
@@ -482,6 +483,22 @@ xfs_bmbt_alloc_block(
        if (error)
                goto error0;
 
+       /*
+        * During a CoW operation, the allocation and bmbt updates occur in
+        * different transactions.  The mapping code tries to put new bmbt
+        * blocks near extents being mapped, but the only way to guarantee this
+        * is if the alloc and the mapping happen in a single transaction that
+        * has a block reservation.  That isn't the case here, so if we run out
+        * of space we'll try again with another AG.
+        */
+       if (xfs_sb_version_hasreflink(&cur->bc_mp->m_sb) &&
+           args.fsbno == NULLFSBLOCK &&
+           args.type == XFS_ALLOCTYPE_NEAR_BNO) {
+               cur->bc_private.b.dfops->dop_low = true;
+               args.fsbno = cur->bc_private.b.firstblock;
+               goto try_another_ag;
+       }
+
        if (args.fsbno == NULLFSBLOCK && args.minleft) {
                /*
                 * Could not find an AG with enough free space to satisfy
@@ -777,6 +794,7 @@ xfs_bmbt_init_cursor(
 {
        struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
        struct xfs_btree_cur    *cur;
+       ASSERT(whichfork != XFS_COW_FORK);
 
        cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);