diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2006-01-06 03:19:38 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:33:55 -0500 |
commit | 8cbdf1e6f6876b37d2a0d96fd15ea9f90f7d51c1 (patch) | |
tree | 03633d1c84e651b2e9fafda1159847a05b89b0b2 /fs/fuse/dir.c | |
parent | de5f12025572ef8fcffa4be5453061725acfb754 (diff) |
[PATCH] fuse: support caching negative dentries
Add support for caching negative dentries.
Up till now, ->d_revalidate() always forced a new lookup on these. Now let
the lookup method return a zero node ID (not used for anything else) meaning a
negative entry, but with a positive cache timeout. The old way of signaling
negative entry (replying ENOENT) still works.
Userspace should check the ABI minor version to see whether sending a zero ID
is allowed by the kernel or not.
Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 64 |
1 files changed, 43 insertions, 21 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 0d1438a9dab3..4c127f2bc814 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -23,9 +23,26 @@ static inline unsigned long time_to_jiffies(unsigned long sec, | |||
23 | 23 | ||
24 | static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) | 24 | static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) |
25 | { | 25 | { |
26 | struct fuse_inode *fi = get_fuse_inode(entry->d_inode); | ||
27 | entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec); | 26 | entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec); |
28 | fi->i_time = time_to_jiffies(o->attr_valid, o->attr_valid_nsec); | 27 | if (entry->d_inode) |
28 | get_fuse_inode(entry->d_inode)->i_time = | ||
29 | time_to_jiffies(o->attr_valid, o->attr_valid_nsec); | ||
30 | } | ||
31 | |||
32 | void fuse_invalidate_attr(struct inode *inode) | ||
33 | { | ||
34 | get_fuse_inode(inode)->i_time = jiffies - 1; | ||
35 | } | ||
36 | |||
37 | static void fuse_invalidate_entry_cache(struct dentry *entry) | ||
38 | { | ||
39 | entry->d_time = jiffies - 1; | ||
40 | } | ||
41 | |||
42 | static void fuse_invalidate_entry(struct dentry *entry) | ||
43 | { | ||
44 | d_invalidate(entry); | ||
45 | fuse_invalidate_entry_cache(entry); | ||
29 | } | 46 | } |
30 | 47 | ||
31 | static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, | 48 | static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, |
@@ -45,15 +62,22 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, | |||
45 | 62 | ||
46 | static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | 63 | static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) |
47 | { | 64 | { |
48 | if (!entry->d_inode || is_bad_inode(entry->d_inode)) | 65 | struct inode *inode = entry->d_inode; |
66 | |||
67 | if (inode && is_bad_inode(inode)) | ||
49 | return 0; | 68 | return 0; |
50 | else if (time_after(jiffies, entry->d_time)) { | 69 | else if (time_after(jiffies, entry->d_time)) { |
51 | int err; | 70 | int err; |
52 | struct fuse_entry_out outarg; | 71 | struct fuse_entry_out outarg; |
53 | struct inode *inode = entry->d_inode; | 72 | struct fuse_conn *fc; |
54 | struct fuse_inode *fi = get_fuse_inode(inode); | 73 | struct fuse_req *req; |
55 | struct fuse_conn *fc = get_fuse_conn(inode); | 74 | |
56 | struct fuse_req *req = fuse_get_request(fc); | 75 | fuse_invalidate_entry_cache(entry); |
76 | if (!inode) | ||
77 | return 0; | ||
78 | |||
79 | fc = get_fuse_conn(inode); | ||
80 | req = fuse_get_request(fc); | ||
57 | if (!req) | 81 | if (!req) |
58 | return 0; | 82 | return 0; |
59 | 83 | ||
@@ -61,6 +85,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
61 | request_send(fc, req); | 85 | request_send(fc, req); |
62 | err = req->out.h.error; | 86 | err = req->out.h.error; |
63 | if (!err) { | 87 | if (!err) { |
88 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
64 | if (outarg.nodeid != get_node_id(inode)) { | 89 | if (outarg.nodeid != get_node_id(inode)) { |
65 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 90 | fuse_send_forget(fc, req, outarg.nodeid, 1); |
66 | return 0; | 91 | return 0; |
@@ -118,9 +143,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
118 | fuse_lookup_init(req, dir, entry, &outarg); | 143 | fuse_lookup_init(req, dir, entry, &outarg); |
119 | request_send(fc, req); | 144 | request_send(fc, req); |
120 | err = req->out.h.error; | 145 | err = req->out.h.error; |
121 | if (!err && invalid_nodeid(outarg.nodeid)) | 146 | if (!err && outarg.nodeid && invalid_nodeid(outarg.nodeid)) |
122 | err = -EIO; | 147 | err = -EIO; |
123 | if (!err) { | 148 | if (!err && outarg.nodeid) { |
124 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 149 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
125 | &outarg.attr); | 150 | &outarg.attr); |
126 | if (!inode) { | 151 | if (!inode) { |
@@ -138,22 +163,13 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
138 | } | 163 | } |
139 | d_add(entry, inode); | 164 | d_add(entry, inode); |
140 | entry->d_op = &fuse_dentry_operations; | 165 | entry->d_op = &fuse_dentry_operations; |
141 | if (inode) | 166 | if (!err) |
142 | fuse_change_timeout(entry, &outarg); | 167 | fuse_change_timeout(entry, &outarg); |
168 | else | ||
169 | fuse_invalidate_entry_cache(entry); | ||
143 | return NULL; | 170 | return NULL; |
144 | } | 171 | } |
145 | 172 | ||
146 | void fuse_invalidate_attr(struct inode *inode) | ||
147 | { | ||
148 | get_fuse_inode(inode)->i_time = jiffies - 1; | ||
149 | } | ||
150 | |||
151 | static void fuse_invalidate_entry(struct dentry *entry) | ||
152 | { | ||
153 | d_invalidate(entry); | ||
154 | entry->d_time = jiffies - 1; | ||
155 | } | ||
156 | |||
157 | static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | 173 | static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, |
158 | struct nameidata *nd) | 174 | struct nameidata *nd) |
159 | { | 175 | { |
@@ -387,6 +403,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) | |||
387 | inode->i_nlink = 0; | 403 | inode->i_nlink = 0; |
388 | fuse_invalidate_attr(inode); | 404 | fuse_invalidate_attr(inode); |
389 | fuse_invalidate_attr(dir); | 405 | fuse_invalidate_attr(dir); |
406 | fuse_invalidate_entry_cache(entry); | ||
390 | } else if (err == -EINTR) | 407 | } else if (err == -EINTR) |
391 | fuse_invalidate_entry(entry); | 408 | fuse_invalidate_entry(entry); |
392 | return err; | 409 | return err; |
@@ -412,6 +429,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) | |||
412 | if (!err) { | 429 | if (!err) { |
413 | entry->d_inode->i_nlink = 0; | 430 | entry->d_inode->i_nlink = 0; |
414 | fuse_invalidate_attr(dir); | 431 | fuse_invalidate_attr(dir); |
432 | fuse_invalidate_entry_cache(entry); | ||
415 | } else if (err == -EINTR) | 433 | } else if (err == -EINTR) |
416 | fuse_invalidate_entry(entry); | 434 | fuse_invalidate_entry(entry); |
417 | return err; | 435 | return err; |
@@ -447,6 +465,10 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent, | |||
447 | fuse_invalidate_attr(olddir); | 465 | fuse_invalidate_attr(olddir); |
448 | if (olddir != newdir) | 466 | if (olddir != newdir) |
449 | fuse_invalidate_attr(newdir); | 467 | fuse_invalidate_attr(newdir); |
468 | |||
469 | /* newent will end up negative */ | ||
470 | if (newent->d_inode) | ||
471 | fuse_invalidate_entry_cache(newent); | ||
450 | } else if (err == -EINTR) { | 472 | } else if (err == -EINTR) { |
451 | /* If request was interrupted, DEITY only knows if the | 473 | /* If request was interrupted, DEITY only knows if the |
452 | rename actually took place. If the invalidation | 474 | rename actually took place. If the invalidation |