Re: [fuse-devel] [PATCH] fuse: avoid deadlock when write fuse inode
On Tue, Feb 2, 2021 at 5:41 AM Huang Jianan via fuse-devel wrote: > > We found the following deadlock situations in low memory scenarios: > Thread A Thread B > - __writeback_single_inode > - fuse_write_inode > - fuse_simple_request >- __fuse_request_send > - request_wait_answer > - fuse_dev_splice_read > - fuse_copy_fill >- __alloc_pages_direct_reclaim > - do_shrink_slab > - super_cache_scan > - shrink_dentry_list >- dentry_unlink_inode > - iput_final > - inode_wait_for_writeback On what kernel are you seeing this? I don't see how it can happen on upstream kernels, since there's a "write_inode_now(inode, 1)" call in fuse_release() and nothing can dirty the inode after the file has been released. Thanks, Miklos
Re: [fuse-devel] [PATCH] fuse: avoid deadlock when write fuse inode
friendly ping ... On 2021/2/2 12:11, Huang Jianan via fuse-devel wrote: Hi all, This patch works well in our product, but I am not sure this is the correct way to solve this problem. I think that the inode->i_count shouldn't be zero after iput is executed in dentry_unlink_inode, then the inode won't be writeback. But i haven't found where iget is missing. Thanks, Jianan On 2021/2/2 12:08, Huang Jianan wrote: We found the following deadlock situations in low memory scenarios: Thread A Thread B - __writeback_single_inode - fuse_write_inode - fuse_simple_request - __fuse_request_send - request_wait_answer - fuse_dev_splice_read - fuse_copy_fill - __alloc_pages_direct_reclaim - do_shrink_slab - super_cache_scan - shrink_dentry_list - dentry_unlink_inode - iput_final - inode_wait_for_writeback The request and inode processed by Thread A and B are the same, which causes a deadlock. To avoid this, we remove the __GFP_FS flag when allocating memory in fuse_copy_fill, so there will be no memory reclaimation in super_cache_scan. Signed-off-by: Huang Jianan Signed-off-by: Guo Weichao --- 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 588f8d1240aa..e580b9d04c25 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -721,7 +721,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;
Re: [PATCH] fuse: avoid deadlock when write fuse inode
Hi all, This patch works well in our product, but I am not sure this is the correct way to solve this problem. I think that the inode->i_count shouldn't be zero after iput is executed in dentry_unlink_inode, then the inode won't be writeback. But i haven't found where iget is missing. Thanks, Jianan On 2021/2/2 12:08, Huang Jianan wrote: We found the following deadlock situations in low memory scenarios: Thread A Thread B - __writeback_single_inode - fuse_write_inode - fuse_simple_request - __fuse_request_send - request_wait_answer - fuse_dev_splice_read - fuse_copy_fill - __alloc_pages_direct_reclaim - do_shrink_slab - super_cache_scan - shrink_dentry_list - dentry_unlink_inode - iput_final - inode_wait_for_writeback The request and inode processed by Thread A and B are the same, which causes a deadlock. To avoid this, we remove the __GFP_FS flag when allocating memory in fuse_copy_fill, so there will be no memory reclaimation in super_cache_scan. Signed-off-by: Huang Jianan Signed-off-by: Guo Weichao --- 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 588f8d1240aa..e580b9d04c25 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -721,7 +721,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;
[PATCH] fuse: avoid deadlock when write fuse inode
We found the following deadlock situations in low memory scenarios: Thread A Thread B - __writeback_single_inode - fuse_write_inode - fuse_simple_request - __fuse_request_send - request_wait_answer - fuse_dev_splice_read - fuse_copy_fill - __alloc_pages_direct_reclaim - do_shrink_slab - super_cache_scan - shrink_dentry_list - dentry_unlink_inode - iput_final - inode_wait_for_writeback The request and inode processed by Thread A and B are the same, which causes a deadlock. To avoid this, we remove the __GFP_FS flag when allocating memory in fuse_copy_fill, so there will be no memory reclaimation in super_cache_scan. Signed-off-by: Huang Jianan Signed-off-by: Guo Weichao --- 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 588f8d1240aa..e580b9d04c25 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -721,7 +721,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; -- 2.25.1