| From 87114373ea507895a62afb10d2910bd9adac35a8 Mon Sep 17 00:00:00 2001 |
| From: Miklos Szeredi <mszeredi@redhat.com> |
| Date: Thu, 26 Jul 2018 16:13:11 +0200 |
| Subject: fuse: fix double request_end() |
| |
| From: Miklos Szeredi <mszeredi@redhat.com> |
| |
| commit 87114373ea507895a62afb10d2910bd9adac35a8 upstream. |
| |
| Refcounting of request is broken when fuse_abort_conn() is called and |
| request is on the fpq->io list: |
| |
| - ref is taken too late |
| - then it is not dropped |
| |
| Fixes: 0d8e84b0432b ("fuse: simplify request abort") |
| Cc: <stable@vger.kernel.org> # v4.2 |
| Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/fuse/dev.c | 5 +++-- |
| 1 file changed, 3 insertions(+), 2 deletions(-) |
| |
| --- a/fs/fuse/dev.c |
| +++ b/fs/fuse/dev.c |
| @@ -364,7 +364,7 @@ static void request_end(struct fuse_conn |
| struct fuse_iqueue *fiq = &fc->iq; |
| |
| if (test_and_set_bit(FR_FINISHED, &req->flags)) |
| - return; |
| + goto out_put_req; |
| |
| spin_lock(&fiq->waitq.lock); |
| list_del_init(&req->intr_entry); |
| @@ -393,6 +393,7 @@ static void request_end(struct fuse_conn |
| wake_up(&req->waitq); |
| if (req->end) |
| req->end(fc, req); |
| +out_put_req: |
| fuse_put_request(fc, req); |
| } |
| |
| @@ -2103,6 +2104,7 @@ void fuse_abort_conn(struct fuse_conn *f |
| set_bit(FR_ABORTED, &req->flags); |
| if (!test_bit(FR_LOCKED, &req->flags)) { |
| set_bit(FR_PRIVATE, &req->flags); |
| + __fuse_get_request(req); |
| list_move(&req->list, &to_end1); |
| } |
| spin_unlock(&req->waitq.lock); |
| @@ -2129,7 +2131,6 @@ void fuse_abort_conn(struct fuse_conn *f |
| |
| while (!list_empty(&to_end1)) { |
| req = list_first_entry(&to_end1, struct fuse_req, list); |
| - __fuse_get_request(req); |
| list_del_init(&req->list); |
| request_end(fc, req); |
| } |