[RHEL7,COMMIT] fuse kio: Read file attributes every first open

Submitted by Konstantin Khorenko on July 6, 2018, 9:41 a.m.

Details

Message ID 201807060941.w669fmdA015181@finist_ce7.work
State New
Series "fuse kio: Read file attributes every first open"
Headers show

Commit Message

Konstantin Khorenko July 6, 2018, 9:41 a.m.
The commit is pushed to "branch-rh7-3.10.0-862.3.2.vz7.61.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-862.3.2.vz7.61.15
------>
commit 80b98e3954a755753cbb88c4d69b342feaf61029
Author: Kirill Tkhai <ktkhai@virtuozzo.com>
Date:   Fri Jul 6 12:41:48 2018 +0300

    fuse kio: Read file attributes every first open
    
    Currently we do not reread file attributes in case of
    this is the existing inode:
    
    [root@s143 ~]# echo 1 >> /vzt/a.txt
    [root@s134 ~]# cat /vzt/a.txt
    1
    [root@s143 ~]# echo 1 >> /vzt/a.txt
    [root@s134 ~]# cat /vzt/a.txt
    1
    [root@s143 ~]# echo 1 >> /vzt/a.txt
    [root@s134 ~]# cat /vzt/a.txt
    1
    [root@s143 ~]# cat /vzt/a.txt
    1
    1
    1
    
    In this example the file was changed on s143, but s134
    used it's cached metadata.
    
    The patch reworks open sequence and makes dentry info
    to be populated every time we reopen the file again.
    Also, it fixed races during open of new file, since
    a new file may be obtained by another thread before
    the creator executes ->file_open(). So, we create
    every inode with num_users == 0, and then the first
    of them makes file_open().
    
    Note, that openers are synchronized by inode->mutex.
    Also, keep in mind that num_users are modified under
    fc->lock (except one unlikely path), and this exists
    long ago. So in further I'm going to make it like
    plain int, since this atomic does not do anything
    and just confuser a reader.
    
    https://jira.sw.ru/browse/PSBM-86234
    
    Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
    Acked-by: Alexey Kuznetsov <kuznet@virtuozzo.com>
