[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