diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2006-07-30 06:04:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-31 16:28:43 -0400 |
commit | 0a0898cf413876d4ed6e371f3e04bf38600a9205 (patch) | |
tree | 700c9e87bdd78392bd3fa11f2f976d360b8a5cd2 | |
parent | 685d16ddb07b74537fb18972784e6214840fdd20 (diff) |
[PATCH] fuse: use jiffies_64
It is entirely possible (though rare) that jiffies half-wraps around, while a
dentry/inode remains in the cache. This could mean that the dentry/inode is
not invalidated for another half wraparound-time.
To get around this problem, use 64-bit jiffies. The only problem with this is
that dentry->d_time is 32 bits on 32-bit archs. So use d_fsdata as the high
32 bits. This is an ugly hack, but far simpler, than having to allocate
private data just for this purpose.
Since 64-bit jiffies can be assumed never to wrap around, simple comparison
can be used, and a zero time value can represent "invalid".
Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/fuse/dir.c | 44 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 2 | ||||
-rw-r--r-- | fs/fuse/inode.c | 2 |
3 files changed, 38 insertions, 10 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 6db66ec386ae..409ce6a7cca4 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -14,6 +14,33 @@ | |||
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/namei.h> | 15 | #include <linux/namei.h> |
16 | 16 | ||
17 | #if BITS_PER_LONG >= 64 | ||
18 | static inline void fuse_dentry_settime(struct dentry *entry, u64 time) | ||
19 | { | ||
20 | entry->d_time = time; | ||
21 | } | ||
22 | |||
23 | static inline u64 fuse_dentry_time(struct dentry *entry) | ||
24 | { | ||
25 | return entry->d_time; | ||
26 | } | ||
27 | #else | ||
28 | /* | ||
29 | * On 32 bit archs store the high 32 bits of time in d_fsdata | ||
30 | */ | ||
31 | static void fuse_dentry_settime(struct dentry *entry, u64 time) | ||
32 | { | ||
33 | entry->d_time = time; | ||
34 | entry->d_fsdata = (void *) (unsigned long) (time >> 32); | ||
35 | } | ||
36 | |||
37 | static u64 fuse_dentry_time(struct dentry *entry) | ||
38 | { | ||
39 | return (u64) entry->d_time + | ||
40 | ((u64) (unsigned long) entry->d_fsdata << 32); | ||
41 | } | ||
42 | #endif | ||
43 | |||
17 | /* | 44 | /* |
18 | * FUSE caches dentries and attributes with separate timeout. The | 45 | * FUSE caches dentries and attributes with separate timeout. The |
19 | * time in jiffies until the dentry/attributes are valid is stored in | 46 | * time in jiffies until the dentry/attributes are valid is stored in |
@@ -23,13 +50,13 @@ | |||
23 | /* | 50 | /* |
24 | * Calculate the time in jiffies until a dentry/attributes are valid | 51 | * Calculate the time in jiffies until a dentry/attributes are valid |
25 | */ | 52 | */ |
26 | static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec) | 53 | static u64 time_to_jiffies(unsigned long sec, unsigned long nsec) |
27 | { | 54 | { |
28 | if (sec || nsec) { | 55 | if (sec || nsec) { |
29 | struct timespec ts = {sec, nsec}; | 56 | struct timespec ts = {sec, nsec}; |
30 | return jiffies + timespec_to_jiffies(&ts); | 57 | return get_jiffies_64() + timespec_to_jiffies(&ts); |
31 | } else | 58 | } else |
32 | return jiffies - 1; | 59 | return 0; |
33 | } | 60 | } |
34 | 61 | ||
35 | /* | 62 | /* |
@@ -38,7 +65,8 @@ static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec) | |||
38 | */ | 65 | */ |
39 | static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) | 66 | static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) |
40 | { | 67 | { |
41 | entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec); | 68 | fuse_dentry_settime(entry, |
69 | time_to_jiffies(o->entry_valid, o->entry_valid_nsec)); | ||
42 | if (entry->d_inode) | 70 | if (entry->d_inode) |
43 | get_fuse_inode(entry->d_inode)->i_time = | 71 | get_fuse_inode(entry->d_inode)->i_time = |
44 | time_to_jiffies(o->attr_valid, o->attr_valid_nsec); | 72 | time_to_jiffies(o->attr_valid, o->attr_valid_nsec); |
@@ -50,7 +78,7 @@ static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) | |||
50 | */ | 78 | */ |
51 | void fuse_invalidate_attr(struct inode *inode) | 79 | void fuse_invalidate_attr(struct inode *inode) |
52 | { | 80 | { |
53 | get_fuse_inode(inode)->i_time = jiffies - 1; | 81 | get_fuse_inode(inode)->i_time = 0; |
54 | } | 82 | } |
55 | 83 | ||
56 | /* | 84 | /* |
@@ -63,7 +91,7 @@ void fuse_invalidate_attr(struct inode *inode) | |||
63 | */ | 91 | */ |
64 | static void fuse_invalidate_entry_cache(struct dentry *entry) | 92 | static void fuse_invalidate_entry_cache(struct dentry *entry) |
65 | { | 93 | { |
66 | entry->d_time = jiffies - 1; | 94 | fuse_dentry_settime(entry, 0); |
67 | } | 95 | } |
68 | 96 | ||
69 | /* | 97 | /* |
@@ -105,7 +133,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
105 | 133 | ||
106 | if (inode && is_bad_inode(inode)) | 134 | if (inode && is_bad_inode(inode)) |
107 | return 0; | 135 | return 0; |
108 | else if (time_after(jiffies, entry->d_time)) { | 136 | else if (fuse_dentry_time(entry) < get_jiffies_64()) { |
109 | int err; | 137 | int err; |
110 | struct fuse_entry_out outarg; | 138 | struct fuse_entry_out outarg; |
111 | struct fuse_conn *fc; | 139 | struct fuse_conn *fc; |
@@ -669,7 +697,7 @@ static int fuse_revalidate(struct dentry *entry) | |||
669 | if (!fuse_allow_task(fc, current)) | 697 | if (!fuse_allow_task(fc, current)) |
670 | return -EACCES; | 698 | return -EACCES; |
671 | if (get_node_id(inode) != FUSE_ROOT_ID && | 699 | if (get_node_id(inode) != FUSE_ROOT_ID && |
672 | time_before_eq(jiffies, fi->i_time)) | 700 | fi->i_time >= get_jiffies_64()) |
673 | return 0; | 701 | return 0; |
674 | 702 | ||
675 | return fuse_do_getattr(inode); | 703 | return fuse_do_getattr(inode); |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 0dbf96621841..69c7750d55b8 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -59,7 +59,7 @@ struct fuse_inode { | |||
59 | struct fuse_req *forget_req; | 59 | struct fuse_req *forget_req; |
60 | 60 | ||
61 | /** Time in jiffies until the file attributes are valid */ | 61 | /** Time in jiffies until the file attributes are valid */ |
62 | unsigned long i_time; | 62 | u64 i_time; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | /** FUSE specific file data */ | 65 | /** FUSE specific file data */ |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index dcaaabd3b9c4..7d25092262ae 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -51,7 +51,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
51 | return NULL; | 51 | return NULL; |
52 | 52 | ||
53 | fi = get_fuse_inode(inode); | 53 | fi = get_fuse_inode(inode); |
54 | fi->i_time = jiffies - 1; | 54 | fi->i_time = 0; |
55 | fi->nodeid = 0; | 55 | fi->nodeid = 0; |
56 | fi->nlookup = 0; | 56 | fi->nlookup = 0; |
57 | fi->forget_req = fuse_request_alloc(); | 57 | fi->forget_req = fuse_request_alloc(); |