Skip to content

Commit 756b1c3

Browse files
dgchinnerDarrick J. Wong
authored andcommitted
xfs: use current->journal_info for detecting transaction recursion
Because the iomap code using PF_MEMALLOC_NOFS to detect transaction recursion in XFS is just wrong. Remove it from the iomap code and replace it with XFS specific internal checks using current->journal_info instead. [djwong: This change also realigns the lifetime of NOFS flag changes to match the incore transaction, instead of the inconsistent scheme we have now.] Fixes: 9070733 ("xfs: abstract PF_FSTRANS to PF_MEMALLOC_NOFS") 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: Christoph Hellwig <hch@lst.de>
1 parent 9febcda commit 756b1c3

5 files changed

Lines changed: 60 additions & 26 deletions

File tree

fs/iomap/buffered-io.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,13 +1458,6 @@ iomap_do_writepage(struct page *page, struct writeback_control *wbc, void *data)
14581458
PF_MEMALLOC))
14591459
goto redirty;
14601460

1461-
/*
1462-
* Given that we do not allow direct reclaim to call us, we should
1463-
* never be called in a recursive filesystem reclaim context.
1464-
*/
1465-
if (WARN_ON_ONCE(current->flags & PF_MEMALLOC_NOFS))
1466-
goto redirty;
1467-
14681461
/*
14691462
* Is this page beyond the end of the file?
14701463
*

fs/xfs/libxfs/xfs_btree.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,7 +2805,7 @@ xfs_btree_split_worker(
28052805
struct xfs_btree_split_args *args = container_of(work,
28062806
struct xfs_btree_split_args, work);
28072807
unsigned long pflags;
2808-
unsigned long new_pflags = PF_MEMALLOC_NOFS;
2808+
unsigned long new_pflags = 0;
28092809

28102810
/*
28112811
* we are in a transaction context here, but may also be doing work
@@ -2817,12 +2817,20 @@ xfs_btree_split_worker(
28172817
new_pflags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD;
28182818

28192819
current_set_flags_nested(&pflags, new_pflags);
2820+
xfs_trans_set_context(args->cur->bc_tp);
28202821

28212822
args->result = __xfs_btree_split(args->cur, args->level, args->ptrp,
28222823
args->key, args->curp, args->stat);
2823-
complete(args->done);
28242824

2825+
xfs_trans_clear_context(args->cur->bc_tp);
28252826
current_restore_flags_nested(&pflags, new_pflags);
2827+
2828+
/*
2829+
* Do not access args after complete() has run here. We don't own args
2830+
* and the owner may run and free args before we return here.
2831+
*/
2832+
complete(args->done);
2833+
28262834
}
28272835

28282836
/*

fs/xfs/xfs_aops.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ xfs_setfilesize_trans_alloc(
6262
* We hand off the transaction to the completion thread now, so
6363
* clear the flag here.
6464
*/
65-
current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
65+
xfs_trans_clear_context(tp);
6666
return 0;
6767
}
6868

