diff options
author | Maxim Patlasov <MPatlasov@parallels.com> | 2013-12-26 10:51:11 -0500 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2014-04-02 09:38:48 -0400 |
commit | b0aa760652179072119582375f8dc896ed5b5dfd (patch) | |
tree | cbc990b308b9894eba032101db994b05e75ad444 /fs/fuse/inode.c | |
parent | 8373200b124d03de7fa2e99be56de8642e604e9e (diff) |
fuse: Trust kernel i_mtime only
Let the kernel maintain i_mtime locally:
- clear S_NOCMTIME
- implement i_op->update_time()
- flush mtime on fsync and last close
- update i_mtime explicitly on truncate and fallocate
Fuse inode flag FUSE_I_MTIME_DIRTY serves as indication that local i_mtime
should be flushed to the server eventually.
Signed-off-by: Maxim Patlasov <MPatlasov@parallels.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index c668c8436894..1061b0d9b86d 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -170,8 +170,11 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | |||
170 | inode->i_blocks = attr->blocks; | 170 | inode->i_blocks = attr->blocks; |
171 | inode->i_atime.tv_sec = attr->atime; | 171 | inode->i_atime.tv_sec = attr->atime; |
172 | inode->i_atime.tv_nsec = attr->atimensec; | 172 | inode->i_atime.tv_nsec = attr->atimensec; |
173 | inode->i_mtime.tv_sec = attr->mtime; | 173 | /* mtime from server may be stale due to local buffered write */ |
174 | inode->i_mtime.tv_nsec = attr->mtimensec; | 174 | if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) { |
175 | inode->i_mtime.tv_sec = attr->mtime; | ||
176 | inode->i_mtime.tv_nsec = attr->mtimensec; | ||
177 | } | ||
175 | inode->i_ctime.tv_sec = attr->ctime; | 178 | inode->i_ctime.tv_sec = attr->ctime; |
176 | inode->i_ctime.tv_nsec = attr->ctimensec; | 179 | inode->i_ctime.tv_nsec = attr->ctimensec; |
177 | 180 | ||
@@ -250,6 +253,8 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) | |||
250 | { | 253 | { |
251 | inode->i_mode = attr->mode & S_IFMT; | 254 | inode->i_mode = attr->mode & S_IFMT; |
252 | inode->i_size = attr->size; | 255 | inode->i_size = attr->size; |
256 | inode->i_mtime.tv_sec = attr->mtime; | ||
257 | inode->i_mtime.tv_nsec = attr->mtimensec; | ||
253 | if (S_ISREG(inode->i_mode)) { | 258 | if (S_ISREG(inode->i_mode)) { |
254 | fuse_init_common(inode); | 259 | fuse_init_common(inode); |
255 | fuse_init_file_inode(inode); | 260 | fuse_init_file_inode(inode); |
@@ -296,7 +301,9 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, | |||
296 | return NULL; | 301 | return NULL; |
297 | 302 | ||
298 | if ((inode->i_state & I_NEW)) { | 303 | if ((inode->i_state & I_NEW)) { |
299 | inode->i_flags |= S_NOATIME|S_NOCMTIME; | 304 | inode->i_flags |= S_NOATIME; |
305 | if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) | ||
306 | inode->i_flags |= S_NOCMTIME; | ||
300 | inode->i_generation = generation; | 307 | inode->i_generation = generation; |
301 | inode->i_data.backing_dev_info = &fc->bdi; | 308 | inode->i_data.backing_dev_info = &fc->bdi; |
302 | fuse_init_inode(inode, attr); | 309 | fuse_init_inode(inode, attr); |