[Devel] [PATCH RHEL7 COMMIT] fs/fuse: add non-blocking request flag

Konstantin Khorenko khorenko at virtuozzo.com
Wed Jul 25 18:05:15 MSK 2018


The commit is pushed to "branch-rh7-3.10.0-862.9.1.vz7.63.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.9.1.vz7.63.2
------>
commit 735fe2738a862ede3b5b6880789d3d5dd107d812
Author: Pavel Butsykin <pbutsykin at virtuozzo.com>
Date:   Wed Jul 25 18:05:14 2018 +0300

    fs/fuse: add non-blocking request flag
    
    This patch adds the ability to create non-blocking requests, it's necessary for
    the implementation of throttling in kio. The active r/w kio requests can wait
    for a pcs_map resolving, but in case when the inflight kio becomes equal to
    fc->max_background, we will not be able to send PCS_IOC_GETMAP request,
    as a result, it can lead to the hanging of kio requests that will endlessly wait
    for pcs_map resolving. The same situation with PCS_IOC_CSCONN, cs_connect() is
    performed under ep->mutex, so blocking PCS_IOC_CSCONN request could lead to
    deadlock. In general, this patch is aimed to protect against such kind of hangs
    when fc->max_background limit will work for kio requests.
    
    https://pmc.acronis.com/browse/VSTOR-12335
    
    Signed-off-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
---
 fs/fuse/dev.c                      | 26 ++++++++++++++++++++++++++
 fs/fuse/fuse_i.h                   |  4 ++++
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c |  5 ++---
 3 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 707ac13ca52d..f7aca3094a83 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -216,6 +216,21 @@ struct fuse_req *fuse_get_req_for_background(struct fuse_conn *fc,
 }
 EXPORT_SYMBOL_GPL(fuse_get_req_for_background);
 
+struct fuse_req *fuse_get_nonblock_req_for_background(struct fuse_conn *fc,
+						      unsigned npages)
+{
+	struct fuse_req *req = __fuse_get_req(fc, npages, false);
+	if (IS_ERR(req))
+		return req;
+
+	__set_bit(FR_BACKGROUND, &req->flags);
+	__set_bit(FR_NONBLOCKING, &req->flags);
+
+	return req;
+}
+
+EXPORT_SYMBOL_GPL(fuse_get_nonblock_req_for_background);
+
 /*
  * Return request in fuse_file->reserved_req.  However that may
  * currently be in use.  If that is the case, wait for it to become
@@ -562,6 +577,17 @@ void fuse_request_send_background_locked(struct fuse_conn *fc,
 		set_bdi_congested(&fc->bdi, BLK_RW_SYNC);
 		set_bdi_congested(&fc->bdi, BLK_RW_ASYNC);
 	}
+
+	if (test_bit(FR_NONBLOCKING, &req->flags)) {
+		fc->active_background++;
+		spin_lock(&fiq->waitq.lock);
+		req->in.h.unique = fuse_get_unique(fiq);
+		queue_request(fiq, req);
+		spin_unlock(&fiq->waitq.lock);
+
+		return;
+	}
+
 	list_add_tail(&req->list, &fc->bg_queue);
 	flush_bg_queue(fc, fiq);
 }
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index da5cf0aed3ba..9069cddc42a2 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -297,6 +297,7 @@ struct fuse_io_priv {
  * FR_SENT:		request is in userspace, waiting for an answer
  * FR_FINISHED:		request is finished
  * FR_PRIVATE:		request is on private list
+ * FR_NONBLOCKING:	non-blocking request (only needed for KIO)
  */
 enum fuse_req_flag {
 	FR_ISREPLY,
@@ -310,6 +311,7 @@ enum fuse_req_flag {
 	FR_SENT,
 	FR_FINISHED,
 	FR_PRIVATE,
+	FR_NONBLOCKING,
 };
 
 /**
@@ -920,6 +922,8 @@ void fuse_request_free(struct fuse_conn *fc, struct fuse_req *req);
 struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages);
 struct fuse_req *fuse_get_req_for_background(struct fuse_conn *fc,
 					     unsigned npages);
+struct fuse_req *fuse_get_nonblock_req_for_background(struct fuse_conn *fc,
+						      unsigned npages);
 
 /*
  * Increment reference count on request
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index 8a6f9e60fece..105869d6f81f 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -411,14 +411,13 @@ int fuse_map_resolve(struct pcs_map_entry *m, int direction)
 		kfree(map_ioc);
 		return -ENOMEM;
 	}
-	req = fuse_get_req_for_background(fc, 0);
+	req = fuse_get_nonblock_req_for_background(fc, 0);
 	if (IS_ERR(req)) {
 		kfree(map_ioc);
 		kfree(reply_work);
 		return PTR_ERR(req);
 	}
 
-
 	memset(&req->misc.ioctl, 0, sizeof(req->misc.ioctl));
 	inarg = &req->misc.ioctl.in;
 	outarg = &req->misc.ioctl.out;
@@ -543,7 +542,7 @@ int fuse_pcs_csconn_send(struct fuse_conn *fc, struct pcs_rpc *ep, int flags)
 		return -ENOMEM;
 	}
 
-	req = fuse_get_req_for_background(fc, 0);
+	req = fuse_get_nonblock_req_for_background(fc, 0);
 	if (IS_ERR(req)) {
 		kfree(csconn);
 		kfree(reply_work);


More information about the Devel mailing list