diff options
-rw-r--r-- | fs/nfsd/export.c | 136 |
1 files changed, 99 insertions, 37 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 2ebd77d758bc..abd68965822f 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -57,17 +57,6 @@ static int exp_verify_string(char *cp, int max); | |||
57 | #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) | 57 | #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) |
58 | static struct cache_head *expkey_table[EXPKEY_HASHMAX]; | 58 | static struct cache_head *expkey_table[EXPKEY_HASHMAX]; |
59 | 59 | ||
60 | static inline int svc_expkey_hash(struct svc_expkey *item) | ||
61 | { | ||
62 | int hash = item->ek_fsidtype; | ||
63 | char * cp = (char*)item->ek_fsid; | ||
64 | int len = key_len(item->ek_fsidtype); | ||
65 | |||
66 | hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); | ||
67 | hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); | ||
68 | return hash & EXPKEY_HASHMASK; | ||
69 | } | ||
70 | |||
71 | void expkey_put(struct cache_head *item, struct cache_detail *cd) | 60 | void expkey_put(struct cache_head *item, struct cache_detail *cd) |
72 | { | 61 | { |
73 | if (cache_put(item, cd)) { | 62 | if (cache_put(item, cd)) { |
@@ -97,7 +86,8 @@ static void expkey_request(struct cache_detail *cd, | |||
97 | (*bpp)[-1] = '\n'; | 86 | (*bpp)[-1] = '\n'; |
98 | } | 87 | } |
99 | 88 | ||
100 | static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int); | 89 | static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); |
90 | static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); | ||
101 | static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | 91 | static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) |
102 | { | 92 | { |
103 | /* client fsidtype fsid [path] */ | 93 | /* client fsidtype fsid [path] */ |
@@ -108,6 +98,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
108 | int fsidtype; | 98 | int fsidtype; |
109 | char *ep; | 99 | char *ep; |
110 | struct svc_expkey key; | 100 | struct svc_expkey key; |
101 | struct svc_expkey *ek; | ||
111 | 102 | ||
112 | if (mesg[mlen-1] != '\n') | 103 | if (mesg[mlen-1] != '\n') |
113 | return -EINVAL; | 104 | return -EINVAL; |
@@ -152,20 +143,25 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
152 | key.ek_fsidtype = fsidtype; | 143 | key.ek_fsidtype = fsidtype; |
153 | memcpy(key.ek_fsid, buf, len); | 144 | memcpy(key.ek_fsid, buf, len); |
154 | 145 | ||
146 | ek = svc_expkey_lookup(&key); | ||
147 | err = -ENOMEM; | ||
148 | if (!ek) | ||
149 | goto out; | ||
150 | |||
155 | /* now we want a pathname, or empty meaning NEGATIVE */ | 151 | /* now we want a pathname, or empty meaning NEGATIVE */ |
152 | err = -EINVAL; | ||
156 | if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) | 153 | if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) |
157 | goto out; | 154 | goto out; |
158 | dprintk("Path seems to be <%s>\n", buf); | 155 | dprintk("Path seems to be <%s>\n", buf); |
159 | err = 0; | 156 | err = 0; |
160 | if (len == 0) { | 157 | if (len == 0) { |
161 | struct svc_expkey *ek; | ||
162 | set_bit(CACHE_NEGATIVE, &key.h.flags); | 158 | set_bit(CACHE_NEGATIVE, &key.h.flags); |
163 | ek = svc_expkey_lookup(&key, 1); | 159 | ek = svc_expkey_update(&key, ek); |
164 | if (ek) | 160 | if (ek) |
165 | expkey_put(&ek->h, &svc_expkey_cache); | 161 | expkey_put(&ek->h, &svc_expkey_cache); |
162 | else err = -ENOMEM; | ||
166 | } else { | 163 | } else { |
167 | struct nameidata nd; | 164 | struct nameidata nd; |
168 | struct svc_expkey *ek; | ||
169 | err = path_lookup(buf, 0, &nd); | 165 | err = path_lookup(buf, 0, &nd); |
170 | if (err) | 166 | if (err) |
171 | goto out; | 167 | goto out; |
@@ -174,10 +170,11 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
174 | key.ek_mnt = nd.mnt; | 170 | key.ek_mnt = nd.mnt; |
175 | key.ek_dentry = nd.dentry; | 171 | key.ek_dentry = nd.dentry; |
176 | 172 | ||
177 | ek = svc_expkey_lookup(&key, 1); | 173 | ek = svc_expkey_update(&key, ek); |
178 | if (ek) | 174 | if (ek) |
179 | expkey_put(&ek->h, &svc_expkey_cache); | 175 | expkey_put(&ek->h, &svc_expkey_cache); |
180 | err = 0; | 176 | else |
177 | err = -ENOMEM; | ||
181 | path_release(&nd); | 178 | path_release(&nd); |
182 | } | 179 | } |
183 | cache_flush(); | 180 | cache_flush(); |
@@ -213,29 +210,25 @@ static int expkey_show(struct seq_file *m, | |||
213 | seq_printf(m, "\n"); | 210 | seq_printf(m, "\n"); |
214 | return 0; | 211 | return 0; |
215 | } | 212 | } |
216 | |||
217 | struct cache_detail svc_expkey_cache = { | ||
218 | .owner = THIS_MODULE, | ||
219 | .hash_size = EXPKEY_HASHMAX, | ||
220 | .hash_table = expkey_table, | ||
221 | .name = "nfsd.fh", | ||
222 | .cache_put = expkey_put, | ||
223 | .cache_request = expkey_request, | ||
224 | .cache_parse = expkey_parse, | ||
225 | .cache_show = expkey_show, | ||
226 | }; | ||
227 | 213 | ||
228 | static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b) | 214 | static inline int expkey_match (struct cache_head *a, struct cache_head *b) |
229 | { | 215 | { |
230 | if (a->ek_fsidtype != b->ek_fsidtype || | 216 | struct svc_expkey *orig = container_of(a, struct svc_expkey, h); |
231 | a->ek_client != b->ek_client || | 217 | struct svc_expkey *new = container_of(b, struct svc_expkey, h); |
232 | memcmp(a->ek_fsid, b->ek_fsid, key_len(a->ek_fsidtype)) != 0) | 218 | |
219 | if (orig->ek_fsidtype != new->ek_fsidtype || | ||
220 | orig->ek_client != new->ek_client || | ||
221 | memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0) | ||
233 | return 0; | 222 | return 0; |
234 | return 1; | 223 | return 1; |
235 | } | 224 | } |
236 | 225 | ||
237 | static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item) | 226 | static inline void expkey_init(struct cache_head *cnew, |
227 | struct cache_head *citem) | ||
238 | { | 228 | { |
229 | struct svc_expkey *new = container_of(cnew, struct svc_expkey, h); | ||
230 | struct svc_expkey *item = container_of(citem, struct svc_expkey, h); | ||
231 | |||
239 | kref_get(&item->ek_client->ref); | 232 | kref_get(&item->ek_client->ref); |
240 | new->ek_client = item->ek_client; | 233 | new->ek_client = item->ek_client; |
241 | new->ek_fsidtype = item->ek_fsidtype; | 234 | new->ek_fsidtype = item->ek_fsidtype; |
@@ -244,13 +237,80 @@ static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *it | |||
244 | new->ek_fsid[2] = item->ek_fsid[2]; | 237 | new->ek_fsid[2] = item->ek_fsid[2]; |
245 | } | 238 | } |
246 | 239 | ||
247 | static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item) | 240 | static inline void expkey_update(struct cache_head *cnew, |
241 | struct cache_head *citem) | ||
248 | { | 242 | { |
243 | struct svc_expkey *new = container_of(cnew, struct svc_expkey, h); | ||
244 | struct svc_expkey *item = container_of(citem, struct svc_expkey, h); | ||
245 | |||
249 | new->ek_mnt = mntget(item->ek_mnt); | 246 | new->ek_mnt = mntget(item->ek_mnt); |
250 | new->ek_dentry = dget(item->ek_dentry); | 247 | new->ek_dentry = dget(item->ek_dentry); |
251 | } | 248 | } |
252 | 249 | ||
253 | static DefineSimpleCacheLookup(svc_expkey, svc_expkey) | 250 | static struct cache_head *expkey_alloc(void) |
251 | { | ||
252 | struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL); | ||
253 | if (i) | ||
254 | return &i->h; | ||
255 | else | ||
256 | return NULL; | ||
257 | } | ||
258 | |||
259 | struct cache_detail svc_expkey_cache = { | ||
260 | .owner = THIS_MODULE, | ||
261 | .hash_size = EXPKEY_HASHMAX, | ||
262 | .hash_table = expkey_table, | ||
263 | .name = "nfsd.fh", | ||
264 | .cache_put = expkey_put, | ||
265 | .cache_request = expkey_request, | ||
266 | .cache_parse = expkey_parse, | ||
267 | .cache_show = expkey_show, | ||
268 | .match = expkey_match, | ||
269 | .init = expkey_init, | ||
270 | .update = expkey_update, | ||
271 | .alloc = expkey_alloc, | ||
272 | }; | ||
273 | |||
274 | static struct svc_expkey * | ||
275 | svc_expkey_lookup(struct svc_expkey *item) | ||
276 | { | ||
277 | struct cache_head *ch; | ||
278 | int hash = item->ek_fsidtype; | ||
279 | char * cp = (char*)item->ek_fsid; | ||
280 | int len = key_len(item->ek_fsidtype); | ||
281 | |||
282 | hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); | ||
283 | hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); | ||
284 | hash &= EXPKEY_HASHMASK; | ||
285 | |||
286 | ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h, | ||
287 | hash); | ||
288 | if (ch) | ||
289 | return container_of(ch, struct svc_expkey, h); | ||
290 | else | ||
291 | return NULL; | ||
292 | } | ||
293 | |||
294 | static struct svc_expkey * | ||
295 | svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) | ||
296 | { | ||
297 | struct cache_head *ch; | ||
298 | int hash = new->ek_fsidtype; | ||
299 | char * cp = (char*)new->ek_fsid; | ||
300 | int len = key_len(new->ek_fsidtype); | ||
301 | |||
302 | hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); | ||
303 | hash ^= hash_ptr(new->ek_client, EXPKEY_HASHBITS); | ||
304 | hash &= EXPKEY_HASHMASK; | ||
305 | |||
306 | ch = sunrpc_cache_update(&svc_expkey_cache, &new->h, | ||
307 | &old->h, hash); | ||
308 | if (ch) | ||
309 | return container_of(ch, struct svc_expkey, h); | ||
310 | else | ||
311 | return NULL; | ||
312 | } | ||
313 | |||
254 | 314 | ||
255 | #define EXPORT_HASHBITS 8 | 315 | #define EXPORT_HASHBITS 8 |
256 | #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) | 316 | #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) |
@@ -549,7 +609,7 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) | |||
549 | key.ek_fsidtype = fsid_type; | 609 | key.ek_fsidtype = fsid_type; |
550 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); | 610 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); |
551 | 611 | ||
552 | ek = svc_expkey_lookup(&key, 0); | 612 | ek = svc_expkey_lookup(&key); |
553 | if (ek != NULL) | 613 | if (ek != NULL) |
554 | if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) | 614 | if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) |
555 | ek = ERR_PTR(err); | 615 | ek = ERR_PTR(err); |
@@ -569,7 +629,9 @@ static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, | |||
569 | key.h.expiry_time = NEVER; | 629 | key.h.expiry_time = NEVER; |
570 | key.h.flags = 0; | 630 | key.h.flags = 0; |
571 | 631 | ||
572 | ek = svc_expkey_lookup(&key, 1); | 632 | ek = svc_expkey_lookup(&key); |
633 | if (ek) | ||
634 | ek = svc_expkey_update(&key,ek); | ||
573 | if (ek) { | 635 | if (ek) { |
574 | expkey_put(&ek->h, &svc_expkey_cache); | 636 | expkey_put(&ek->h, &svc_expkey_cache); |
575 | return 0; | 637 | return 0; |