summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2018-07-26 16:13:11 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-09-05 09:20:08 +0200
commit501c4caeb3e437eb18bb95b2c58d153aadc70d6e (patch)
treeaf184b52ba4bc1d8f9fccee5c0a98381798471bb
parent68fbfcb7cd4375889bb000d181dcf46aa45d06a9 (diff)
fuse: fix double request_end()
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>
-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 ce558c853722..9382ba430be5 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -363,7 +363,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);
@@ -393,6 +393,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);
}
@@ -2097,6 +2098,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
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);
@@ -2123,7 +2125,6 @@ void fuse_abort_conn(struct fuse_conn *fc)
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);
}