aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dir.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2007-10-17 02:31:01 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 11:43:03 -0400
commite00d2c2d4aead747d0fbee99001b00612d1082b0 (patch)
treec57228fae55fdb0b91fa6c211431a4ced2435c53 /fs/fuse/dir.c
parentc756e0a4d79202535774806f148026e40466a5eb (diff)
fuse: truncate on spontaneous size change
Memory mappings were only truncated on an explicit truncate, but not when the file size was changed externally. Fix this by moving the truncation code from fuse_setattr to fuse_change_attributes. Yes, there are races between write and and external truncation, but we can't really do anything about them. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r--fs/fuse/dir.c46
1 files changed, 13 insertions, 33 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 35e5cabb3b8c..29fef75f2360 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -980,23 +980,6 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
980 } 980 }
981} 981}
982 982
983static void fuse_vmtruncate(struct inode *inode, loff_t offset)
984{
985 struct fuse_conn *fc = get_fuse_conn(inode);
986 int need_trunc;
987
988 spin_lock(&fc->lock);
989 need_trunc = inode->i_size > offset;
990 i_size_write(inode, offset);
991 spin_unlock(&fc->lock);
992
993 if (need_trunc) {
994 struct address_space *mapping = inode->i_mapping;
995 unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
996 truncate_inode_pages(mapping, offset);
997 }
998}
999
1000/* 983/*
1001 * Set attributes, and at the same time refresh them. 984 * Set attributes, and at the same time refresh them.
1002 * 985 *
@@ -1014,7 +997,6 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
1014 struct fuse_setattr_in inarg; 997 struct fuse_setattr_in inarg;
1015 struct fuse_attr_out outarg; 998 struct fuse_attr_out outarg;
1016 int err; 999 int err;
1017 int is_truncate = 0;
1018 1000
1019 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 1001 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
1020 err = inode_change_ok(inode, attr); 1002 err = inode_change_ok(inode, attr);
@@ -1024,7 +1006,6 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
1024 1006
1025 if (attr->ia_valid & ATTR_SIZE) { 1007 if (attr->ia_valid & ATTR_SIZE) {
1026 unsigned long limit; 1008 unsigned long limit;
1027 is_truncate = 1;
1028 if (IS_SWAPFILE(inode)) 1009 if (IS_SWAPFILE(inode))
1029 return -ETXTBSY; 1010 return -ETXTBSY;
1030 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; 1011 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
@@ -1051,21 +1032,20 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
1051 request_send(fc, req); 1032 request_send(fc, req);
1052 err = req->out.h.error; 1033 err = req->out.h.error;
1053 fuse_put_request(fc, req); 1034 fuse_put_request(fc, req);
1054 if (!err) { 1035 if (err) {
1055 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { 1036 if (err == -EINTR)
1056 make_bad_inode(inode); 1037 fuse_invalidate_attr(inode);
1057 err = -EIO; 1038 return err;
1058 } else { 1039 }
1059 if (is_truncate)
1060 fuse_vmtruncate(inode, outarg.attr.size);
1061 fuse_change_attributes(inode, &outarg.attr);
1062 fi->i_time = time_to_jiffies(outarg.attr_valid,
1063 outarg.attr_valid_nsec);
1064 }
1065 } else if (err == -EINTR)
1066 fuse_invalidate_attr(inode);
1067 1040
1068 return err; 1041 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
1042 make_bad_inode(inode);
1043 return -EIO;
1044 }
1045
1046 fuse_change_attributes(inode, &outarg.attr);
1047 fi->i_time = time_to_jiffies(outarg.attr_valid, outarg.attr_valid_nsec);
1048 return 0;
1069} 1049}
1070 1050
1071static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, 1051static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,