aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse
diff options
context:
space:
mode:
authorMaxim Patlasov <MPatlasov@parallels.com>2013-12-26 10:51:11 -0500
committerMiklos Szeredi <mszeredi@suse.cz>2014-04-02 09:38:48 -0400
commitb0aa760652179072119582375f8dc896ed5b5dfd (patch)
treecbc990b308b9894eba032101db994b05e75ad444 /fs/fuse
parent8373200b124d03de7fa2e99be56de8642e604e9e (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')
-rw-r--r--fs/fuse/dir.c108
-rw-r--r--fs/fuse/file.c30
-rw-r--r--fs/fuse/fuse_i.h6
-rw-r--r--fs/fuse/inode.c13
4 files changed, 132 insertions, 25 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index c52f143da9ad..5b4e035b364c 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -842,8 +842,11 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
842 struct fuse_conn *fc = get_fuse_conn(inode); 842 struct fuse_conn *fc = get_fuse_conn(inode);
843 843
844 /* see the comment in fuse_change_attributes() */ 844 /* see the comment in fuse_change_attributes() */
845 if (fc->writeback_cache && S_ISREG(inode->i_mode)) 845 if (fc->writeback_cache && S_ISREG(inode->i_mode)) {
846 attr->size = i_size_read(inode); 846 attr->size = i_size_read(inode);
847 attr->mtime = inode->i_mtime.tv_sec;
848 attr->mtimensec = inode->i_mtime.tv_nsec;
849 }
847 850
848 stat->dev = inode->i_sb->s_dev; 851 stat->dev = inode->i_sb->s_dev;
849 stat->ino = attr->ino; 852 stat->ino = attr->ino;
@@ -1482,12 +1485,16 @@ static long fuse_dir_compat_ioctl(struct file *file, unsigned int cmd,
1482 FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR); 1485 FUSE_IOCTL_COMPAT | FUSE_IOCTL_DIR);
1483} 1486}
1484 1487
1485static bool update_mtime(unsigned ivalid) 1488static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
1486{ 1489{
1487 /* Always update if mtime is explicitly set */ 1490 /* Always update if mtime is explicitly set */
1488 if (ivalid & ATTR_MTIME_SET) 1491 if (ivalid & ATTR_MTIME_SET)
1489 return true; 1492 return true;
1490 1493
1494 /* Or if kernel i_mtime is the official one */
1495 if (trust_local_mtime)
1496 return true;
1497
1491 /* If it's an open(O_TRUNC) or an ftruncate(), don't update */ 1498 /* If it's an open(O_TRUNC) or an ftruncate(), don't update */
1492 if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE))) 1499 if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))
1493 return false; 1500 return false;
@@ -1496,7 +1503,8 @@ static bool update_mtime(unsigned ivalid)
1496 return true; 1503 return true;
1497} 1504}
1498 1505
1499static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) 1506static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
1507 bool trust_local_mtime)
1500{ 1508{
1501 unsigned ivalid = iattr->ia_valid; 1509 unsigned ivalid = iattr->ia_valid;
1502 1510
@@ -1515,11 +1523,11 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
1515 if (!(ivalid & ATTR_ATIME_SET)) 1523 if (!(ivalid & ATTR_ATIME_SET))
1516 arg->valid |= FATTR_ATIME_NOW; 1524 arg->valid |= FATTR_ATIME_NOW;
1517 } 1525 }
1518 if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) { 1526 if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, trust_local_mtime)) {
1519 arg->valid |= FATTR_MTIME; 1527 arg->valid |= FATTR_MTIME;
1520 arg->mtime = iattr->ia_mtime.tv_sec; 1528 arg->mtime = iattr->ia_mtime.tv_sec;
1521 arg->mtimensec = iattr->ia_mtime.tv_nsec; 1529 arg->mtimensec = iattr->ia_mtime.tv_nsec;
1522 if (!(ivalid & ATTR_MTIME_SET)) 1530 if (!(ivalid & ATTR_MTIME_SET) && !trust_local_mtime)
1523 arg->valid |= FATTR_MTIME_NOW; 1531 arg->valid |= FATTR_MTIME_NOW;
1524 } 1532 }
1525} 1533}
@@ -1568,6 +1576,63 @@ void fuse_release_nowrite(struct inode *inode)
1568 spin_unlock(&fc->lock); 1576 spin_unlock(&fc->lock);
1569} 1577}
1570 1578
1579static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_req *req,
1580 struct inode *inode,
1581 struct fuse_setattr_in *inarg_p,
1582 struct fuse_attr_out *outarg_p)
1583{
1584 req->in.h.opcode = FUSE_SETATTR;
1585 req->in.h.nodeid = get_node_id(inode);
1586 req->in.numargs = 1;
1587 req->in.args[0].size = sizeof(*inarg_p);
1588 req->in.args[0].value = inarg_p;
1589 req->out.numargs = 1;
1590 if (fc->minor < 9)
1591 req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
1592 else
1593 req->out.args[0].size = sizeof(*outarg_p);
1594 req->out.args[0].value = outarg_p;
1595}
1596
1597/*
1598 * Flush inode->i_mtime to the server
1599 */
1600int fuse_flush_mtime(struct file *file, bool nofail)
1601{
1602 struct inode *inode = file->f_mapping->host;
1603 struct fuse_inode *fi = get_fuse_inode(inode);
1604 struct fuse_conn *fc = get_fuse_conn(inode);
1605 struct fuse_req *req = NULL;
1606 struct fuse_setattr_in inarg;
1607 struct fuse_attr_out outarg;
1608 int err;
1609
1610 if (nofail) {
1611 req = fuse_get_req_nofail_nopages(fc, file);
1612 } else {
1613 req = fuse_get_req_nopages(fc);
1614 if (IS_ERR(req))
1615 return PTR_ERR(req);
1616 }
1617
1618 memset(&inarg, 0, sizeof(inarg));
1619 memset(&outarg, 0, sizeof(outarg));
1620
1621 inarg.valid |= FATTR_MTIME;
1622 inarg.mtime = inode->i_mtime.tv_sec;
1623 inarg.mtimensec = inode->i_mtime.tv_nsec;
1624
1625 fuse_setattr_fill(fc, req, inode, &inarg, &outarg);
1626 fuse_request_send(fc, req);
1627 err = req->out.h.error;
1628 fuse_put_request(fc, req);
1629
1630 if (!err)
1631 clear_bit(FUSE_I_MTIME_DIRTY, &fi->state);
1632
1633 return err;
1634}
1635
1571/* 1636/*
1572 * Set attributes, and at the same time refresh them. 1637 * Set attributes, and at the same time refresh them.
1573 * 1638 *
@@ -1588,6 +1653,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
1588 bool is_wb = fc->writeback_cache; 1653 bool is_wb = fc->writeback_cache;
1589 loff_t oldsize; 1654 loff_t oldsize;
1590 int err; 1655 int err;
1656 bool trust_local_mtime = is_wb && S_ISREG(inode->i_mode);
1591 1657
1592 if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) 1658 if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
1593 attr->ia_valid |= ATTR_FORCE; 1659 attr->ia_valid |= ATTR_FORCE;
@@ -1616,7 +1682,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
1616 1682
1617 memset(&inarg, 0, sizeof(inarg)); 1683 memset(&inarg, 0, sizeof(inarg));
1618 memset(&outarg, 0, sizeof(outarg)); 1684 memset(&outarg, 0, sizeof(outarg));
1619 iattr_to_fattr(attr, &inarg); 1685 iattr_to_fattr(attr, &inarg, trust_local_mtime);
1620 if (file) { 1686 if (file) {
1621 struct fuse_file *ff = file->private_data; 1687 struct fuse_file *ff = file->private_data;
1622 inarg.valid |= FATTR_FH; 1688 inarg.valid |= FATTR_FH;
@@ -1627,17 +1693,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
1627 inarg.valid |= FATTR_LOCKOWNER; 1693 inarg.valid |= FATTR_LOCKOWNER;
1628 inarg.lock_owner = fuse_lock_owner_id(fc, current->files); 1694 inarg.lock_owner = fuse_lock_owner_id(fc, current->files);
1629 } 1695 }
1630 req->in.h.opcode = FUSE_SETATTR; 1696 fuse_setattr_fill(fc, req, inode, &inarg, &outarg);
1631 req->in.h.nodeid = get_node_id(inode);
1632 req->in.numargs = 1;
1633 req->in.args[0].size = sizeof(inarg);
1634 req->in.args[0].value = &inarg;
1635 req->out.numargs = 1;
1636 if (fc->minor < 9)
1637 req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
1638 else
1639 req->out.args[0].size = sizeof(outarg);
1640 req->out.args[0].value = &outarg;
1641 fuse_request_send(fc, req); 1697 fuse_request_send(fc, req);
1642 err = req->out.h.error; 1698 err = req->out.h.error;
1643 fuse_put_request(fc, req); 1699 fuse_put_request(fc, req);
@@ -1654,6 +1710,12 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
1654 } 1710 }
1655 1711
1656 spin_lock(&fc->lock); 1712 spin_lock(&fc->lock);
1713 /* the kernel maintains i_mtime locally */
1714 if (trust_local_mtime && (attr->ia_valid & ATTR_MTIME)) {
1715 inode->i_mtime = attr->ia_mtime;
1716 clear_bit(FUSE_I_MTIME_DIRTY, &fi->state);
1717 }
1718
1657 fuse_change_attributes_common(inode, &outarg.attr, 1719 fuse_change_attributes_common(inode, &outarg.attr,
1658 attr_timeout(&outarg)); 1720 attr_timeout(&outarg));
1659 oldsize = inode->i_size; 1721 oldsize = inode->i_size;
@@ -1884,6 +1946,17 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
1884 return err; 1946 return err;
1885} 1947}
1886 1948
1949static int fuse_update_time(struct inode *inode, struct timespec *now,
1950 int flags)
1951{
1952 if (flags & S_MTIME) {
1953 inode->i_mtime = *now;
1954 set_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state);
1955 BUG_ON(!S_ISREG(inode->i_mode));
1956 }
1957 return 0;
1958}
1959
1887static const struct inode_operations fuse_dir_inode_operations = { 1960static const struct inode_operations fuse_dir_inode_operations = {
1888 .lookup = fuse_lookup, 1961 .lookup = fuse_lookup,
1889 .mkdir = fuse_mkdir, 1962 .mkdir = fuse_mkdir,
@@ -1923,6 +1996,7 @@ static const struct inode_operations fuse_common_inode_operations = {
1923 .getxattr = fuse_getxattr, 1996 .getxattr = fuse_getxattr,
1924 .listxattr = fuse_listxattr, 1997 .listxattr = fuse_listxattr,
1925 .removexattr = fuse_removexattr, 1998 .removexattr = fuse_removexattr,
1999 .update_time = fuse_update_time,
1926}; 2000};
1927 2001
1928static const struct inode_operations fuse_symlink_inode_operations = { 2002static const struct inode_operations fuse_symlink_inode_operations = {
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index c091a17d3ffc..69de9b860c39 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -308,6 +308,9 @@ static int fuse_open(struct inode *inode, struct file *file)
308 308
309static int fuse_release(struct inode *inode, struct file *file) 309static int fuse_release(struct inode *inode, struct file *file)
310{ 310{
311 if (test_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state))
312 fuse_flush_mtime(file, true);
313
311 fuse_release_common(file, FUSE_RELEASE); 314 fuse_release_common(file, FUSE_RELEASE);
312 315
313 /* return value is ignored by VFS */ 316 /* return value is ignored by VFS */
@@ -475,6 +478,12 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
475 478
476 fuse_sync_writes(inode); 479 fuse_sync_writes(inode);
477 480
481 if (test_bit(FUSE_I_MTIME_DIRTY, &get_fuse_inode(inode)->state)) {
482 int err = fuse_flush_mtime(file, false);
483 if (err)
484 goto out;
485 }
486
478 req = fuse_get_req_nopages(fc); 487 req = fuse_get_req_nopages(fc);
479 if (IS_ERR(req)) { 488 if (IS_ERR(req)) {
480 err = PTR_ERR(req); 489 err = PTR_ERR(req);
@@ -960,16 +969,21 @@ static size_t fuse_send_write(struct fuse_req *req, struct fuse_io_priv *io,
960 return req->misc.write.out.size; 969 return req->misc.write.out.size;
961} 970}
962 971
963void fuse_write_update_size(struct inode *inode, loff_t pos) 972bool fuse_write_update_size(struct inode *inode, loff_t pos)
964{ 973{
965 struct fuse_conn *fc = get_fuse_conn(inode); 974 struct fuse_conn *fc = get_fuse_conn(inode);
966 struct fuse_inode *fi = get_fuse_inode(inode); 975 struct fuse_inode *fi = get_fuse_inode(inode);
976 bool ret = false;
967 977
968 spin_lock(&fc->lock); 978 spin_lock(&fc->lock);
969 fi->attr_version = ++fc->attr_version; 979 fi->attr_version = ++fc->attr_version;
970 if (pos > inode->i_size) 980 if (pos > inode->i_size) {
971 i_size_write(inode, pos); 981 i_size_write(inode, pos);
982 ret = true;
983 }
972 spin_unlock(&fc->lock); 984 spin_unlock(&fc->lock);
985
986 return ret;
973} 987}
974 988
975static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file, 989static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file,
@@ -2877,8 +2891,16 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
2877 goto out; 2891 goto out;
2878 2892
2879 /* we could have extended the file */ 2893 /* we could have extended the file */
2880 if (!(mode & FALLOC_FL_KEEP_SIZE)) 2894 if (!(mode & FALLOC_FL_KEEP_SIZE)) {
2881 fuse_write_update_size(inode, offset + length); 2895 bool changed = fuse_write_update_size(inode, offset + length);
2896
2897 if (changed && fc->writeback_cache) {
2898 struct fuse_inode *fi = get_fuse_inode(inode);
2899
2900 inode->i_mtime = current_fs_time(inode->i_sb);
2901 set_bit(FUSE_I_MTIME_DIRTY, &fi->state);
2902 }
2903 }
2882 2904
2883 if (mode & FALLOC_FL_PUNCH_HOLE) 2905 if (mode & FALLOC_FL_PUNCH_HOLE)
2884 truncate_pagecache_range(inode, offset, offset + length - 1); 2906 truncate_pagecache_range(inode, offset, offset + length - 1);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 374a8be014fd..1e6ad6d43051 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -119,6 +119,8 @@ enum {
119 FUSE_I_INIT_RDPLUS, 119 FUSE_I_INIT_RDPLUS,
120 /** An operation changing file size is in progress */ 120 /** An operation changing file size is in progress */
121 FUSE_I_SIZE_UNSTABLE, 121 FUSE_I_SIZE_UNSTABLE,
122 /** i_mtime has been updated locally; a flush to userspace needed */
123 FUSE_I_MTIME_DIRTY,
122}; 124};
123 125
124struct fuse_conn; 126struct fuse_conn;
@@ -876,7 +878,9 @@ long fuse_ioctl_common(struct file *file, unsigned int cmd,
876unsigned fuse_file_poll(struct file *file, poll_table *wait); 878unsigned fuse_file_poll(struct file *file, poll_table *wait);
877int fuse_dev_release(struct inode *inode, struct file *file); 879int fuse_dev_release(struct inode *inode, struct file *file);
878 880
879void fuse_write_update_size(struct inode *inode, loff_t pos); 881bool fuse_write_update_size(struct inode *inode, loff_t pos);
882
883int fuse_flush_mtime(struct file *file, bool nofail);
880 884
881int fuse_do_setattr(struct inode *inode, struct iattr *attr, 885int fuse_do_setattr(struct inode *inode, struct iattr *attr,
882 struct file *file); 886 struct file *file);
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);