[Devel] [PATCH 1/4] fs/fuse kio: forward fuse_file pointer to kpcs_req_send()

Pavel Butsykin pbutsykin at virtuozzo.com
Wed May 15 11:53:55 MSK 2019


Unfortunately, synchronous requests don't reference ff, and at the same time use
page cache. In such a situation, it's just not possible to check ff->ff_state
inside pcs_fuse_submit(), that may lead to a race bug and as result deadlock
with fuse_invalidate_files(). To fix this, let's forward fuse_file pointer to
kpcs_req_send() for synchronous requests with pages.

Signed-off-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
---
 fs/fuse/dev.c                      |  6 +++---
 fs/fuse/fuse_i.h                   |  4 ++--
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 12 +++++++-----
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index a43d0bfd8025..4a2cf4d236a9 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -401,7 +401,7 @@ static void flush_bg_queue(struct fuse_conn *fc, struct fuse_iqueue *fiq)
 		list_del_init(&req->list);
 		fc->active_background++;
 
-		if (fc->kio.op && !fc->kio.op->req_send(fc, req, true, true))
+		if (fc->kio.op && !fc->kio.op->req_send(fc, req, NULL, true, true))
 			continue;
 
 		spin_lock(&fiq->waitq.lock);
@@ -540,7 +540,7 @@ static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req,
 
 	BUG_ON(test_bit(FR_BACKGROUND, &req->flags));
 
-	if (fc->kio.op && !fc->kio.op->req_send(fc, req, false, false))
+	if (fc->kio.op && !fc->kio.op->req_send(fc, req, ff, false, false))
 		return;
 
 	spin_lock(&fiq->waitq.lock);
@@ -630,7 +630,7 @@ void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
 	bool fail;
 	WARN_ON(!req->end);
 
-	if (fc->kio.op && !fc->kio.op->req_send(fc, req, true, false))
+	if (fc->kio.op && !fc->kio.op->req_send(fc, req, NULL, true, false))
 		return;
 
 	spin_lock(&fc->lock);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 0ea0340c6b70..ab81131585d1 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -527,8 +527,8 @@ struct fuse_kio_ops {
 	/* Request handling hooks */
 	struct fuse_req *(*req_alloc)(struct fuse_conn *fc, unsigned nrpages,
 				      gfp_t flags);
-	int (*req_send)(struct fuse_conn *fc, struct fuse_req *req, bool bg,
-			bool locked);
+	int (*req_send)(struct fuse_conn *fc, struct fuse_req *req,
+			struct fuse_file *ff, bool bg, bool locked);
 
 	/* Inode scope hooks */
 	int  (*file_open)(struct fuse_conn *fc, struct file *file,
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index 75bd8c6b91bc..efa2b4054215 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -903,7 +903,8 @@ static int pcs_fuse_prep_rw(struct pcs_fuse_req *r)
 	return ret;
 }
 
-static void pcs_fuse_submit(struct pcs_fuse_cluster *pfc, struct fuse_req *req, bool async, bool lk)
+static void pcs_fuse_submit(struct pcs_fuse_cluster *pfc, struct fuse_req *req,
+			    struct fuse_file *ff, bool async, bool lk)
 {
 	struct pcs_fuse_req *r = pcs_req_from_fuse(req);
 	struct fuse_inode *fi = get_fuse_inode(req->io_inode);
@@ -996,7 +997,7 @@ error:
 
 submit:
 	spin_lock(&di->kq_lock);
-	if (req->ff && test_bit(FUSE_S_FAIL_IMMEDIATELY, &req->ff->ff_state)) {
+	if (ff && test_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state)) {
 		spin_unlock(&di->kq_lock);
 		req->out.h.error = -EIO;
 		goto error;
@@ -1070,7 +1071,7 @@ static void _pcs_shrink_end(struct fuse_conn *fc, struct fuse_req *req)
 
 		TRACE("resubmit %p\n", &r->req);
 		list_del_init(&ireq->list);
-		pcs_fuse_submit(pfc, &r->req, true, false);
+		pcs_fuse_submit(pfc, &r->req, NULL, true, false);
 	}
 }
 
@@ -1173,7 +1174,8 @@ fail:
 	return -EINVAL;
 }
 
-static int kpcs_req_send(struct fuse_conn* fc, struct fuse_req *req, bool bg, bool lk)
+static int kpcs_req_send(struct fuse_conn* fc, struct fuse_req *req,
+			 struct fuse_file *ff, bool bg, bool lk)
 {
 	struct pcs_fuse_cluster *pfc = (struct pcs_fuse_cluster*)fc->kio.ctx;
 	int ret;
@@ -1229,7 +1231,7 @@ static int kpcs_req_send(struct fuse_conn* fc, struct fuse_req *req, bool bg, bo
 	}
 	__clear_bit(FR_PENDING, &req->flags);
 
-	pcs_fuse_submit(pfc, req, lk, lk);
+	pcs_fuse_submit(pfc, req, ff ? : req->ff, lk, lk);
 	if (!bg)
 		wait_event(req->waitq,
 			   test_bit(FR_FINISHED, &req->flags) && !req->end);
-- 
2.15.1



More information about the Devel mailing list