diff options
Diffstat (limited to 'fs/orangefs/dcache.c')
-rw-r--r-- | fs/orangefs/dcache.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/fs/orangefs/dcache.c b/fs/orangefs/dcache.c new file mode 100644 index 000000000000..5dfc4f3cfe68 --- /dev/null +++ b/fs/orangefs/dcache.c | |||
@@ -0,0 +1,138 @@ | |||
1 | /* | ||
2 | * (C) 2001 Clemson University and The University of Chicago | ||
3 | * | ||
4 | * See COPYING in top-level directory. | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Implementation of dentry (directory cache) functions. | ||
9 | */ | ||
10 | |||
11 | #include "protocol.h" | ||
12 | #include "orangefs-kernel.h" | ||
13 | |||
14 | /* Returns 1 if dentry can still be trusted, else 0. */ | ||
15 | static int orangefs_revalidate_lookup(struct dentry *dentry) | ||
16 | { | ||
17 | struct dentry *parent_dentry = dget_parent(dentry); | ||
18 | struct inode *parent_inode = parent_dentry->d_inode; | ||
19 | struct orangefs_inode_s *parent = ORANGEFS_I(parent_inode); | ||
20 | struct inode *inode = dentry->d_inode; | ||
21 | struct orangefs_kernel_op_s *new_op; | ||
22 | int ret = 0; | ||
23 | int err = 0; | ||
24 | |||
25 | gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: attempting lookup.\n", __func__); | ||
26 | |||
27 | new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP); | ||
28 | if (!new_op) | ||
29 | goto out_put_parent; | ||
30 | |||
31 | new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW; | ||
32 | new_op->upcall.req.lookup.parent_refn = parent->refn; | ||
33 | strncpy(new_op->upcall.req.lookup.d_name, | ||
34 | dentry->d_name.name, | ||
35 | ORANGEFS_NAME_MAX); | ||
36 | |||
37 | gossip_debug(GOSSIP_DCACHE_DEBUG, | ||
38 | "%s:%s:%d interrupt flag [%d]\n", | ||
39 | __FILE__, | ||
40 | __func__, | ||
41 | __LINE__, | ||
42 | get_interruptible_flag(parent_inode)); | ||
43 | |||
44 | err = service_operation(new_op, "orangefs_lookup", | ||
45 | get_interruptible_flag(parent_inode)); | ||
46 | |||
47 | /* Positive dentry: reject if error or not the same inode. */ | ||
48 | if (inode) { | ||
49 | if (err) { | ||
50 | gossip_debug(GOSSIP_DCACHE_DEBUG, | ||
51 | "%s:%s:%d lookup failure.\n", | ||
52 | __FILE__, __func__, __LINE__); | ||
53 | goto out_drop; | ||
54 | } | ||
55 | if (!match_handle(new_op->downcall.resp.lookup.refn.khandle, | ||
56 | inode)) { | ||
57 | gossip_debug(GOSSIP_DCACHE_DEBUG, | ||
58 | "%s:%s:%d no match.\n", | ||
59 | __FILE__, __func__, __LINE__); | ||
60 | goto out_drop; | ||
61 | } | ||
62 | |||
63 | /* Negative dentry: reject if success or error other than ENOENT. */ | ||
64 | } else { | ||
65 | gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: negative dentry.\n", | ||
66 | __func__); | ||
67 | if (!err || err != -ENOENT) { | ||
68 | if (new_op->downcall.status != 0) | ||
69 | gossip_debug(GOSSIP_DCACHE_DEBUG, | ||
70 | "%s:%s:%d lookup failure.\n", | ||
71 | __FILE__, __func__, __LINE__); | ||
72 | goto out_drop; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | ret = 1; | ||
77 | out_release_op: | ||
78 | op_release(new_op); | ||
79 | out_put_parent: | ||
80 | dput(parent_dentry); | ||
81 | return ret; | ||
82 | out_drop: | ||
83 | gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d revalidate failed\n", | ||
84 | __FILE__, __func__, __LINE__); | ||
85 | goto out_release_op; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * Verify that dentry is valid. | ||
90 | * | ||
91 | * Should return 1 if dentry can still be trusted, else 0. | ||
92 | */ | ||
93 | static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags) | ||
94 | { | ||
95 | int ret; | ||
96 | |||
97 | if (flags & LOOKUP_RCU) | ||
98 | return -ECHILD; | ||
99 | |||
100 | gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n", | ||
101 | __func__, dentry); | ||
102 | |||
103 | /* skip root handle lookups. */ | ||
104 | if (dentry->d_inode && is_root_handle(dentry->d_inode)) | ||
105 | return 1; | ||
106 | |||
107 | /* | ||
108 | * If this passes, the positive dentry still exists or the negative | ||
109 | * dentry still does not exist. | ||
110 | */ | ||
111 | if (!orangefs_revalidate_lookup(dentry)) | ||
112 | return 0; | ||
113 | |||
114 | /* We do not need to continue with negative dentries. */ | ||
115 | if (!dentry->d_inode) | ||
116 | goto out; | ||
117 | |||
118 | /* Now we must perform a getattr to validate the inode contents. */ | ||
119 | |||
120 | ret = orangefs_inode_check_changed(dentry->d_inode); | ||
121 | if (ret < 0) { | ||
122 | gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n", | ||
123 | __FILE__, __func__, __LINE__); | ||
124 | return 0; | ||
125 | } | ||
126 | if (ret == 0) | ||
127 | return 0; | ||
128 | |||
129 | out: | ||
130 | gossip_debug(GOSSIP_DCACHE_DEBUG, | ||
131 | "%s: negative dentry or positive dentry and inode valid.\n", | ||
132 | __func__); | ||
133 | return 1; | ||
134 | } | ||
135 | |||
136 | const struct dentry_operations orangefs_dentry_operations = { | ||
137 | .d_revalidate = orangefs_d_revalidate, | ||
138 | }; | ||