diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2018-07-26 10:13:11 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2018-07-26 10:13:11 -0400 |
commit | 87114373ea507895a62afb10d2910bd9adac35a8 (patch) | |
tree | 9dfa57730ad5ebd87559b3700910dd71b90e3478 /fs/fuse | |
parent | ce397d215ccd07b8ae3f71db689aedb85d56ab40 (diff) |
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')
-rw-r--r-- | fs/fuse/dev.c | 5 |
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) | |||
371 | struct fuse_iqueue *fiq = &fc->iq; | 371 | struct fuse_iqueue *fiq = &fc->iq; |
372 | 372 | ||
373 | if (test_and_set_bit(FR_FINISHED, &req->flags)) | 373 | if (test_and_set_bit(FR_FINISHED, &req->flags)) |
374 | return; | 374 | goto out_put_req; |
375 | 375 | ||
376 | spin_lock(&fiq->waitq.lock); | 376 | spin_lock(&fiq->waitq.lock); |
377 | list_del_init(&req->intr_entry); | 377 | list_del_init(&req->intr_entry); |
@@ -400,6 +400,7 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) | |||
400 | wake_up(&req->waitq); | 400 | wake_up(&req->waitq); |
401 | if (req->end) | 401 | if (req->end) |
402 | req->end(fc, req); | 402 | req->end(fc, req); |
403 | out_put_req: | ||
403 | fuse_put_request(fc, req); | 404 | fuse_put_request(fc, req); |
404 | } | 405 | } |
405 | 406 | ||
@@ -2105,6 +2106,7 @@ void fuse_abort_conn(struct fuse_conn *fc, bool is_abort) | |||
2105 | set_bit(FR_ABORTED, &req->flags); | 2106 | set_bit(FR_ABORTED, &req->flags); |
2106 | if (!test_bit(FR_LOCKED, &req->flags)) { | 2107 | if (!test_bit(FR_LOCKED, &req->flags)) { |
2107 | set_bit(FR_PRIVATE, &req->flags); | 2108 | set_bit(FR_PRIVATE, &req->flags); |
2109 | __fuse_get_request(req); | ||
2108 | list_move(&req->list, &to_end1); | 2110 | list_move(&req->list, &to_end1); |
2109 | } | 2111 | } |
2110 | spin_unlock(&req->waitq.lock); | 2112 | spin_unlock(&req->waitq.lock); |
@@ -2131,7 +2133,6 @@ void fuse_abort_conn(struct fuse_conn *fc, bool is_abort) | |||
2131 | 2133 | ||
2132 | while (!list_empty(&to_end1)) { | 2134 | while (!list_empty(&to_end1)) { |
2133 | req = list_first_entry(&to_end1, struct fuse_req, list); | 2135 | req = list_first_entry(&to_end1, struct fuse_req, list); |
2134 | __fuse_get_request(req); | ||
2135 | list_del_init(&req->list); | 2136 | list_del_init(&req->list); |
2136 | request_end(fc, req); | 2137 | request_end(fc, req); |
2137 | } | 2138 | } |