---
 fs/fuse/dir.c                      | 27 +++++++++++++++++----------
 fs/fuse/file.c                     |  9 ++++-----
 fs/fuse/inode.c                    |  3 +--
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 26 +++++++++++++-------------
 4 files changed, 35 insertions(+), 30 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index b04023bf230a..8dcad8b8c20e 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -490,24 +490,31 @@  static int fuse_create_open(struct inode *dir, struct dentry *entry,
 	fuse_invalidate_attr(dir);
 	err = finish_open(file, entry, generic_file_open, opened);
 	if (err) {
-		if (fc->writeback_cache) {
-			struct fuse_inode *fi = get_fuse_inode(inode);
-			atomic_dec(&fi->num_openers);
-		}
 		fuse_sync_release(ff, flags);
 		return err;
 	}
 
 	file->private_data = fuse_file_get(ff);
 	fuse_finish_open(inode, file);
-	if (fc->kio.op && fc->kio.op->file_open &&
-	    fc->kio.op->file_open(fc, file, inode)) {
-		if (err) {
-			fput(file);
-			return  err;
+
+	if (fc->writeback_cache) {
+		struct fuse_inode *fi = get_fuse_inode(inode);
+		bool need_open;
+
+		mutex_lock(&inode->i_mutex);
+		spin_lock(&fc->lock);
+		need_open = (atomic_inc_return(&fi->num_openers) == 1);
+		spin_unlock(&fc->lock);
+
+		if (need_open && fc->kio.op && fc->kio.op->file_open) {
+			err = fc->kio.op->file_open(fc, file, inode);
+			if (err)
+				fput(file);
 		}
+		mutex_unlock(&inode->i_mutex);
 	}
-	return 0;
+
+	return err;
 
 out_free_ff:
 	fuse_file_free(ff);
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 313f81191ada..f96667cdabc8 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -291,11 +291,6 @@  int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
 	err = fuse_do_open(fc, get_node_id(inode), file, isdir);
 	if (err)
 		return err;
-	if (fc->kio.op && fc->kio.op->file_open &&
-	    fc->kio.op->file_open(fc, file, inode)) {
-		fuse_release_common(file, FUSE_RELEASE);
-		return -EINVAL;
-	}
 
 	if (fc->writeback_cache && !isdir) {
 		struct fuse_inode *fi = get_fuse_inode(inode);
@@ -308,6 +303,10 @@  int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
 			fi->i_size_unstable = 1;
 			spin_unlock(&fc->lock);
 			err = fuse_getattr_size(inode, file, &size);
+
+			if (!err && fc->kio.op && fc->kio.op->file_open)
+				err = fc->kio.op->file_open(fc, file, inode);
+
 			spin_lock(&fc->lock);
 			fi->i_size_unstable = 0;
 			if (err)
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 6fc09495357a..13571c9bce93 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -327,8 +327,7 @@  struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
 			inode->i_flags |= S_NOCMTIME;
 		inode->i_generation = generation;
 		inode->i_data.backing_dev_info = &fc->bdi;
-		fuse_init_inode(inode, attr,
-				fc->writeback_cache ? creat : 0);
+		fuse_init_inode(inode, attr, 0);
 		unlock_new_inode(inode);
 	} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
 		/* Inode has changed type, any I/O on the old should fail */
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index c9a291391405..118b75bf920c 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -296,18 +296,8 @@  static int kpcs_do_file_open(struct fuse_conn *fc, struct file *file, struct ino
 	      fi->nodeid, di->fileinfo.sys.chunk_size,
 	      di->fileinfo.sys.stripe_depth, di->fileinfo.sys.strip_width);
 
-	mutex_lock(&inode->i_mutex);
-	/* Some one already initialized it under us ? */
-	if (fi->private) {
-		mutex_unlock(&inode->i_mutex);
-		pcs_mapping_invalidate(&di->mapping);
-		pcs_mapping_deinit(&di->mapping);
-		kfree(di);
-		return 0;
-	}
 	ret = fuse_pcs_kdirect_claim_op(fc, file, true);
 	if (ret) {
-		mutex_unlock(&inode->i_mutex);
 		pcs_mapping_invalidate(&di->mapping);
 		pcs_mapping_deinit(&di->mapping);
 		kfree(di);
@@ -315,21 +305,31 @@  static int kpcs_do_file_open(struct fuse_conn *fc, struct file *file, struct ino
 	}
 	/* TODO: Propper initialization of dentry should be here!!! */
 	fi->private = di;
-	mutex_unlock(&inode->i_mutex);
 	return 0;
 }
 
 int kpcs_file_open(struct fuse_conn *fc, struct file *file, struct inode *inode)
 {
 	struct fuse_inode *fi = get_fuse_inode(inode);
+	struct pcs_dentry_info *di = fi->private;
+	struct pcs_mds_fileinfo info;
+	int ret;
 
 	if (!S_ISREG(inode->i_mode))
 		return 0;
 	if (fi->nodeid - FUSE_ROOT_ID >= PCS_FUSE_INO_SPECIAL_)
 		return 0;
-	/* Already initialized */
-	if (fi->private) {
+
+	lockdep_assert_held(&inode->i_mutex);
+	/* Already initialized. Update file size etc */
+	if (di) {
 		/*TODO: propper refcount for claim_cnt should be here */
+		ret = fuse_pcs_getfileinfo(fc, file, &info);
+		if (ret)
+			return ret;
+		spin_lock(&di->lock);
+		pcs_set_fileinfo(di, &info);
+		spin_unlock(&di->lock);
 		return 0;
 	}
 	return kpcs_do_file_open(fc, file, inode);