diff options
Diffstat (limited to 'net/sunrpc/svcauth_unix.c')
-rw-r--r-- | net/sunrpc/svcauth_unix.c | 229 |
1 files changed, 161 insertions, 68 deletions
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 207311610988..c8e10216c113 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
@@ -18,6 +18,8 @@ | |||
18 | 18 | ||
19 | #include <linux/sunrpc/clnt.h> | 19 | #include <linux/sunrpc/clnt.h> |
20 | 20 | ||
21 | #include "netns.h" | ||
22 | |||
21 | /* | 23 | /* |
22 | * AUTHUNIX and AUTHNULL credentials are both handled here. | 24 | * AUTHUNIX and AUTHNULL credentials are both handled here. |
23 | * AUTHNULL is treated just like AUTHUNIX except that the uid/gid | 25 | * AUTHNULL is treated just like AUTHUNIX except that the uid/gid |
@@ -28,12 +30,22 @@ | |||
28 | 30 | ||
29 | struct unix_domain { | 31 | struct unix_domain { |
30 | struct auth_domain h; | 32 | struct auth_domain h; |
33 | #ifdef CONFIG_NFSD_DEPRECATED | ||
31 | int addr_changes; | 34 | int addr_changes; |
35 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
32 | /* other stuff later */ | 36 | /* other stuff later */ |
33 | }; | 37 | }; |
34 | 38 | ||
35 | extern struct auth_ops svcauth_unix; | 39 | extern struct auth_ops svcauth_unix; |
36 | 40 | ||
41 | static void svcauth_unix_domain_release(struct auth_domain *dom) | ||
42 | { | ||
43 | struct unix_domain *ud = container_of(dom, struct unix_domain, h); | ||
44 | |||
45 | kfree(dom->name); | ||
46 | kfree(ud); | ||
47 | } | ||
48 | |||
37 | struct auth_domain *unix_domain_find(char *name) | 49 | struct auth_domain *unix_domain_find(char *name) |
38 | { | 50 | { |
39 | struct auth_domain *rv; | 51 | struct auth_domain *rv; |
@@ -43,7 +55,7 @@ struct auth_domain *unix_domain_find(char *name) | |||
43 | while(1) { | 55 | while(1) { |
44 | if (rv) { | 56 | if (rv) { |
45 | if (new && rv != &new->h) | 57 | if (new && rv != &new->h) |
46 | auth_domain_put(&new->h); | 58 | svcauth_unix_domain_release(&new->h); |
47 | 59 | ||
48 | if (rv->flavour != &svcauth_unix) { | 60 | if (rv->flavour != &svcauth_unix) { |
49 | auth_domain_put(rv); | 61 | auth_domain_put(rv); |
@@ -62,20 +74,14 @@ struct auth_domain *unix_domain_find(char *name) | |||
62 | return NULL; | 74 | return NULL; |
63 | } | 75 | } |
64 | new->h.flavour = &svcauth_unix; | 76 | new->h.flavour = &svcauth_unix; |
77 | #ifdef CONFIG_NFSD_DEPRECATED | ||
65 | new->addr_changes = 0; | 78 | new->addr_changes = 0; |
79 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
66 | rv = auth_domain_lookup(name, &new->h); | 80 | rv = auth_domain_lookup(name, &new->h); |
67 | } | 81 | } |
68 | } | 82 | } |
69 | EXPORT_SYMBOL_GPL(unix_domain_find); | 83 | EXPORT_SYMBOL_GPL(unix_domain_find); |
70 | 84 | ||
71 | static void svcauth_unix_domain_release(struct auth_domain *dom) | ||
72 | { | ||
73 | struct unix_domain *ud = container_of(dom, struct unix_domain, h); | ||
74 | |||
75 | kfree(dom->name); | ||
76 | kfree(ud); | ||
77 | } | ||
78 | |||
79 | 85 | ||
80 | /************************************************** | 86 | /************************************************** |
81 | * cache for IP address to unix_domain | 87 | * cache for IP address to unix_domain |
@@ -83,16 +89,16 @@ static void svcauth_unix_domain_release(struct auth_domain *dom) | |||
83 | */ | 89 | */ |
84 | #define IP_HASHBITS 8 | 90 | #define IP_HASHBITS 8 |
85 | #define IP_HASHMAX (1<<IP_HASHBITS) | 91 | #define IP_HASHMAX (1<<IP_HASHBITS) |
86 | #define IP_HASHMASK (IP_HASHMAX-1) | ||
87 | 92 | ||
88 | struct ip_map { | 93 | struct ip_map { |
89 | struct cache_head h; | 94 | struct cache_head h; |
90 | char m_class[8]; /* e.g. "nfsd" */ | 95 | char m_class[8]; /* e.g. "nfsd" */ |
91 | struct in6_addr m_addr; | 96 | struct in6_addr m_addr; |
92 | struct unix_domain *m_client; | 97 | struct unix_domain *m_client; |
98 | #ifdef CONFIG_NFSD_DEPRECATED | ||
93 | int m_add_change; | 99 | int m_add_change; |
100 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
94 | }; | 101 | }; |
95 | static struct cache_head *ip_table[IP_HASHMAX]; | ||
96 | 102 | ||
97 | static void ip_map_put(struct kref *kref) | 103 | static void ip_map_put(struct kref *kref) |
98 | { | 104 | { |
@@ -145,7 +151,9 @@ static void update(struct cache_head *cnew, struct cache_head *citem) | |||
145 | 151 | ||
146 | kref_get(&item->m_client->h.ref); | 152 | kref_get(&item->m_client->h.ref); |
147 | new->m_client = item->m_client; | 153 | new->m_client = item->m_client; |
154 | #ifdef CONFIG_NFSD_DEPRECATED | ||
148 | new->m_add_change = item->m_add_change; | 155 | new->m_add_change = item->m_add_change; |
156 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
149 | } | 157 | } |
150 | static struct cache_head *ip_map_alloc(void) | 158 | static struct cache_head *ip_map_alloc(void) |
151 | { | 159 | { |
@@ -178,8 +186,8 @@ static int ip_map_upcall(struct cache_detail *cd, struct cache_head *h) | |||
178 | return sunrpc_cache_pipe_upcall(cd, h, ip_map_request); | 186 | return sunrpc_cache_pipe_upcall(cd, h, ip_map_request); |
179 | } | 187 | } |
180 | 188 | ||
181 | static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr); | 189 | static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr); |
182 | static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry); | 190 | static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time_t expiry); |
183 | 191 | ||
184 | static int ip_map_parse(struct cache_detail *cd, | 192 | static int ip_map_parse(struct cache_detail *cd, |
185 | char *mesg, int mlen) | 193 | char *mesg, int mlen) |
@@ -219,10 +227,9 @@ static int ip_map_parse(struct cache_detail *cd, | |||
219 | switch (address.sa.sa_family) { | 227 | switch (address.sa.sa_family) { |
220 | case AF_INET: | 228 | case AF_INET: |
221 | /* Form a mapped IPv4 address in sin6 */ | 229 | /* Form a mapped IPv4 address in sin6 */ |
222 | memset(&sin6, 0, sizeof(sin6)); | ||
223 | sin6.sin6_family = AF_INET6; | 230 | sin6.sin6_family = AF_INET6; |
224 | sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); | 231 | ipv6_addr_set_v4mapped(address.s4.sin_addr.s_addr, |
225 | sin6.sin6_addr.s6_addr32[3] = address.s4.sin_addr.s_addr; | 232 | &sin6.sin6_addr); |
226 | break; | 233 | break; |
227 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 234 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
228 | case AF_INET6: | 235 | case AF_INET6: |
@@ -249,9 +256,9 @@ static int ip_map_parse(struct cache_detail *cd, | |||
249 | dom = NULL; | 256 | dom = NULL; |
250 | 257 | ||
251 | /* IPv6 scope IDs are ignored for now */ | 258 | /* IPv6 scope IDs are ignored for now */ |
252 | ipmp = ip_map_lookup(class, &sin6.sin6_addr); | 259 | ipmp = __ip_map_lookup(cd, class, &sin6.sin6_addr); |
253 | if (ipmp) { | 260 | if (ipmp) { |
254 | err = ip_map_update(ipmp, | 261 | err = __ip_map_update(cd, ipmp, |
255 | container_of(dom, struct unix_domain, h), | 262 | container_of(dom, struct unix_domain, h), |
256 | expiry); | 263 | expiry); |
257 | } else | 264 | } else |
@@ -294,29 +301,15 @@ static int ip_map_show(struct seq_file *m, | |||
294 | } | 301 | } |
295 | 302 | ||
296 | 303 | ||
297 | struct cache_detail ip_map_cache = { | 304 | static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, |
298 | .owner = THIS_MODULE, | 305 | struct in6_addr *addr) |
299 | .hash_size = IP_HASHMAX, | ||
300 | .hash_table = ip_table, | ||
301 | .name = "auth.unix.ip", | ||
302 | .cache_put = ip_map_put, | ||
303 | .cache_upcall = ip_map_upcall, | ||
304 | .cache_parse = ip_map_parse, | ||
305 | .cache_show = ip_map_show, | ||
306 | .match = ip_map_match, | ||
307 | .init = ip_map_init, | ||
308 | .update = update, | ||
309 | .alloc = ip_map_alloc, | ||
310 | }; | ||
311 | |||
312 | static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr) | ||
313 | { | 306 | { |
314 | struct ip_map ip; | 307 | struct ip_map ip; |
315 | struct cache_head *ch; | 308 | struct cache_head *ch; |
316 | 309 | ||
317 | strcpy(ip.m_class, class); | 310 | strcpy(ip.m_class, class); |
318 | ipv6_addr_copy(&ip.m_addr, addr); | 311 | ipv6_addr_copy(&ip.m_addr, addr); |
319 | ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h, | 312 | ch = sunrpc_cache_lookup(cd, &ip.h, |
320 | hash_str(class, IP_HASHBITS) ^ | 313 | hash_str(class, IP_HASHBITS) ^ |
321 | hash_ip6(*addr)); | 314 | hash_ip6(*addr)); |
322 | 315 | ||
@@ -326,7 +319,17 @@ static struct ip_map *ip_map_lookup(char *class, struct in6_addr *addr) | |||
326 | return NULL; | 319 | return NULL; |
327 | } | 320 | } |
328 | 321 | ||
329 | static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry) | 322 | static inline struct ip_map *ip_map_lookup(struct net *net, char *class, |
323 | struct in6_addr *addr) | ||
324 | { | ||
325 | struct sunrpc_net *sn; | ||
326 | |||
327 | sn = net_generic(net, sunrpc_net_id); | ||
328 | return __ip_map_lookup(sn->ip_map_cache, class, addr); | ||
329 | } | ||
330 | |||
331 | static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, | ||
332 | struct unix_domain *udom, time_t expiry) | ||
330 | { | 333 | { |
331 | struct ip_map ip; | 334 | struct ip_map ip; |
332 | struct cache_head *ch; | 335 | struct cache_head *ch; |
@@ -335,6 +338,7 @@ static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t ex | |||
335 | ip.h.flags = 0; | 338 | ip.h.flags = 0; |
336 | if (!udom) | 339 | if (!udom) |
337 | set_bit(CACHE_NEGATIVE, &ip.h.flags); | 340 | set_bit(CACHE_NEGATIVE, &ip.h.flags); |
341 | #ifdef CONFIG_NFSD_DEPRECATED | ||
338 | else { | 342 | else { |
339 | ip.m_add_change = udom->addr_changes; | 343 | ip.m_add_change = udom->addr_changes; |
340 | /* if this is from the legacy set_client system call, | 344 | /* if this is from the legacy set_client system call, |
@@ -343,18 +347,28 @@ static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t ex | |||
343 | if (expiry == NEVER) | 347 | if (expiry == NEVER) |
344 | ip.m_add_change++; | 348 | ip.m_add_change++; |
345 | } | 349 | } |
350 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
346 | ip.h.expiry_time = expiry; | 351 | ip.h.expiry_time = expiry; |
347 | ch = sunrpc_cache_update(&ip_map_cache, | 352 | ch = sunrpc_cache_update(cd, &ip.h, &ipm->h, |
348 | &ip.h, &ipm->h, | ||
349 | hash_str(ipm->m_class, IP_HASHBITS) ^ | 353 | hash_str(ipm->m_class, IP_HASHBITS) ^ |
350 | hash_ip6(ipm->m_addr)); | 354 | hash_ip6(ipm->m_addr)); |
351 | if (!ch) | 355 | if (!ch) |
352 | return -ENOMEM; | 356 | return -ENOMEM; |
353 | cache_put(ch, &ip_map_cache); | 357 | cache_put(ch, cd); |
354 | return 0; | 358 | return 0; |
355 | } | 359 | } |
356 | 360 | ||
357 | int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom) | 361 | static inline int ip_map_update(struct net *net, struct ip_map *ipm, |
362 | struct unix_domain *udom, time_t expiry) | ||
363 | { | ||
364 | struct sunrpc_net *sn; | ||
365 | |||
366 | sn = net_generic(net, sunrpc_net_id); | ||
367 | return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry); | ||
368 | } | ||
369 | |||
370 | #ifdef CONFIG_NFSD_DEPRECATED | ||
371 | int auth_unix_add_addr(struct net *net, struct in6_addr *addr, struct auth_domain *dom) | ||
358 | { | 372 | { |
359 | struct unix_domain *udom; | 373 | struct unix_domain *udom; |
360 | struct ip_map *ipmp; | 374 | struct ip_map *ipmp; |
@@ -362,10 +376,10 @@ int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom) | |||
362 | if (dom->flavour != &svcauth_unix) | 376 | if (dom->flavour != &svcauth_unix) |
363 | return -EINVAL; | 377 | return -EINVAL; |
364 | udom = container_of(dom, struct unix_domain, h); | 378 | udom = container_of(dom, struct unix_domain, h); |
365 | ipmp = ip_map_lookup("nfsd", addr); | 379 | ipmp = ip_map_lookup(net, "nfsd", addr); |
366 | 380 | ||
367 | if (ipmp) | 381 | if (ipmp) |
368 | return ip_map_update(ipmp, udom, NEVER); | 382 | return ip_map_update(net, ipmp, udom, NEVER); |
369 | else | 383 | else |
370 | return -ENOMEM; | 384 | return -ENOMEM; |
371 | } | 385 | } |
@@ -383,42 +397,51 @@ int auth_unix_forget_old(struct auth_domain *dom) | |||
383 | } | 397 | } |
384 | EXPORT_SYMBOL_GPL(auth_unix_forget_old); | 398 | EXPORT_SYMBOL_GPL(auth_unix_forget_old); |
385 | 399 | ||
386 | struct auth_domain *auth_unix_lookup(struct in6_addr *addr) | 400 | struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr) |
387 | { | 401 | { |
388 | struct ip_map *ipm; | 402 | struct ip_map *ipm; |
389 | struct auth_domain *rv; | 403 | struct auth_domain *rv; |
404 | struct sunrpc_net *sn; | ||
390 | 405 | ||
391 | ipm = ip_map_lookup("nfsd", addr); | 406 | sn = net_generic(net, sunrpc_net_id); |
407 | ipm = ip_map_lookup(net, "nfsd", addr); | ||
392 | 408 | ||
393 | if (!ipm) | 409 | if (!ipm) |
394 | return NULL; | 410 | return NULL; |
395 | if (cache_check(&ip_map_cache, &ipm->h, NULL)) | 411 | if (cache_check(sn->ip_map_cache, &ipm->h, NULL)) |
396 | return NULL; | 412 | return NULL; |
397 | 413 | ||
398 | if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) { | 414 | if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) { |
399 | if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0) | 415 | sunrpc_invalidate(&ipm->h, sn->ip_map_cache); |
400 | auth_domain_put(&ipm->m_client->h); | ||
401 | rv = NULL; | 416 | rv = NULL; |
402 | } else { | 417 | } else { |
403 | rv = &ipm->m_client->h; | 418 | rv = &ipm->m_client->h; |
404 | kref_get(&rv->ref); | 419 | kref_get(&rv->ref); |
405 | } | 420 | } |
406 | cache_put(&ipm->h, &ip_map_cache); | 421 | cache_put(&ipm->h, sn->ip_map_cache); |
407 | return rv; | 422 | return rv; |
408 | } | 423 | } |
409 | EXPORT_SYMBOL_GPL(auth_unix_lookup); | 424 | EXPORT_SYMBOL_GPL(auth_unix_lookup); |
425 | #endif /* CONFIG_NFSD_DEPRECATED */ | ||
410 | 426 | ||
411 | void svcauth_unix_purge(void) | 427 | void svcauth_unix_purge(void) |
412 | { | 428 | { |
413 | cache_purge(&ip_map_cache); | 429 | struct net *net; |
430 | |||
431 | for_each_net(net) { | ||
432 | struct sunrpc_net *sn; | ||
433 | |||
434 | sn = net_generic(net, sunrpc_net_id); | ||
435 | cache_purge(sn->ip_map_cache); | ||
436 | } | ||
414 | } | 437 | } |
415 | EXPORT_SYMBOL_GPL(svcauth_unix_purge); | 438 | EXPORT_SYMBOL_GPL(svcauth_unix_purge); |
416 | 439 | ||
417 | static inline struct ip_map * | 440 | static inline struct ip_map * |
418 | ip_map_cached_get(struct svc_rqst *rqstp) | 441 | ip_map_cached_get(struct svc_xprt *xprt) |
419 | { | 442 | { |
420 | struct ip_map *ipm = NULL; | 443 | struct ip_map *ipm = NULL; |
421 | struct svc_xprt *xprt = rqstp->rq_xprt; | 444 | struct sunrpc_net *sn; |
422 | 445 | ||
423 | if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) { | 446 | if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) { |
424 | spin_lock(&xprt->xpt_lock); | 447 | spin_lock(&xprt->xpt_lock); |
@@ -430,9 +453,10 @@ ip_map_cached_get(struct svc_rqst *rqstp) | |||
430 | * remembered, e.g. by a second mount from the | 453 | * remembered, e.g. by a second mount from the |
431 | * same IP address. | 454 | * same IP address. |
432 | */ | 455 | */ |
456 | sn = net_generic(xprt->xpt_net, sunrpc_net_id); | ||
433 | xprt->xpt_auth_cache = NULL; | 457 | xprt->xpt_auth_cache = NULL; |
434 | spin_unlock(&xprt->xpt_lock); | 458 | spin_unlock(&xprt->xpt_lock); |
435 | cache_put(&ipm->h, &ip_map_cache); | 459 | cache_put(&ipm->h, sn->ip_map_cache); |
436 | return NULL; | 460 | return NULL; |
437 | } | 461 | } |
438 | cache_get(&ipm->h); | 462 | cache_get(&ipm->h); |
@@ -443,10 +467,8 @@ ip_map_cached_get(struct svc_rqst *rqstp) | |||
443 | } | 467 | } |
444 | 468 | ||
445 | static inline void | 469 | static inline void |
446 | ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm) | 470 | ip_map_cached_put(struct svc_xprt *xprt, struct ip_map *ipm) |
447 | { | 471 | { |
448 | struct svc_xprt *xprt = rqstp->rq_xprt; | ||
449 | |||
450 | if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) { | 472 | if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) { |
451 | spin_lock(&xprt->xpt_lock); | 473 | spin_lock(&xprt->xpt_lock); |
452 | if (xprt->xpt_auth_cache == NULL) { | 474 | if (xprt->xpt_auth_cache == NULL) { |
@@ -456,15 +478,26 @@ ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm) | |||
456 | } | 478 | } |
457 | spin_unlock(&xprt->xpt_lock); | 479 | spin_unlock(&xprt->xpt_lock); |
458 | } | 480 | } |
459 | if (ipm) | 481 | if (ipm) { |
460 | cache_put(&ipm->h, &ip_map_cache); | 482 | struct sunrpc_net *sn; |
483 | |||
484 | sn = net_generic(xprt->xpt_net, sunrpc_net_id); | ||
485 | cache_put(&ipm->h, sn->ip_map_cache); | ||
486 | } | ||
461 | } | 487 | } |
462 | 488 | ||
463 | void | 489 | void |
464 | svcauth_unix_info_release(void *info) | 490 | svcauth_unix_info_release(struct svc_xprt *xpt) |
465 | { | 491 | { |
466 | struct ip_map *ipm = info; | 492 | struct ip_map *ipm; |
467 | cache_put(&ipm->h, &ip_map_cache); | 493 | |
494 | ipm = xpt->xpt_auth_cache; | ||
495 | if (ipm != NULL) { | ||
496 | struct sunrpc_net *sn; | ||
497 | |||
498 | sn = net_generic(xpt->xpt_net, sunrpc_net_id); | ||
499 | cache_put(&ipm->h, sn->ip_map_cache); | ||
500 | } | ||
468 | } | 501 | } |
469 | 502 | ||
470 | /**************************************************************************** | 503 | /**************************************************************************** |
@@ -474,7 +507,6 @@ svcauth_unix_info_release(void *info) | |||
474 | */ | 507 | */ |
475 | #define GID_HASHBITS 8 | 508 | #define GID_HASHBITS 8 |
476 | #define GID_HASHMAX (1<<GID_HASHBITS) | 509 | #define GID_HASHMAX (1<<GID_HASHBITS) |
477 | #define GID_HASHMASK (GID_HASHMAX - 1) | ||
478 | 510 | ||
479 | struct unix_gid { | 511 | struct unix_gid { |
480 | struct cache_head h; | 512 | struct cache_head h; |
@@ -674,6 +706,8 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp) | |||
674 | switch (ret) { | 706 | switch (ret) { |
675 | case -ENOENT: | 707 | case -ENOENT: |
676 | return ERR_PTR(-ENOENT); | 708 | return ERR_PTR(-ENOENT); |
709 | case -ETIMEDOUT: | ||
710 | return ERR_PTR(-ESHUTDOWN); | ||
677 | case 0: | 711 | case 0: |
678 | gi = get_group_info(ug->gi); | 712 | gi = get_group_info(ug->gi); |
679 | cache_put(&ug->h, &unix_gid_cache); | 713 | cache_put(&ug->h, &unix_gid_cache); |
@@ -691,6 +725,9 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) | |||
691 | struct ip_map *ipm; | 725 | struct ip_map *ipm; |
692 | struct group_info *gi; | 726 | struct group_info *gi; |
693 | struct svc_cred *cred = &rqstp->rq_cred; | 727 | struct svc_cred *cred = &rqstp->rq_cred; |
728 | struct svc_xprt *xprt = rqstp->rq_xprt; | ||
729 | struct net *net = xprt->xpt_net; | ||
730 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
694 | 731 | ||
695 | switch (rqstp->rq_addr.ss_family) { | 732 | switch (rqstp->rq_addr.ss_family) { |
696 | case AF_INET: | 733 | case AF_INET: |
@@ -709,26 +746,27 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) | |||
709 | if (rqstp->rq_proc == 0) | 746 | if (rqstp->rq_proc == 0) |
710 | return SVC_OK; | 747 | return SVC_OK; |
711 | 748 | ||
712 | ipm = ip_map_cached_get(rqstp); | 749 | ipm = ip_map_cached_get(xprt); |
713 | if (ipm == NULL) | 750 | if (ipm == NULL) |
714 | ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class, | 751 | ipm = __ip_map_lookup(sn->ip_map_cache, rqstp->rq_server->sv_program->pg_class, |
715 | &sin6->sin6_addr); | 752 | &sin6->sin6_addr); |
716 | 753 | ||
717 | if (ipm == NULL) | 754 | if (ipm == NULL) |
718 | return SVC_DENIED; | 755 | return SVC_DENIED; |
719 | 756 | ||
720 | switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) { | 757 | switch (cache_check(sn->ip_map_cache, &ipm->h, &rqstp->rq_chandle)) { |
721 | default: | 758 | default: |
722 | BUG(); | 759 | BUG(); |
723 | case -EAGAIN: | ||
724 | case -ETIMEDOUT: | 760 | case -ETIMEDOUT: |
761 | return SVC_CLOSE; | ||
762 | case -EAGAIN: | ||
725 | return SVC_DROP; | 763 | return SVC_DROP; |
726 | case -ENOENT: | 764 | case -ENOENT: |
727 | return SVC_DENIED; | 765 | return SVC_DENIED; |
728 | case 0: | 766 | case 0: |
729 | rqstp->rq_client = &ipm->m_client->h; | 767 | rqstp->rq_client = &ipm->m_client->h; |
730 | kref_get(&rqstp->rq_client->ref); | 768 | kref_get(&rqstp->rq_client->ref); |
731 | ip_map_cached_put(rqstp, ipm); | 769 | ip_map_cached_put(xprt, ipm); |
732 | break; | 770 | break; |
733 | } | 771 | } |
734 | 772 | ||
@@ -736,6 +774,8 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) | |||
736 | switch (PTR_ERR(gi)) { | 774 | switch (PTR_ERR(gi)) { |
737 | case -EAGAIN: | 775 | case -EAGAIN: |
738 | return SVC_DROP; | 776 | return SVC_DROP; |
777 | case -ESHUTDOWN: | ||
778 | return SVC_CLOSE; | ||
739 | case -ENOENT: | 779 | case -ENOENT: |
740 | break; | 780 | break; |
741 | default: | 781 | default: |
@@ -776,7 +816,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
776 | cred->cr_gid = (gid_t) -1; | 816 | cred->cr_gid = (gid_t) -1; |
777 | cred->cr_group_info = groups_alloc(0); | 817 | cred->cr_group_info = groups_alloc(0); |
778 | if (cred->cr_group_info == NULL) | 818 | if (cred->cr_group_info == NULL) |
779 | return SVC_DROP; /* kmalloc failure - client must retry */ | 819 | return SVC_CLOSE; /* kmalloc failure - client must retry */ |
780 | 820 | ||
781 | /* Put NULL verifier */ | 821 | /* Put NULL verifier */ |
782 | svc_putnl(resv, RPC_AUTH_NULL); | 822 | svc_putnl(resv, RPC_AUTH_NULL); |
@@ -840,7 +880,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
840 | goto badcred; | 880 | goto badcred; |
841 | cred->cr_group_info = groups_alloc(slen); | 881 | cred->cr_group_info = groups_alloc(slen); |
842 | if (cred->cr_group_info == NULL) | 882 | if (cred->cr_group_info == NULL) |
843 | return SVC_DROP; | 883 | return SVC_CLOSE; |
844 | for (i = 0; i < slen; i++) | 884 | for (i = 0; i < slen; i++) |
845 | GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv); | 885 | GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv); |
846 | if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { | 886 | if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { |
@@ -886,3 +926,56 @@ struct auth_ops svcauth_unix = { | |||
886 | .set_client = svcauth_unix_set_client, | 926 | .set_client = svcauth_unix_set_client, |
887 | }; | 927 | }; |
888 | 928 | ||
929 | int ip_map_cache_create(struct net *net) | ||
930 | { | ||
931 | int err = -ENOMEM; | ||
932 | struct cache_detail *cd; | ||
933 | struct cache_head **tbl; | ||
934 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
935 | |||
936 | cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL); | ||
937 | if (cd == NULL) | ||
938 | goto err_cd; | ||
939 | |||
940 | tbl = kzalloc(IP_HASHMAX * sizeof(struct cache_head *), GFP_KERNEL); | ||
941 | if (tbl == NULL) | ||
942 | goto err_tbl; | ||
943 | |||
944 | cd->owner = THIS_MODULE, | ||
945 | cd->hash_size = IP_HASHMAX, | ||
946 | cd->hash_table = tbl, | ||
947 | cd->name = "auth.unix.ip", | ||
948 | cd->cache_put = ip_map_put, | ||
949 | cd->cache_upcall = ip_map_upcall, | ||
950 | cd->cache_parse = ip_map_parse, | ||
951 | cd->cache_show = ip_map_show, | ||
952 | cd->match = ip_map_match, | ||
953 | cd->init = ip_map_init, | ||
954 | cd->update = update, | ||
955 | cd->alloc = ip_map_alloc, | ||
956 | |||
957 | err = cache_register_net(cd, net); | ||
958 | if (err) | ||
959 | goto err_reg; | ||
960 | |||
961 | sn->ip_map_cache = cd; | ||
962 | return 0; | ||
963 | |||
964 | err_reg: | ||
965 | kfree(tbl); | ||
966 | err_tbl: | ||
967 | kfree(cd); | ||
968 | err_cd: | ||
969 | return err; | ||
970 | } | ||
971 | |||
972 | void ip_map_cache_destroy(struct net *net) | ||
973 | { | ||
974 | struct sunrpc_net *sn; | ||
975 | |||
976 | sn = net_generic(net, sunrpc_net_id); | ||
977 | cache_purge(sn->ip_map_cache); | ||
978 | cache_unregister_net(sn->ip_map_cache, net); | ||
979 | kfree(sn->ip_map_cache->hash_table); | ||
980 | kfree(sn->ip_map_cache); | ||
981 | } | ||