aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/inode.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/inode.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/inode.c')
-rw-r--r--fs/fuse/inode.c25
1 files changed, 20 insertions, 5 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 95c8a9738ca7..b584de33a6a7 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -109,20 +109,24 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
109 return 0; 109 return 0;
110} 110}
111 111
112static void fuse_truncate(struct address_space *mapping, loff_t offset)
113{
114 /* See vmtruncate() */
115 unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
116 truncate_inode_pages(mapping, offset);
117 unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
118}
119
112void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) 120void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
113{ 121{
114 struct fuse_conn *fc = get_fuse_conn(inode); 122 struct fuse_conn *fc = get_fuse_conn(inode);
115 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) 123 loff_t oldsize;
116 invalidate_mapping_pages(inode->i_mapping, 0, -1);
117 124
118 inode->i_ino = attr->ino; 125 inode->i_ino = attr->ino;
119 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777); 126 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
120 inode->i_nlink = attr->nlink; 127 inode->i_nlink = attr->nlink;
121 inode->i_uid = attr->uid; 128 inode->i_uid = attr->uid;
122 inode->i_gid = attr->gid; 129 inode->i_gid = attr->gid;
123 spin_lock(&fc->lock);
124 i_size_write(inode, attr->size);
125 spin_unlock(&fc->lock);
126 inode->i_blocks = attr->blocks; 130 inode->i_blocks = attr->blocks;
127 inode->i_atime.tv_sec = attr->atime; 131 inode->i_atime.tv_sec = attr->atime;
128 inode->i_atime.tv_nsec = attr->atimensec; 132 inode->i_atime.tv_nsec = attr->atimensec;
@@ -130,6 +134,17 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
130 inode->i_mtime.tv_nsec = attr->mtimensec; 134 inode->i_mtime.tv_nsec = attr->mtimensec;
131 inode->i_ctime.tv_sec = attr->ctime; 135 inode->i_ctime.tv_sec = attr->ctime;
132 inode->i_ctime.tv_nsec = attr->ctimensec; 136 inode->i_ctime.tv_nsec = attr->ctimensec;
137
138 spin_lock(&fc->lock);
139 oldsize = inode->i_size;
140 i_size_write(inode, attr->size);
141 spin_unlock(&fc->lock);
142
143 if (S_ISREG(inode->i_mode) && oldsize != attr->size) {
144 if (attr->size < oldsize)
145 fuse_truncate(inode->i_mapping, attr->size);
146 invalidate_mapping_pages(inode->i_mapping, 0, -1);
147 }
133} 148}
134 149
135static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) 150static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)