diff options
author | Pavel Emelyanov <xemul@openvz.org> | 2013-10-10 09:10:46 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2014-04-02 09:38:48 -0400 |
commit | 8373200b124d03de7fa2e99be56de8642e604e9e (patch) | |
tree | 853b6590ced17b0449883093350bf681e5e9cbd7 /fs/fuse/dir.c | |
parent | d5cd66c58edf10a7ee786659994595fd43995aab (diff) |
fuse: Trust kernel i_size only
Make fuse think that when writeback is on the inode's i_size is always
up-to-date and not update it with the value received from the userspace.
This is done because the page cache code may update i_size without letting
the FS know.
This assumption implies fixing the previously introduced short-read helper --
when a short read occurs the 'hole' is filled with zeroes.
fuse_file_fallocate() is also fixed because now we should keep i_size up to
date, so it must be updated if FUSE_FALLOCATE request succeeded.
Signed-off-by: Maxim V. Patlasov <MPatlasov@parallels.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 1d1292c581c3..c52f143da9ad 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -839,6 +839,11 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, | |||
839 | struct kstat *stat) | 839 | struct kstat *stat) |
840 | { | 840 | { |
841 | unsigned int blkbits; | 841 | unsigned int blkbits; |
842 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
843 | |||
844 | /* see the comment in fuse_change_attributes() */ | ||
845 | if (fc->writeback_cache && S_ISREG(inode->i_mode)) | ||
846 | attr->size = i_size_read(inode); | ||
842 | 847 | ||
843 | stat->dev = inode->i_sb->s_dev; | 848 | stat->dev = inode->i_sb->s_dev; |
844 | stat->ino = attr->ino; | 849 | stat->ino = attr->ino; |
@@ -1580,6 +1585,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, | |||
1580 | struct fuse_setattr_in inarg; | 1585 | struct fuse_setattr_in inarg; |
1581 | struct fuse_attr_out outarg; | 1586 | struct fuse_attr_out outarg; |
1582 | bool is_truncate = false; | 1587 | bool is_truncate = false; |
1588 | bool is_wb = fc->writeback_cache; | ||
1583 | loff_t oldsize; | 1589 | loff_t oldsize; |
1584 | int err; | 1590 | int err; |
1585 | 1591 | ||
@@ -1651,7 +1657,9 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, | |||
1651 | fuse_change_attributes_common(inode, &outarg.attr, | 1657 | fuse_change_attributes_common(inode, &outarg.attr, |
1652 | attr_timeout(&outarg)); | 1658 | attr_timeout(&outarg)); |
1653 | oldsize = inode->i_size; | 1659 | oldsize = inode->i_size; |
1654 | i_size_write(inode, outarg.attr.size); | 1660 | /* see the comment in fuse_change_attributes() */ |
1661 | if (!is_wb || is_truncate || !S_ISREG(inode->i_mode)) | ||
1662 | i_size_write(inode, outarg.attr.size); | ||
1655 | 1663 | ||
1656 | if (is_truncate) { | 1664 | if (is_truncate) { |
1657 | /* NOTE: this may release/reacquire fc->lock */ | 1665 | /* NOTE: this may release/reacquire fc->lock */ |
@@ -1663,7 +1671,8 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, | |||
1663 | * Only call invalidate_inode_pages2() after removing | 1671 | * Only call invalidate_inode_pages2() after removing |
1664 | * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. | 1672 | * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock. |
1665 | */ | 1673 | */ |
1666 | if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { | 1674 | if ((is_truncate || !is_wb) && |
1675 | S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) { | ||
1667 | truncate_pagecache(inode, outarg.attr.size); | 1676 | truncate_pagecache(inode, outarg.attr.size); |
1668 | invalidate_inode_pages2(inode->i_mapping); | 1677 | invalidate_inode_pages2(inode->i_mapping); |
1669 | } | 1678 | } |