Skip to content

Commit b742d7b

Browse files
Dave ChinnerDarrick J. Wong
authored andcommitted
xfs: use deferred frees for btree block freeing
Btrees that aren't freespace management trees use the normal extent allocation and freeing routines for their blocks. Hence when a btree block is freed, a direct call to xfs_free_extent() is made and the extent is immediately freed. This puts the entire free space management btrees under this path, so we are stacking btrees on btrees in the call stack. The inobt, finobt and refcount btrees all do this. However, the bmap btree does not do this - it calls xfs_free_extent_later() to defer the extent free operation via an XEFI and hence it gets processed in deferred operation processing during the commit of the primary transaction (i.e. via intent chaining). We need to change xfs_free_extent() to behave in a non-blocking manner so that we can avoid deadlocks with busy extents near ENOSPC in transactions that free multiple extents. Inserting or removing a record from a btree can cause a multi-level tree merge operation and that will free multiple blocks from the btree in a single transaction. i.e. we can call xfs_free_extent() multiple times, and hence the btree manipulation transaction is vulnerable to this busy extent deadlock vector. To fix this, convert all the remaining callers of xfs_free_extent() to use xfs_free_extent_later() to queue XEFIs and hence defer processing of the extent frees to a context that can be safely restarted if a deadlock condition is detected. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Chandan Babu R <chandan.babu@oracle.com>
1 parent 939bd50 commit b742d7b

File tree

11 files changed

+33
-26
lines changed

11 files changed

+33
-26
lines changed

fs/xfs/libxfs/xfs_ag.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,7 @@ xfs_ag_shrink_space(
985985
goto resv_err;
986986

987987
err2 = __xfs_free_extent_later(*tpp, args.fsbno, delta, NULL,
988-
true);
988+
XFS_AG_RESV_NONE, true);
989989
if (err2)
990990
goto resv_err;
991991

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,6 +2449,7 @@ xfs_defer_agfl_block(
24492449
xefi->xefi_startblock = XFS_AGB_TO_FSB(mp, agno, agbno);
24502450
xefi->xefi_blockcount = 1;
24512451
xefi->xefi_owner = oinfo->oi_owner;
2452+
xefi->xefi_agresv = XFS_AG_RESV_AGFL;
24522453

24532454
if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbno(mp, xefi->xefi_startblock)))
24542455
return -EFSCORRUPTED;
@@ -2470,6 +2471,7 @@ __xfs_free_extent_later(
24702471
xfs_fsblock_t bno,
24712472
xfs_filblks_t len,
24722473
const struct xfs_owner_info *oinfo,
2474+
enum xfs_ag_resv_type type,
24732475
bool skip_discard)
24742476
{
24752477
struct xfs_extent_free_item *xefi;
@@ -2490,6 +2492,7 @@ __xfs_free_extent_later(
24902492
ASSERT(agbno + len <= mp->m_sb.sb_agblocks);
24912493
#endif
24922494
ASSERT(xfs_extfree_item_cache != NULL);
2495+
ASSERT(type != XFS_AG_RESV_AGFL);
24932496

24942497
if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbext(mp, bno, len)))
24952498
return -EFSCORRUPTED;
@@ -2498,6 +2501,7 @@ __xfs_free_extent_later(
24982501
GFP_KERNEL | __GFP_NOFAIL);
24992502
xefi->xefi_startblock = bno;
25002503
xefi->xefi_blockcount = (xfs_extlen_t)len;
2504+
xefi->xefi_agresv = type;
25012505
if (skip_discard)
25022506
xefi->xefi_flags |= XFS_EFI_SKIP_DISCARD;
25032507
if (oinfo) {

fs/xfs/libxfs/xfs_alloc.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ xfs_buf_to_agfl_bno(
232232

233233
int __xfs_free_extent_later(struct xfs_trans *tp, xfs_fsblock_t bno,
234234
xfs_filblks_t len, const struct xfs_owner_info *oinfo,
235-
bool skip_discard);
235+
enum xfs_ag_resv_type type, bool skip_discard);
236236

237237
/*
238238
* List of extents to be free "later".
@@ -245,6 +245,7 @@ struct xfs_extent_free_item {
245245
xfs_extlen_t xefi_blockcount;/* number of blocks in extent */
246246
struct xfs_perag *xefi_pag;
247247
unsigned int xefi_flags;
248+
enum xfs_ag_resv_type xefi_agresv;
248249
};
249250

