[Devel] [PATCH 4/4] fs/fuse kio: keep fuse_file for requests waiting for shrink

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


A pending request due to shrink operation may lose passed fuse_file. To fix it,
let's take the reference and save ff pointer to req->ff and then release it in
req->end() callback.

Signed-off-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
---
 fs/fuse/file.c                     |  1 +
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 16 ++++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 7929f4b6b346..611955c8ea7f 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -120,6 +120,7 @@ struct fuse_file *fuse_file_get(struct fuse_file *ff)
 	atomic_inc(&ff->count);
 	return ff;
 }
+EXPORT_SYMBOL_GPL(fuse_file_get);
 
 static void fuse_release_async(struct work_struct *work)
 {
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index ba53a7ac6472..7d1de6f86a4a 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -815,6 +815,17 @@ static void wait_shrink(struct pcs_fuse_req *r, struct pcs_dentry_info *di)
 	list_add_tail(&r->exec.ireq.list, &di->size.queue);
 }
 
+static void _pcs_ff_free_end(struct fuse_conn *fc, struct fuse_req *req)
+{
+	struct pcs_fuse_req *r = pcs_req_from_fuse(req);
+
+	BUG_ON(!req->ff);
+	fuse_release_ff(req->inode, req->ff);
+
+	if (r->end)
+		r->end(fc, req);
+}
+
 static bool kqueue_insert(struct pcs_dentry_info *di, struct fuse_file *ff,
 			  struct fuse_req *req)
 {
@@ -844,6 +855,11 @@ static int pcs_fuse_prep_rw(struct pcs_fuse_req *r, struct fuse_file *ff)
 	spin_lock(&di->lock);
 	/* Deffer all requests if shrink requested to prevent livelock */
 	if (di->size.op == PCS_SIZE_SHRINK) {
+		if (ff && !r->req.ff) {
+			r->end = r->req.end;
+			r->req.ff = fuse_file_get(ff);
+			r->req.end = _pcs_ff_free_end;
+		}
 		wait_shrink(r, di);
 		ret = 1;
 		goto out;
-- 
2.15.1



More information about the Devel mailing list