diff options
Diffstat (limited to 'net/sunrpc/svcauth_unix.c')
-rw-r--r-- | net/sunrpc/svcauth_unix.c | 195 |
1 files changed, 93 insertions, 102 deletions
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 4d012920373..ce136323da8 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <net/sock.h> | 14 | #include <net/sock.h> |
15 | #include <net/ipv6.h> | 15 | #include <net/ipv6.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/user_namespace.h> | ||
18 | #define RPCDBG_FACILITY RPCDBG_AUTH | 17 | #define RPCDBG_FACILITY RPCDBG_AUTH |
19 | 18 | ||
20 | #include <linux/sunrpc/clnt.h> | 19 | #include <linux/sunrpc/clnt.h> |
@@ -104,9 +103,23 @@ static void ip_map_put(struct kref *kref) | |||
104 | kfree(im); | 103 | kfree(im); |
105 | } | 104 | } |
106 | 105 | ||
107 | static inline int hash_ip6(const struct in6_addr *ip) | 106 | #if IP_HASHBITS == 8 |
107 | /* hash_long on a 64 bit machine is currently REALLY BAD for | ||
108 | * IP addresses in reverse-endian (i.e. on a little-endian machine). | ||
109 | * So use a trivial but reliable hash instead | ||
110 | */ | ||
111 | static inline int hash_ip(__be32 ip) | ||
112 | { | ||
113 | int hash = (__force u32)ip ^ ((__force u32)ip>>16); | ||
114 | return (hash ^ (hash>>8)) & 0xff; | ||
115 | } | ||
116 | #endif | ||
117 | static inline int hash_ip6(struct in6_addr ip) | ||
108 | { | 118 | { |
109 | return hash_32(ipv6_addr_hash(ip), IP_HASHBITS); | 119 | return (hash_ip(ip.s6_addr32[0]) ^ |
120 | hash_ip(ip.s6_addr32[1]) ^ | ||
121 | hash_ip(ip.s6_addr32[2]) ^ | ||
122 | hash_ip(ip.s6_addr32[3])); | ||
110 | } | 123 | } |
111 | static int ip_map_match(struct cache_head *corig, struct cache_head *cnew) | 124 | static int ip_map_match(struct cache_head *corig, struct cache_head *cnew) |
112 | { | 125 | { |
@@ -121,7 +134,7 @@ static void ip_map_init(struct cache_head *cnew, struct cache_head *citem) | |||
121 | struct ip_map *item = container_of(citem, struct ip_map, h); | 134 | struct ip_map *item = container_of(citem, struct ip_map, h); |
122 | 135 | ||
123 | strcpy(new->m_class, item->m_class); | 136 | strcpy(new->m_class, item->m_class); |
124 | new->m_addr = item->m_addr; | 137 | ipv6_addr_copy(&new->m_addr, &item->m_addr); |
125 | } | 138 | } |
126 | static void update(struct cache_head *cnew, struct cache_head *citem) | 139 | static void update(struct cache_head *cnew, struct cache_head *citem) |
127 | { | 140 | { |
@@ -198,7 +211,7 @@ static int ip_map_parse(struct cache_detail *cd, | |||
198 | len = qword_get(&mesg, buf, mlen); | 211 | len = qword_get(&mesg, buf, mlen); |
199 | if (len <= 0) return -EINVAL; | 212 | if (len <= 0) return -EINVAL; |
200 | 213 | ||
201 | if (rpc_pton(cd->net, buf, len, &address.sa, sizeof(address)) == 0) | 214 | if (rpc_pton(buf, len, &address.sa, sizeof(address)) == 0) |
202 | return -EINVAL; | 215 | return -EINVAL; |
203 | switch (address.sa.sa_family) { | 216 | switch (address.sa.sa_family) { |
204 | case AF_INET: | 217 | case AF_INET: |
@@ -207,7 +220,7 @@ static int ip_map_parse(struct cache_detail *cd, | |||
207 | ipv6_addr_set_v4mapped(address.s4.sin_addr.s_addr, | 220 | ipv6_addr_set_v4mapped(address.s4.sin_addr.s_addr, |
208 | &sin6.sin6_addr); | 221 | &sin6.sin6_addr); |
209 | break; | 222 | break; |
210 | #if IS_ENABLED(CONFIG_IPV6) | 223 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
211 | case AF_INET6: | 224 | case AF_INET6: |
212 | memcpy(&sin6, &address.s6, sizeof(sin6)); | 225 | memcpy(&sin6, &address.s6, sizeof(sin6)); |
213 | break; | 226 | break; |
@@ -261,7 +274,7 @@ static int ip_map_show(struct seq_file *m, | |||
261 | } | 274 | } |
262 | im = container_of(h, struct ip_map, h); | 275 | im = container_of(h, struct ip_map, h); |
263 | /* class addr domain */ | 276 | /* class addr domain */ |
264 | addr = im->m_addr; | 277 | ipv6_addr_copy(&addr, &im->m_addr); |
265 | 278 | ||
266 | if (test_bit(CACHE_VALID, &h->flags) && | 279 | if (test_bit(CACHE_VALID, &h->flags) && |
267 | !test_bit(CACHE_NEGATIVE, &h->flags)) | 280 | !test_bit(CACHE_NEGATIVE, &h->flags)) |
@@ -284,10 +297,10 @@ static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, | |||
284 | struct cache_head *ch; | 297 | struct cache_head *ch; |
285 | 298 | ||
286 | strcpy(ip.m_class, class); | 299 | strcpy(ip.m_class, class); |
287 | ip.m_addr = *addr; | 300 | ipv6_addr_copy(&ip.m_addr, addr); |
288 | ch = sunrpc_cache_lookup(cd, &ip.h, | 301 | ch = sunrpc_cache_lookup(cd, &ip.h, |
289 | hash_str(class, IP_HASHBITS) ^ | 302 | hash_str(class, IP_HASHBITS) ^ |
290 | hash_ip6(addr)); | 303 | hash_ip6(*addr)); |
291 | 304 | ||
292 | if (ch) | 305 | if (ch) |
293 | return container_of(ch, struct ip_map, h); | 306 | return container_of(ch, struct ip_map, h); |
@@ -317,7 +330,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, | |||
317 | ip.h.expiry_time = expiry; | 330 | ip.h.expiry_time = expiry; |
318 | ch = sunrpc_cache_update(cd, &ip.h, &ipm->h, | 331 | ch = sunrpc_cache_update(cd, &ip.h, &ipm->h, |
319 | hash_str(ipm->m_class, IP_HASHBITS) ^ | 332 | hash_str(ipm->m_class, IP_HASHBITS) ^ |
320 | hash_ip6(&ipm->m_addr)); | 333 | hash_ip6(ipm->m_addr)); |
321 | if (!ch) | 334 | if (!ch) |
322 | return -ENOMEM; | 335 | return -ENOMEM; |
323 | cache_put(ch, cd); | 336 | cache_put(ch, cd); |
@@ -333,12 +346,17 @@ static inline int ip_map_update(struct net *net, struct ip_map *ipm, | |||
333 | return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry); | 346 | return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry); |
334 | } | 347 | } |
335 | 348 | ||
336 | void svcauth_unix_purge(struct net *net) | 349 | |
350 | void svcauth_unix_purge(void) | ||
337 | { | 351 | { |
338 | struct sunrpc_net *sn; | 352 | struct net *net; |
339 | 353 | ||
340 | sn = net_generic(net, sunrpc_net_id); | 354 | for_each_net(net) { |
341 | cache_purge(sn->ip_map_cache); | 355 | struct sunrpc_net *sn; |
356 | |||
357 | sn = net_generic(net, sunrpc_net_id); | ||
358 | cache_purge(sn->ip_map_cache); | ||
359 | } | ||
342 | } | 360 | } |
343 | EXPORT_SYMBOL_GPL(svcauth_unix_purge); | 361 | EXPORT_SYMBOL_GPL(svcauth_unix_purge); |
344 | 362 | ||
@@ -418,6 +436,7 @@ struct unix_gid { | |||
418 | uid_t uid; | 436 | uid_t uid; |
419 | struct group_info *gi; | 437 | struct group_info *gi; |
420 | }; | 438 | }; |
439 | static struct cache_head *gid_table[GID_HASHMAX]; | ||
421 | 440 | ||
422 | static void unix_gid_put(struct kref *kref) | 441 | static void unix_gid_put(struct kref *kref) |
423 | { | 442 | { |
@@ -475,7 +494,8 @@ static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h) | |||
475 | return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request); | 494 | return sunrpc_cache_pipe_upcall(cd, h, unix_gid_request); |
476 | } | 495 | } |
477 | 496 | ||
478 | static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid); | 497 | static struct unix_gid *unix_gid_lookup(uid_t uid); |
498 | extern struct cache_detail unix_gid_cache; | ||
479 | 499 | ||
480 | static int unix_gid_parse(struct cache_detail *cd, | 500 | static int unix_gid_parse(struct cache_detail *cd, |
481 | char *mesg, int mlen) | 501 | char *mesg, int mlen) |
@@ -489,7 +509,7 @@ static int unix_gid_parse(struct cache_detail *cd, | |||
489 | time_t expiry; | 509 | time_t expiry; |
490 | struct unix_gid ug, *ugp; | 510 | struct unix_gid ug, *ugp; |
491 | 511 | ||
492 | if (mesg[mlen - 1] != '\n') | 512 | if (mlen <= 0 || mesg[mlen-1] != '\n') |
493 | return -EINVAL; | 513 | return -EINVAL; |
494 | mesg[mlen-1] = 0; | 514 | mesg[mlen-1] = 0; |
495 | 515 | ||
@@ -512,30 +532,26 @@ static int unix_gid_parse(struct cache_detail *cd, | |||
512 | 532 | ||
513 | for (i = 0 ; i < gids ; i++) { | 533 | for (i = 0 ; i < gids ; i++) { |
514 | int gid; | 534 | int gid; |
515 | kgid_t kgid; | ||
516 | rv = get_int(&mesg, &gid); | 535 | rv = get_int(&mesg, &gid); |
517 | err = -EINVAL; | 536 | err = -EINVAL; |
518 | if (rv) | 537 | if (rv) |
519 | goto out; | 538 | goto out; |
520 | kgid = make_kgid(&init_user_ns, gid); | 539 | GROUP_AT(ug.gi, i) = gid; |
521 | if (!gid_valid(kgid)) | ||
522 | goto out; | ||
523 | GROUP_AT(ug.gi, i) = kgid; | ||
524 | } | 540 | } |
525 | 541 | ||
526 | ugp = unix_gid_lookup(cd, uid); | 542 | ugp = unix_gid_lookup(uid); |
527 | if (ugp) { | 543 | if (ugp) { |
528 | struct cache_head *ch; | 544 | struct cache_head *ch; |
529 | ug.h.flags = 0; | 545 | ug.h.flags = 0; |
530 | ug.h.expiry_time = expiry; | 546 | ug.h.expiry_time = expiry; |
531 | ch = sunrpc_cache_update(cd, | 547 | ch = sunrpc_cache_update(&unix_gid_cache, |
532 | &ug.h, &ugp->h, | 548 | &ug.h, &ugp->h, |
533 | hash_long(uid, GID_HASHBITS)); | 549 | hash_long(uid, GID_HASHBITS)); |
534 | if (!ch) | 550 | if (!ch) |
535 | err = -ENOMEM; | 551 | err = -ENOMEM; |
536 | else { | 552 | else { |
537 | err = 0; | 553 | err = 0; |
538 | cache_put(ch, cd); | 554 | cache_put(ch, &unix_gid_cache); |
539 | } | 555 | } |
540 | } else | 556 | } else |
541 | err = -ENOMEM; | 557 | err = -ENOMEM; |
@@ -549,7 +565,6 @@ static int unix_gid_show(struct seq_file *m, | |||
549 | struct cache_detail *cd, | 565 | struct cache_detail *cd, |
550 | struct cache_head *h) | 566 | struct cache_head *h) |
551 | { | 567 | { |
552 | struct user_namespace *user_ns = current_user_ns(); | ||
553 | struct unix_gid *ug; | 568 | struct unix_gid *ug; |
554 | int i; | 569 | int i; |
555 | int glen; | 570 | int glen; |
@@ -567,14 +582,15 @@ static int unix_gid_show(struct seq_file *m, | |||
567 | 582 | ||
568 | seq_printf(m, "%u %d:", ug->uid, glen); | 583 | seq_printf(m, "%u %d:", ug->uid, glen); |
569 | for (i = 0; i < glen; i++) | 584 | for (i = 0; i < glen; i++) |
570 | seq_printf(m, " %d", from_kgid_munged(user_ns, GROUP_AT(ug->gi, i))); | 585 | seq_printf(m, " %d", GROUP_AT(ug->gi, i)); |
571 | seq_printf(m, "\n"); | 586 | seq_printf(m, "\n"); |
572 | return 0; | 587 | return 0; |
573 | } | 588 | } |
574 | 589 | ||
575 | static struct cache_detail unix_gid_cache_template = { | 590 | struct cache_detail unix_gid_cache = { |
576 | .owner = THIS_MODULE, | 591 | .owner = THIS_MODULE, |
577 | .hash_size = GID_HASHMAX, | 592 | .hash_size = GID_HASHMAX, |
593 | .hash_table = gid_table, | ||
578 | .name = "auth.unix.gid", | 594 | .name = "auth.unix.gid", |
579 | .cache_put = unix_gid_put, | 595 | .cache_put = unix_gid_put, |
580 | .cache_upcall = unix_gid_upcall, | 596 | .cache_upcall = unix_gid_upcall, |
@@ -586,42 +602,14 @@ static struct cache_detail unix_gid_cache_template = { | |||
586 | .alloc = unix_gid_alloc, | 602 | .alloc = unix_gid_alloc, |
587 | }; | 603 | }; |
588 | 604 | ||
589 | int unix_gid_cache_create(struct net *net) | 605 | static struct unix_gid *unix_gid_lookup(uid_t uid) |
590 | { | ||
591 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
592 | struct cache_detail *cd; | ||
593 | int err; | ||
594 | |||
595 | cd = cache_create_net(&unix_gid_cache_template, net); | ||
596 | if (IS_ERR(cd)) | ||
597 | return PTR_ERR(cd); | ||
598 | err = cache_register_net(cd, net); | ||
599 | if (err) { | ||
600 | cache_destroy_net(cd, net); | ||
601 | return err; | ||
602 | } | ||
603 | sn->unix_gid_cache = cd; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | void unix_gid_cache_destroy(struct net *net) | ||
608 | { | ||
609 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
610 | struct cache_detail *cd = sn->unix_gid_cache; | ||
611 | |||
612 | sn->unix_gid_cache = NULL; | ||
613 | cache_purge(cd); | ||
614 | cache_unregister_net(cd, net); | ||
615 | cache_destroy_net(cd, net); | ||
616 | } | ||
617 | |||
618 | static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, uid_t uid) | ||
619 | { | 606 | { |
620 | struct unix_gid ug; | 607 | struct unix_gid ug; |
621 | struct cache_head *ch; | 608 | struct cache_head *ch; |
622 | 609 | ||
623 | ug.uid = uid; | 610 | ug.uid = uid; |
624 | ch = sunrpc_cache_lookup(cd, &ug.h, hash_long(uid, GID_HASHBITS)); | 611 | ch = sunrpc_cache_lookup(&unix_gid_cache, &ug.h, |
612 | hash_long(uid, GID_HASHBITS)); | ||
625 | if (ch) | 613 | if (ch) |
626 | return container_of(ch, struct unix_gid, h); | 614 | return container_of(ch, struct unix_gid, h); |
627 | else | 615 | else |
@@ -633,13 +621,11 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp) | |||
633 | struct unix_gid *ug; | 621 | struct unix_gid *ug; |
634 | struct group_info *gi; | 622 | struct group_info *gi; |
635 | int ret; | 623 | int ret; |
636 | struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, | ||
637 | sunrpc_net_id); | ||
638 | 624 | ||
639 | ug = unix_gid_lookup(sn->unix_gid_cache, uid); | 625 | ug = unix_gid_lookup(uid); |
640 | if (!ug) | 626 | if (!ug) |
641 | return ERR_PTR(-EAGAIN); | 627 | return ERR_PTR(-EAGAIN); |
642 | ret = cache_check(sn->unix_gid_cache, &ug->h, &rqstp->rq_chandle); | 628 | ret = cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle); |
643 | switch (ret) { | 629 | switch (ret) { |
644 | case -ENOENT: | 630 | case -ENOENT: |
645 | return ERR_PTR(-ENOENT); | 631 | return ERR_PTR(-ENOENT); |
@@ -647,7 +633,7 @@ static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp) | |||
647 | return ERR_PTR(-ESHUTDOWN); | 633 | return ERR_PTR(-ESHUTDOWN); |
648 | case 0: | 634 | case 0: |
649 | gi = get_group_info(ug->gi); | 635 | gi = get_group_info(ug->gi); |
650 | cache_put(&ug->h, sn->unix_gid_cache); | 636 | cache_put(&ug->h, &unix_gid_cache); |
651 | return gi; | 637 | return gi; |
652 | default: | 638 | default: |
653 | return ERR_PTR(-EAGAIN); | 639 | return ERR_PTR(-EAGAIN); |
@@ -732,7 +718,6 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
732 | struct svc_cred *cred = &rqstp->rq_cred; | 718 | struct svc_cred *cred = &rqstp->rq_cred; |
733 | 719 | ||
734 | cred->cr_group_info = NULL; | 720 | cred->cr_group_info = NULL; |
735 | cred->cr_principal = NULL; | ||
736 | rqstp->rq_client = NULL; | 721 | rqstp->rq_client = NULL; |
737 | 722 | ||
738 | if (argv->iov_len < 3*4) | 723 | if (argv->iov_len < 3*4) |
@@ -760,7 +745,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
760 | svc_putnl(resv, RPC_AUTH_NULL); | 745 | svc_putnl(resv, RPC_AUTH_NULL); |
761 | svc_putnl(resv, 0); | 746 | svc_putnl(resv, 0); |
762 | 747 | ||
763 | rqstp->rq_cred.cr_flavor = RPC_AUTH_NULL; | 748 | rqstp->rq_flavor = RPC_AUTH_NULL; |
764 | return SVC_OK; | 749 | return SVC_OK; |
765 | } | 750 | } |
766 | 751 | ||
@@ -798,7 +783,6 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
798 | int len = argv->iov_len; | 783 | int len = argv->iov_len; |
799 | 784 | ||
800 | cred->cr_group_info = NULL; | 785 | cred->cr_group_info = NULL; |
801 | cred->cr_principal = NULL; | ||
802 | rqstp->rq_client = NULL; | 786 | rqstp->rq_client = NULL; |
803 | 787 | ||
804 | if ((len -= 3*4) < 0) | 788 | if ((len -= 3*4) < 0) |
@@ -820,12 +804,8 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
820 | cred->cr_group_info = groups_alloc(slen); | 804 | cred->cr_group_info = groups_alloc(slen); |
821 | if (cred->cr_group_info == NULL) | 805 | if (cred->cr_group_info == NULL) |
822 | return SVC_CLOSE; | 806 | return SVC_CLOSE; |
823 | for (i = 0; i < slen; i++) { | 807 | for (i = 0; i < slen; i++) |
824 | kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv)); | 808 | GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv); |
825 | if (!gid_valid(kgid)) | ||
826 | goto badcred; | ||
827 | GROUP_AT(cred->cr_group_info, i) = kgid; | ||
828 | } | ||
829 | if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { | 809 | if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { |
830 | *authp = rpc_autherr_badverf; | 810 | *authp = rpc_autherr_badverf; |
831 | return SVC_DENIED; | 811 | return SVC_DENIED; |
@@ -835,7 +815,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
835 | svc_putnl(resv, RPC_AUTH_NULL); | 815 | svc_putnl(resv, RPC_AUTH_NULL); |
836 | svc_putnl(resv, 0); | 816 | svc_putnl(resv, 0); |
837 | 817 | ||
838 | rqstp->rq_cred.cr_flavor = RPC_AUTH_UNIX; | 818 | rqstp->rq_flavor = RPC_AUTH_UNIX; |
839 | return SVC_OK; | 819 | return SVC_OK; |
840 | 820 | ||
841 | badcred: | 821 | badcred: |
@@ -869,45 +849,56 @@ struct auth_ops svcauth_unix = { | |||
869 | .set_client = svcauth_unix_set_client, | 849 | .set_client = svcauth_unix_set_client, |
870 | }; | 850 | }; |
871 | 851 | ||
872 | static struct cache_detail ip_map_cache_template = { | ||
873 | .owner = THIS_MODULE, | ||
874 | .hash_size = IP_HASHMAX, | ||
875 | .name = "auth.unix.ip", | ||
876 | .cache_put = ip_map_put, | ||
877 | .cache_upcall = ip_map_upcall, | ||
878 | .cache_parse = ip_map_parse, | ||
879 | .cache_show = ip_map_show, | ||
880 | .match = ip_map_match, | ||
881 | .init = ip_map_init, | ||
882 | .update = update, | ||
883 | .alloc = ip_map_alloc, | ||
884 | }; | ||
885 | |||
886 | int ip_map_cache_create(struct net *net) | 852 | int ip_map_cache_create(struct net *net) |
887 | { | 853 | { |
888 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 854 | int err = -ENOMEM; |
889 | struct cache_detail *cd; | 855 | struct cache_detail *cd; |
890 | int err; | 856 | struct cache_head **tbl; |
857 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
858 | |||
859 | cd = kzalloc(sizeof(struct cache_detail), GFP_KERNEL); | ||
860 | if (cd == NULL) | ||
861 | goto err_cd; | ||
862 | |||
863 | tbl = kzalloc(IP_HASHMAX * sizeof(struct cache_head *), GFP_KERNEL); | ||
864 | if (tbl == NULL) | ||
865 | goto err_tbl; | ||
866 | |||
867 | cd->owner = THIS_MODULE, | ||
868 | cd->hash_size = IP_HASHMAX, | ||
869 | cd->hash_table = tbl, | ||
870 | cd->name = "auth.unix.ip", | ||
871 | cd->cache_put = ip_map_put, | ||
872 | cd->cache_upcall = ip_map_upcall, | ||
873 | cd->cache_parse = ip_map_parse, | ||
874 | cd->cache_show = ip_map_show, | ||
875 | cd->match = ip_map_match, | ||
876 | cd->init = ip_map_init, | ||
877 | cd->update = update, | ||
878 | cd->alloc = ip_map_alloc, | ||
891 | 879 | ||
892 | cd = cache_create_net(&ip_map_cache_template, net); | ||
893 | if (IS_ERR(cd)) | ||
894 | return PTR_ERR(cd); | ||
895 | err = cache_register_net(cd, net); | 880 | err = cache_register_net(cd, net); |
896 | if (err) { | 881 | if (err) |
897 | cache_destroy_net(cd, net); | 882 | goto err_reg; |
898 | return err; | 883 | |
899 | } | ||
900 | sn->ip_map_cache = cd; | 884 | sn->ip_map_cache = cd; |
901 | return 0; | 885 | return 0; |
886 | |||
887 | err_reg: | ||
888 | kfree(tbl); | ||
889 | err_tbl: | ||
890 | kfree(cd); | ||
891 | err_cd: | ||
892 | return err; | ||
902 | } | 893 | } |
903 | 894 | ||
904 | void ip_map_cache_destroy(struct net *net) | 895 | void ip_map_cache_destroy(struct net *net) |
905 | { | 896 | { |
906 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 897 | struct sunrpc_net *sn; |
907 | struct cache_detail *cd = sn->ip_map_cache; | ||
908 | 898 | ||
909 | sn->ip_map_cache = NULL; | 899 | sn = net_generic(net, sunrpc_net_id); |
910 | cache_purge(cd); | 900 | cache_purge(sn->ip_map_cache); |
911 | cache_unregister_net(cd, net); | 901 | cache_unregister_net(sn->ip_map_cache, net); |
912 | cache_destroy_net(cd, net); | 902 | kfree(sn->ip_map_cache->hash_table); |
903 | kfree(sn->ip_map_cache); | ||
913 | } | 904 | } |