aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/svc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/svc.c')
-rw-r--r--net/sunrpc/svc.c62
1 files changed, 50 insertions, 12 deletions
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 9805143d0660..9eb78a771da5 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -28,6 +28,8 @@
28 28
29#define RPCDBG_FACILITY RPCDBG_SVCDSP 29#define RPCDBG_FACILITY RPCDBG_SVCDSP
30 30
31static void svc_unregister(const struct svc_serv *serv);
32
31#define svc_serv_is_pooled(serv) ((serv)->sv_function) 33#define svc_serv_is_pooled(serv) ((serv)->sv_function)
32 34
33/* 35/*
@@ -417,9 +419,8 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
417 spin_lock_init(&pool->sp_lock); 419 spin_lock_init(&pool->sp_lock);
418 } 420 }
419 421
420
421 /* Remove any stale portmap registrations */ 422 /* Remove any stale portmap registrations */
422 svc_register(serv, 0, 0); 423 svc_unregister(serv);
423 424
424 return serv; 425 return serv;
425} 426}
@@ -487,8 +488,7 @@ svc_destroy(struct svc_serv *serv)
487 if (svc_serv_is_pooled(serv)) 488 if (svc_serv_is_pooled(serv))
488 svc_pool_map_put(); 489 svc_pool_map_put();
489 490
490 /* Unregister service with the portmapper */ 491 svc_unregister(serv);
491 svc_register(serv, 0, 0);
492 kfree(serv->sv_pools); 492 kfree(serv->sv_pools);
493 kfree(serv); 493 kfree(serv);
494} 494}
@@ -728,12 +728,10 @@ int
728svc_register(struct svc_serv *serv, int proto, unsigned short port) 728svc_register(struct svc_serv *serv, int proto, unsigned short port)
729{ 729{
730 struct svc_program *progp; 730 struct svc_program *progp;
731 unsigned long flags;
732 unsigned int i; 731 unsigned int i;
733 int error = 0; 732 int error = 0;
734 733
735 if (!port) 734 BUG_ON(proto == 0 && port == 0);
736 clear_thread_flag(TIF_SIGPENDING);
737 735
738 for (progp = serv->sv_program; progp; progp = progp->pg_next) { 736 for (progp = serv->sv_program; progp; progp = progp->pg_next) {
739 for (i = 0; i < progp->pg_nvers; i++) { 737 for (i = 0; i < progp->pg_nvers; i++) {
@@ -757,13 +755,53 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
757 } 755 }
758 } 756 }
759 757
760 if (!port) { 758 return error;
761 spin_lock_irqsave(&current->sighand->siglock, flags); 759}
762 recalc_sigpending(); 760
763 spin_unlock_irqrestore(&current->sighand->siglock, flags); 761/*
762 * All transport protocols and ports for this service are removed
763 * from the local rpcbind database if the service is not hidden.
764 *
765 * The result of unregistration is reported via dprintk for those
766 * who want verification of the result, but is otherwise not
767 * important.
768 *
769 * The local rpcbind daemon listens on either only IPv6 or only
770 * IPv4. The kernel can't tell how it's configured. However,
771 * AF_INET addresses are mapped to AF_INET6 in IPv6-only config-
772 * urations, so even an unregistration request on AF_INET will
773 * get to a local rpcbind daemon listening only on AF_INET6. So
774 * we always unregister via AF_INET.
775 *
776 * At this point we don't need rpcbind version 4 for unregis-
777 * tration: A v2 UNSET request will clear all transports (netids),
778 * addresses, and address families for [program, version].
779 */
780static void svc_unregister(const struct svc_serv *serv)
781{
782 struct svc_program *progp;
783 unsigned long flags;
784 unsigned int i;
785 int error;
786
787 clear_thread_flag(TIF_SIGPENDING);
788
789 for (progp = serv->sv_program; progp; progp = progp->pg_next) {
790 for (i = 0; i < progp->pg_nvers; i++) {
791 if (progp->pg_vers[i] == NULL)
792 continue;
793 if (progp->pg_vers[i]->vs_hidden)
794 continue;
795
796 error = rpcb_register(progp->pg_prog, i, 0, 0);
797 dprintk("svc: svc_unregister(%sv%u), error %d\n",
798 progp->pg_name, i, error);
799 }
764 } 800 }
765 801
766 return error; 802 spin_lock_irqsave(&current->sighand->siglock, flags);
803 recalc_sigpending();
804 spin_unlock_irqrestore(&current->sighand->siglock, flags);
767} 805}
768 806
769/* 807/*