aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2016-10-03 12:11:45 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2016-10-05 19:26:28 -0400
commit90e2056d76adc7894a019f5289d259de58065e13 (patch)
treea442c9b59ed16f95f4ba73e19990a2114cdccf0f
parent6fa164b865e44ac1d1ffc9a24ccd442f17acc4f6 (diff)
xfs: try other AGs to allocate a BMBT block
Prior to the introduction of reflink, allocating a block and mapping it into a file was performed in a single transaction with a single block reservation, and the allocator was supposed to find enough blocks to allocate the extent and any BMBT blocks that might be necessary (unless we're low on space). However, due to the way copy on write works, allocation and mapping have been split into two transactions, which means that we must be able to handle the case where we allocate an extent for CoW but that AG runs out of free space before the blocks can be mapped into a file, and the mapping requires a new BMBT block. When this happens, look in one of the other AGs for a BMBT block instead of taking the FS down. The same applies to the functions that convert a data fork to extents and later btree format. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c30
-rw-r--r--fs/xfs/libxfs/xfs_bmap_btree.c17
2 files changed, 47 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 9702f4c112bf..c27344cf38e1 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -753,6 +753,7 @@ xfs_bmap_extents_to_btree(
753 args.type = XFS_ALLOCTYPE_START_BNO; 753 args.type = XFS_ALLOCTYPE_START_BNO;
754 args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino); 754 args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino);
755 } else if (dfops->dop_low) { 755 } else if (dfops->dop_low) {
756try_another_ag:
756 args.type = XFS_ALLOCTYPE_START_BNO; 757 args.type = XFS_ALLOCTYPE_START_BNO;
757 args.fsbno = *firstblock; 758 args.fsbno = *firstblock;
758 } else { 759 } else {
@@ -767,6 +768,21 @@ xfs_bmap_extents_to_btree(
767 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); 768 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
768 return error; 769 return error;
769 } 770 }
771
772 /*
773 * During a CoW operation, the allocation and bmbt updates occur in
774 * different transactions. The mapping code tries to put new bmbt
775 * blocks near extents being mapped, but the only way to guarantee this
776 * is if the alloc and the mapping happen in a single transaction that
777 * has a block reservation. That isn't the case here, so if we run out
778 * of space we'll try again with another AG.
779 */
780 if (xfs_sb_version_hasreflink(&cur->bc_mp->m_sb) &&
781 args.fsbno == NULLFSBLOCK &&
782 args.type == XFS_ALLOCTYPE_NEAR_BNO) {
783 dfops->dop_low = true;
784 goto try_another_ag;
785 }
770 /* 786 /*
771 * Allocation can't fail, the space was reserved. 787 * Allocation can't fail, the space was reserved.
772 */ 788 */
@@ -902,6 +918,7 @@ xfs_bmap_local_to_extents(
902 * file currently fits in an inode. 918 * file currently fits in an inode.
903 */ 919 */
904 if (*firstblock == NULLFSBLOCK) { 920 if (*firstblock == NULLFSBLOCK) {
921try_another_ag:
905 args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino); 922 args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino);
906 args.type = XFS_ALLOCTYPE_START_BNO; 923 args.type = XFS_ALLOCTYPE_START_BNO;
907 } else { 924 } else {
@@ -914,6 +931,19 @@ xfs_bmap_local_to_extents(
914 if (error) 931 if (error)
915 goto done; 932 goto done;
916 933
934 /*
935 * During a CoW operation, the allocation and bmbt updates occur in
936 * different transactions. The mapping code tries to put new bmbt
937 * blocks near extents being mapped, but the only way to guarantee this
938 * is if the alloc and the mapping happen in a single transaction that
939 * has a block reservation. That isn't the case here, so if we run out
940 * of space we'll try again with another AG.
941 */
942 if (xfs_sb_version_hasreflink(&ip->i_mount->m_sb) &&
943 args.fsbno == NULLFSBLOCK &&
944 args.type == XFS_ALLOCTYPE_NEAR_BNO) {
945 goto try_another_ag;
946 }
917 /* Can't fail, the space was reserved. */ 947 /* Can't fail, the space was reserved. */
918 ASSERT(args.fsbno != NULLFSBLOCK); 948 ASSERT(args.fsbno != NULLFSBLOCK);
919 ASSERT(args.len == 1); 949 ASSERT(args.len == 1);
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c
index 37f0d9daafce..8007d2ba9aef 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.c
+++ b/fs/xfs/libxfs/xfs_bmap_btree.c
@@ -453,6 +453,7 @@ xfs_bmbt_alloc_block(
453 453
454 if (args.fsbno == NULLFSBLOCK) { 454 if (args.fsbno == NULLFSBLOCK) {
455 args.fsbno = be64_to_cpu(start->l); 455 args.fsbno = be64_to_cpu(start->l);
456try_another_ag:
456 args.type = XFS_ALLOCTYPE_START_BNO; 457 args.type = XFS_ALLOCTYPE_START_BNO;
457 /* 458 /*
458 * Make sure there is sufficient room left in the AG to 459 * Make sure there is sufficient room left in the AG to
@@ -482,6 +483,22 @@ xfs_bmbt_alloc_block(
482 if (error) 483 if (error)
483 goto error0; 484 goto error0;
484 485
486 /*
487 * During a CoW operation, the allocation and bmbt updates occur in
488 * different transactions. The mapping code tries to put new bmbt
489 * blocks near extents being mapped, but the only way to guarantee this
490 * is if the alloc and the mapping happen in a single transaction that
491 * has a block reservation. That isn't the case here, so if we run out
492 * of space we'll try again with another AG.
493 */
494 if (xfs_sb_version_hasreflink(&cur->bc_mp->m_sb) &&
495 args.fsbno == NULLFSBLOCK &&
496 args.type == XFS_ALLOCTYPE_NEAR_BNO) {
497 cur->bc_private.b.dfops->dop_low = true;
498 args.fsbno = cur->bc_private.b.firstblock;
499 goto try_another_ag;
500 }
501
485 if (args.fsbno == NULLFSBLOCK && args.minleft) { 502 if (args.fsbno == NULLFSBLOCK && args.minleft) {
486 /* 503 /*
487 * Could not find an AG with enough free space to satisfy 504 * Could not find an AG with enough free space to satisfy