250251
void xfs_extent_free_get_group(struct xfs_mount *mp,
@@ -259,9 +260,10 @@ xfs_free_extent_later(
259260
struct xfs_trans *tp,
260261
xfs_fsblock_t bno,
261262
xfs_filblks_t len,
262-
const struct xfs_owner_info *oinfo)
263+
const struct xfs_owner_info *oinfo,
264+
enum xfs_ag_resv_type type)
263265
{
264-
return __xfs_free_extent_later(tp, bno, len, oinfo, false);
266+
return __xfs_free_extent_later(tp, bno, len, oinfo, type, false);
265267
}
266268

267269

fs/xfs/libxfs/xfs_bmap.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,8 @@ xfs_bmap_btree_to_extents(
574574
return error;
575575

576576
xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork);
577-
error = xfs_free_extent_later(cur->bc_tp, cbno, 1, &oinfo);
577+
error = xfs_free_extent_later(cur->bc_tp, cbno, 1, &oinfo,
578+
XFS_AG_RESV_NONE);
578579
if (error)
579580
return error;
580581

@@ -5236,8 +5237,9 @@ xfs_bmap_del_extent_real(
52365237
} else {
52375238
error = __xfs_free_extent_later(tp, del->br_startblock,
52385239
del->br_blockcount, NULL,
5239-
(bflags & XFS_BMAPI_NODISCARD) ||
5240-
del->br_state == XFS_EXT_UNWRITTEN);
5240+
XFS_AG_RESV_NONE,
5241+
((bflags & XFS_BMAPI_NODISCARD) ||
5242+
del->br_state == XFS_EXT_UNWRITTEN));
52415243
if (error)
52425244
goto done;
52435245
}

fs/xfs/libxfs/xfs_bmap_btree.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ xfs_bmbt_free_block(
271271
int error;
272272

273273
xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_ino.whichfork);
274-
error = xfs_free_extent_later(cur->bc_tp, fsbno, 1, &oinfo);
274+
error = xfs_free_extent_later(cur->bc_tp, fsbno, 1, &oinfo,
275+
XFS_AG_RESV_NONE);
275276
if (error)
276277
return error;
277278

fs/xfs/libxfs/xfs_ialloc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1853,8 +1853,8 @@ xfs_difree_inode_chunk(
18531853
/* not sparse, calculate extent info directly */
18541854
return xfs_free_extent_later(tp,
18551855
XFS_AGB_TO_FSB(mp, agno, sagbno),
1856-
M_IGEO(mp)->ialloc_blks,
1857-
&XFS_RMAP_OINFO_INODES);
1856+
M_IGEO(mp)->ialloc_blks, &XFS_RMAP_OINFO_INODES,
1857+
XFS_AG_RESV_NONE);
18581858
}
18591859

18601860
/* holemask is only 16-bits (fits in an unsigned long) */
@@ -1899,8 +1899,8 @@ xfs_difree_inode_chunk(
18991899
ASSERT(agbno % mp->m_sb.sb_spino_align == 0);
19001900
ASSERT(contigblk % mp->m_sb.sb_spino_align == 0);
19011901
error = xfs_free_extent_later(tp,
1902-
XFS_AGB_TO_FSB(mp, agno, agbno),
1903-
contigblk, &XFS_RMAP_OINFO_INODES);
1902+
XFS_AGB_TO_FSB(mp, agno, agbno), contigblk,
1903+
&XFS_RMAP_OINFO_INODES, XFS_AG_RESV_NONE);
19041904
if (error)
19051905
return error;
19061906

