aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/fuse_i.h
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/fuse_i.h
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/fuse_i.h')
-rw-r--r--fs/fuse/fuse_i.h12
1 files changed, 10 insertions, 2 deletions
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index e7464b8ebbfb..ffbcadaa7d67 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -67,6 +67,9 @@ struct fuse_inode {
67 /** The sticky bit in inode->i_mode may have been removed, so 67 /** The sticky bit in inode->i_mode may have been removed, so
68 preserve the original mode */ 68 preserve the original mode */
69 mode_t orig_i_mode; 69 mode_t orig_i_mode;
70
71 /** Version of last attribute change */
72 u64 attr_version;
70}; 73};
71 74
72/** FUSE specific file data */ 75/** FUSE specific file data */
@@ -387,6 +390,9 @@ struct fuse_conn {
387 390
388 /** Reserved request for the DESTROY message */ 391 /** Reserved request for the DESTROY message */
389 struct fuse_req *destroy_req; 392 struct fuse_req *destroy_req;
393
394 /** Version counter for attribute changes */
395 u64 attr_version;
390}; 396};
391 397
392static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) 398static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
@@ -416,7 +422,8 @@ extern const struct file_operations fuse_dev_operations;
416 * Get a filled in inode 422 * Get a filled in inode
417 */ 423 */
418struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, 424struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
419 int generation, struct fuse_attr *attr); 425 int generation, struct fuse_attr *attr,
426 u64 attr_valid, u64 attr_version);
420 427
421/** 428/**
422 * Send FORGET command 429 * Send FORGET command
@@ -477,7 +484,8 @@ void fuse_init_symlink(struct inode *inode);
477/** 484/**
478 * Change attributes of an inode 485 * Change attributes of an inode
479 */ 486 */
480void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr); 487void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
488 u64 attr_valid, u64 attr_version);
481 489
482/** 490/**
483 * Initialize the client device 491 * Initialize the client device