[Devel] [PATCH RHEL7 COMMIT] fuse kio: Introduce cached_op

Konstantin Khorenko khorenko at virtuozzo.com
Tue Oct 9 11:50:44 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.4
------>
commit da5f2dcfd2f0a68b9493718ec8898ca2fce033d9
Author: Kirill Tkhai <ktkhai at virtuozzo.com>
Date:   Tue Oct 9 11:50:41 2018 +0300

    fuse kio: Introduce cached_op
    
    Next patches introduce kio version fallback.
    There are at least two approach. First one
    is to clear fc->kio.op in case of version
    mismatch in process_pcs_init_reply(). The
    second one is to assign kio.op there.
    I choose the second one, since it allows
    to leave places like:
    
            if (fc->kio.op && fc->kio.op->req_send)
    
    as is, and not to worry, that fc->kio.op become
    zero and freed in between of them. This allows
    to avoid some additional synchronization around
    such the places, like in would have been in the
    first approach.
    
    Normally, we mustn't be near such the places
    before we're initialized (I've reviewed all of them),
    but this additional protection won't excess (I think).
    
    Note, that going to !kio path before kio is enabled
    is bad thing anyway. For example, we may lose kio
    file initialization in that case. But, again, all
    current places go thru req allocation and they will
    sleep till connection is initialized.
    
    Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
    Reviewed-by: Pavel Butsykin <pbutsykin at virtuozzo.com>
    
    Changes:
      v2:   Add cached_op to destroy_inode for safety
      v2.1: Fix spelling
---
 fs/fuse/fuse_i.h                   |  1 +
 fs/fuse/inode.c                    | 20 ++++++++++----------
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c |  6 ++++++
 3 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 4ececf9acff5..69dfd0c318fe 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -766,6 +766,7 @@ struct fuse_conn {
 	/** Kdirect io operations */
 	struct {
 		struct fuse_kio_ops *op;
+		struct fuse_kio_ops *cached_op;
 		void *ctx;
 	} kio;
 
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 409dc5abd461..ca9a146d39fa 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -131,8 +131,8 @@ static void fuse_destroy_inode(struct inode *inode)
 	kfree(fi->forget);
 
 	/* TODO: Probably kio context should be released inside fuse forget */
-	if (fc->kio.op && fc->kio.op->inode_release)
-		fc->kio.op->inode_release(fi);
+	if (fc->kio.cached_op && fc->kio.cached_op->inode_release)
+		fc->kio.cached_op->inode_release(fi);
 
 	call_rcu(&inode->i_rcu, fuse_i_callback);
 }
@@ -512,8 +512,8 @@ static void fuse_kio_put(struct fuse_kio_ops *ops)
 
 static void fuse_kdirect_put(struct fuse_conn *fc)
 {
-	if (fc->kio.op)
-		fuse_kio_put(fc->kio.op);
+	if (fc->kio.cached_op)
+		fuse_kio_put(fc->kio.cached_op);
 }
 
 static void fuse_put_super(struct super_block *sb)
@@ -753,8 +753,8 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
 		seq_printf(m, ",blksize=%lu", sb->s_blocksize);
 	if (fc->writeback_cache)
 		seq_puts(m, ",writeback_enable");
-	if (fc->kio.op)
-		seq_printf(m, ",kdirect=%s", fc->kio.op->name);
+	if (fc->kio.cached_op)
+		seq_printf(m, ",kdirect=%s", fc->kio.cached_op->name);
 	return 0;
 }
 
@@ -1113,8 +1113,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
 		fc->max_write = max_t(unsigned, 4096, fc->max_write);
 		fc->conn_init = 1;
 
-		if (fc->kio.op) {
-			if (!fc->kio.op->conn_init(fc))
+		if (fc->kio.cached_op) {
+			if (!fc->kio.cached_op->conn_init(fc))
 				return;
 			fc->conn_error = 1;
 		}
@@ -1327,8 +1327,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 		err = -EINVAL;
 		if (!fc->writeback_cache)
 			goto err_dev_free;
-		fc->kio.op = fuse_kio_get(fc, d.kio_name);
-		if (!fc->kio.op)
+		fc->kio.cached_op = fuse_kio_get(fc, d.kio_name);
+		if (!fc->kio.cached_op)
 			goto err_dev_free;
 	}
 	/* Used by get_root_inode() */
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index 431df2419e65..6512107bdafb 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -86,6 +86,12 @@ static void process_pcs_init_reply(struct fuse_conn *fc, struct fuse_req *req)
 		goto out;
 	}
 
+	/*
+	 * It looks like all potential tasks, which can dereference
+	 * fc->kio.op, are waiting for fuse_set_initialized().
+	 */
+	fc->kio.op = fc->kio.cached_op;
+
 	pfc = kvmalloc(sizeof(*pfc), GFP_KERNEL);
 	if (!pfc) {
 		fc->conn_error = 1;



More information about the Devel mailing list