aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/file.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2007-10-18 06:06:58 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-18 17:37:30 -0400
commit1fb69e7817296da8a6824804bb206ca1e7f31425 (patch)
tree51f8ac8ab4f06207a406cb9e917a48d71616235c /fs/fuse/file.c
parente57ac68378a287d6336d187b26971f35f7ee7251 (diff)
fuse: fix race between getattr and write
Getattr and lookup operations can be running in parallel to attribute changing operations, such as write and setattr. This means, that if for example getattr was slower than a write, the cached size attribute could be set to a stale value. To prevent this race, introduce a per-filesystem attribute version counter. This counter is incremented whenever cached attributes are modified, and the incremented value stored in the inode. Before storing new attributes in the cache, getattr and lookup check, using the version number, whether the attributes have been modified during the request's lifetime. If so, the returned attributes are not cached, because they might be stale. Thanks to Jakub Bogusz for the bug report and test program. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Cc: Jakub Bogusz <jakub.bogusz@gemius.pl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r--fs/fuse/file.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index c4b98c03a46e..4a28c3d37732 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -478,6 +478,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode,
478 int err; 478 int err;
479 size_t nres; 479 size_t nres;
480 struct fuse_conn *fc = get_fuse_conn(inode); 480 struct fuse_conn *fc = get_fuse_conn(inode);
481 struct fuse_inode *fi = get_fuse_inode(inode);
481 unsigned offset = pos & (PAGE_CACHE_SIZE - 1); 482 unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
482 struct fuse_req *req; 483 struct fuse_req *req;
483 484
@@ -499,6 +500,7 @@ static int fuse_buffered_write(struct file *file, struct inode *inode,
499 if (!err) { 500 if (!err) {
500 pos += nres; 501 pos += nres;
501 spin_lock(&fc->lock); 502 spin_lock(&fc->lock);
503 fi->attr_version = ++fc->attr_version;
502 if (pos > inode->i_size) 504 if (pos > inode->i_size)
503 i_size_write(inode, pos); 505 i_size_write(inode, pos);
504 spin_unlock(&fc->lock); 506 spin_unlock(&fc->lock);