[Devel] [PATCH 6/7] fuse: clear FUSE_I_CTIME_DIRTY flag on setattr

Maxim Patlasov MPatlasov at parallels.com
Tue Apr 15 04:32:17 PDT 2014


The patch addresses two use-cases when the flag may be safely cleared:

1. fuse_do_setattr() is called with ATTR_CTIME flag set in attr->ia_valid.
In this case attr->ia_ctime bears actual value. In-kernel fuse must send it
to the userspace server and then assign the value to inode->i_ctime.

2. fuse_do_setattr() is called with ATTR_SIZE flag set in attr->ia_valid,
whereas ATTR_CTIME is not set (truncate(2)).
In this case in-kernel fuse must sent "now" to the userspace server and then
assign the value to inode->i_ctime.

In both cases fuse can clear FUSE_I_CTIME_DIRTY flag because actual ctime
value was flushed to the server.

Signed-off-by: Maxim Patlasov <MPatlasov at parallels.com>
---
 fs/fuse/dir.c |   38 ++++++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 2187960..3495aaf 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1518,8 +1518,9 @@ static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
 	return true;
 }
 
-static void iattr_to_fattr(struct inode *inode, struct iattr *iattr,
-			   struct fuse_setattr_in *arg, bool trust_local_mtime)
+static void iattr_to_fattr(struct fuse_conn *fc, struct inode *inode,
+			   struct iattr *iattr, struct fuse_setattr_in *arg,
+			   bool trust_local_mtime, struct timespec *ctime)
 {
 	unsigned ivalid = iattr->ia_valid;
 	struct timespec now = current_fs_time(inode->i_sb);
@@ -1550,6 +1551,19 @@ static void iattr_to_fattr(struct inode *inode, struct iattr *iattr,
 		arg->mtime = now.tv_sec;
 		arg->mtimensec = now.tv_nsec;
 	}
+
+	if ((ivalid & ATTR_CTIME) && trust_local_mtime)
+		*ctime = iattr->ia_ctime;
+	else if ((ivalid & ATTR_SIZE) && trust_local_mtime)
+		*ctime = now;
+	else
+		ctime = NULL;
+
+	if (ctime && fc->minor >= 24) {
+		arg->valid |= FATTR_CTIME;
+		arg->ctime = ctime->tv_sec;
+		arg->ctimensec = ctime->tv_nsec;
+	}
 }
 
 /*
@@ -1688,6 +1702,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
 	loff_t oldsize;
 	int err;
 	bool trust_local_mtime = is_wb && S_ISREG(inode->i_mode);
+	struct timespec ctime;
 
 	if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
 		attr->ia_valid |= ATTR_FORCE;
@@ -1716,7 +1731,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
 
 	memset(&inarg, 0, sizeof(inarg));
 	memset(&outarg, 0, sizeof(outarg));
-	iattr_to_fattr(inode, attr, &inarg, trust_local_mtime);
+	iattr_to_fattr(fc, inode, attr, &inarg, trust_local_mtime, &ctime);
 	if (file) {
 		struct fuse_file *ff = file->private_data;
 		inarg.valid |= FATTR_FH;
@@ -1744,11 +1759,18 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
 	}
 
 	spin_lock(&fc->lock);
-	/* the kernel maintains i_mtime locally */
-	if (trust_local_mtime && (attr->ia_valid & (ATTR_MTIME | ATTR_SIZE))) {
-		inode->i_mtime.tv_sec = inarg.mtime;
-		inode->i_mtime.tv_nsec = inarg.mtimensec;
-		clear_bit(FUSE_I_MTIME_DIRTY, &fi->state);
+	/* the kernel maintains i_mtime and i_ctime locally */
+	if (trust_local_mtime) {
+		if (attr->ia_valid & (ATTR_MTIME | ATTR_SIZE)) {
+			inode->i_mtime.tv_sec = inarg.mtime;
+			inode->i_mtime.tv_nsec = inarg.mtimensec;
+			clear_bit(FUSE_I_MTIME_DIRTY, &fi->state);
+		}
+
+		if (attr->ia_valid & (ATTR_CTIME | ATTR_SIZE)) {
+			inode->i_ctime = ctime;
+			clear_bit(FUSE_I_CTIME_DIRTY, &fi->state);
+		}
 	}
 
 	fuse_change_attributes_common(inode, &outarg.attr,




More information about the Devel mailing list