fuse: trust kernel i_ctime only
authorMaxim Patlasov <MPatlasov@parallels.com>
Mon, 28 Apr 2014 12:19:24 +0000 (14:19 +0200)
committerMiklos Szeredi <mszeredi@suse.cz>
Mon, 28 Apr 2014 12:19:24 +0000 (14:19 +0200)
Let the kernel maintain i_ctime locally: update i_ctime explicitly on
truncate, fallocate, open(O_TRUNC), setxattr, removexattr, link, rename,
unlink.

The inode flag I_DIRTY_SYNC serves as indication that local i_ctime should
be flushed to the server eventually.  The patch sets the flag and updates
i_ctime in course of operations listed above.

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

index 65357bd1d17ba06d508998b1bfa258aa7d243b6a..f62ab8eedb5f2ce1728da74cd238cf049d28e9f7 100644 (file)
@@ -679,6 +679,14 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
        return create_new_entry(fc, req, dir, entry, S_IFLNK);
 }
 
+static inline void fuse_update_ctime(struct inode *inode)
+{
+       if (!IS_NOCMTIME(inode)) {
+               inode->i_ctime = current_fs_time(inode->i_sb);
+               mark_inode_dirty_sync(inode);
+       }
+}
+
 static int fuse_unlink(struct inode *dir, struct dentry *entry)
 {
        int err;
@@ -713,6 +721,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
                fuse_invalidate_attr(inode);
                fuse_invalidate_attr(dir);
                fuse_invalidate_entry_cache(entry);
+               fuse_update_ctime(inode);
        } else if (err == -EINTR)
                fuse_invalidate_entry(entry);
        return err;
@@ -771,6 +780,7 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
        if (!err) {
                /* ctime changes */
                fuse_invalidate_attr(oldent->d_inode);
+               fuse_update_ctime(oldent->d_inode);
 
                fuse_invalidate_attr(olddir);
                if (olddir != newdir)
@@ -780,6 +790,7 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
                if (newent->d_inode) {
                        fuse_invalidate_attr(newent->d_inode);
                        fuse_invalidate_entry_cache(newent);
+                       fuse_update_ctime(newent->d_inode);
                }
        } else if (err == -EINTR) {
                /* If request was interrupted, DEITY only knows if the
@@ -829,6 +840,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
                inc_nlink(inode);
                spin_unlock(&fc->lock);
                fuse_invalidate_attr(inode);
+               fuse_update_ctime(inode);
        } else if (err == -EINTR) {
                fuse_invalidate_attr(inode);
        }
@@ -846,6 +858,8 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
                attr->size = i_size_read(inode);
                attr->mtime = inode->i_mtime.tv_sec;
                attr->mtimensec = inode->i_mtime.tv_nsec;
+               attr->ctime = inode->i_ctime.tv_sec;
+               attr->ctimensec = inode->i_ctime.tv_nsec;
        }
 
        stat->dev = inode->i_sb->s_dev;
@@ -1811,8 +1825,10 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
                fc->no_setxattr = 1;
                err = -EOPNOTSUPP;
        }
-       if (!err)
+       if (!err) {
                fuse_invalidate_attr(inode);
+               fuse_update_ctime(inode);
+       }
        return err;
 }
 
@@ -1942,8 +1958,10 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
                fc->no_removexattr = 1;
                err = -EOPNOTSUPP;
        }
-       if (!err)
+       if (!err) {
                fuse_invalidate_attr(inode);
+               fuse_update_ctime(inode);
+       }
        return err;
 }
 
index 560eafcdd6a748e5db556139ad374557023e419c..e9ecb187810947b1e865e406571046d2599a8a80 100644 (file)
@@ -175,9 +175,9 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
        if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) {
                inode->i_mtime.tv_sec   = attr->mtime;
                inode->i_mtime.tv_nsec  = attr->mtimensec;
+               inode->i_ctime.tv_sec   = attr->ctime;
+               inode->i_ctime.tv_nsec  = attr->ctimensec;
        }
-       inode->i_ctime.tv_sec   = attr->ctime;
-       inode->i_ctime.tv_nsec  = attr->ctimensec;
 
        if (attr->blksize != 0)
                inode->i_blkbits = ilog2(attr->blksize);
@@ -256,6 +256,8 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
        inode->i_size = attr->size;
        inode->i_mtime.tv_sec  = attr->mtime;
        inode->i_mtime.tv_nsec = attr->mtimensec;
+       inode->i_ctime.tv_sec  = attr->ctime;
+       inode->i_ctime.tv_nsec = attr->ctimensec;
        if (S_ISREG(inode->i_mode)) {
                fuse_init_common(inode);
                fuse_init_file_inode(inode);