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

From: Maxim Patlasov
Date: Tue Apr 15 2014 - 07:32:31 EST


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@xxxxxxxxxxxxx>
---
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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/