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 |
