fuse: clear FUSE_I_CTIME_DIRTY flag on setattr
authorMaxim Patlasov <MPatlasov@parallels.com>
Mon, 28 Apr 2014 12:19:25 +0000 (14:19 +0200)
committerMiklos Szeredi <mszeredi@suse.cz>
Mon, 28 Apr 2014 12:19:25 +0000 (14:19 +0200)
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 we could clear I_DIRTY_SYNC, but that needs more thought.

Signed-off-by: Maxim Patlasov <MPatlasov@parallels.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
fs/fuse/dir.c

index f62ab8e..843dcf1 100644 (file)
@@ -1518,7 +1518,7 @@ static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
 }
 
 static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
-                          bool trust_local_mtime)
+                          bool trust_local_cmtime)
 {
        unsigned ivalid = iattr->ia_valid;
 
@@ -1537,13 +1537,18 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
                if (!(ivalid & ATTR_ATIME_SET))
                        arg->valid |= FATTR_ATIME_NOW;
        }
-       if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_mtime)) {
+       if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_cmtime)) {
                arg->valid |= FATTR_MTIME;
                arg->mtime = iattr->ia_mtime.tv_sec;
                arg->mtimensec = iattr->ia_mtime.tv_nsec;
-               if (!(ivalid & ATTR_MTIME_SET) && !trust_local_mtime)
+               if (!(ivalid & ATTR_MTIME_SET) && !trust_local_cmtime)
                        arg->valid |= FATTR_MTIME_NOW;
        }
+       if ((ivalid & ATTR_CTIME) && trust_local_cmtime) {
+               arg->valid |= FATTR_CTIME;
+               arg->ctime = iattr->ia_ctime.tv_sec;
+               arg->ctimensec = iattr->ia_ctime.tv_nsec;
+       }
 }
 
 /*
@@ -1666,7 +1671,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
        bool is_wb = fc->writeback_cache;
        loff_t oldsize;
        int err;
-       bool trust_local_mtime = is_wb && S_ISREG(inode->i_mode);
+       bool trust_local_cmtime = is_wb && S_ISREG(inode->i_mode);
 
        if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
                attr->ia_valid |= ATTR_FORCE;
@@ -1691,13 +1696,13 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
        if (is_truncate) {
                fuse_set_nowrite(inode);
                set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
-               if (trust_local_mtime && attr->ia_size != inode->i_size)
-                       attr->ia_valid |= ATTR_MTIME;
+               if (trust_local_cmtime && attr->ia_size != inode->i_size)
+                       attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
        }
 
        memset(&inarg, 0, sizeof(inarg));
        memset(&outarg, 0, sizeof(outarg));
-       iattr_to_fattr(attr, &inarg, trust_local_mtime);
+       iattr_to_fattr(attr, &inarg, trust_local_cmtime);
        if (file) {
                struct fuse_file *ff = file->private_data;
                inarg.valid |= FATTR_FH;
@@ -1726,8 +1731,11 @@ 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)) {
-               inode->i_mtime = attr->ia_mtime;
+       if (trust_local_cmtime) {
+               if (attr->ia_valid & ATTR_MTIME)
+                       inode->i_mtime = attr->ia_mtime;
+               if (attr->ia_valid & ATTR_CTIME)
+                       inode->i_ctime = attr->ia_ctime;
                /* FIXME: clear I_DIRTY_SYNC? */
        }