diff options
Diffstat (limited to 'net/sunrpc/svcsock.c')
-rw-r--r-- | net/sunrpc/svcsock.c | 123 |
1 files changed, 71 insertions, 52 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 63ae94771b8e..22f61aee4824 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -82,6 +82,7 @@ static void svc_delete_socket(struct svc_sock *svsk); | |||
82 | static void svc_udp_data_ready(struct sock *, int); | 82 | static void svc_udp_data_ready(struct sock *, int); |
83 | static int svc_udp_recvfrom(struct svc_rqst *); | 83 | static int svc_udp_recvfrom(struct svc_rqst *); |
84 | static int svc_udp_sendto(struct svc_rqst *); | 84 | static int svc_udp_sendto(struct svc_rqst *); |
85 | static void svc_close_socket(struct svc_sock *svsk); | ||
85 | 86 | ||
86 | static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk); | 87 | static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk); |
87 | static int svc_deferred_recv(struct svc_rqst *rqstp); | 88 | static int svc_deferred_recv(struct svc_rqst *rqstp); |
@@ -131,13 +132,13 @@ static char *__svc_print_addr(struct sockaddr *addr, char *buf, size_t len) | |||
131 | NIPQUAD(((struct sockaddr_in *) addr)->sin_addr), | 132 | NIPQUAD(((struct sockaddr_in *) addr)->sin_addr), |
132 | htons(((struct sockaddr_in *) addr)->sin_port)); | 133 | htons(((struct sockaddr_in *) addr)->sin_port)); |
133 | break; | 134 | break; |
134 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 135 | |
135 | case AF_INET6: | 136 | case AF_INET6: |
136 | snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x, port=%u", | 137 | snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x, port=%u", |
137 | NIP6(((struct sockaddr_in6 *) addr)->sin6_addr), | 138 | NIP6(((struct sockaddr_in6 *) addr)->sin6_addr), |
138 | htons(((struct sockaddr_in6 *) addr)->sin6_port)); | 139 | htons(((struct sockaddr_in6 *) addr)->sin6_port)); |
139 | break; | 140 | break; |
140 | #endif | 141 | |
141 | default: | 142 | default: |
142 | snprintf(buf, len, "unknown address type: %d", addr->sa_family); | 143 | snprintf(buf, len, "unknown address type: %d", addr->sa_family); |
143 | break; | 144 | break; |
@@ -449,10 +450,10 @@ svc_wake_up(struct svc_serv *serv) | |||
449 | 450 | ||
450 | union svc_pktinfo_u { | 451 | union svc_pktinfo_u { |
451 | struct in_pktinfo pkti; | 452 | struct in_pktinfo pkti; |
452 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
453 | struct in6_pktinfo pkti6; | 453 | struct in6_pktinfo pkti6; |
454 | #endif | ||
455 | }; | 454 | }; |
455 | #define SVC_PKTINFO_SPACE \ | ||
456 | CMSG_SPACE(sizeof(union svc_pktinfo_u)) | ||
456 | 457 | ||
457 | static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) | 458 | static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) |
458 | { | 459 | { |
@@ -467,7 +468,7 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) | |||
467 | cmh->cmsg_len = CMSG_LEN(sizeof(*pki)); | 468 | cmh->cmsg_len = CMSG_LEN(sizeof(*pki)); |
468 | } | 469 | } |
469 | break; | 470 | break; |
470 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 471 | |
471 | case AF_INET6: { | 472 | case AF_INET6: { |
472 | struct in6_pktinfo *pki = CMSG_DATA(cmh); | 473 | struct in6_pktinfo *pki = CMSG_DATA(cmh); |
473 | 474 | ||
@@ -479,7 +480,6 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) | |||
479 | cmh->cmsg_len = CMSG_LEN(sizeof(*pki)); | 480 | cmh->cmsg_len = CMSG_LEN(sizeof(*pki)); |
480 | } | 481 | } |
481 | break; | 482 | break; |
482 | #endif | ||
483 | } | 483 | } |
484 | return; | 484 | return; |
485 | } | 485 | } |
@@ -493,8 +493,11 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) | |||
493 | struct svc_sock *svsk = rqstp->rq_sock; | 493 | struct svc_sock *svsk = rqstp->rq_sock; |
494 | struct socket *sock = svsk->sk_sock; | 494 | struct socket *sock = svsk->sk_sock; |
495 | int slen; | 495 | int slen; |
496 | char buffer[CMSG_SPACE(sizeof(union svc_pktinfo_u))]; | 496 | union { |
497 | struct cmsghdr *cmh = (struct cmsghdr *)buffer; | 497 | struct cmsghdr hdr; |
498 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; | ||
499 | } buffer; | ||
500 | struct cmsghdr *cmh = &buffer.hdr; | ||
498 | int len = 0; | 501 | int len = 0; |
499 | int result; | 502 | int result; |
500 | int size; | 503 | int size; |
@@ -721,45 +724,21 @@ svc_write_space(struct sock *sk) | |||
721 | } | 724 | } |
722 | } | 725 | } |
723 | 726 | ||
724 | static void svc_udp_get_sender_address(struct svc_rqst *rqstp, | 727 | static inline void svc_udp_get_dest_address(struct svc_rqst *rqstp, |
725 | struct sk_buff *skb) | 728 | struct cmsghdr *cmh) |
726 | { | 729 | { |
727 | switch (rqstp->rq_sock->sk_sk->sk_family) { | 730 | switch (rqstp->rq_sock->sk_sk->sk_family) { |
728 | case AF_INET: { | 731 | case AF_INET: { |
729 | /* this seems to come from net/ipv4/udp.c:udp_recvmsg */ | 732 | struct in_pktinfo *pki = CMSG_DATA(cmh); |
730 | struct sockaddr_in *sin = svc_addr_in(rqstp); | 733 | rqstp->rq_daddr.addr.s_addr = pki->ipi_spec_dst.s_addr; |
731 | |||
732 | sin->sin_family = AF_INET; | ||
733 | sin->sin_port = skb->h.uh->source; | ||
734 | sin->sin_addr.s_addr = skb->nh.iph->saddr; | ||
735 | rqstp->rq_addrlen = sizeof(struct sockaddr_in); | ||
736 | /* Remember which interface received this request */ | ||
737 | rqstp->rq_daddr.addr.s_addr = skb->nh.iph->daddr; | ||
738 | } | ||
739 | break; | 734 | break; |
740 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
741 | case AF_INET6: { | ||
742 | /* this is derived from net/ipv6/udp.c:udpv6_recvmesg */ | ||
743 | struct sockaddr_in6 *sin6 = svc_addr_in6(rqstp); | ||
744 | |||
745 | sin6->sin6_family = AF_INET6; | ||
746 | sin6->sin6_port = skb->h.uh->source; | ||
747 | sin6->sin6_flowinfo = 0; | ||
748 | sin6->sin6_scope_id = 0; | ||
749 | if (ipv6_addr_type(&sin6->sin6_addr) & | ||
750 | IPV6_ADDR_LINKLOCAL) | ||
751 | sin6->sin6_scope_id = IP6CB(skb)->iif; | ||
752 | ipv6_addr_copy(&sin6->sin6_addr, | ||
753 | &skb->nh.ipv6h->saddr); | ||
754 | rqstp->rq_addrlen = sizeof(struct sockaddr_in); | ||
755 | /* Remember which interface received this request */ | ||
756 | ipv6_addr_copy(&rqstp->rq_daddr.addr6, | ||
757 | &skb->nh.ipv6h->saddr); | ||
758 | } | 735 | } |
736 | case AF_INET6: { | ||
737 | struct in6_pktinfo *pki = CMSG_DATA(cmh); | ||
738 | ipv6_addr_copy(&rqstp->rq_daddr.addr6, &pki->ipi6_addr); | ||
759 | break; | 739 | break; |
760 | #endif | 740 | } |
761 | } | 741 | } |
762 | return; | ||
763 | } | 742 | } |
764 | 743 | ||
765 | /* | 744 | /* |
@@ -771,7 +750,18 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
771 | struct svc_sock *svsk = rqstp->rq_sock; | 750 | struct svc_sock *svsk = rqstp->rq_sock; |
772 | struct svc_serv *serv = svsk->sk_server; | 751 | struct svc_serv *serv = svsk->sk_server; |
773 | struct sk_buff *skb; | 752 | struct sk_buff *skb; |
753 | union { | ||
754 | struct cmsghdr hdr; | ||
755 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; | ||
756 | } buffer; | ||
757 | struct cmsghdr *cmh = &buffer.hdr; | ||
774 | int err, len; | 758 | int err, len; |
759 | struct msghdr msg = { | ||
760 | .msg_name = svc_addr(rqstp), | ||
761 | .msg_control = cmh, | ||
762 | .msg_controllen = sizeof(buffer), | ||
763 | .msg_flags = MSG_DONTWAIT, | ||
764 | }; | ||
775 | 765 | ||
776 | if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags)) | 766 | if (test_and_clear_bit(SK_CHNGBUF, &svsk->sk_flags)) |
777 | /* udp sockets need large rcvbuf as all pending | 767 | /* udp sockets need large rcvbuf as all pending |
@@ -797,7 +787,9 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
797 | } | 787 | } |
798 | 788 | ||
799 | clear_bit(SK_DATA, &svsk->sk_flags); | 789 | clear_bit(SK_DATA, &svsk->sk_flags); |
800 | while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) { | 790 | while ((err = kernel_recvmsg(svsk->sk_sock, &msg, NULL, |
791 | 0, 0, MSG_PEEK | MSG_DONTWAIT)) < 0 || | ||
792 | (skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) { | ||
801 | if (err == -EAGAIN) { | 793 | if (err == -EAGAIN) { |
802 | svc_sock_received(svsk); | 794 | svc_sock_received(svsk); |
803 | return err; | 795 | return err; |
@@ -805,16 +797,13 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
805 | /* possibly an icmp error */ | 797 | /* possibly an icmp error */ |
806 | dprintk("svc: recvfrom returned error %d\n", -err); | 798 | dprintk("svc: recvfrom returned error %d\n", -err); |
807 | } | 799 | } |
808 | if (skb->tstamp.off_sec == 0) { | 800 | rqstp->rq_addrlen = sizeof(rqstp->rq_addr); |
809 | struct timeval tv; | 801 | if (skb->tstamp.tv64 == 0) { |
810 | 802 | skb->tstamp = ktime_get_real(); | |
811 | tv.tv_sec = xtime.tv_sec; | ||
812 | tv.tv_usec = xtime.tv_nsec / NSEC_PER_USEC; | ||
813 | skb_set_timestamp(skb, &tv); | ||
814 | /* Don't enable netstamp, sunrpc doesn't | 803 | /* Don't enable netstamp, sunrpc doesn't |
815 | need that much accuracy */ | 804 | need that much accuracy */ |
816 | } | 805 | } |
817 | skb_get_timestamp(skb, &svsk->sk_sk->sk_stamp); | 806 | svsk->sk_sk->sk_stamp = skb->tstamp; |
818 | set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */ | 807 | set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */ |
819 | 808 | ||
820 | /* | 809 | /* |
@@ -827,7 +816,16 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
827 | 816 | ||
828 | rqstp->rq_prot = IPPROTO_UDP; | 817 | rqstp->rq_prot = IPPROTO_UDP; |
829 | 818 | ||
830 | svc_udp_get_sender_address(rqstp, skb); | 819 | if (cmh->cmsg_level != IPPROTO_IP || |
820 | cmh->cmsg_type != IP_PKTINFO) { | ||
821 | if (net_ratelimit()) | ||
822 | printk("rpcsvc: received unknown control message:" | ||
823 | "%d/%d\n", | ||
824 | cmh->cmsg_level, cmh->cmsg_type); | ||
825 | skb_free_datagram(svsk->sk_sk, skb); | ||
826 | return 0; | ||
827 | } | ||
828 | svc_udp_get_dest_address(rqstp, cmh); | ||
831 | 829 | ||
832 | if (skb_is_nonlinear(skb)) { | 830 | if (skb_is_nonlinear(skb)) { |
833 | /* we have to copy */ | 831 | /* we have to copy */ |
@@ -884,6 +882,9 @@ svc_udp_sendto(struct svc_rqst *rqstp) | |||
884 | static void | 882 | static void |
885 | svc_udp_init(struct svc_sock *svsk) | 883 | svc_udp_init(struct svc_sock *svsk) |
886 | { | 884 | { |
885 | int one = 1; | ||
886 | mm_segment_t oldfs; | ||
887 | |||
887 | svsk->sk_sk->sk_data_ready = svc_udp_data_ready; | 888 | svsk->sk_sk->sk_data_ready = svc_udp_data_ready; |
888 | svsk->sk_sk->sk_write_space = svc_write_space; | 889 | svsk->sk_sk->sk_write_space = svc_write_space; |
889 | svsk->sk_recvfrom = svc_udp_recvfrom; | 890 | svsk->sk_recvfrom = svc_udp_recvfrom; |
@@ -899,6 +900,13 @@ svc_udp_init(struct svc_sock *svsk) | |||
899 | 900 | ||
900 | set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */ | 901 | set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */ |
901 | set_bit(SK_CHNGBUF, &svsk->sk_flags); | 902 | set_bit(SK_CHNGBUF, &svsk->sk_flags); |
903 | |||
904 | oldfs = get_fs(); | ||
905 | set_fs(KERNEL_DS); | ||
906 | /* make sure we get destination address info */ | ||
907 | svsk->sk_sock->ops->setsockopt(svsk->sk_sock, IPPROTO_IP, IP_PKTINFO, | ||
908 | (char __user *)&one, sizeof(one)); | ||
909 | set_fs(oldfs); | ||
902 | } | 910 | } |
903 | 911 | ||
904 | /* | 912 | /* |
@@ -977,11 +985,9 @@ static inline int svc_port_is_privileged(struct sockaddr *sin) | |||
977 | case AF_INET: | 985 | case AF_INET: |
978 | return ntohs(((struct sockaddr_in *)sin)->sin_port) | 986 | return ntohs(((struct sockaddr_in *)sin)->sin_port) |
979 | < PROT_SOCK; | 987 | < PROT_SOCK; |
980 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
981 | case AF_INET6: | 988 | case AF_INET6: |
982 | return ntohs(((struct sockaddr_in6 *)sin)->sin6_port) | 989 | return ntohs(((struct sockaddr_in6 *)sin)->sin6_port) |
983 | < PROT_SOCK; | 990 | < PROT_SOCK; |
984 | #endif | ||
985 | default: | 991 | default: |
986 | return 0; | 992 | return 0; |
987 | } | 993 | } |
@@ -1786,7 +1792,7 @@ svc_delete_socket(struct svc_sock *svsk) | |||
1786 | spin_unlock_bh(&serv->sv_lock); | 1792 | spin_unlock_bh(&serv->sv_lock); |
1787 | } | 1793 | } |
1788 | 1794 | ||
1789 | void svc_close_socket(struct svc_sock *svsk) | 1795 | static void svc_close_socket(struct svc_sock *svsk) |
1790 | { | 1796 | { |
1791 | set_bit(SK_CLOSE, &svsk->sk_flags); | 1797 | set_bit(SK_CLOSE, &svsk->sk_flags); |
1792 | if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) | 1798 | if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) |
@@ -1799,6 +1805,19 @@ void svc_close_socket(struct svc_sock *svsk) | |||
1799 | svc_sock_put(svsk); | 1805 | svc_sock_put(svsk); |
1800 | } | 1806 | } |
1801 | 1807 | ||
1808 | void svc_force_close_socket(struct svc_sock *svsk) | ||
1809 | { | ||
1810 | set_bit(SK_CLOSE, &svsk->sk_flags); | ||
1811 | if (test_bit(SK_BUSY, &svsk->sk_flags)) { | ||
1812 | /* Waiting to be processed, but no threads left, | ||
1813 | * So just remove it from the waiting list | ||
1814 | */ | ||
1815 | list_del_init(&svsk->sk_ready); | ||
1816 | clear_bit(SK_BUSY, &svsk->sk_flags); | ||
1817 | } | ||
1818 | svc_close_socket(svsk); | ||
1819 | } | ||
1820 | |||
1802 | /** | 1821 | /** |
1803 | * svc_makesock - Make a socket for nfsd and lockd | 1822 | * svc_makesock - Make a socket for nfsd and lockd |
1804 | * @serv: RPC server structure | 1823 | * @serv: RPC server structure |