fs/xfs/libxfs/xfs_ialloc_btree.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,7 @@ __xfs_inobt_free_block(
160160

161161
xfs_inobt_mod_blockcount(cur, -1);
162162
fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, xfs_buf_daddr(bp));
163-
return xfs_free_extent(cur->bc_tp, cur->bc_ag.pag,
164-
XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1,
163+
return xfs_free_extent_later(cur->bc_tp, fsbno, 1,
165164
&XFS_RMAP_OINFO_INOBT, resv);
166165
}
167166

fs/xfs/libxfs/xfs_refcount.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,8 @@ xfs_refcount_adjust_extents(
11521152
cur->bc_ag.pag->pag_agno,
11531153
tmp.rc_startblock);
11541154
error = xfs_free_extent_later(cur->bc_tp, fsbno,
1155-
tmp.rc_blockcount, NULL);
1155+
tmp.rc_blockcount, NULL,
1156+
XFS_AG_RESV_NONE);
11561157
if (error)
11571158
goto out_error;
11581159
}
@@ -1213,7 +1214,8 @@ xfs_refcount_adjust_extents(
12131214
cur->bc_ag.pag->pag_agno,
12141215
ext.rc_startblock);
12151216
error = xfs_free_extent_later(cur->bc_tp, fsbno,
1216-
ext.rc_blockcount, NULL);
1217+
ext.rc_blockcount, NULL,
1218+
XFS_AG_RESV_NONE);
12171219
if (error)
12181220
goto out_error;
12191221
}
@@ -1981,7 +1983,8 @@ xfs_refcount_recover_cow_leftovers(
19811983

19821984
/* Free the block. */
19831985
error = xfs_free_extent_later(tp, fsb,
1984-
rr->rr_rrec.rc_blockcount, NULL);
1986+
rr->rr_rrec.rc_blockcount, NULL,
1987+
XFS_AG_RESV_NONE);
19851988
if (error)
19861989
goto out_trans;
19871990

fs/xfs/libxfs/xfs_refcount_btree.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,19 +106,13 @@ xfs_refcountbt_free_block(
106106
struct xfs_buf *agbp = cur->bc_ag.agbp;
107107
struct xfs_agf *agf = agbp->b_addr;
108108
xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp));
109-
int error;
110109

111110
trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_ag.pag->pag_agno,
112111
XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1);
113112
be32_add_cpu(&agf->agf_refcount_blocks, -1);
114113
xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
115-
error = xfs_free_extent(cur->bc_tp, cur->bc_ag.pag,
116-
XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1,
114+
return xfs_free_extent_later(cur->bc_tp, fsbno, 1,
117115
&XFS_RMAP_OINFO_REFC, XFS_AG_RESV_METADATA);
118-
if (error)
119-
return error;
120-
121-
return error;
122116
}
123117

124118
STATIC int

fs/xfs/xfs_extfree_item.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ xfs_trans_free_extent(
365365
agbno, xefi->xefi_blockcount);
366366

367367
error = __xfs_free_extent(tp, xefi->xefi_pag, agbno,
368-
xefi->xefi_blockcount, &oinfo, XFS_AG_RESV_NONE,
368+
xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv,
369369
xefi->xefi_flags & XFS_EFI_SKIP_DISCARD);
370370

371371
/*
@@ -644,6 +644,7 @@ xfs_efi_item_recover(
644644
for (i = 0; i < efip->efi_format.efi_nextents; i++) {
645645
struct xfs_extent_free_item fake = {
646646
.xefi_owner = XFS_RMAP_OWN_UNKNOWN,
647+
.xefi_agresv = XFS_AG_RESV_NONE,
647648
};
648649
struct xfs_extent *extp;
649650

0 commit comments

Comments
 (0)