@@ -125,7 +125,7 @@ xfs_setfilesize_ioend(
125125
* thus we need to mark ourselves as being in a transaction manually.
126126
* Similarly for freeze protection.
127127
*/
128-
current_set_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
128+
xfs_trans_set_context(tp);
129129
__sb_writers_acquired(VFS_I(ip)->i_sb, SB_FREEZE_FS);
130130

131131
/* we abort the update if there was an IO error */
@@ -568,6 +568,12 @@ xfs_vm_writepage(
568568
{
569569
struct xfs_writepage_ctx wpc = { };
570570

571+
if (WARN_ON_ONCE(current->journal_info)) {
572+
redirty_page_for_writepage(wbc, page);
573+
unlock_page(page);
574+
return 0;
575+
}
576+
571577
return iomap_writepage(page, wbc, &wpc.ctx, &xfs_writeback_ops);
572578
}
573579

@@ -578,6 +584,13 @@ xfs_vm_writepages(
578584
{
579585
struct xfs_writepage_ctx wpc = { };
580586

587+
/*
588+
* Writing back data in a transaction context can result in recursive
589+
* transactions. This is bad, so issue a warning and get out of here.
590+
*/
591+
if (WARN_ON_ONCE(current->journal_info))
592+
return 0;
593+
581594
xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED);
582595
return iomap_writepages(mapping, wbc, &wpc.ctx, &xfs_writeback_ops);
583596
}

fs/xfs/xfs_trans.c

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ xfs_trans_free(
7272
xfs_extent_busy_clear(tp->t_mountp, &tp->t_busy, false);
7373

7474
trace_xfs_trans_free(tp, _RET_IP_);
75+
xfs_trans_clear_context(tp);
7576
if (!(tp->t_flags & XFS_TRANS_NO_WRITECOUNT))
7677
sb_end_intwrite(tp->t_mountp->m_super);
7778
xfs_trans_free_dqinfo(tp);
@@ -123,7 +124,8 @@ xfs_trans_dup(
123124

124125
ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used;
125126
tp->t_rtx_res = tp->t_rtx_res_used;
126-
ntp->t_pflags = tp->t_pflags;
127+
128+
xfs_trans_switch_context(tp, ntp);
127129

128130
/* move deferred ops over to the new tp */
129131
xfs_defer_move(ntp, tp);
@@ -157,20 +159,15 @@ xfs_trans_reserve(
157159
int error = 0;
158160
bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
159161

160-
/* Mark this thread as being in a transaction */
161-
current_set_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
162-
163162
/*
164163
* Attempt to reserve the needed disk blocks by decrementing
165164
* the number needed from the number available. This will
166165
* fail if the count would go below zero.
167166
*/
168167
if (blocks > 0) {
169168
error = xfs_mod_fdblocks(mp, -((int64_t)blocks), rsvd);
170-
if (error != 0) {
171-
current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
169+
if (error != 0)
172170
return -ENOSPC;
173-
}
174171
tp->t_blk_res += blocks;
175172
}
176173

@@ -244,9 +241,6 @@ xfs_trans_reserve(
244241
xfs_mod_fdblocks(mp, (int64_t)blocks, rsvd);
245242
tp->t_blk_res = 0;
246243
}
247-
248-
current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
249-
250244
return error;
251245
}
252246

@@ -272,6 +266,7 @@ xfs_trans_alloc(
272266
tp = kmem_cache_zalloc(xfs_trans_zone, GFP_KERNEL | __GFP_NOFAIL);
273267
if (!(flags & XFS_TRANS_NO_WRITECOUNT))
274268
sb_start_intwrite(mp->m_super);
269+
xfs_trans_set_context(tp);
275270

276271
/*
277272
* Zero-reservation ("empty") transactions can't modify anything, so
@@ -900,7 +895,6 @@ __xfs_trans_commit(
900895

901896
xfs_log_commit_cil(mp, tp, &commit_lsn, regrant);
902897

903-
current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
904898
xfs_trans_free(tp);
905899

906900
/*
@@ -932,7 +926,6 @@ __xfs_trans_commit(
932926
xfs_log_ticket_ungrant(mp->m_log, tp->t_ticket);
933927
tp->t_ticket = NULL;
934928
}
935-
current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
936929
xfs_trans_free_items(tp, !!error);
937930
xfs_trans_free(tp);
938931

@@ -992,9 +985,6 @@ xfs_trans_cancel(
992985
tp->t_ticket = NULL;
993986
}
994987

995-
/* mark this thread as no longer being in a transaction */
996-
current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS);
997-
998988
xfs_trans_free_items(tp, dirty);
999989
xfs_trans_free(tp);
1000990
}

fs/xfs/xfs_trans.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,4 +281,34 @@ int xfs_trans_alloc_ichange(struct xfs_inode *ip, struct xfs_dquot *udqp,
281281
struct xfs_dquot *gdqp, struct xfs_dquot *pdqp, bool force,
282282
struct xfs_trans **tpp);
283283

284+
static inline void
285+
xfs_trans_set_context(
286+
struct xfs_trans *tp)
287+
{
288+
ASSERT(current->journal_info == NULL);
289+
tp->t_pflags = memalloc_nofs_save();
290+
current->journal_info = tp;
291+
}
292+
293+
static inline void
294+
xfs_trans_clear_context(
295+
struct xfs_trans *tp)
296+
{
297+
if (current->journal_info == tp) {
298+
memalloc_nofs_restore(tp->t_pflags);
299+
current->journal_info = NULL;
300+
}
301+
}
302+
303+
static inline void
304+
xfs_trans_switch_context(
305+
struct xfs_trans *old_tp,
306+
struct xfs_trans *new_tp)
307+
{
308+
ASSERT(current->journal_info == old_tp);
309+
new_tp->t_pflags = old_tp->t_pflags;
310+
old_tp->t_pflags = 0;
311+
current->journal_info = new_tp;
312+
}
313+
284314
#endif /* __XFS_TRANS_H__ */

0 commit comments

Comments
 (0)