aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dir.c
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-01-06 03:19:38 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:55 -0500
commit8cbdf1e6f6876b37d2a0d96fd15ea9f90f7d51c1 (patch)
tree03633d1c84e651b2e9fafda1159847a05b89b0b2 /fs/fuse/dir.c
parentde5f12025572ef8fcffa4be5453061725acfb754 (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.c64
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
24static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) 24static 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
32void fuse_invalidate_attr(struct inode *inode)
33{
34 get_fuse_inode(inode)->i_time = jiffies - 1;
35}
36
37static void fuse_invalidate_entry_cache(struct dentry *entry)
38{
39 entry->d_time = jiffies - 1;
40}
41
42static void fuse_invalidate_entry(struct dentry *entry)
43{
44 d_invalidate(entry);
45 fuse_invalidate_entry_cache(entry);
29} 46}
30 47
31static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, 48static 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
46static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) 63static 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
146void fuse_invalidate_attr(struct inode *inode)
147{
148 get_fuse_inode(inode)->i_time = jiffies - 1;
149}
150
151static void fuse_invalidate_entry(struct dentry *entry)
152{
153 d_invalidate(entry);
154 entry->d_time = jiffies - 1;
155}
156
157static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, 173static 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