[Devel] [PATCH RHEL7 COMMIT] fs/fuse kio_pcs: fix race between req->end() and request_wait_answer()
Konstantin Khorenko
khorenko at virtuozzo.com
Thu Oct 4 16:18:39 MSK 2018
The commit is pushed to "branch-rh7-3.10.0-862.14.4.vz7.72.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.14.4.vz7.72.2
------>
commit bb6092c3a11c5daf2a593ef24d109288763fa60c
Author: Pavel Butsykin <pbutsykin at virtuozzo.com>
Date: Wed Oct 3 17:08:53 2018 +0300
fs/fuse kio_pcs: fix race between req->end() and request_wait_answer()
There is already a patch for this issue:
commit c76d20779550
Author: Dmitry Monakhov <dmonakhov at openvz.org>
Date: Mon Feb 19 14:06:59 2018 +0300
fuse: fix ->end() vs ->waitq ordering
But there's still a small window when waiter can be notified about request
completion before req->end() callback executed. This can happen because
synchronous requests can use interruptible wait and such wait can be completed
based only on FR_FINISHED flag, although req->end() may not be executed yet.
Signed-off-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
=======================================================
Patchset description:
RPC connection double close fixes
https://pmc.acronis.com/browse/VSTOR-15378
Pavel Butsykin (3):
fs/fuse kio_pcs: fix race between req->end() and request_wait_answer()
fs/fuse kio_pcs: remove fuse destroy request
fs/fuse kio_pcs: drop rpc connection close in pcs_rpc_engine_fini()
---
fs/fuse/dev.c | 15 ++++++++++-----
fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 3 ++-
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 03f9acca6e24..0a7e3f4c6168 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -428,16 +428,19 @@ static void flush_bg_queue(struct fuse_conn *fc, struct fuse_iqueue *fiq)
void request_end(struct fuse_conn *fc, struct fuse_req *req)
{
struct fuse_iqueue *fiq = req->fiq;
+ bool bg;
if (test_and_set_bit(FR_FINISHED, &req->flags))
return;
+ bg = test_bit(FR_BACKGROUND, &req->flags);
+
spin_lock(&fiq->waitq.lock);
list_del_init(&req->intr_entry);
spin_unlock(&fiq->waitq.lock);
WARN_ON(test_bit(FR_PENDING, &req->flags));
WARN_ON(test_bit(FR_SENT, &req->flags));
- if (test_bit(FR_BACKGROUND, &req->flags)) {
+ if (bg) {
spin_lock(&fc->lock);
clear_bit(FR_BACKGROUND, &req->flags);
if (fc->num_background == fc->max_background) {
@@ -464,8 +467,11 @@ void request_end(struct fuse_conn *fc, struct fuse_req *req)
flush_bg_queue(fc, fiq);
spin_unlock(&fc->lock);
}
- if (req->end)
+ if (req->end) {
req->end(fc, req);
+ if (!bg)
+ req->end = NULL;
+ }
wake_up(&req->waitq);
fuse_put_request(fc, req);
}
@@ -494,7 +500,7 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
if (!fc->no_interrupt) {
/* Any signal may interrupt this */
err = wait_event_interruptible(req->waitq,
- test_bit(FR_FINISHED, &req->flags));
+ test_bit(FR_FINISHED, &req->flags) && !req->end);
if (!err)
return;
@@ -508,8 +514,7 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
if (!test_bit(FR_FORCE, &req->flags)) {
/* Only fatal signals may interrupt this */
err = wait_event_killable(req->waitq,
- test_bit(FR_FINISHED, &req->flags));
-
+ test_bit(FR_FINISHED, &req->flags) && !req->end);
if (!err)
return;
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index f73b72f036e8..85ede13a6ebe 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -1113,7 +1113,8 @@ static int kpcs_req_send(struct fuse_conn* fc, struct fuse_req *req, bool bg, bo
pcs_fuse_submit(pfc, req, lk);
if (!bg)
- wait_event(req->waitq, test_bit(FR_FINISHED, &req->flags));
+ wait_event(req->waitq,
+ test_bit(FR_FINISHED, &req->flags) && !req->end);
return 0;
}
More information about the Devel
mailing list