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 <mpatla...@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,

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to