summaryrefslogtreecommitdiffstats
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2018-07-26 16:13:11 +0200
committerMiklos Szeredi <mszeredi@redhat.com>2018-07-26 16:13:11 +0200
commit87114373ea507895a62afb10d2910bd9adac35a8 (patch)
tree9dfa57730ad5ebd87559b3700910dd71b90e3478 /fs/fuse/dev.c
parentce397d215ccd07b8ae3f71db689aedb85d56ab40 (diff)
downloadlinux-87114373ea507895a62afb10d2910bd9adac35a8.tar.gz
linux-87114373ea507895a62afb10d2910bd9adac35a8.tar.bz2
linux-87114373ea507895a62afb10d2910bd9adac35a8.zip
fuse: fix double request_end()
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>
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index c6b88fa85e2e..8564d91c7d41 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -371,7 +371,7 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
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);
@@ -400,6 +400,7 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
wake_up(&req->waitq);
if (req->end)
req->end(fc, req);
+out_put_req:
fuse_put_request(fc, req);
}
@@ -2105,6 +2106,7 @@ void fuse_abort_conn(struct fuse_conn *fc, bool is_abort)
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);
@@ -2131,7 +2133,6 @@ void fuse_abort_conn(struct fuse_conn *fc, bool is_abort)
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);
}