diff options
Diffstat (limited to 'net/sunrpc/svc.c')
-rw-r--r-- | net/sunrpc/svc.c | 251 |
1 files changed, 221 insertions, 30 deletions
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 5a32cb7c4bb4..54c98d876847 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 | ||
31 | static 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 | /* |
@@ -357,7 +359,7 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu) | |||
357 | */ | 359 | */ |
358 | static struct svc_serv * | 360 | static struct svc_serv * |
359 | __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, | 361 | __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, |
360 | void (*shutdown)(struct svc_serv *serv)) | 362 | sa_family_t family, void (*shutdown)(struct svc_serv *serv)) |
361 | { | 363 | { |
362 | struct svc_serv *serv; | 364 | struct svc_serv *serv; |
363 | unsigned int vers; | 365 | unsigned int vers; |
@@ -366,6 +368,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, | |||
366 | 368 | ||
367 | if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) | 369 | if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) |
368 | return NULL; | 370 | return NULL; |
371 | serv->sv_family = family; | ||
369 | serv->sv_name = prog->pg_name; | 372 | serv->sv_name = prog->pg_name; |
370 | serv->sv_program = prog; | 373 | serv->sv_program = prog; |
371 | serv->sv_nrthreads = 1; | 374 | serv->sv_nrthreads = 1; |
@@ -416,30 +419,29 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, | |||
416 | spin_lock_init(&pool->sp_lock); | 419 | spin_lock_init(&pool->sp_lock); |
417 | } | 420 | } |
418 | 421 | ||
419 | |||
420 | /* Remove any stale portmap registrations */ | 422 | /* Remove any stale portmap registrations */ |
421 | svc_register(serv, 0, 0); | 423 | svc_unregister(serv); |
422 | 424 | ||
423 | return serv; | 425 | return serv; |
424 | } | 426 | } |
425 | 427 | ||
426 | struct svc_serv * | 428 | struct svc_serv * |
427 | svc_create(struct svc_program *prog, unsigned int bufsize, | 429 | svc_create(struct svc_program *prog, unsigned int bufsize, |
428 | void (*shutdown)(struct svc_serv *serv)) | 430 | sa_family_t family, void (*shutdown)(struct svc_serv *serv)) |
429 | { | 431 | { |
430 | return __svc_create(prog, bufsize, /*npools*/1, shutdown); | 432 | return __svc_create(prog, bufsize, /*npools*/1, family, shutdown); |
431 | } | 433 | } |
432 | EXPORT_SYMBOL(svc_create); | 434 | EXPORT_SYMBOL(svc_create); |
433 | 435 | ||
434 | struct svc_serv * | 436 | struct svc_serv * |
435 | svc_create_pooled(struct svc_program *prog, unsigned int bufsize, | 437 | svc_create_pooled(struct svc_program *prog, unsigned int bufsize, |
436 | void (*shutdown)(struct svc_serv *serv), | 438 | sa_family_t family, void (*shutdown)(struct svc_serv *serv), |
437 | svc_thread_fn func, struct module *mod) | 439 | svc_thread_fn func, struct module *mod) |
438 | { | 440 | { |
439 | struct svc_serv *serv; | 441 | struct svc_serv *serv; |
440 | unsigned int npools = svc_pool_map_get(); | 442 | unsigned int npools = svc_pool_map_get(); |
441 | 443 | ||
442 | serv = __svc_create(prog, bufsize, npools, shutdown); | 444 | serv = __svc_create(prog, bufsize, npools, family, shutdown); |
443 | 445 | ||
444 | if (serv != NULL) { | 446 | if (serv != NULL) { |
445 | serv->sv_function = func; | 447 | serv->sv_function = func; |
@@ -486,8 +488,7 @@ svc_destroy(struct svc_serv *serv) | |||
486 | if (svc_serv_is_pooled(serv)) | 488 | if (svc_serv_is_pooled(serv)) |
487 | svc_pool_map_put(); | 489 | svc_pool_map_put(); |
488 | 490 | ||
489 | /* Unregister service with the portmapper */ | 491 | svc_unregister(serv); |
490 | svc_register(serv, 0, 0); | ||
491 | kfree(serv->sv_pools); | 492 | kfree(serv->sv_pools); |
492 | kfree(serv); | 493 | kfree(serv); |
493 | } | 494 | } |
@@ -718,55 +719,245 @@ svc_exit_thread(struct svc_rqst *rqstp) | |||
718 | } | 719 | } |
719 | EXPORT_SYMBOL(svc_exit_thread); | 720 | EXPORT_SYMBOL(svc_exit_thread); |
720 | 721 | ||
722 | #ifdef CONFIG_SUNRPC_REGISTER_V4 | ||
723 | |||
721 | /* | 724 | /* |
722 | * Register an RPC service with the local portmapper. | 725 | * Register an "inet" protocol family netid with the local |
723 | * To unregister a service, call this routine with | 726 | * rpcbind daemon via an rpcbind v4 SET request. |
724 | * proto and port == 0. | 727 | * |
728 | * No netconfig infrastructure is available in the kernel, so | ||
729 | * we map IP_ protocol numbers to netids by hand. | ||
730 | * | ||
731 | * Returns zero on success; a negative errno value is returned | ||
732 | * if any error occurs. | ||
725 | */ | 733 | */ |
726 | int | 734 | static int __svc_rpcb_register4(const u32 program, const u32 version, |
727 | svc_register(struct svc_serv *serv, int proto, unsigned short port) | 735 | const unsigned short protocol, |
736 | const unsigned short port) | ||
737 | { | ||
738 | struct sockaddr_in sin = { | ||
739 | .sin_family = AF_INET, | ||
740 | .sin_addr.s_addr = htonl(INADDR_ANY), | ||
741 | .sin_port = htons(port), | ||
742 | }; | ||
743 | char *netid; | ||
744 | |||
745 | switch (protocol) { | ||
746 | case IPPROTO_UDP: | ||
747 | netid = RPCBIND_NETID_UDP; | ||
748 | break; | ||
749 | case IPPROTO_TCP: | ||
750 | netid = RPCBIND_NETID_TCP; | ||
751 | break; | ||
752 | default: | ||
753 | return -EPROTONOSUPPORT; | ||
754 | } | ||
755 | |||
756 | return rpcb_v4_register(program, version, | ||
757 | (struct sockaddr *)&sin, netid); | ||
758 | } | ||
759 | |||
760 | /* | ||
761 | * Register an "inet6" protocol family netid with the local | ||
762 | * rpcbind daemon via an rpcbind v4 SET request. | ||
763 | * | ||
764 | * No netconfig infrastructure is available in the kernel, so | ||
765 | * we map IP_ protocol numbers to netids by hand. | ||
766 | * | ||
767 | * Returns zero on success; a negative errno value is returned | ||
768 | * if any error occurs. | ||
769 | */ | ||
770 | static int __svc_rpcb_register6(const u32 program, const u32 version, | ||
771 | const unsigned short protocol, | ||
772 | const unsigned short port) | ||
773 | { | ||
774 | struct sockaddr_in6 sin6 = { | ||
775 | .sin6_family = AF_INET6, | ||
776 | .sin6_addr = IN6ADDR_ANY_INIT, | ||
777 | .sin6_port = htons(port), | ||
778 | }; | ||
779 | char *netid; | ||
780 | |||
781 | switch (protocol) { | ||
782 | case IPPROTO_UDP: | ||
783 | netid = RPCBIND_NETID_UDP6; | ||
784 | break; | ||
785 | case IPPROTO_TCP: | ||
786 | netid = RPCBIND_NETID_TCP6; | ||
787 | break; | ||
788 | default: | ||
789 | return -EPROTONOSUPPORT; | ||
790 | } | ||
791 | |||
792 | return rpcb_v4_register(program, version, | ||
793 | (struct sockaddr *)&sin6, netid); | ||
794 | } | ||
795 | |||
796 | /* | ||
797 | * Register a kernel RPC service via rpcbind version 4. | ||
798 | * | ||
799 | * Returns zero on success; a negative errno value is returned | ||
800 | * if any error occurs. | ||
801 | */ | ||
802 | static int __svc_register(const u32 program, const u32 version, | ||
803 | const sa_family_t family, | ||
804 | const unsigned short protocol, | ||
805 | const unsigned short port) | ||
806 | { | ||
807 | int error; | ||
808 | |||
809 | switch (family) { | ||
810 | case AF_INET: | ||
811 | return __svc_rpcb_register4(program, version, | ||
812 | protocol, port); | ||
813 | case AF_INET6: | ||
814 | error = __svc_rpcb_register6(program, version, | ||
815 | protocol, port); | ||
816 | if (error < 0) | ||
817 | return error; | ||
818 | |||
819 | /* | ||
820 | * Work around bug in some versions of Linux rpcbind | ||
821 | * which don't allow registration of both inet and | ||
822 | * inet6 netids. | ||
823 | * | ||
824 | * Error return ignored for now. | ||
825 | */ | ||
826 | __svc_rpcb_register4(program, version, | ||
827 | protocol, port); | ||
828 | return 0; | ||
829 | } | ||
830 | |||
831 | return -EAFNOSUPPORT; | ||
832 | } | ||
833 | |||
834 | #else /* CONFIG_SUNRPC_REGISTER_V4 */ | ||
835 | |||
836 | /* | ||
837 | * Register a kernel RPC service via rpcbind version 2. | ||
838 | * | ||
839 | * Returns zero on success; a negative errno value is returned | ||
840 | * if any error occurs. | ||
841 | */ | ||
842 | static int __svc_register(const u32 program, const u32 version, | ||
843 | sa_family_t family, | ||
844 | const unsigned short protocol, | ||
845 | const unsigned short port) | ||
846 | { | ||
847 | if (family != AF_INET) | ||
848 | return -EAFNOSUPPORT; | ||
849 | |||
850 | return rpcb_register(program, version, protocol, port); | ||
851 | } | ||
852 | |||
853 | #endif /* CONFIG_SUNRPC_REGISTER_V4 */ | ||
854 | |||
855 | /** | ||
856 | * svc_register - register an RPC service with the local portmapper | ||
857 | * @serv: svc_serv struct for the service to register | ||
858 | * @proto: transport protocol number to advertise | ||
859 | * @port: port to advertise | ||
860 | * | ||
861 | * Service is registered for any address in serv's address family | ||
862 | */ | ||
863 | int svc_register(const struct svc_serv *serv, const unsigned short proto, | ||
864 | const unsigned short port) | ||
728 | { | 865 | { |
729 | struct svc_program *progp; | 866 | struct svc_program *progp; |
730 | unsigned long flags; | ||
731 | unsigned int i; | 867 | unsigned int i; |
732 | int error = 0, dummy; | 868 | int error = 0; |
733 | 869 | ||
734 | if (!port) | 870 | BUG_ON(proto == 0 && port == 0); |
735 | clear_thread_flag(TIF_SIGPENDING); | ||
736 | 871 | ||
737 | for (progp = serv->sv_program; progp; progp = progp->pg_next) { | 872 | for (progp = serv->sv_program; progp; progp = progp->pg_next) { |
738 | for (i = 0; i < progp->pg_nvers; i++) { | 873 | for (i = 0; i < progp->pg_nvers; i++) { |
739 | if (progp->pg_vers[i] == NULL) | 874 | if (progp->pg_vers[i] == NULL) |
740 | continue; | 875 | continue; |
741 | 876 | ||
742 | dprintk("svc: svc_register(%s, %s, %d, %d)%s\n", | 877 | dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n", |
743 | progp->pg_name, | 878 | progp->pg_name, |
879 | i, | ||
744 | proto == IPPROTO_UDP? "udp" : "tcp", | 880 | proto == IPPROTO_UDP? "udp" : "tcp", |
745 | port, | 881 | port, |
746 | i, | 882 | serv->sv_family, |
747 | progp->pg_vers[i]->vs_hidden? | 883 | progp->pg_vers[i]->vs_hidden? |
748 | " (but not telling portmap)" : ""); | 884 | " (but not telling portmap)" : ""); |
749 | 885 | ||
750 | if (progp->pg_vers[i]->vs_hidden) | 886 | if (progp->pg_vers[i]->vs_hidden) |
751 | continue; | 887 | continue; |
752 | 888 | ||
753 | error = rpcb_register(progp->pg_prog, i, proto, port, &dummy); | 889 | error = __svc_register(progp->pg_prog, i, |
890 | serv->sv_family, proto, port); | ||
754 | if (error < 0) | 891 | if (error < 0) |
755 | break; | 892 | break; |
756 | if (port && !dummy) { | ||
757 | error = -EACCES; | ||
758 | break; | ||
759 | } | ||
760 | } | 893 | } |
761 | } | 894 | } |
762 | 895 | ||
763 | if (!port) { | 896 | return error; |
764 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 897 | } |
765 | recalc_sigpending(); | 898 | |
766 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 899 | #ifdef CONFIG_SUNRPC_REGISTER_V4 |
900 | |||
901 | static void __svc_unregister(const u32 program, const u32 version, | ||
902 | const char *progname) | ||
903 | { | ||
904 | struct sockaddr_in6 sin6 = { | ||
905 | .sin6_family = AF_INET6, | ||
906 | .sin6_addr = IN6ADDR_ANY_INIT, | ||
907 | .sin6_port = 0, | ||
908 | }; | ||
909 | int error; | ||
910 | |||
911 | error = rpcb_v4_register(program, version, | ||
912 | (struct sockaddr *)&sin6, ""); | ||
913 | dprintk("svc: %s(%sv%u), error %d\n", | ||
914 | __func__, progname, version, error); | ||
915 | } | ||
916 | |||
917 | #else /* CONFIG_SUNRPC_REGISTER_V4 */ | ||
918 | |||
919 | static void __svc_unregister(const u32 program, const u32 version, | ||
920 | const char *progname) | ||
921 | { | ||
922 | int error; | ||
923 | |||
924 | error = rpcb_register(program, version, 0, 0); | ||
925 | dprintk("svc: %s(%sv%u), error %d\n", | ||
926 | __func__, progname, version, error); | ||
927 | } | ||
928 | |||
929 | #endif /* CONFIG_SUNRPC_REGISTER_V4 */ | ||
930 | |||
931 | /* | ||
932 | * All netids, bind addresses and ports registered for [program, version] | ||
933 | * are removed from the local rpcbind database (if the service is not | ||
934 | * hidden) to make way for a new instance of the service. | ||
935 | * | ||
936 | * The result of unregistration is reported via dprintk for those who want | ||
937 | * verification of the result, but is otherwise not important. | ||
938 | */ | ||
939 | static void svc_unregister(const struct svc_serv *serv) | ||
940 | { | ||
941 | struct svc_program *progp; | ||
942 | unsigned long flags; | ||
943 | unsigned int i; | ||
944 | |||
945 | clear_thread_flag(TIF_SIGPENDING); | ||
946 | |||
947 | for (progp = serv->sv_program; progp; progp = progp->pg_next) { | ||
948 | for (i = 0; i < progp->pg_nvers; i++) { | ||
949 | if (progp->pg_vers[i] == NULL) | ||
950 | continue; | ||
951 | if (progp->pg_vers[i]->vs_hidden) | ||
952 | continue; | ||
953 | |||
954 | __svc_unregister(progp->pg_prog, i, progp->pg_name); | ||
955 | } | ||
767 | } | 956 | } |
768 | 957 | ||
769 | return error; | 958 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
959 | recalc_sigpending(); | ||
960 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
770 | } | 961 | } |
771 | 962 | ||
772 | /* | 963 | /* |