From 5b37c88ad4d4c6585633a90d0955128afb3849a5 Mon Sep 17 00:00:00 2001 From: Ashish Samant Date: Fri, 21 Jul 2017 19:20:06 -0700 Subject: [PATCH] fuse: Call end_queued_requests() after releasing fc->lock in fuse_dev_release() Orabug: 27215268 During fs teardown,the following self deadlock can happen. [] _raw_spin_lock+0x2a/0x60 [] ? fuse_abort_conn+0x31/0x270 [fuse] [] ? cuse_read_iter+0x70/0x70 [cuse] [] cuse_process_init_reply+0x54/0x490 [cuse] [] ? cuse_read_iter+0x70/0x70 [cuse] [] request_end+0xbf/0x170 [fuse] [] end_queued_requests.isra.19+0x86/0x160 [fuse] [] fuse_dev_release+0x9f/0xd0 [fuse] [] cuse_channel_release+0x8a/0xa0 [cuse] [] __fput+0xe4/0x220 [] ____fput+0xe/0x10 [] task_work_run+0xb7/0xf0 [] do_notify_resume+0x8d/0xa0 [] int_signal+0x12/0x17 The deadlock happens when an attempt is made to take fc->lock in fuse_abort_conn(). The same lock has already been taken in fuse_dev_release() in the stack. This flow is initiated from cuse_process_init_reply() in case of an error and so, it is a very rare scenario, but it can lockup the fuse fs. Fix this by releasing the spin lock before calling end_queued_requests() instead of after, since it does not make a difference anyway. Signed-off-by: Ashish Samant Reviewed-by: Somasundaram Krishnasamy --- 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 9ae98d471975..1dbb7129345f 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2366,9 +2366,9 @@ int fuse_dev_release(struct inode *inode, struct file *file) wake_up_all(&fn->blocked_waitq); spin_unlock(&fn->lock); } - end_queued_requests(fc); end_polls(fc); spin_unlock(&fc->lock); + end_queued_requests(fc); fuse_conn_put(fc); } -- 2.50.1