Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit f2e812c

Browse files
Dave ChinnerChandan Babu R
authored andcommitted
xfs: don't use current->journal_info
syzbot reported an ext4 panic during a page fault where found a journal handle when it didn't expect to find one. The structure it tripped over had a value of 'TRAN' in the first entry in the structure, and that indicates it tripped over a struct xfs_trans instead of a jbd2 handle. The reason for this is that the page fault was taken during a copy-out to a user buffer from an xfs bulkstat operation. XFS uses an "empty" transaction context for bulkstat to do automated metadata buffer cleanup, and so the transaction context is valid across the copyout of the bulkstat info into the user buffer. We are using empty transaction contexts like this in XFS to reduce the risk of failing to release objects we reference during the operation, especially during error handling. Hence we really need to ensure that we can take page faults from these contexts without leaving landmines for the code processing the page fault to trip over. However, this same behaviour could happen from any other filesystem that triggers a page fault or any other exception that is handled on-stack from within a task context that has current->journal_info set. Having a page fault from some other filesystem bounce into XFS where we have to run a transaction isn't a bug at all, but the usage of current->journal_info means that this could result corruption of the outer task's journal_info structure. The problem is purely that we now have two different contexts that now think they own current->journal_info. IOWs, no filesystem can allow page faults or on-stack exceptions while current->journal_info is set by the filesystem because the exception processing might use current->journal_info itself. If we end up with nested XFS transactions whilst holding an empty transaction, then it isn't an issue as the outer transaction does not hold a log reservation. If we ignore the current->journal_info usage, then the only problem that might occur is a deadlock if the exception tries to take the same locks the upper context holds. That, however, is not a problem that setting current->journal_info would solve, so it's largely an irrelevant concern here. IOWs, we really only use current->journal_info for a warning check in xfs_vm_writepages() to ensure we aren't doing writeback from a transaction context. Writeback might need to do allocation, so it can need to run transactions itself. Hence it's a debug check to warn us that we've done something silly, and largely it is not all that useful. So let's just remove all the use of current->journal_info in XFS and get rid of all the potential issues from nested contexts where current->journal_info might get misused by another filesystem context. Reported-by: syzbot+cdee56dbcdf0096ef605@syzkaller.appspotmail.com Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: "Darrick J. Wong" <djwong@kernel.org> Reviewed-by: Mark Tinguely <mark.tinguely@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
1 parent 15922f5 commit f2e812c

File tree

4 files changed

+7
-21
lines changed

4 files changed

+7
-21
lines changed

fs/xfs/scrub/common.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,9 +1044,7 @@ xchk_irele(
10441044
struct xfs_scrub *sc,
10451045
struct xfs_inode *ip)
10461046
{
1047-
if (current->journal_info != NULL) {
1048-
ASSERT(current->journal_info == sc->tp);
1049-
1047+
if (sc->tp) {
10501048
/*
10511049
* If we are in a transaction, we /cannot/ drop the inode
10521050
* ourselves, because the VFS will trigger writeback, which

fs/xfs/xfs_aops.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -503,13 +503,6 @@ xfs_vm_writepages(
503503
{
504504
struct xfs_writepage_ctx wpc = { };
505505

506-
/*
507-
* Writing back data in a transaction context can result in recursive
508-
* transactions. This is bad, so issue a warning and get out of here.
509-
*/
510-
if (WARN_ON_ONCE(current->journal_info))
511-
return 0;
512-
513506
xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED);
514507
return iomap_writepages(mapping, wbc, &wpc.ctx, &xfs_writeback_ops);
515508
}

fs/xfs/xfs_icache.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,16 +2039,18 @@ xfs_inodegc_want_queue_work(
20392039
* - Memory shrinkers queued the inactivation worker and it hasn't finished.
20402040
* - The queue depth exceeds the maximum allowable percpu backlog.
20412041
*
2042-
* Note: If the current thread is running a transaction, we don't ever want to
2043-
* wait for other transactions because that could introduce a deadlock.
2042+
* Note: If we are in a NOFS context here (e.g. current thread is running a
2043+
* transaction) the we don't want to block here as inodegc progress may require
2044+
* filesystem resources we hold to make progress and that could result in a
2045+
* deadlock. Hence we skip out of here if we are in a scoped NOFS context.
20442046
*/
20452047
static inline bool
20462048
xfs_inodegc_want_flush_work(
20472049
struct xfs_inode *ip,
20482050
unsigned int items,
20492051
unsigned int shrinker_hits)
20502052
{
2051-
if (current->journal_info)
2053+
if (current->flags & PF_MEMALLOC_NOFS)
20522054
return false;
20532055

20542056
if (shrinker_hits > 0)

fs/xfs/xfs_trans.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -268,30 +268,23 @@ static inline void
268268
xfs_trans_set_context(
269269
struct xfs_trans *tp)
270270
{
271-
ASSERT(current->journal_info == NULL);
272271
tp->t_pflags = memalloc_nofs_save();
273-
current->journal_info = tp;
274272
}
275273

276274
static inline void
277275
xfs_trans_clear_context(
278276
struct xfs_trans *tp)
279277
{
280-
if (current->journal_info == tp) {
281-
memalloc_nofs_restore(tp->t_pflags);
282-
current->journal_info = NULL;
283-
}
278+
memalloc_nofs_restore(tp->t_pflags);
284279
}
285280

286281
static inline void
287282
xfs_trans_switch_context(
288283
struct xfs_trans *old_tp,
289284
struct xfs_trans *new_tp)
290285
{
291-
ASSERT(current->journal_info == old_tp);
292286
new_tp->t_pflags = old_tp->t_pflags;
293287
old_tp->t_pflags = 0;
294-
current->journal_info = new_tp;
295288
}
296289

297290
#endif /* __XFS_TRANS_H__ */

0 commit comments

Comments
 (0)