2020-09-25 06:16:19

by jing xia

[permalink] [raw]
Subject: [PATCH] fuse: avoid deadlock by clearing __GFP_FS

From: Jing Xia <[email protected]>

Writeback thread and fuse block each other.
Writeback thread waits fuse's reply with inode's I_SYNC being
held.Fuse enters the slowpath of memory allocation when handle
the request and has to wait the inode's I_SYNC is cleared.

writeback's backtrace
---------------------
PID: 6197 TASK: ed130780 CPU: 3 COMMAND: "kworker/u8:7"
#0 [<c0a0bae0>] (__schedule) from [<c0a0bdb0>]
#1 [<c0a0bdb0>] (schedule) from [<c03d1330>]
#2 [<c03d1330>] (__fuse_request_send) from [<c03d16a0>]
#3 [<c03d16a0>] (fuse_simple_request) from [<c03d58fc>]
#4 [<c03d58fc>] (fuse_flush_times) from [<c03d95dc>]
#5 [<c03d95dc>] (fuse_write_inode) from [<c02df87c>]
#6 [<c02df87c>] (__writeback_single_inode) from [<c02dee4c>]
#7 [<c02dee4c>] (writeback_sb_inodes) from [<c02df0e8>]
#8 [<c02df0e8>] (__writeback_inodes_wb) from [<c02de72c>]
#9 [<c02de72c>] (wb_writeback) from [<c02dbafc>]
#10 [<c02dbafc>] (wb_workfn) from [<c014d3d0>]
#11 [<c014d3d0>] (process_one_work) from [<c014d9b8>]
#12 [<c014d9b8>] (worker_thread) from [<c0151e40>]
#13 [<c0151e40>] (kthread) from [<c0107648>]

fuse's backtrace
---------------------
PID: 4412 TASK: c4b47800 CPU: 3 COMMAND: "Thread-9"
#0 [<c0a0bae0>] (__schedule) from [<c0a0bdb0>]
#1 [<c0a0bdb0>] (schedule) from [<c0a0c74c>]
#2 [<c0a0c74c>] (bit_wait) from [<c0a0c310>]
#3 [<c0a0c310>] (__wait_on_bit) from [<c02db7d0>]
#4 [<c02db7d0>] (__inode_wait_for_writeback) from [<c02db700>]
#5 [<c02db700>] (inode_wait_for_writeback) from [<c02cb33c>]
#6 [<c02cb33c>] (evict) from [<c02c40fc>]
#7 [<c02c40fc>] (__dentry_kill) from [<c02c4430>]
#8 [<c02c4430>] (shrink_dentry_list) from [<c02c41dc>]
#9 [<c02c41dc>] (prune_dcache_sb) from [<c02af8a0>]
#10 [<c02af8a0>] (super_cache_scan) from [<c0258f2c>]
#11 [<c0258f2c>] (shrink_slab) from [<c025dc6c>]
#12 [<c025dc6c>] (shrink_node) from [<c025b240>]
#13 [<c025b240>] (do_try_to_free_pages) from [<c025adc0>]
#14 [<c025adc0>] (try_to_free_pages) from [<c0249cb0>]
#15 [<c0249cb0>] (__alloc_pages_nodemask) from [<c03d3638>]
#16 [<c03d3638>] (fuse_copy_fill) from [<c03d33c0>]
#17 [<c03d33c0>] (fuse_copy_one) from [<c03d2fe4>]
#18 [<c03d2fe4>] (fuse_dev_do_read) from [<c03d2814>]
#19 [<c03d2814>] (fuse_dev_splice_read) from [<c02e2548>]
#20 [<c02e2548>] (sys_splice) from [<c0107740>]

This patch clears __GFP_FS flag when fuse alloctes pages to avoid
deadlock,as super_cache_scan will directly return SHRINK_STOP when
__GFP_FS is not set.

Signed-off-by: Jing Xia <[email protected]>
---
fs/fuse/dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 02b3c36..165c416 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -708,7 +708,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
if (cs->nr_segs >= cs->pipe->max_usage)
return -EIO;

- page = alloc_page(GFP_HIGHUSER);
+ page = alloc_page(GFP_HIGHUSER & ~__GFP_FS);
if (!page)
return -ENOMEM;

--
1.9.1