diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/ieee802154/af_ieee802154.c | 12 | ||||
| -rw-r--r-- | net/ipv4/route.c | 14 | ||||
| -rw-r--r-- | net/iucv/af_iucv.c | 297 | ||||
| -rw-r--r-- | net/rfkill/core.c | 56 | ||||
| -rw-r--r-- | net/sunrpc/Makefile | 1 | ||||
| -rw-r--r-- | net/sunrpc/backchannel_rqst.c | 281 | ||||
| -rw-r--r-- | net/sunrpc/bc_svc.c | 81 | ||||
| -rw-r--r-- | net/sunrpc/cache.c | 2 | ||||
| -rw-r--r-- | net/sunrpc/clnt.c | 143 | ||||
| -rw-r--r-- | net/sunrpc/sched.c | 2 | ||||
| -rw-r--r-- | net/sunrpc/stats.c | 8 | ||||
| -rw-r--r-- | net/sunrpc/sunrpc.h | 37 | ||||
| -rw-r--r-- | net/sunrpc/svc.c | 134 | ||||
| -rw-r--r-- | net/sunrpc/svc_xprt.c | 57 | ||||
| -rw-r--r-- | net/sunrpc/svcsock.c | 161 | ||||
| -rw-r--r-- | net/sunrpc/xprt.c | 60 | ||||
| -rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 8 | ||||
| -rw-r--r-- | net/sunrpc/xprtsock.c | 217 | ||||
| -rw-r--r-- | net/wireless/nl80211.c | 95 |
19 files changed, 1369 insertions, 297 deletions
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index 882a927cefae..3bb6bdb1dac1 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c | |||
| @@ -39,14 +39,6 @@ | |||
| 39 | 39 | ||
| 40 | #include "af802154.h" | 40 | #include "af802154.h" |
| 41 | 41 | ||
| 42 | #define DBG_DUMP(data, len) { \ | ||
| 43 | int i; \ | ||
| 44 | pr_debug("function: %s: data: len %d:\n", __func__, len); \ | ||
| 45 | for (i = 0; i < len; i++) {\ | ||
| 46 | pr_debug("%02x: %02x\n", i, (data)[i]); \ | ||
| 47 | } \ | ||
| 48 | } | ||
| 49 | |||
| 50 | /* | 42 | /* |
| 51 | * Utility function for families | 43 | * Utility function for families |
| 52 | */ | 44 | */ |
| @@ -302,10 +294,12 @@ static struct net_proto_family ieee802154_family_ops = { | |||
| 302 | static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev, | 294 | static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev, |
| 303 | struct packet_type *pt, struct net_device *orig_dev) | 295 | struct packet_type *pt, struct net_device *orig_dev) |
| 304 | { | 296 | { |
| 305 | DBG_DUMP(skb->data, skb->len); | ||
| 306 | if (!netif_running(dev)) | 297 | if (!netif_running(dev)) |
| 307 | return -ENODEV; | 298 | return -ENODEV; |
| 308 | pr_debug("got frame, type %d, dev %p\n", dev->type, dev); | 299 | pr_debug("got frame, type %d, dev %p\n", dev->type, dev); |
| 300 | #ifdef DEBUG | ||
| 301 | print_hex_dump_bytes("ieee802154_rcv ", DUMP_PREFIX_NONE, skb->data, skb->len); | ||
| 302 | #endif | ||
| 309 | 303 | ||
| 310 | if (!net_eq(dev_net(dev), &init_net)) | 304 | if (!net_eq(dev_net(dev), &init_net)) |
| 311 | goto drop; | 305 | goto drop; |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index cd76b3cb7092..65b3a8b11a6c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -1085,8 +1085,16 @@ restart: | |||
| 1085 | now = jiffies; | 1085 | now = jiffies; |
| 1086 | 1086 | ||
| 1087 | if (!rt_caching(dev_net(rt->u.dst.dev))) { | 1087 | if (!rt_caching(dev_net(rt->u.dst.dev))) { |
| 1088 | rt_drop(rt); | 1088 | /* |
| 1089 | return 0; | 1089 | * If we're not caching, just tell the caller we |
| 1090 | * were successful and don't touch the route. The | ||
| 1091 | * caller hold the sole reference to the cache entry, and | ||
| 1092 | * it will be released when the caller is done with it. | ||
| 1093 | * If we drop it here, the callers have no way to resolve routes | ||
| 1094 | * when we're not caching. Instead, just point *rp at rt, so | ||
| 1095 | * the caller gets a single use out of the route | ||
| 1096 | */ | ||
| 1097 | goto report_and_exit; | ||
| 1090 | } | 1098 | } |
| 1091 | 1099 | ||
| 1092 | rthp = &rt_hash_table[hash].chain; | 1100 | rthp = &rt_hash_table[hash].chain; |
| @@ -1217,6 +1225,8 @@ restart: | |||
| 1217 | rcu_assign_pointer(rt_hash_table[hash].chain, rt); | 1225 | rcu_assign_pointer(rt_hash_table[hash].chain, rt); |
| 1218 | 1226 | ||
| 1219 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1227 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
| 1228 | |||
| 1229 | report_and_exit: | ||
| 1220 | if (rp) | 1230 | if (rp) |
| 1221 | *rp = rt; | 1231 | *rp = rt; |
| 1222 | else | 1232 | else |
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 656cbd195825..6be5f92d1094 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c | |||
| @@ -54,6 +54,38 @@ static const u8 iprm_shutdown[8] = | |||
| 54 | #define CB_TRGCLS(skb) ((skb)->cb + CB_TAG_LEN) /* iucv msg target class */ | 54 | #define CB_TRGCLS(skb) ((skb)->cb + CB_TAG_LEN) /* iucv msg target class */ |
| 55 | #define CB_TRGCLS_LEN (TRGCLS_SIZE) | 55 | #define CB_TRGCLS_LEN (TRGCLS_SIZE) |
| 56 | 56 | ||
| 57 | #define __iucv_sock_wait(sk, condition, timeo, ret) \ | ||
| 58 | do { \ | ||
| 59 | DEFINE_WAIT(__wait); \ | ||
| 60 | long __timeo = timeo; \ | ||
| 61 | ret = 0; \ | ||
| 62 | while (!(condition)) { \ | ||
| 63 | prepare_to_wait(sk->sk_sleep, &__wait, TASK_INTERRUPTIBLE); \ | ||
| 64 | if (!__timeo) { \ | ||
| 65 | ret = -EAGAIN; \ | ||
| 66 | break; \ | ||
| 67 | } \ | ||
| 68 | if (signal_pending(current)) { \ | ||
| 69 | ret = sock_intr_errno(__timeo); \ | ||
| 70 | break; \ | ||
| 71 | } \ | ||
| 72 | release_sock(sk); \ | ||
| 73 | __timeo = schedule_timeout(__timeo); \ | ||
| 74 | lock_sock(sk); \ | ||
| 75 | ret = sock_error(sk); \ | ||
| 76 | if (ret) \ | ||
| 77 | break; \ | ||
| 78 | } \ | ||
| 79 | finish_wait(sk->sk_sleep, &__wait); \ | ||
| 80 | } while (0) | ||
| 81 | |||
| 82 | #define iucv_sock_wait(sk, condition, timeo) \ | ||
| 83 | ({ \ | ||
| 84 | int __ret = 0; \ | ||
| 85 | if (!(condition)) \ | ||
| 86 | __iucv_sock_wait(sk, condition, timeo, __ret); \ | ||
| 87 | __ret; \ | ||
| 88 | }) | ||
| 57 | 89 | ||
| 58 | static void iucv_sock_kill(struct sock *sk); | 90 | static void iucv_sock_kill(struct sock *sk); |
| 59 | static void iucv_sock_close(struct sock *sk); | 91 | static void iucv_sock_close(struct sock *sk); |
| @@ -238,6 +270,48 @@ static inline size_t iucv_msg_length(struct iucv_message *msg) | |||
| 238 | return msg->length; | 270 | return msg->length; |
| 239 | } | 271 | } |
| 240 | 272 | ||
| 273 | /** | ||
| 274 | * iucv_sock_in_state() - check for specific states | ||
| 275 | * @sk: sock structure | ||
| 276 | * @state: first iucv sk state | ||
| 277 | * @state: second iucv sk state | ||
| 278 | * | ||
| 279 | * Returns true if the socket in either in the first or second state. | ||
| 280 | */ | ||
| 281 | static int iucv_sock_in_state(struct sock *sk, int state, int state2) | ||
| 282 | { | ||
| 283 | return (sk->sk_state == state || sk->sk_state == state2); | ||
| 284 | } | ||
| 285 | |||
| 286 | /** | ||
| 287 | * iucv_below_msglim() - function to check if messages can be sent | ||
| 288 | * @sk: sock structure | ||
| 289 | * | ||
| 290 | * Returns true if the send queue length is lower than the message limit. | ||
| 291 | * Always returns true if the socket is not connected (no iucv path for | ||
| 292 | * checking the message limit). | ||
| 293 | */ | ||
| 294 | static inline int iucv_below_msglim(struct sock *sk) | ||
| 295 | { | ||
| 296 | struct iucv_sock *iucv = iucv_sk(sk); | ||
| 297 | |||
| 298 | if (sk->sk_state != IUCV_CONNECTED) | ||
| 299 | return 1; | ||
| 300 | return (skb_queue_len(&iucv->send_skb_q) < iucv->path->msglim); | ||
| 301 | } | ||
| 302 | |||
| 303 | /** | ||
| 304 | * iucv_sock_wake_msglim() - Wake up thread waiting on msg limit | ||
| 305 | */ | ||
| 306 | static void iucv_sock_wake_msglim(struct sock *sk) | ||
| 307 | { | ||
| 308 | read_lock(&sk->sk_callback_lock); | ||
| 309 | if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) | ||
| 310 | wake_up_interruptible_all(sk->sk_sleep); | ||
| 311 | sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); | ||
| 312 | read_unlock(&sk->sk_callback_lock); | ||
| 313 | } | ||
| 314 | |||
| 241 | /* Timers */ | 315 | /* Timers */ |
| 242 | static void iucv_sock_timeout(unsigned long arg) | 316 | static void iucv_sock_timeout(unsigned long arg) |
| 243 | { | 317 | { |
| @@ -329,7 +403,9 @@ static void iucv_sock_close(struct sock *sk) | |||
| 329 | timeo = sk->sk_lingertime; | 403 | timeo = sk->sk_lingertime; |
| 330 | else | 404 | else |
| 331 | timeo = IUCV_DISCONN_TIMEOUT; | 405 | timeo = IUCV_DISCONN_TIMEOUT; |
| 332 | err = iucv_sock_wait_state(sk, IUCV_CLOSED, 0, timeo); | 406 | err = iucv_sock_wait(sk, |
| 407 | iucv_sock_in_state(sk, IUCV_CLOSED, 0), | ||
| 408 | timeo); | ||
| 333 | } | 409 | } |
| 334 | 410 | ||
| 335 | case IUCV_CLOSING: /* fall through */ | 411 | case IUCV_CLOSING: /* fall through */ |
| @@ -510,39 +586,6 @@ struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock) | |||
| 510 | return NULL; | 586 | return NULL; |
| 511 | } | 587 | } |
| 512 | 588 | ||
| 513 | int iucv_sock_wait_state(struct sock *sk, int state, int state2, | ||
| 514 | unsigned long timeo) | ||
| 515 | { | ||
| 516 | DECLARE_WAITQUEUE(wait, current); | ||
| 517 | int err = 0; | ||
| 518 | |||
| 519 | add_wait_queue(sk->sk_sleep, &wait); | ||
| 520 | while (sk->sk_state != state && sk->sk_state != state2) { | ||
| 521 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 522 | |||
| 523 | if (!timeo) { | ||
| 524 | err = -EAGAIN; | ||
| 525 | break; | ||
| 526 | } | ||
| 527 | |||
| 528 | if (signal_pending(current)) { | ||
| 529 | err = sock_intr_errno(timeo); | ||
| 530 | break; | ||
| 531 | } | ||
| 532 | |||
| 533 | release_sock(sk); | ||
| 534 | timeo = schedule_timeout(timeo); | ||
| 535 | lock_sock(sk); | ||
| 536 | |||
| 537 | err = sock_error(sk); | ||
| 538 | if (err) | ||
| 539 | break; | ||
| 540 | } | ||
| 541 | set_current_state(TASK_RUNNING); | ||
| 542 | remove_wait_queue(sk->sk_sleep, &wait); | ||
| 543 | return err; | ||
| 544 | } | ||
| 545 | |||
| 546 | /* Bind an unbound socket */ | 589 | /* Bind an unbound socket */ |
| 547 | static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, | 590 | static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, |
| 548 | int addr_len) | 591 | int addr_len) |
| @@ -687,8 +730,9 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, | |||
| 687 | } | 730 | } |
| 688 | 731 | ||
| 689 | if (sk->sk_state != IUCV_CONNECTED) { | 732 | if (sk->sk_state != IUCV_CONNECTED) { |
| 690 | err = iucv_sock_wait_state(sk, IUCV_CONNECTED, IUCV_DISCONN, | 733 | err = iucv_sock_wait(sk, iucv_sock_in_state(sk, IUCV_CONNECTED, |
| 691 | sock_sndtimeo(sk, flags & O_NONBLOCK)); | 734 | IUCV_DISCONN), |
| 735 | sock_sndtimeo(sk, flags & O_NONBLOCK)); | ||
| 692 | } | 736 | } |
| 693 | 737 | ||
| 694 | if (sk->sk_state == IUCV_DISCONN) { | 738 | if (sk->sk_state == IUCV_DISCONN) { |
| @@ -842,9 +886,11 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 842 | struct iucv_message txmsg; | 886 | struct iucv_message txmsg; |
| 843 | struct cmsghdr *cmsg; | 887 | struct cmsghdr *cmsg; |
| 844 | int cmsg_done; | 888 | int cmsg_done; |
| 889 | long timeo; | ||
| 845 | char user_id[9]; | 890 | char user_id[9]; |
| 846 | char appl_id[9]; | 891 | char appl_id[9]; |
| 847 | int err; | 892 | int err; |
| 893 | int noblock = msg->msg_flags & MSG_DONTWAIT; | ||
| 848 | 894 | ||
| 849 | err = sock_error(sk); | 895 | err = sock_error(sk); |
| 850 | if (err) | 896 | if (err) |
| @@ -864,108 +910,119 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 864 | goto out; | 910 | goto out; |
| 865 | } | 911 | } |
| 866 | 912 | ||
| 867 | if (sk->sk_state == IUCV_CONNECTED) { | 913 | /* Return if the socket is not in connected state */ |
| 868 | /* initialize defaults */ | 914 | if (sk->sk_state != IUCV_CONNECTED) { |
| 869 | cmsg_done = 0; /* check for duplicate headers */ | 915 | err = -ENOTCONN; |
| 870 | txmsg.class = 0; | 916 | goto out; |
| 917 | } | ||
| 871 | 918 | ||
| 872 | /* iterate over control messages */ | 919 | /* initialize defaults */ |
| 873 | for (cmsg = CMSG_FIRSTHDR(msg); cmsg; | 920 | cmsg_done = 0; /* check for duplicate headers */ |
| 874 | cmsg = CMSG_NXTHDR(msg, cmsg)) { | 921 | txmsg.class = 0; |
| 875 | 922 | ||
| 876 | if (!CMSG_OK(msg, cmsg)) { | 923 | /* iterate over control messages */ |
| 877 | err = -EINVAL; | 924 | for (cmsg = CMSG_FIRSTHDR(msg); cmsg; |
| 878 | goto out; | 925 | cmsg = CMSG_NXTHDR(msg, cmsg)) { |
| 879 | } | 926 | |
| 927 | if (!CMSG_OK(msg, cmsg)) { | ||
| 928 | err = -EINVAL; | ||
| 929 | goto out; | ||
| 930 | } | ||
| 931 | |||
| 932 | if (cmsg->cmsg_level != SOL_IUCV) | ||
| 933 | continue; | ||
| 880 | 934 | ||
| 881 | if (cmsg->cmsg_level != SOL_IUCV) | 935 | if (cmsg->cmsg_type & cmsg_done) { |
| 882 | continue; | 936 | err = -EINVAL; |
| 937 | goto out; | ||
| 938 | } | ||
| 939 | cmsg_done |= cmsg->cmsg_type; | ||
| 883 | 940 | ||
| 884 | if (cmsg->cmsg_type & cmsg_done) { | 941 | switch (cmsg->cmsg_type) { |
| 942 | case SCM_IUCV_TRGCLS: | ||
| 943 | if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) { | ||
| 885 | err = -EINVAL; | 944 | err = -EINVAL; |
| 886 | goto out; | 945 | goto out; |
| 887 | } | 946 | } |
| 888 | cmsg_done |= cmsg->cmsg_type; | ||
| 889 | |||
| 890 | switch (cmsg->cmsg_type) { | ||
| 891 | case SCM_IUCV_TRGCLS: | ||
| 892 | if (cmsg->cmsg_len != CMSG_LEN(TRGCLS_SIZE)) { | ||
| 893 | err = -EINVAL; | ||
| 894 | goto out; | ||
| 895 | } | ||
| 896 | 947 | ||
| 897 | /* set iucv message target class */ | 948 | /* set iucv message target class */ |
| 898 | memcpy(&txmsg.class, | 949 | memcpy(&txmsg.class, |
| 899 | (void *) CMSG_DATA(cmsg), TRGCLS_SIZE); | 950 | (void *) CMSG_DATA(cmsg), TRGCLS_SIZE); |
| 900 | 951 | ||
| 901 | break; | 952 | break; |
| 902 | 953 | ||
| 903 | default: | 954 | default: |
| 904 | err = -EINVAL; | 955 | err = -EINVAL; |
| 905 | goto out; | 956 | goto out; |
| 906 | break; | 957 | break; |
| 907 | } | ||
| 908 | } | 958 | } |
| 959 | } | ||
| 909 | 960 | ||
| 910 | /* allocate one skb for each iucv message: | 961 | /* allocate one skb for each iucv message: |
| 911 | * this is fine for SOCK_SEQPACKET (unless we want to support | 962 | * this is fine for SOCK_SEQPACKET (unless we want to support |
| 912 | * segmented records using the MSG_EOR flag), but | 963 | * segmented records using the MSG_EOR flag), but |
| 913 | * for SOCK_STREAM we might want to improve it in future */ | 964 | * for SOCK_STREAM we might want to improve it in future */ |
| 914 | if (!(skb = sock_alloc_send_skb(sk, len, | 965 | skb = sock_alloc_send_skb(sk, len, noblock, &err); |
| 915 | msg->msg_flags & MSG_DONTWAIT, | 966 | if (!skb) |
| 916 | &err))) | 967 | goto out; |
| 917 | goto out; | 968 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { |
| 969 | err = -EFAULT; | ||
| 970 | goto fail; | ||
| 971 | } | ||
| 918 | 972 | ||
| 919 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | 973 | /* wait if outstanding messages for iucv path has reached */ |
| 920 | err = -EFAULT; | 974 | timeo = sock_sndtimeo(sk, noblock); |
| 921 | goto fail; | 975 | err = iucv_sock_wait(sk, iucv_below_msglim(sk), timeo); |
| 922 | } | 976 | if (err) |
| 977 | goto fail; | ||
| 923 | 978 | ||
| 924 | /* increment and save iucv message tag for msg_completion cbk */ | 979 | /* return -ECONNRESET if the socket is no longer connected */ |
| 925 | txmsg.tag = iucv->send_tag++; | 980 | if (sk->sk_state != IUCV_CONNECTED) { |
| 926 | memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN); | 981 | err = -ECONNRESET; |
| 927 | skb_queue_tail(&iucv->send_skb_q, skb); | 982 | goto fail; |
| 983 | } | ||
| 928 | 984 | ||
| 929 | if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags) | 985 | /* increment and save iucv message tag for msg_completion cbk */ |
| 930 | && skb->len <= 7) { | 986 | txmsg.tag = iucv->send_tag++; |
| 931 | err = iucv_send_iprm(iucv->path, &txmsg, skb); | 987 | memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN); |
| 988 | skb_queue_tail(&iucv->send_skb_q, skb); | ||
| 932 | 989 | ||
| 933 | /* on success: there is no message_complete callback | 990 | if (((iucv->path->flags & IUCV_IPRMDATA) & iucv->flags) |
| 934 | * for an IPRMDATA msg; remove skb from send queue */ | 991 | && skb->len <= 7) { |
| 935 | if (err == 0) { | 992 | err = iucv_send_iprm(iucv->path, &txmsg, skb); |
| 936 | skb_unlink(skb, &iucv->send_skb_q); | ||
| 937 | kfree_skb(skb); | ||
| 938 | } | ||
| 939 | 993 | ||
| 940 | /* this error should never happen since the | 994 | /* on success: there is no message_complete callback |
| 941 | * IUCV_IPRMDATA path flag is set... sever path */ | 995 | * for an IPRMDATA msg; remove skb from send queue */ |
| 942 | if (err == 0x15) { | 996 | if (err == 0) { |
| 943 | iucv_path_sever(iucv->path, NULL); | 997 | skb_unlink(skb, &iucv->send_skb_q); |
| 944 | skb_unlink(skb, &iucv->send_skb_q); | 998 | kfree_skb(skb); |
| 945 | err = -EPIPE; | 999 | } |
| 946 | goto fail; | 1000 | |
| 947 | } | 1001 | /* this error should never happen since the |
| 948 | } else | 1002 | * IUCV_IPRMDATA path flag is set... sever path */ |
| 949 | err = iucv_message_send(iucv->path, &txmsg, 0, 0, | 1003 | if (err == 0x15) { |
| 950 | (void *) skb->data, skb->len); | 1004 | iucv_path_sever(iucv->path, NULL); |
| 951 | if (err) { | ||
| 952 | if (err == 3) { | ||
| 953 | user_id[8] = 0; | ||
| 954 | memcpy(user_id, iucv->dst_user_id, 8); | ||
| 955 | appl_id[8] = 0; | ||
| 956 | memcpy(appl_id, iucv->dst_name, 8); | ||
| 957 | pr_err("Application %s on z/VM guest %s" | ||
| 958 | " exceeds message limit\n", | ||
| 959 | user_id, appl_id); | ||
| 960 | } | ||
| 961 | skb_unlink(skb, &iucv->send_skb_q); | 1005 | skb_unlink(skb, &iucv->send_skb_q); |
| 962 | err = -EPIPE; | 1006 | err = -EPIPE; |
| 963 | goto fail; | 1007 | goto fail; |
| 964 | } | 1008 | } |
| 965 | 1009 | } else | |
| 966 | } else { | 1010 | err = iucv_message_send(iucv->path, &txmsg, 0, 0, |
| 967 | err = -ENOTCONN; | 1011 | (void *) skb->data, skb->len); |
| 968 | goto out; | 1012 | if (err) { |
| 1013 | if (err == 3) { | ||
| 1014 | user_id[8] = 0; | ||
| 1015 | memcpy(user_id, iucv->dst_user_id, 8); | ||
| 1016 | appl_id[8] = 0; | ||
| 1017 | memcpy(appl_id, iucv->dst_name, 8); | ||
| 1018 | pr_err("Application %s on z/VM guest %s" | ||
| 1019 | " exceeds message limit\n", | ||
| 1020 | appl_id, user_id); | ||
| 1021 | err = -EAGAIN; | ||
| 1022 | } else | ||
| 1023 | err = -EPIPE; | ||
| 1024 | skb_unlink(skb, &iucv->send_skb_q); | ||
| 1025 | goto fail; | ||
| 969 | } | 1026 | } |
| 970 | 1027 | ||
| 971 | release_sock(sk); | 1028 | release_sock(sk); |
| @@ -1581,7 +1638,11 @@ static void iucv_callback_txdone(struct iucv_path *path, | |||
| 1581 | 1638 | ||
| 1582 | spin_unlock_irqrestore(&list->lock, flags); | 1639 | spin_unlock_irqrestore(&list->lock, flags); |
| 1583 | 1640 | ||
| 1584 | kfree_skb(this); | 1641 | if (this) { |
| 1642 | kfree_skb(this); | ||
| 1643 | /* wake up any process waiting for sending */ | ||
| 1644 | iucv_sock_wake_msglim(sk); | ||
| 1645 | } | ||
| 1585 | } | 1646 | } |
| 1586 | BUG_ON(!this); | 1647 | BUG_ON(!this); |
| 1587 | 1648 | ||
diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 4e68ab439d5d..79693fe2001e 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c | |||
| @@ -56,7 +56,6 @@ struct rfkill { | |||
| 56 | u32 idx; | 56 | u32 idx; |
| 57 | 57 | ||
| 58 | bool registered; | 58 | bool registered; |
| 59 | bool suspended; | ||
| 60 | bool persistent; | 59 | bool persistent; |
| 61 | 60 | ||
| 62 | const struct rfkill_ops *ops; | 61 | const struct rfkill_ops *ops; |
| @@ -224,7 +223,7 @@ static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op) | |||
| 224 | 223 | ||
| 225 | static void rfkill_event(struct rfkill *rfkill) | 224 | static void rfkill_event(struct rfkill *rfkill) |
| 226 | { | 225 | { |
| 227 | if (!rfkill->registered || rfkill->suspended) | 226 | if (!rfkill->registered) |
| 228 | return; | 227 | return; |
| 229 | 228 | ||
| 230 | kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); | 229 | kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); |
| @@ -270,6 +269,9 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | |||
| 270 | unsigned long flags; | 269 | unsigned long flags; |
| 271 | int err; | 270 | int err; |
| 272 | 271 | ||
| 272 | if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) | ||
| 273 | return; | ||
| 274 | |||
| 273 | /* | 275 | /* |
| 274 | * Some platforms (...!) generate input events which affect the | 276 | * Some platforms (...!) generate input events which affect the |
| 275 | * _hard_ kill state -- whenever something tries to change the | 277 | * _hard_ kill state -- whenever something tries to change the |
| @@ -292,9 +294,6 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) | |||
| 292 | rfkill->state |= RFKILL_BLOCK_SW_SETCALL; | 294 | rfkill->state |= RFKILL_BLOCK_SW_SETCALL; |
| 293 | spin_unlock_irqrestore(&rfkill->lock, flags); | 295 | spin_unlock_irqrestore(&rfkill->lock, flags); |
| 294 | 296 | ||
| 295 | if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) | ||
| 296 | return; | ||
| 297 | |||
| 298 | err = rfkill->ops->set_block(rfkill->data, blocked); | 297 | err = rfkill->ops->set_block(rfkill->data, blocked); |
| 299 | 298 | ||
| 300 | spin_lock_irqsave(&rfkill->lock, flags); | 299 | spin_lock_irqsave(&rfkill->lock, flags); |
| @@ -508,19 +507,32 @@ bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) | |||
| 508 | blocked = blocked || hwblock; | 507 | blocked = blocked || hwblock; |
| 509 | spin_unlock_irqrestore(&rfkill->lock, flags); | 508 | spin_unlock_irqrestore(&rfkill->lock, flags); |
| 510 | 509 | ||
| 511 | if (!rfkill->registered) { | 510 | if (!rfkill->registered) |
| 512 | rfkill->persistent = true; | 511 | return blocked; |
| 513 | } else { | ||
| 514 | if (prev != blocked && !hwblock) | ||
| 515 | schedule_work(&rfkill->uevent_work); | ||
| 516 | 512 | ||
| 517 | rfkill_led_trigger_event(rfkill); | 513 | if (prev != blocked && !hwblock) |
| 518 | } | 514 | schedule_work(&rfkill->uevent_work); |
| 515 | |||
| 516 | rfkill_led_trigger_event(rfkill); | ||
| 519 | 517 | ||
| 520 | return blocked; | 518 | return blocked; |
| 521 | } | 519 | } |
| 522 | EXPORT_SYMBOL(rfkill_set_sw_state); | 520 | EXPORT_SYMBOL(rfkill_set_sw_state); |
| 523 | 521 | ||
| 522 | void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked) | ||
| 523 | { | ||
| 524 | unsigned long flags; | ||
| 525 | |||
| 526 | BUG_ON(!rfkill); | ||
| 527 | BUG_ON(rfkill->registered); | ||
| 528 | |||
| 529 | spin_lock_irqsave(&rfkill->lock, flags); | ||
| 530 | __rfkill_set_sw_state(rfkill, blocked); | ||
| 531 | rfkill->persistent = true; | ||
| 532 | spin_unlock_irqrestore(&rfkill->lock, flags); | ||
| 533 | } | ||
| 534 | EXPORT_SYMBOL(rfkill_init_sw_state); | ||
| 535 | |||
| 524 | void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) | 536 | void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) |
| 525 | { | 537 | { |
| 526 | unsigned long flags; | 538 | unsigned long flags; |
| @@ -598,6 +610,15 @@ static ssize_t rfkill_idx_show(struct device *dev, | |||
| 598 | return sprintf(buf, "%d\n", rfkill->idx); | 610 | return sprintf(buf, "%d\n", rfkill->idx); |
| 599 | } | 611 | } |
| 600 | 612 | ||
| 613 | static ssize_t rfkill_persistent_show(struct device *dev, | ||
| 614 | struct device_attribute *attr, | ||
| 615 | char *buf) | ||
| 616 | { | ||
| 617 | struct rfkill *rfkill = to_rfkill(dev); | ||
| 618 | |||
| 619 | return sprintf(buf, "%d\n", rfkill->persistent); | ||
| 620 | } | ||
| 621 | |||
| 601 | static u8 user_state_from_blocked(unsigned long state) | 622 | static u8 user_state_from_blocked(unsigned long state) |
| 602 | { | 623 | { |
| 603 | if (state & RFKILL_BLOCK_HW) | 624 | if (state & RFKILL_BLOCK_HW) |
| @@ -656,6 +677,7 @@ static struct device_attribute rfkill_dev_attrs[] = { | |||
| 656 | __ATTR(name, S_IRUGO, rfkill_name_show, NULL), | 677 | __ATTR(name, S_IRUGO, rfkill_name_show, NULL), |
| 657 | __ATTR(type, S_IRUGO, rfkill_type_show, NULL), | 678 | __ATTR(type, S_IRUGO, rfkill_type_show, NULL), |
| 658 | __ATTR(index, S_IRUGO, rfkill_idx_show, NULL), | 679 | __ATTR(index, S_IRUGO, rfkill_idx_show, NULL), |
| 680 | __ATTR(persistent, S_IRUGO, rfkill_persistent_show, NULL), | ||
| 659 | __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), | 681 | __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store), |
| 660 | __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), | 682 | __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store), |
| 661 | __ATTR_NULL | 683 | __ATTR_NULL |
| @@ -718,8 +740,6 @@ static int rfkill_suspend(struct device *dev, pm_message_t state) | |||
| 718 | 740 | ||
| 719 | rfkill_pause_polling(rfkill); | 741 | rfkill_pause_polling(rfkill); |
| 720 | 742 | ||
| 721 | rfkill->suspended = true; | ||
| 722 | |||
| 723 | return 0; | 743 | return 0; |
| 724 | } | 744 | } |
| 725 | 745 | ||
| @@ -728,10 +748,10 @@ static int rfkill_resume(struct device *dev) | |||
| 728 | struct rfkill *rfkill = to_rfkill(dev); | 748 | struct rfkill *rfkill = to_rfkill(dev); |
| 729 | bool cur; | 749 | bool cur; |
| 730 | 750 | ||
| 731 | cur = !!(rfkill->state & RFKILL_BLOCK_SW); | 751 | if (!rfkill->persistent) { |
| 732 | rfkill_set_block(rfkill, cur); | 752 | cur = !!(rfkill->state & RFKILL_BLOCK_SW); |
| 733 | 753 | rfkill_set_block(rfkill, cur); | |
| 734 | rfkill->suspended = false; | 754 | } |
| 735 | 755 | ||
| 736 | rfkill_resume_polling(rfkill); | 756 | rfkill_resume_polling(rfkill); |
| 737 | 757 | ||
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile index 5369aa369b35..db73fd2a3f0e 100644 --- a/net/sunrpc/Makefile +++ b/net/sunrpc/Makefile | |||
| @@ -13,5 +13,6 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ | |||
| 13 | rpcb_clnt.o timer.o xdr.o \ | 13 | rpcb_clnt.o timer.o xdr.o \ |
| 14 | sunrpc_syms.o cache.o rpc_pipe.o \ | 14 | sunrpc_syms.o cache.o rpc_pipe.o \ |
| 15 | svc_xprt.o | 15 | svc_xprt.o |
| 16 | sunrpc-$(CONFIG_NFS_V4_1) += backchannel_rqst.o bc_svc.o | ||
| 16 | sunrpc-$(CONFIG_PROC_FS) += stats.o | 17 | sunrpc-$(CONFIG_PROC_FS) += stats.o |
| 17 | sunrpc-$(CONFIG_SYSCTL) += sysctl.o | 18 | sunrpc-$(CONFIG_SYSCTL) += sysctl.o |
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c new file mode 100644 index 000000000000..553621fb2c41 --- /dev/null +++ b/net/sunrpc/backchannel_rqst.c | |||
| @@ -0,0 +1,281 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | |||
| 3 | (c) 2007 Network Appliance, Inc. All Rights Reserved. | ||
| 4 | (c) 2009 NetApp. All Rights Reserved. | ||
| 5 | |||
| 6 | NetApp provides this source code under the GPL v2 License. | ||
| 7 | The GPL v2 license is available at | ||
| 8 | http://opensource.org/licenses/gpl-license.php. | ||
| 9 | |||
| 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 11 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 12 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 13 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
| 14 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| 15 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| 16 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
| 17 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 18 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 19 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| 20 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 21 | |||
| 22 | ******************************************************************************/ | ||
| 23 | |||
| 24 | #include <linux/tcp.h> | ||
| 25 | #include <linux/sunrpc/xprt.h> | ||
| 26 | |||
| 27 | #ifdef RPC_DEBUG | ||
| 28 | #define RPCDBG_FACILITY RPCDBG_TRANS | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #if defined(CONFIG_NFS_V4_1) | ||
| 32 | |||
| 33 | /* | ||
| 34 | * Helper routines that track the number of preallocation elements | ||
| 35 | * on the transport. | ||
| 36 | */ | ||
| 37 | static inline int xprt_need_to_requeue(struct rpc_xprt *xprt) | ||
| 38 | { | ||
| 39 | return xprt->bc_alloc_count > 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | static inline void xprt_inc_alloc_count(struct rpc_xprt *xprt, unsigned int n) | ||
| 43 | { | ||
| 44 | xprt->bc_alloc_count += n; | ||
| 45 | } | ||
| 46 | |||
| 47 | static inline int xprt_dec_alloc_count(struct rpc_xprt *xprt, unsigned int n) | ||
| 48 | { | ||
| 49 | return xprt->bc_alloc_count -= n; | ||
| 50 | } | ||
| 51 | |||
| 52 | /* | ||
| 53 | * Free the preallocated rpc_rqst structure and the memory | ||
| 54 | * buffers hanging off of it. | ||
| 55 | */ | ||
| 56 | static void xprt_free_allocation(struct rpc_rqst *req) | ||
| 57 | { | ||
| 58 | struct xdr_buf *xbufp; | ||
| 59 | |||
| 60 | dprintk("RPC: free allocations for req= %p\n", req); | ||
| 61 | BUG_ON(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); | ||
| 62 | xbufp = &req->rq_private_buf; | ||
| 63 | free_page((unsigned long)xbufp->head[0].iov_base); | ||
| 64 | xbufp = &req->rq_snd_buf; | ||
| 65 | free_page((unsigned long)xbufp->head[0].iov_base); | ||
| 66 | list_del(&req->rq_bc_pa_list); | ||
| 67 | kfree(req); | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Preallocate up to min_reqs structures and related buffers for use | ||
| 72 | * by the backchannel. This function can be called multiple times | ||
| 73 | * when creating new sessions that use the same rpc_xprt. The | ||
| 74 | * preallocated buffers are added to the pool of resources used by | ||
| 75 | * the rpc_xprt. Anyone of these resources may be used used by an | ||
| 76 | * incoming callback request. It's up to the higher levels in the | ||
| 77 | * stack to enforce that the maximum number of session slots is not | ||
| 78 | * being exceeded. | ||
| 79 | * | ||
| 80 | * Some callback arguments can be large. For example, a pNFS server | ||
| 81 | * using multiple deviceids. The list can be unbound, but the client | ||
| 82 | * has the ability to tell the server the maximum size of the callback | ||
| 83 | * requests. Each deviceID is 16 bytes, so allocate one page | ||
| 84 | * for the arguments to have enough room to receive a number of these | ||
| 85 | * deviceIDs. The NFS client indicates to the pNFS server that its | ||
| 86 | * callback requests can be up to 4096 bytes in size. | ||
| 87 | */ | ||
| 88 | int xprt_setup_backchannel(struct rpc_xprt *xprt, unsigned int min_reqs) | ||
| 89 | { | ||
| 90 | struct page *page_rcv = NULL, *page_snd = NULL; | ||
| 91 | struct xdr_buf *xbufp = NULL; | ||
| 92 | struct rpc_rqst *req, *tmp; | ||
| 93 | struct list_head tmp_list; | ||
| 94 | int i; | ||
| 95 | |||
| 96 | dprintk("RPC: setup backchannel transport\n"); | ||
| 97 | |||
| 98 | /* | ||
| 99 | * We use a temporary list to keep track of the preallocated | ||
| 100 | * buffers. Once we're done building the list we splice it | ||
| 101 | * into the backchannel preallocation list off of the rpc_xprt | ||
| 102 | * struct. This helps minimize the amount of time the list | ||
| 103 | * lock is held on the rpc_xprt struct. It also makes cleanup | ||
| 104 | * easier in case of memory allocation errors. | ||
| 105 | */ | ||
| 106 | INIT_LIST_HEAD(&tmp_list); | ||
| 107 | for (i = 0; i < min_reqs; i++) { | ||
| 108 | /* Pre-allocate one backchannel rpc_rqst */ | ||
| 109 | req = kzalloc(sizeof(struct rpc_rqst), GFP_KERNEL); | ||
| 110 | if (req == NULL) { | ||
| 111 | printk(KERN_ERR "Failed to create bc rpc_rqst\n"); | ||
| 112 | goto out_free; | ||
| 113 | } | ||
| 114 | |||
| 115 | /* Add the allocated buffer to the tmp list */ | ||
| 116 | dprintk("RPC: adding req= %p\n", req); | ||
| 117 | list_add(&req->rq_bc_pa_list, &tmp_list); | ||
| 118 | |||
| 119 | req->rq_xprt = xprt; | ||
| 120 | INIT_LIST_HEAD(&req->rq_list); | ||
| 121 | INIT_LIST_HEAD(&req->rq_bc_list); | ||
| 122 | |||
| 123 | /* Preallocate one XDR receive buffer */ | ||
| 124 | page_rcv = alloc_page(GFP_KERNEL); | ||
| 125 | if (page_rcv == NULL) { | ||
| 126 | printk(KERN_ERR "Failed to create bc receive xbuf\n"); | ||
| 127 | goto out_free; | ||
| 128 | } | ||
| 129 | xbufp = &req->rq_rcv_buf; | ||
| 130 | xbufp->head[0].iov_base = page_address(page_rcv); | ||
| 131 | xbufp->head[0].iov_len = PAGE_SIZE; | ||
| 132 | xbufp->tail[0].iov_base = NULL; | ||
| 133 | xbufp->tail[0].iov_len = 0; | ||
| 134 | xbufp->page_len = 0; | ||
| 135 | xbufp->len = PAGE_SIZE; | ||
| 136 | xbufp->buflen = PAGE_SIZE; | ||
| 137 | |||
| 138 | /* Preallocate one XDR send buffer */ | ||
| 139 | page_snd = alloc_page(GFP_KERNEL); | ||
| 140 | if (page_snd == NULL) { | ||
| 141 | printk(KERN_ERR "Failed to create bc snd xbuf\n"); | ||
| 142 | goto out_free; | ||
| 143 | } | ||
| 144 | |||
| 145 | xbufp = &req->rq_snd_buf; | ||
| 146 | xbufp->head[0].iov_base = page_address(page_snd); | ||
| 147 | xbufp->head[0].iov_len = 0; | ||
| 148 | xbufp->tail[0].iov_base = NULL; | ||
| 149 | xbufp->tail[0].iov_len = 0; | ||
| 150 | xbufp->page_len = 0; | ||
| 151 | xbufp->len = 0; | ||
| 152 | xbufp->buflen = PAGE_SIZE; | ||
| 153 | } | ||
| 154 | |||
| 155 | /* | ||
| 156 | * Add the temporary list to the backchannel preallocation list | ||
| 157 | */ | ||
| 158 | spin_lock_bh(&xprt->bc_pa_lock); | ||
| 159 | list_splice(&tmp_list, &xprt->bc_pa_list); | ||
| 160 | xprt_inc_alloc_count(xprt, min_reqs); | ||
| 161 | spin_unlock_bh(&xprt->bc_pa_lock); | ||
| 162 | |||
| 163 | dprintk("RPC: setup backchannel transport done\n"); | ||
| 164 | return 0; | ||
| 165 | |||
| 166 | out_free: | ||
| 167 | /* | ||
| 168 | * Memory allocation failed, free the temporary list | ||
| 169 | */ | ||
| 170 | list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) | ||
| 171 | xprt_free_allocation(req); | ||
| 172 | |||
| 173 | dprintk("RPC: setup backchannel transport failed\n"); | ||
| 174 | return -1; | ||
| 175 | } | ||
| 176 | EXPORT_SYMBOL(xprt_setup_backchannel); | ||
| 177 | |||
| 178 | /* | ||
| 179 | * Destroys the backchannel preallocated structures. | ||
| 180 | * Since these structures may have been allocated by multiple calls | ||
| 181 | * to xprt_setup_backchannel, we only destroy up to the maximum number | ||
| 182 | * of reqs specified by the caller. | ||
| 183 | * @xprt: the transport holding the preallocated strucures | ||
| 184 | * @max_reqs the maximum number of preallocated structures to destroy | ||
| 185 | */ | ||
| 186 | void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs) | ||
| 187 | { | ||
| 188 | struct rpc_rqst *req = NULL, *tmp = NULL; | ||
| 189 | |||
| 190 | dprintk("RPC: destroy backchannel transport\n"); | ||
| 191 | |||
| 192 | BUG_ON(max_reqs == 0); | ||
| 193 | spin_lock_bh(&xprt->bc_pa_lock); | ||
| 194 | xprt_dec_alloc_count(xprt, max_reqs); | ||
| 195 | list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) { | ||
| 196 | dprintk("RPC: req=%p\n", req); | ||
| 197 | xprt_free_allocation(req); | ||
| 198 | if (--max_reqs == 0) | ||
| 199 | break; | ||
| 200 | } | ||
| 201 | spin_unlock_bh(&xprt->bc_pa_lock); | ||
| 202 | |||
| 203 | dprintk("RPC: backchannel list empty= %s\n", | ||
| 204 | list_empty(&xprt->bc_pa_list) ? "true" : "false"); | ||
| 205 | } | ||
| 206 | EXPORT_SYMBOL(xprt_destroy_backchannel); | ||
| 207 | |||
| 208 | /* | ||
| 209 | * One or more rpc_rqst structure have been preallocated during the | ||
| 210 | * backchannel setup. Buffer space for the send and private XDR buffers | ||
| 211 | * has been preallocated as well. Use xprt_alloc_bc_request to allocate | ||
| 212 | * to this request. Use xprt_free_bc_request to return it. | ||
| 213 | * | ||
| 214 | * We know that we're called in soft interrupt context, grab the spin_lock | ||
| 215 | * since there is no need to grab the bottom half spin_lock. | ||
| 216 | * | ||
| 217 | * Return an available rpc_rqst, otherwise NULL if non are available. | ||
| 218 | */ | ||
| 219 | struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt) | ||
| 220 | { | ||
| 221 | struct rpc_rqst *req; | ||
| 222 | |||
| 223 | dprintk("RPC: allocate a backchannel request\n"); | ||
| 224 | spin_lock(&xprt->bc_pa_lock); | ||
| 225 | if (!list_empty(&xprt->bc_pa_list)) { | ||
| 226 | req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst, | ||
| 227 | rq_bc_pa_list); | ||
| 228 | list_del(&req->rq_bc_pa_list); | ||
| 229 | } else { | ||
| 230 | req = NULL; | ||
| 231 | } | ||
| 232 | spin_unlock(&xprt->bc_pa_lock); | ||
| 233 | |||
| 234 | if (req != NULL) { | ||
| 235 | set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); | ||
| 236 | req->rq_reply_bytes_recvd = 0; | ||
| 237 | req->rq_bytes_sent = 0; | ||
| 238 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, | ||
| 239 | sizeof(req->rq_private_buf)); | ||
| 240 | } | ||
| 241 | dprintk("RPC: backchannel req=%p\n", req); | ||
| 242 | return req; | ||
| 243 | } | ||
| 244 | |||
| 245 | /* | ||
| 246 | * Return the preallocated rpc_rqst structure and XDR buffers | ||
| 247 | * associated with this rpc_task. | ||
| 248 | */ | ||
| 249 | void xprt_free_bc_request(struct rpc_rqst *req) | ||
| 250 | { | ||
| 251 | struct rpc_xprt *xprt = req->rq_xprt; | ||
| 252 | |||
| 253 | dprintk("RPC: free backchannel req=%p\n", req); | ||
| 254 | |||
| 255 | smp_mb__before_clear_bit(); | ||
| 256 | BUG_ON(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); | ||
| 257 | clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); | ||
| 258 | smp_mb__after_clear_bit(); | ||
| 259 | |||
| 260 | if (!xprt_need_to_requeue(xprt)) { | ||
| 261 | /* | ||
| 262 | * The last remaining session was destroyed while this | ||
| 263 | * entry was in use. Free the entry and don't attempt | ||
| 264 | * to add back to the list because there is no need to | ||
| 265 | * have anymore preallocated entries. | ||
| 266 | */ | ||
| 267 | dprintk("RPC: Last session removed req=%p\n", req); | ||
| 268 | xprt_free_allocation(req); | ||
| 269 | return; | ||
| 270 | } | ||
| 271 | |||
| 272 | /* | ||
| 273 | * Return it to the list of preallocations so that it | ||
| 274 | * may be reused by a new callback request. | ||
| 275 | */ | ||
| 276 | spin_lock_bh(&xprt->bc_pa_lock); | ||
| 277 | list_add(&req->rq_bc_pa_list, &xprt->bc_pa_list); | ||
| 278 | spin_unlock_bh(&xprt->bc_pa_lock); | ||
| 279 | } | ||
| 280 | |||
| 281 | #endif /* CONFIG_NFS_V4_1 */ | ||
diff --git a/net/sunrpc/bc_svc.c b/net/sunrpc/bc_svc.c new file mode 100644 index 000000000000..13f214f53120 --- /dev/null +++ b/net/sunrpc/bc_svc.c | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | |||
| 3 | (c) 2007 Network Appliance, Inc. All Rights Reserved. | ||
| 4 | (c) 2009 NetApp. All Rights Reserved. | ||
| 5 | |||
| 6 | NetApp provides this source code under the GPL v2 License. | ||
| 7 | The GPL v2 license is available at | ||
| 8 | http://opensource.org/licenses/gpl-license.php. | ||
| 9 | |||
| 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 11 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 12 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 13 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
| 14 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| 15 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| 16 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
| 17 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 18 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 19 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| 20 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 21 | |||
| 22 | ******************************************************************************/ | ||
| 23 | |||
| 24 | /* | ||
| 25 | * The NFSv4.1 callback service helper routines. | ||
| 26 | * They implement the transport level processing required to send the | ||
| 27 | * reply over an existing open connection previously established by the client. | ||
| 28 | */ | ||
| 29 | |||
| 30 | #if defined(CONFIG_NFS_V4_1) | ||
| 31 | |||
| 32 | #include <linux/module.h> | ||
| 33 | |||
| 34 | #include <linux/sunrpc/xprt.h> | ||
| 35 | #include <linux/sunrpc/sched.h> | ||
| 36 | #include <linux/sunrpc/bc_xprt.h> | ||
| 37 | |||
| 38 | #define RPCDBG_FACILITY RPCDBG_SVCDSP | ||
| 39 | |||
| 40 | void bc_release_request(struct rpc_task *task) | ||
| 41 | { | ||
| 42 | struct rpc_rqst *req = task->tk_rqstp; | ||
| 43 | |||
| 44 | dprintk("RPC: bc_release_request: task= %p\n", task); | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Release this request only if it's a backchannel | ||
| 48 | * preallocated request | ||
| 49 | */ | ||
| 50 | if (!bc_prealloc(req)) | ||
| 51 | return; | ||
| 52 | xprt_free_bc_request(req); | ||
| 53 | } | ||
| 54 | |||
| 55 | /* Empty callback ops */ | ||
| 56 | static const struct rpc_call_ops nfs41_callback_ops = { | ||
| 57 | }; | ||
| 58 | |||
| 59 | |||
| 60 | /* | ||
| 61 | * Send the callback reply | ||
| 62 | */ | ||
| 63 | int bc_send(struct rpc_rqst *req) | ||
| 64 | { | ||
| 65 | struct rpc_task *task; | ||
| 66 | int ret; | ||
| 67 | |||
| 68 | dprintk("RPC: bc_send req= %p\n", req); | ||
| 69 | task = rpc_run_bc_task(req, &nfs41_callback_ops); | ||
| 70 | if (IS_ERR(task)) | ||
| 71 | ret = PTR_ERR(task); | ||
| 72 | else { | ||
| 73 | BUG_ON(atomic_read(&task->tk_count) != 1); | ||
| 74 | ret = task->tk_status; | ||
| 75 | rpc_put_task(task); | ||
| 76 | } | ||
| 77 | return ret; | ||
| 78 | dprintk("RPC: bc_send ret= %d \n", ret); | ||
| 79 | } | ||
| 80 | |||
| 81 | #endif /* CONFIG_NFS_V4_1 */ | ||
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 20029a79a5de..ff0c23053d2f 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
| @@ -488,7 +488,7 @@ static void do_cache_clean(struct work_struct *work) | |||
| 488 | { | 488 | { |
| 489 | int delay = 5; | 489 | int delay = 5; |
| 490 | if (cache_clean() == -1) | 490 | if (cache_clean() == -1) |
| 491 | delay = 30*HZ; | 491 | delay = round_jiffies_relative(30*HZ); |
| 492 | 492 | ||
| 493 | if (list_empty(&cache_list)) | 493 | if (list_empty(&cache_list)) |
| 494 | delay = 0; | 494 | delay = 0; |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 5abab094441f..5bc2f45bddf0 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -36,7 +36,9 @@ | |||
| 36 | #include <linux/sunrpc/clnt.h> | 36 | #include <linux/sunrpc/clnt.h> |
| 37 | #include <linux/sunrpc/rpc_pipe_fs.h> | 37 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| 38 | #include <linux/sunrpc/metrics.h> | 38 | #include <linux/sunrpc/metrics.h> |
| 39 | #include <linux/sunrpc/bc_xprt.h> | ||
| 39 | 40 | ||
| 41 | #include "sunrpc.h" | ||
| 40 | 42 | ||
| 41 | #ifdef RPC_DEBUG | 43 | #ifdef RPC_DEBUG |
| 42 | # define RPCDBG_FACILITY RPCDBG_CALL | 44 | # define RPCDBG_FACILITY RPCDBG_CALL |
| @@ -63,6 +65,9 @@ static void call_decode(struct rpc_task *task); | |||
| 63 | static void call_bind(struct rpc_task *task); | 65 | static void call_bind(struct rpc_task *task); |
| 64 | static void call_bind_status(struct rpc_task *task); | 66 | static void call_bind_status(struct rpc_task *task); |
| 65 | static void call_transmit(struct rpc_task *task); | 67 | static void call_transmit(struct rpc_task *task); |
| 68 | #if defined(CONFIG_NFS_V4_1) | ||
| 69 | static void call_bc_transmit(struct rpc_task *task); | ||
| 70 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 66 | static void call_status(struct rpc_task *task); | 71 | static void call_status(struct rpc_task *task); |
| 67 | static void call_transmit_status(struct rpc_task *task); | 72 | static void call_transmit_status(struct rpc_task *task); |
| 68 | static void call_refresh(struct rpc_task *task); | 73 | static void call_refresh(struct rpc_task *task); |
| @@ -613,6 +618,50 @@ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags, | |||
| 613 | } | 618 | } |
| 614 | EXPORT_SYMBOL_GPL(rpc_call_async); | 619 | EXPORT_SYMBOL_GPL(rpc_call_async); |
| 615 | 620 | ||
| 621 | #if defined(CONFIG_NFS_V4_1) | ||
| 622 | /** | ||
| 623 | * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run | ||
| 624 | * rpc_execute against it | ||
| 625 | * @ops: RPC call ops | ||
| 626 | */ | ||
| 627 | struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, | ||
| 628 | const struct rpc_call_ops *tk_ops) | ||
| 629 | { | ||
| 630 | struct rpc_task *task; | ||
| 631 | struct xdr_buf *xbufp = &req->rq_snd_buf; | ||
| 632 | struct rpc_task_setup task_setup_data = { | ||
| 633 | .callback_ops = tk_ops, | ||
| 634 | }; | ||
| 635 | |||
| 636 | dprintk("RPC: rpc_run_bc_task req= %p\n", req); | ||
| 637 | /* | ||
| 638 | * Create an rpc_task to send the data | ||
| 639 | */ | ||
| 640 | task = rpc_new_task(&task_setup_data); | ||
| 641 | if (!task) { | ||
| 642 | xprt_free_bc_request(req); | ||
| 643 | goto out; | ||
| 644 | } | ||
| 645 | task->tk_rqstp = req; | ||
| 646 | |||
| 647 | /* | ||
| 648 | * Set up the xdr_buf length. | ||
| 649 | * This also indicates that the buffer is XDR encoded already. | ||
| 650 | */ | ||
| 651 | xbufp->len = xbufp->head[0].iov_len + xbufp->page_len + | ||
| 652 | xbufp->tail[0].iov_len; | ||
| 653 | |||
| 654 | task->tk_action = call_bc_transmit; | ||
| 655 | atomic_inc(&task->tk_count); | ||
| 656 | BUG_ON(atomic_read(&task->tk_count) != 2); | ||
| 657 | rpc_execute(task); | ||
| 658 | |||
| 659 | out: | ||
| 660 | dprintk("RPC: rpc_run_bc_task: task= %p\n", task); | ||
| 661 | return task; | ||
| 662 | } | ||
| 663 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 664 | |||
| 616 | void | 665 | void |
| 617 | rpc_call_start(struct rpc_task *task) | 666 | rpc_call_start(struct rpc_task *task) |
| 618 | { | 667 | { |
| @@ -695,6 +744,19 @@ void rpc_force_rebind(struct rpc_clnt *clnt) | |||
| 695 | EXPORT_SYMBOL_GPL(rpc_force_rebind); | 744 | EXPORT_SYMBOL_GPL(rpc_force_rebind); |
| 696 | 745 | ||
| 697 | /* | 746 | /* |
| 747 | * Restart an (async) RPC call from the call_prepare state. | ||
| 748 | * Usually called from within the exit handler. | ||
| 749 | */ | ||
| 750 | void | ||
| 751 | rpc_restart_call_prepare(struct rpc_task *task) | ||
| 752 | { | ||
| 753 | if (RPC_ASSASSINATED(task)) | ||
| 754 | return; | ||
| 755 | task->tk_action = rpc_prepare_task; | ||
| 756 | } | ||
| 757 | EXPORT_SYMBOL_GPL(rpc_restart_call_prepare); | ||
| 758 | |||
| 759 | /* | ||
| 698 | * Restart an (async) RPC call. Usually called from within the | 760 | * Restart an (async) RPC call. Usually called from within the |
| 699 | * exit handler. | 761 | * exit handler. |
| 700 | */ | 762 | */ |
| @@ -1085,7 +1147,7 @@ call_transmit(struct rpc_task *task) | |||
| 1085 | * in order to allow access to the socket to other RPC requests. | 1147 | * in order to allow access to the socket to other RPC requests. |
| 1086 | */ | 1148 | */ |
| 1087 | call_transmit_status(task); | 1149 | call_transmit_status(task); |
| 1088 | if (task->tk_msg.rpc_proc->p_decode != NULL) | 1150 | if (rpc_reply_expected(task)) |
| 1089 | return; | 1151 | return; |
| 1090 | task->tk_action = rpc_exit_task; | 1152 | task->tk_action = rpc_exit_task; |
| 1091 | rpc_wake_up_queued_task(&task->tk_xprt->pending, task); | 1153 | rpc_wake_up_queued_task(&task->tk_xprt->pending, task); |
| @@ -1120,6 +1182,72 @@ call_transmit_status(struct rpc_task *task) | |||
| 1120 | } | 1182 | } |
| 1121 | } | 1183 | } |
| 1122 | 1184 | ||
| 1185 | #if defined(CONFIG_NFS_V4_1) | ||
| 1186 | /* | ||
| 1187 | * 5b. Send the backchannel RPC reply. On error, drop the reply. In | ||
| 1188 | * addition, disconnect on connectivity errors. | ||
| 1189 | */ | ||
| 1190 | static void | ||
| 1191 | call_bc_transmit(struct rpc_task *task) | ||
| 1192 | { | ||
| 1193 | struct rpc_rqst *req = task->tk_rqstp; | ||
| 1194 | |||
| 1195 | BUG_ON(task->tk_status != 0); | ||
| 1196 | task->tk_status = xprt_prepare_transmit(task); | ||
| 1197 | if (task->tk_status == -EAGAIN) { | ||
| 1198 | /* | ||
| 1199 | * Could not reserve the transport. Try again after the | ||
| 1200 | * transport is released. | ||
| 1201 | */ | ||
| 1202 | task->tk_status = 0; | ||
| 1203 | task->tk_action = call_bc_transmit; | ||
| 1204 | return; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | task->tk_action = rpc_exit_task; | ||
| 1208 | if (task->tk_status < 0) { | ||
| 1209 | printk(KERN_NOTICE "RPC: Could not send backchannel reply " | ||
| 1210 | "error: %d\n", task->tk_status); | ||
| 1211 | return; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | xprt_transmit(task); | ||
| 1215 | xprt_end_transmit(task); | ||
| 1216 | dprint_status(task); | ||
| 1217 | switch (task->tk_status) { | ||
| 1218 | case 0: | ||
| 1219 | /* Success */ | ||
| 1220 | break; | ||
| 1221 | case -EHOSTDOWN: | ||
| 1222 | case -EHOSTUNREACH: | ||
| 1223 | case -ENETUNREACH: | ||
| 1224 | case -ETIMEDOUT: | ||
| 1225 | /* | ||
| 1226 | * Problem reaching the server. Disconnect and let the | ||
| 1227 | * forechannel reestablish the connection. The server will | ||
| 1228 | * have to retransmit the backchannel request and we'll | ||
| 1229 | * reprocess it. Since these ops are idempotent, there's no | ||
| 1230 | * need to cache our reply at this time. | ||
| 1231 | */ | ||
| 1232 | printk(KERN_NOTICE "RPC: Could not send backchannel reply " | ||
| 1233 | "error: %d\n", task->tk_status); | ||
| 1234 | xprt_conditional_disconnect(task->tk_xprt, | ||
| 1235 | req->rq_connect_cookie); | ||
| 1236 | break; | ||
| 1237 | default: | ||
| 1238 | /* | ||
| 1239 | * We were unable to reply and will have to drop the | ||
| 1240 | * request. The server should reconnect and retransmit. | ||
| 1241 | */ | ||
| 1242 | BUG_ON(task->tk_status == -EAGAIN); | ||
| 1243 | printk(KERN_NOTICE "RPC: Could not send backchannel reply " | ||
| 1244 | "error: %d\n", task->tk_status); | ||
| 1245 | break; | ||
| 1246 | } | ||
| 1247 | rpc_wake_up_queued_task(&req->rq_xprt->pending, task); | ||
| 1248 | } | ||
| 1249 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1250 | |||
| 1123 | /* | 1251 | /* |
| 1124 | * 6. Sort out the RPC call status | 1252 | * 6. Sort out the RPC call status |
| 1125 | */ | 1253 | */ |
| @@ -1130,8 +1258,8 @@ call_status(struct rpc_task *task) | |||
| 1130 | struct rpc_rqst *req = task->tk_rqstp; | 1258 | struct rpc_rqst *req = task->tk_rqstp; |
| 1131 | int status; | 1259 | int status; |
| 1132 | 1260 | ||
| 1133 | if (req->rq_received > 0 && !req->rq_bytes_sent) | 1261 | if (req->rq_reply_bytes_recvd > 0 && !req->rq_bytes_sent) |
| 1134 | task->tk_status = req->rq_received; | 1262 | task->tk_status = req->rq_reply_bytes_recvd; |
| 1135 | 1263 | ||
| 1136 | dprint_status(task); | 1264 | dprint_status(task); |
| 1137 | 1265 | ||
| @@ -1248,7 +1376,7 @@ call_decode(struct rpc_task *task) | |||
| 1248 | 1376 | ||
| 1249 | /* | 1377 | /* |
| 1250 | * Ensure that we see all writes made by xprt_complete_rqst() | 1378 | * Ensure that we see all writes made by xprt_complete_rqst() |
| 1251 | * before it changed req->rq_received. | 1379 | * before it changed req->rq_reply_bytes_recvd. |
| 1252 | */ | 1380 | */ |
| 1253 | smp_rmb(); | 1381 | smp_rmb(); |
| 1254 | req->rq_rcv_buf.len = req->rq_private_buf.len; | 1382 | req->rq_rcv_buf.len = req->rq_private_buf.len; |
| @@ -1289,7 +1417,7 @@ out_retry: | |||
| 1289 | task->tk_status = 0; | 1417 | task->tk_status = 0; |
| 1290 | /* Note: rpc_verify_header() may have freed the RPC slot */ | 1418 | /* Note: rpc_verify_header() may have freed the RPC slot */ |
| 1291 | if (task->tk_rqstp == req) { | 1419 | if (task->tk_rqstp == req) { |
| 1292 | req->rq_received = req->rq_rcv_buf.len = 0; | 1420 | req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0; |
| 1293 | if (task->tk_client->cl_discrtry) | 1421 | if (task->tk_client->cl_discrtry) |
| 1294 | xprt_conditional_disconnect(task->tk_xprt, | 1422 | xprt_conditional_disconnect(task->tk_xprt, |
| 1295 | req->rq_connect_cookie); | 1423 | req->rq_connect_cookie); |
| @@ -1377,13 +1505,14 @@ rpc_verify_header(struct rpc_task *task) | |||
| 1377 | } | 1505 | } |
| 1378 | if ((len -= 3) < 0) | 1506 | if ((len -= 3) < 0) |
| 1379 | goto out_overflow; | 1507 | goto out_overflow; |
| 1380 | p += 1; /* skip XID */ | ||
| 1381 | 1508 | ||
| 1509 | p += 1; /* skip XID */ | ||
| 1382 | if ((n = ntohl(*p++)) != RPC_REPLY) { | 1510 | if ((n = ntohl(*p++)) != RPC_REPLY) { |
| 1383 | dprintk("RPC: %5u %s: not an RPC reply: %x\n", | 1511 | dprintk("RPC: %5u %s: not an RPC reply: %x\n", |
| 1384 | task->tk_pid, __func__, n); | 1512 | task->tk_pid, __func__, n); |
| 1385 | goto out_garbage; | 1513 | goto out_garbage; |
| 1386 | } | 1514 | } |
| 1515 | |||
| 1387 | if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { | 1516 | if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { |
| 1388 | if (--len < 0) | 1517 | if (--len < 0) |
| 1389 | goto out_overflow; | 1518 | goto out_overflow; |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index ff50a0546865..1102ce1251f7 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
| @@ -569,7 +569,7 @@ EXPORT_SYMBOL_GPL(rpc_delay); | |||
| 569 | /* | 569 | /* |
| 570 | * Helper to call task->tk_ops->rpc_call_prepare | 570 | * Helper to call task->tk_ops->rpc_call_prepare |
| 571 | */ | 571 | */ |
| 572 | static void rpc_prepare_task(struct rpc_task *task) | 572 | void rpc_prepare_task(struct rpc_task *task) |
| 573 | { | 573 | { |
| 574 | task->tk_ops->rpc_call_prepare(task, task->tk_calldata); | 574 | task->tk_ops->rpc_call_prepare(task, task->tk_calldata); |
| 575 | } | 575 | } |
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 1ef6e46d9da2..1b4e6791ecf3 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c | |||
| @@ -141,12 +141,14 @@ EXPORT_SYMBOL_GPL(rpc_free_iostats); | |||
| 141 | void rpc_count_iostats(struct rpc_task *task) | 141 | void rpc_count_iostats(struct rpc_task *task) |
| 142 | { | 142 | { |
| 143 | struct rpc_rqst *req = task->tk_rqstp; | 143 | struct rpc_rqst *req = task->tk_rqstp; |
| 144 | struct rpc_iostats *stats = task->tk_client->cl_metrics; | 144 | struct rpc_iostats *stats; |
| 145 | struct rpc_iostats *op_metrics; | 145 | struct rpc_iostats *op_metrics; |
| 146 | long rtt, execute, queue; | 146 | long rtt, execute, queue; |
| 147 | 147 | ||
| 148 | if (!stats || !req) | 148 | if (!task->tk_client || !task->tk_client->cl_metrics || !req) |
| 149 | return; | 149 | return; |
| 150 | |||
| 151 | stats = task->tk_client->cl_metrics; | ||
| 150 | op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx]; | 152 | op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx]; |
| 151 | 153 | ||
| 152 | op_metrics->om_ops++; | 154 | op_metrics->om_ops++; |
| @@ -154,7 +156,7 @@ void rpc_count_iostats(struct rpc_task *task) | |||
| 154 | op_metrics->om_timeouts += task->tk_timeouts; | 156 | op_metrics->om_timeouts += task->tk_timeouts; |
| 155 | 157 | ||
| 156 | op_metrics->om_bytes_sent += task->tk_bytes_sent; | 158 | op_metrics->om_bytes_sent += task->tk_bytes_sent; |
| 157 | op_metrics->om_bytes_recv += req->rq_received; | 159 | op_metrics->om_bytes_recv += req->rq_reply_bytes_recvd; |
| 158 | 160 | ||
| 159 | queue = (long)req->rq_xtime - task->tk_start; | 161 | queue = (long)req->rq_xtime - task->tk_start; |
| 160 | if (queue < 0) | 162 | if (queue < 0) |
diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h new file mode 100644 index 000000000000..5d9dd742264b --- /dev/null +++ b/net/sunrpc/sunrpc.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | |||
| 3 | (c) 2008 NetApp. All Rights Reserved. | ||
| 4 | |||
| 5 | NetApp provides this source code under the GPL v2 License. | ||
| 6 | The GPL v2 license is available at | ||
| 7 | http://opensource.org/licenses/gpl-license.php. | ||
| 8 | |||
| 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 10 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 11 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| 12 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||
| 13 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| 14 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| 15 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
| 16 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 17 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 18 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| 19 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 20 | |||
| 21 | ******************************************************************************/ | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Functions and macros used internally by RPC | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef _NET_SUNRPC_SUNRPC_H | ||
| 28 | #define _NET_SUNRPC_SUNRPC_H | ||
| 29 | |||
| 30 | static inline int rpc_reply_expected(struct rpc_task *task) | ||
| 31 | { | ||
| 32 | return (task->tk_msg.rpc_proc != NULL) && | ||
| 33 | (task->tk_msg.rpc_proc->p_decode != NULL); | ||
| 34 | } | ||
| 35 | |||
| 36 | #endif /* _NET_SUNRPC_SUNRPC_H */ | ||
| 37 | |||
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 5ed8931dfe98..952f206ff307 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/sunrpc/stats.h> | 25 | #include <linux/sunrpc/stats.h> |
| 26 | #include <linux/sunrpc/svcsock.h> | 26 | #include <linux/sunrpc/svcsock.h> |
| 27 | #include <linux/sunrpc/clnt.h> | 27 | #include <linux/sunrpc/clnt.h> |
| 28 | #include <linux/sunrpc/bc_xprt.h> | ||
| 28 | 29 | ||
| 29 | #define RPCDBG_FACILITY RPCDBG_SVCDSP | 30 | #define RPCDBG_FACILITY RPCDBG_SVCDSP |
| 30 | 31 | ||
| @@ -486,6 +487,10 @@ svc_destroy(struct svc_serv *serv) | |||
| 486 | if (svc_serv_is_pooled(serv)) | 487 | if (svc_serv_is_pooled(serv)) |
| 487 | svc_pool_map_put(); | 488 | svc_pool_map_put(); |
| 488 | 489 | ||
| 490 | #if defined(CONFIG_NFS_V4_1) | ||
| 491 | svc_sock_destroy(serv->bc_xprt); | ||
| 492 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 493 | |||
| 489 | svc_unregister(serv); | 494 | svc_unregister(serv); |
| 490 | kfree(serv->sv_pools); | 495 | kfree(serv->sv_pools); |
| 491 | kfree(serv); | 496 | kfree(serv); |
| @@ -970,20 +975,18 @@ svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) | |||
| 970 | } | 975 | } |
| 971 | 976 | ||
| 972 | /* | 977 | /* |
| 973 | * Process the RPC request. | 978 | * Common routine for processing the RPC request. |
| 974 | */ | 979 | */ |
| 975 | int | 980 | static int |
| 976 | svc_process(struct svc_rqst *rqstp) | 981 | svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) |
| 977 | { | 982 | { |
| 978 | struct svc_program *progp; | 983 | struct svc_program *progp; |
| 979 | struct svc_version *versp = NULL; /* compiler food */ | 984 | struct svc_version *versp = NULL; /* compiler food */ |
| 980 | struct svc_procedure *procp = NULL; | 985 | struct svc_procedure *procp = NULL; |
| 981 | struct kvec * argv = &rqstp->rq_arg.head[0]; | ||
| 982 | struct kvec * resv = &rqstp->rq_res.head[0]; | ||
| 983 | struct svc_serv *serv = rqstp->rq_server; | 986 | struct svc_serv *serv = rqstp->rq_server; |
| 984 | kxdrproc_t xdr; | 987 | kxdrproc_t xdr; |
| 985 | __be32 *statp; | 988 | __be32 *statp; |
| 986 | u32 dir, prog, vers, proc; | 989 | u32 prog, vers, proc; |
| 987 | __be32 auth_stat, rpc_stat; | 990 | __be32 auth_stat, rpc_stat; |
| 988 | int auth_res; | 991 | int auth_res; |
| 989 | __be32 *reply_statp; | 992 | __be32 *reply_statp; |
| @@ -993,19 +996,6 @@ svc_process(struct svc_rqst *rqstp) | |||
| 993 | if (argv->iov_len < 6*4) | 996 | if (argv->iov_len < 6*4) |
| 994 | goto err_short_len; | 997 | goto err_short_len; |
| 995 | 998 | ||
| 996 | /* setup response xdr_buf. | ||
| 997 | * Initially it has just one page | ||
| 998 | */ | ||
| 999 | rqstp->rq_resused = 1; | ||
| 1000 | resv->iov_base = page_address(rqstp->rq_respages[0]); | ||
| 1001 | resv->iov_len = 0; | ||
| 1002 | rqstp->rq_res.pages = rqstp->rq_respages + 1; | ||
| 1003 | rqstp->rq_res.len = 0; | ||
| 1004 | rqstp->rq_res.page_base = 0; | ||
| 1005 | rqstp->rq_res.page_len = 0; | ||
| 1006 | rqstp->rq_res.buflen = PAGE_SIZE; | ||
| 1007 | rqstp->rq_res.tail[0].iov_base = NULL; | ||
| 1008 | rqstp->rq_res.tail[0].iov_len = 0; | ||
| 1009 | /* Will be turned off only in gss privacy case: */ | 999 | /* Will be turned off only in gss privacy case: */ |
| 1010 | rqstp->rq_splice_ok = 1; | 1000 | rqstp->rq_splice_ok = 1; |
| 1011 | /* Will be turned off only when NFSv4 Sessions are used */ | 1001 | /* Will be turned off only when NFSv4 Sessions are used */ |
| @@ -1014,17 +1004,13 @@ svc_process(struct svc_rqst *rqstp) | |||
| 1014 | /* Setup reply header */ | 1004 | /* Setup reply header */ |
| 1015 | rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); | 1005 | rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp); |
| 1016 | 1006 | ||
| 1017 | rqstp->rq_xid = svc_getu32(argv); | ||
| 1018 | svc_putu32(resv, rqstp->rq_xid); | 1007 | svc_putu32(resv, rqstp->rq_xid); |
| 1019 | 1008 | ||
| 1020 | dir = svc_getnl(argv); | ||
| 1021 | vers = svc_getnl(argv); | 1009 | vers = svc_getnl(argv); |
| 1022 | 1010 | ||
| 1023 | /* First words of reply: */ | 1011 | /* First words of reply: */ |
| 1024 | svc_putnl(resv, 1); /* REPLY */ | 1012 | svc_putnl(resv, 1); /* REPLY */ |
| 1025 | 1013 | ||
| 1026 | if (dir != 0) /* direction != CALL */ | ||
| 1027 | goto err_bad_dir; | ||
| 1028 | if (vers != 2) /* RPC version number */ | 1014 | if (vers != 2) /* RPC version number */ |
| 1029 | goto err_bad_rpc; | 1015 | goto err_bad_rpc; |
| 1030 | 1016 | ||
| @@ -1147,7 +1133,7 @@ svc_process(struct svc_rqst *rqstp) | |||
| 1147 | sendit: | 1133 | sendit: |
| 1148 | if (svc_authorise(rqstp)) | 1134 | if (svc_authorise(rqstp)) |
| 1149 | goto dropit; | 1135 | goto dropit; |
| 1150 | return svc_send(rqstp); | 1136 | return 1; /* Caller can now send it */ |
| 1151 | 1137 | ||
| 1152 | dropit: | 1138 | dropit: |
| 1153 | svc_authorise(rqstp); /* doesn't hurt to call this twice */ | 1139 | svc_authorise(rqstp); /* doesn't hurt to call this twice */ |
| @@ -1161,12 +1147,6 @@ err_short_len: | |||
| 1161 | 1147 | ||
| 1162 | goto dropit; /* drop request */ | 1148 | goto dropit; /* drop request */ |
| 1163 | 1149 | ||
| 1164 | err_bad_dir: | ||
| 1165 | svc_printk(rqstp, "bad direction %d, dropping request\n", dir); | ||
| 1166 | |||
| 1167 | serv->sv_stats->rpcbadfmt++; | ||
| 1168 | goto dropit; /* drop request */ | ||
| 1169 | |||
| 1170 | err_bad_rpc: | 1150 | err_bad_rpc: |
| 1171 | serv->sv_stats->rpcbadfmt++; | 1151 | serv->sv_stats->rpcbadfmt++; |
| 1172 | svc_putnl(resv, 1); /* REJECT */ | 1152 | svc_putnl(resv, 1); /* REJECT */ |
| @@ -1220,6 +1200,100 @@ err_bad: | |||
| 1220 | EXPORT_SYMBOL_GPL(svc_process); | 1200 | EXPORT_SYMBOL_GPL(svc_process); |
| 1221 | 1201 | ||
| 1222 | /* | 1202 | /* |
| 1203 | * Process the RPC request. | ||
| 1204 | */ | ||
| 1205 | int | ||
| 1206 | svc_process(struct svc_rqst *rqstp) | ||
| 1207 | { | ||
| 1208 | struct kvec *argv = &rqstp->rq_arg.head[0]; | ||
| 1209 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
| 1210 | struct svc_serv *serv = rqstp->rq_server; | ||
| 1211 | u32 dir; | ||
| 1212 | int error; | ||
| 1213 | |||
| 1214 | /* | ||
| 1215 | * Setup response xdr_buf. | ||
| 1216 | * Initially it has just one page | ||
| 1217 | */ | ||
| 1218 | rqstp->rq_resused = 1; | ||
| 1219 | resv->iov_base = page_address(rqstp->rq_respages[0]); | ||
| 1220 | resv->iov_len = 0; | ||
| 1221 | rqstp->rq_res.pages = rqstp->rq_respages + 1; | ||
| 1222 | rqstp->rq_res.len = 0; | ||
| 1223 | rqstp->rq_res.page_base = 0; | ||
| 1224 | rqstp->rq_res.page_len = 0; | ||
| 1225 | rqstp->rq_res.buflen = PAGE_SIZE; | ||
| 1226 | rqstp->rq_res.tail[0].iov_base = NULL; | ||
| 1227 | rqstp->rq_res.tail[0].iov_len = 0; | ||
| 1228 | |||
| 1229 | rqstp->rq_xid = svc_getu32(argv); | ||
| 1230 | |||
| 1231 | dir = svc_getnl(argv); | ||
| 1232 | if (dir != 0) { | ||
| 1233 | /* direction != CALL */ | ||
| 1234 | svc_printk(rqstp, "bad direction %d, dropping request\n", dir); | ||
| 1235 | serv->sv_stats->rpcbadfmt++; | ||
| 1236 | svc_drop(rqstp); | ||
| 1237 | return 0; | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | error = svc_process_common(rqstp, argv, resv); | ||
| 1241 | if (error <= 0) | ||
| 1242 | return error; | ||
| 1243 | |||
| 1244 | return svc_send(rqstp); | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | #if defined(CONFIG_NFS_V4_1) | ||
| 1248 | /* | ||
| 1249 | * Process a backchannel RPC request that arrived over an existing | ||
| 1250 | * outbound connection | ||
| 1251 | */ | ||
| 1252 | int | ||
| 1253 | bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, | ||
| 1254 | struct svc_rqst *rqstp) | ||
| 1255 | { | ||
| 1256 | struct kvec *argv = &rqstp->rq_arg.head[0]; | ||
| 1257 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
| 1258 | int error; | ||
| 1259 | |||
| 1260 | /* Build the svc_rqst used by the common processing routine */ | ||
| 1261 | rqstp->rq_xprt = serv->bc_xprt; | ||
| 1262 | rqstp->rq_xid = req->rq_xid; | ||
| 1263 | rqstp->rq_prot = req->rq_xprt->prot; | ||
| 1264 | rqstp->rq_server = serv; | ||
| 1265 | |||
| 1266 | rqstp->rq_addrlen = sizeof(req->rq_xprt->addr); | ||
| 1267 | memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen); | ||
| 1268 | memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg)); | ||
| 1269 | memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res)); | ||
| 1270 | |||
| 1271 | /* reset result send buffer "put" position */ | ||
| 1272 | resv->iov_len = 0; | ||
| 1273 | |||
| 1274 | if (rqstp->rq_prot != IPPROTO_TCP) { | ||
| 1275 | printk(KERN_ERR "No support for Non-TCP transports!\n"); | ||
| 1276 | BUG(); | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | /* | ||
| 1280 | * Skip the next two words because they've already been | ||
| 1281 | * processed in the trasport | ||
| 1282 | */ | ||
| 1283 | svc_getu32(argv); /* XID */ | ||
| 1284 | svc_getnl(argv); /* CALLDIR */ | ||
| 1285 | |||
| 1286 | error = svc_process_common(rqstp, argv, resv); | ||
| 1287 | if (error <= 0) | ||
| 1288 | return error; | ||
| 1289 | |||
| 1290 | memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); | ||
| 1291 | return bc_send(req); | ||
| 1292 | } | ||
| 1293 | EXPORT_SYMBOL(bc_svc_process); | ||
| 1294 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1295 | |||
| 1296 | /* | ||
| 1223 | * Return (transport-specific) limit on the rpc payload. | 1297 | * Return (transport-specific) limit on the rpc payload. |
| 1224 | */ | 1298 | */ |
| 1225 | u32 svc_max_payload(const struct svc_rqst *rqstp) | 1299 | u32 svc_max_payload(const struct svc_rqst *rqstp) |
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index c200d92e57e4..6f33d33cc064 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <net/sock.h> | 11 | #include <net/sock.h> |
| 12 | #include <linux/sunrpc/stats.h> | 12 | #include <linux/sunrpc/stats.h> |
| 13 | #include <linux/sunrpc/svc_xprt.h> | 13 | #include <linux/sunrpc/svc_xprt.h> |
| 14 | #include <linux/sunrpc/svcsock.h> | ||
| 14 | 15 | ||
| 15 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT | 16 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT |
| 16 | 17 | ||
| @@ -1097,36 +1098,58 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, | |||
| 1097 | } | 1098 | } |
| 1098 | EXPORT_SYMBOL_GPL(svc_find_xprt); | 1099 | EXPORT_SYMBOL_GPL(svc_find_xprt); |
| 1099 | 1100 | ||
| 1100 | /* | 1101 | static int svc_one_xprt_name(const struct svc_xprt *xprt, |
| 1101 | * Format a buffer with a list of the active transports. A zero for | 1102 | char *pos, int remaining) |
| 1102 | * the buflen parameter disables target buffer overflow checking. | 1103 | { |
| 1104 | int len; | ||
| 1105 | |||
| 1106 | len = snprintf(pos, remaining, "%s %u\n", | ||
| 1107 | xprt->xpt_class->xcl_name, | ||
| 1108 | svc_xprt_local_port(xprt)); | ||
| 1109 | if (len >= remaining) | ||
| 1110 | return -ENAMETOOLONG; | ||
| 1111 | return len; | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | /** | ||
| 1115 | * svc_xprt_names - format a buffer with a list of transport names | ||
| 1116 | * @serv: pointer to an RPC service | ||
| 1117 | * @buf: pointer to a buffer to be filled in | ||
| 1118 | * @buflen: length of buffer to be filled in | ||
| 1119 | * | ||
| 1120 | * Fills in @buf with a string containing a list of transport names, | ||
| 1121 | * each name terminated with '\n'. | ||
| 1122 | * | ||
| 1123 | * Returns positive length of the filled-in string on success; otherwise | ||
| 1124 | * a negative errno value is returned if an error occurs. | ||
| 1103 | */ | 1125 | */ |
| 1104 | int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen) | 1126 | int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen) |
| 1105 | { | 1127 | { |
| 1106 | struct svc_xprt *xprt; | 1128 | struct svc_xprt *xprt; |
| 1107 | char xprt_str[64]; | 1129 | int len, totlen; |
| 1108 | int totlen = 0; | 1130 | char *pos; |
| 1109 | int len; | ||
| 1110 | 1131 | ||
| 1111 | /* Sanity check args */ | 1132 | /* Sanity check args */ |
| 1112 | if (!serv) | 1133 | if (!serv) |
| 1113 | return 0; | 1134 | return 0; |
| 1114 | 1135 | ||
| 1115 | spin_lock_bh(&serv->sv_lock); | 1136 | spin_lock_bh(&serv->sv_lock); |
| 1137 | |||
| 1138 | pos = buf; | ||
| 1139 | totlen = 0; | ||
| 1116 | list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { | 1140 | list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) { |
| 1117 | len = snprintf(xprt_str, sizeof(xprt_str), | 1141 | len = svc_one_xprt_name(xprt, pos, buflen - totlen); |
| 1118 | "%s %d\n", xprt->xpt_class->xcl_name, | 1142 | if (len < 0) { |
| 1119 | svc_xprt_local_port(xprt)); | 1143 | *buf = '\0'; |
| 1120 | /* If the string was truncated, replace with error string */ | 1144 | totlen = len; |
| 1121 | if (len >= sizeof(xprt_str)) | 1145 | } |
| 1122 | strcpy(xprt_str, "name-too-long\n"); | 1146 | if (len <= 0) |
| 1123 | /* Don't overflow buffer */ | ||
| 1124 | len = strlen(xprt_str); | ||
| 1125 | if (buflen && (len + totlen >= buflen)) | ||
| 1126 | break; | 1147 | break; |
| 1127 | strcpy(buf+totlen, xprt_str); | 1148 | |
| 1149 | pos += len; | ||
| 1128 | totlen += len; | 1150 | totlen += len; |
| 1129 | } | 1151 | } |
| 1152 | |||
| 1130 | spin_unlock_bh(&serv->sv_lock); | 1153 | spin_unlock_bh(&serv->sv_lock); |
| 1131 | return totlen; | 1154 | return totlen; |
| 1132 | } | 1155 | } |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 9d504234af4a..23128ee191ae 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -240,42 +240,76 @@ out: | |||
| 240 | /* | 240 | /* |
| 241 | * Report socket names for nfsdfs | 241 | * Report socket names for nfsdfs |
| 242 | */ | 242 | */ |
| 243 | static int one_sock_name(char *buf, struct svc_sock *svsk) | 243 | static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining) |
| 244 | { | 244 | { |
| 245 | const struct sock *sk = svsk->sk_sk; | ||
| 246 | const char *proto_name = sk->sk_protocol == IPPROTO_UDP ? | ||
| 247 | "udp" : "tcp"; | ||
| 245 | int len; | 248 | int len; |
| 246 | 249 | ||
| 247 | switch(svsk->sk_sk->sk_family) { | 250 | switch (sk->sk_family) { |
| 248 | case AF_INET: | 251 | case PF_INET: |
| 249 | len = sprintf(buf, "ipv4 %s %pI4 %d\n", | 252 | len = snprintf(buf, remaining, "ipv4 %s %pI4 %d\n", |
| 250 | svsk->sk_sk->sk_protocol == IPPROTO_UDP ? | 253 | proto_name, |
| 251 | "udp" : "tcp", | 254 | &inet_sk(sk)->rcv_saddr, |
| 252 | &inet_sk(svsk->sk_sk)->rcv_saddr, | 255 | inet_sk(sk)->num); |
| 253 | inet_sk(svsk->sk_sk)->num); | 256 | break; |
| 257 | case PF_INET6: | ||
| 258 | len = snprintf(buf, remaining, "ipv6 %s %pI6 %d\n", | ||
| 259 | proto_name, | ||
| 260 | &inet6_sk(sk)->rcv_saddr, | ||
| 261 | inet_sk(sk)->num); | ||
| 254 | break; | 262 | break; |
| 255 | default: | 263 | default: |
| 256 | len = sprintf(buf, "*unknown-%d*\n", | 264 | len = snprintf(buf, remaining, "*unknown-%d*\n", |
| 257 | svsk->sk_sk->sk_family); | 265 | sk->sk_family); |
| 266 | } | ||
| 267 | |||
| 268 | if (len >= remaining) { | ||
| 269 | *buf = '\0'; | ||
| 270 | return -ENAMETOOLONG; | ||
| 258 | } | 271 | } |
| 259 | return len; | 272 | return len; |
| 260 | } | 273 | } |
| 261 | 274 | ||
| 262 | int | 275 | /** |
| 263 | svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) | 276 | * svc_sock_names - construct a list of listener names in a string |
| 277 | * @serv: pointer to RPC service | ||
| 278 | * @buf: pointer to a buffer to fill in with socket names | ||
| 279 | * @buflen: size of the buffer to be filled | ||
| 280 | * @toclose: pointer to '\0'-terminated C string containing the name | ||
| 281 | * of a listener to be closed | ||
| 282 | * | ||
| 283 | * Fills in @buf with a '\n'-separated list of names of listener | ||
| 284 | * sockets. If @toclose is not NULL, the socket named by @toclose | ||
| 285 | * is closed, and is not included in the output list. | ||
| 286 | * | ||
| 287 | * Returns positive length of the socket name string, or a negative | ||
| 288 | * errno value on error. | ||
| 289 | */ | ||
| 290 | int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen, | ||
| 291 | const char *toclose) | ||
| 264 | { | 292 | { |
| 265 | struct svc_sock *svsk, *closesk = NULL; | 293 | struct svc_sock *svsk, *closesk = NULL; |
| 266 | int len = 0; | 294 | int len = 0; |
| 267 | 295 | ||
| 268 | if (!serv) | 296 | if (!serv) |
| 269 | return 0; | 297 | return 0; |
| 298 | |||
| 270 | spin_lock_bh(&serv->sv_lock); | 299 | spin_lock_bh(&serv->sv_lock); |
| 271 | list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) { | 300 | list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) { |
| 272 | int onelen = one_sock_name(buf+len, svsk); | 301 | int onelen = svc_one_sock_name(svsk, buf + len, buflen - len); |
| 273 | if (toclose && strcmp(toclose, buf+len) == 0) | 302 | if (onelen < 0) { |
| 303 | len = onelen; | ||
| 304 | break; | ||
| 305 | } | ||
| 306 | if (toclose && strcmp(toclose, buf + len) == 0) | ||
| 274 | closesk = svsk; | 307 | closesk = svsk; |
| 275 | else | 308 | else |
| 276 | len += onelen; | 309 | len += onelen; |
| 277 | } | 310 | } |
| 278 | spin_unlock_bh(&serv->sv_lock); | 311 | spin_unlock_bh(&serv->sv_lock); |
| 312 | |||
| 279 | if (closesk) | 313 | if (closesk) |
| 280 | /* Should unregister with portmap, but you cannot | 314 | /* Should unregister with portmap, but you cannot |
| 281 | * unregister just one protocol... | 315 | * unregister just one protocol... |
| @@ -346,6 +380,7 @@ static void svc_sock_setbufsize(struct socket *sock, unsigned int snd, | |||
| 346 | sock->sk->sk_sndbuf = snd * 2; | 380 | sock->sk->sk_sndbuf = snd * 2; |
| 347 | sock->sk->sk_rcvbuf = rcv * 2; | 381 | sock->sk->sk_rcvbuf = rcv * 2; |
| 348 | sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; | 382 | sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; |
| 383 | sock->sk->sk_write_space(sock->sk); | ||
| 349 | release_sock(sock->sk); | 384 | release_sock(sock->sk); |
| 350 | #endif | 385 | #endif |
| 351 | } | 386 | } |
| @@ -387,6 +422,15 @@ static void svc_write_space(struct sock *sk) | |||
| 387 | } | 422 | } |
| 388 | } | 423 | } |
| 389 | 424 | ||
| 425 | static void svc_tcp_write_space(struct sock *sk) | ||
| 426 | { | ||
| 427 | struct socket *sock = sk->sk_socket; | ||
| 428 | |||
| 429 | if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) | ||
| 430 | clear_bit(SOCK_NOSPACE, &sock->flags); | ||
| 431 | svc_write_space(sk); | ||
| 432 | } | ||
| 433 | |||
| 390 | /* | 434 | /* |
| 391 | * Copy the UDP datagram's destination address to the rqstp structure. | 435 | * Copy the UDP datagram's destination address to the rqstp structure. |
| 392 | * The 'destination' address in this case is the address to which the | 436 | * The 'destination' address in this case is the address to which the |
| @@ -427,13 +471,14 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 427 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; | 471 | long all[SVC_PKTINFO_SPACE / sizeof(long)]; |
| 428 | } buffer; | 472 | } buffer; |
| 429 | struct cmsghdr *cmh = &buffer.hdr; | 473 | struct cmsghdr *cmh = &buffer.hdr; |
| 430 | int err, len; | ||
| 431 | struct msghdr msg = { | 474 | struct msghdr msg = { |
| 432 | .msg_name = svc_addr(rqstp), | 475 | .msg_name = svc_addr(rqstp), |
| 433 | .msg_control = cmh, | 476 | .msg_control = cmh, |
| 434 | .msg_controllen = sizeof(buffer), | 477 | .msg_controllen = sizeof(buffer), |
| 435 | .msg_flags = MSG_DONTWAIT, | 478 | .msg_flags = MSG_DONTWAIT, |
| 436 | }; | 479 | }; |
| 480 | size_t len; | ||
| 481 | int err; | ||
| 437 | 482 | ||
| 438 | if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) | 483 | if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags)) |
| 439 | /* udp sockets need large rcvbuf as all pending | 484 | /* udp sockets need large rcvbuf as all pending |
| @@ -465,8 +510,8 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 465 | return -EAGAIN; | 510 | return -EAGAIN; |
| 466 | } | 511 | } |
| 467 | len = svc_addr_len(svc_addr(rqstp)); | 512 | len = svc_addr_len(svc_addr(rqstp)); |
| 468 | if (len < 0) | 513 | if (len == 0) |
| 469 | return len; | 514 | return -EAFNOSUPPORT; |
| 470 | rqstp->rq_addrlen = len; | 515 | rqstp->rq_addrlen = len; |
| 471 | if (skb->tstamp.tv64 == 0) { | 516 | if (skb->tstamp.tv64 == 0) { |
| 472 | skb->tstamp = ktime_get_real(); | 517 | skb->tstamp = ktime_get_real(); |
| @@ -980,25 +1025,16 @@ static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp) | |||
| 980 | static int svc_tcp_has_wspace(struct svc_xprt *xprt) | 1025 | static int svc_tcp_has_wspace(struct svc_xprt *xprt) |
| 981 | { | 1026 | { |
| 982 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); | 1027 | struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt); |
| 983 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; | 1028 | struct svc_serv *serv = svsk->sk_xprt.xpt_server; |
| 984 | int required; | 1029 | int required; |
| 985 | int wspace; | ||
| 986 | 1030 | ||
| 987 | /* | 1031 | if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) |
| 988 | * Set the SOCK_NOSPACE flag before checking the available | 1032 | return 1; |
| 989 | * sock space. | 1033 | required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg; |
| 990 | */ | 1034 | if (sk_stream_wspace(svsk->sk_sk) >= required) |
| 1035 | return 1; | ||
| 991 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | 1036 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); |
| 992 | required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg; | 1037 | return 0; |
| 993 | wspace = sk_stream_wspace(svsk->sk_sk); | ||
| 994 | |||
| 995 | if (wspace < sk_stream_min_wspace(svsk->sk_sk)) | ||
| 996 | return 0; | ||
| 997 | if (required * 2 > wspace) | ||
| 998 | return 0; | ||
| 999 | |||
| 1000 | clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | ||
| 1001 | return 1; | ||
| 1002 | } | 1038 | } |
| 1003 | 1039 | ||
| 1004 | static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, | 1040 | static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, |
| @@ -1054,7 +1090,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) | |||
| 1054 | dprintk("setting up TCP socket for reading\n"); | 1090 | dprintk("setting up TCP socket for reading\n"); |
| 1055 | sk->sk_state_change = svc_tcp_state_change; | 1091 | sk->sk_state_change = svc_tcp_state_change; |
| 1056 | sk->sk_data_ready = svc_tcp_data_ready; | 1092 | sk->sk_data_ready = svc_tcp_data_ready; |
| 1057 | sk->sk_write_space = svc_write_space; | 1093 | sk->sk_write_space = svc_tcp_write_space; |
| 1058 | 1094 | ||
| 1059 | svsk->sk_reclen = 0; | 1095 | svsk->sk_reclen = 0; |
| 1060 | svsk->sk_tcplen = 0; | 1096 | svsk->sk_tcplen = 0; |
| @@ -1148,9 +1184,19 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, | |||
| 1148 | return svsk; | 1184 | return svsk; |
| 1149 | } | 1185 | } |
| 1150 | 1186 | ||
| 1151 | int svc_addsock(struct svc_serv *serv, | 1187 | /** |
| 1152 | int fd, | 1188 | * svc_addsock - add a listener socket to an RPC service |
| 1153 | char *name_return) | 1189 | * @serv: pointer to RPC service to which to add a new listener |
| 1190 | * @fd: file descriptor of the new listener | ||
| 1191 | * @name_return: pointer to buffer to fill in with name of listener | ||
| 1192 | * @len: size of the buffer | ||
| 1193 | * | ||
| 1194 | * Fills in socket name and returns positive length of name if successful. | ||
| 1195 | * Name is terminated with '\n'. On error, returns a negative errno | ||
| 1196 | * value. | ||
| 1197 | */ | ||
| 1198 | int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, | ||
| 1199 | const size_t len) | ||
| 1154 | { | 1200 | { |
| 1155 | int err = 0; | 1201 | int err = 0; |
| 1156 | struct socket *so = sockfd_lookup(fd, &err); | 1202 | struct socket *so = sockfd_lookup(fd, &err); |
| @@ -1190,7 +1236,7 @@ int svc_addsock(struct svc_serv *serv, | |||
| 1190 | sockfd_put(so); | 1236 | sockfd_put(so); |
| 1191 | return err; | 1237 | return err; |
| 1192 | } | 1238 | } |
| 1193 | return one_sock_name(name_return, svsk); | 1239 | return svc_one_sock_name(svsk, name_return, len); |
| 1194 | } | 1240 | } |
| 1195 | EXPORT_SYMBOL_GPL(svc_addsock); | 1241 | EXPORT_SYMBOL_GPL(svc_addsock); |
| 1196 | 1242 | ||
| @@ -1327,3 +1373,42 @@ static void svc_sock_free(struct svc_xprt *xprt) | |||
| 1327 | sock_release(svsk->sk_sock); | 1373 | sock_release(svsk->sk_sock); |
| 1328 | kfree(svsk); | 1374 | kfree(svsk); |
| 1329 | } | 1375 | } |
| 1376 | |||
| 1377 | /* | ||
| 1378 | * Create a svc_xprt. | ||
| 1379 | * | ||
| 1380 | * For internal use only (e.g. nfsv4.1 backchannel). | ||
| 1381 | * Callers should typically use the xpo_create() method. | ||
| 1382 | */ | ||
| 1383 | struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot) | ||
| 1384 | { | ||
| 1385 | struct svc_sock *svsk; | ||
| 1386 | struct svc_xprt *xprt = NULL; | ||
| 1387 | |||
| 1388 | dprintk("svc: %s\n", __func__); | ||
| 1389 | svsk = kzalloc(sizeof(*svsk), GFP_KERNEL); | ||
| 1390 | if (!svsk) | ||
| 1391 | goto out; | ||
| 1392 | |||
| 1393 | xprt = &svsk->sk_xprt; | ||
| 1394 | if (prot == IPPROTO_TCP) | ||
| 1395 | svc_xprt_init(&svc_tcp_class, xprt, serv); | ||
| 1396 | else if (prot == IPPROTO_UDP) | ||
| 1397 | svc_xprt_init(&svc_udp_class, xprt, serv); | ||
| 1398 | else | ||
| 1399 | BUG(); | ||
| 1400 | out: | ||
| 1401 | dprintk("svc: %s return %p\n", __func__, xprt); | ||
| 1402 | return xprt; | ||
| 1403 | } | ||
| 1404 | EXPORT_SYMBOL_GPL(svc_sock_create); | ||
| 1405 | |||
| 1406 | /* | ||
| 1407 | * Destroy a svc_sock. | ||
| 1408 | */ | ||
| 1409 | void svc_sock_destroy(struct svc_xprt *xprt) | ||
| 1410 | { | ||
| 1411 | if (xprt) | ||
| 1412 | kfree(container_of(xprt, struct svc_sock, sk_xprt)); | ||
| 1413 | } | ||
| 1414 | EXPORT_SYMBOL_GPL(svc_sock_destroy); | ||
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 06ca058572f2..f412a852bc73 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -12,8 +12,9 @@ | |||
| 12 | * - Next, the caller puts together the RPC message, stuffs it into | 12 | * - Next, the caller puts together the RPC message, stuffs it into |
| 13 | * the request struct, and calls xprt_transmit(). | 13 | * the request struct, and calls xprt_transmit(). |
| 14 | * - xprt_transmit sends the message and installs the caller on the | 14 | * - xprt_transmit sends the message and installs the caller on the |
| 15 | * transport's wait list. At the same time, it installs a timer that | 15 | * transport's wait list. At the same time, if a reply is expected, |
| 16 | * is run after the packet's timeout has expired. | 16 | * it installs a timer that is run after the packet's timeout has |
| 17 | * expired. | ||
| 17 | * - When a packet arrives, the data_ready handler walks the list of | 18 | * - When a packet arrives, the data_ready handler walks the list of |
| 18 | * pending requests for that transport. If a matching XID is found, the | 19 | * pending requests for that transport. If a matching XID is found, the |
| 19 | * caller is woken up, and the timer removed. | 20 | * caller is woken up, and the timer removed. |
| @@ -46,6 +47,8 @@ | |||
| 46 | #include <linux/sunrpc/clnt.h> | 47 | #include <linux/sunrpc/clnt.h> |
| 47 | #include <linux/sunrpc/metrics.h> | 48 | #include <linux/sunrpc/metrics.h> |
| 48 | 49 | ||
| 50 | #include "sunrpc.h" | ||
| 51 | |||
| 49 | /* | 52 | /* |
| 50 | * Local variables | 53 | * Local variables |
| 51 | */ | 54 | */ |
| @@ -192,8 +195,8 @@ EXPORT_SYMBOL_GPL(xprt_load_transport); | |||
| 192 | */ | 195 | */ |
| 193 | int xprt_reserve_xprt(struct rpc_task *task) | 196 | int xprt_reserve_xprt(struct rpc_task *task) |
| 194 | { | 197 | { |
| 195 | struct rpc_xprt *xprt = task->tk_xprt; | ||
| 196 | struct rpc_rqst *req = task->tk_rqstp; | 198 | struct rpc_rqst *req = task->tk_rqstp; |
| 199 | struct rpc_xprt *xprt = req->rq_xprt; | ||
| 197 | 200 | ||
| 198 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { | 201 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { |
| 199 | if (task == xprt->snd_task) | 202 | if (task == xprt->snd_task) |
| @@ -803,9 +806,10 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) | |||
| 803 | 806 | ||
| 804 | list_del_init(&req->rq_list); | 807 | list_del_init(&req->rq_list); |
| 805 | req->rq_private_buf.len = copied; | 808 | req->rq_private_buf.len = copied; |
| 806 | /* Ensure all writes are done before we update req->rq_received */ | 809 | /* Ensure all writes are done before we update */ |
| 810 | /* req->rq_reply_bytes_recvd */ | ||
| 807 | smp_wmb(); | 811 | smp_wmb(); |
| 808 | req->rq_received = copied; | 812 | req->rq_reply_bytes_recvd = copied; |
| 809 | rpc_wake_up_queued_task(&xprt->pending, task); | 813 | rpc_wake_up_queued_task(&xprt->pending, task); |
| 810 | } | 814 | } |
| 811 | EXPORT_SYMBOL_GPL(xprt_complete_rqst); | 815 | EXPORT_SYMBOL_GPL(xprt_complete_rqst); |
| @@ -820,7 +824,7 @@ static void xprt_timer(struct rpc_task *task) | |||
| 820 | dprintk("RPC: %5u xprt_timer\n", task->tk_pid); | 824 | dprintk("RPC: %5u xprt_timer\n", task->tk_pid); |
| 821 | 825 | ||
| 822 | spin_lock_bh(&xprt->transport_lock); | 826 | spin_lock_bh(&xprt->transport_lock); |
| 823 | if (!req->rq_received) { | 827 | if (!req->rq_reply_bytes_recvd) { |
| 824 | if (xprt->ops->timer) | 828 | if (xprt->ops->timer) |
| 825 | xprt->ops->timer(task); | 829 | xprt->ops->timer(task); |
| 826 | } else | 830 | } else |
| @@ -842,8 +846,8 @@ int xprt_prepare_transmit(struct rpc_task *task) | |||
| 842 | dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); | 846 | dprintk("RPC: %5u xprt_prepare_transmit\n", task->tk_pid); |
| 843 | 847 | ||
| 844 | spin_lock_bh(&xprt->transport_lock); | 848 | spin_lock_bh(&xprt->transport_lock); |
| 845 | if (req->rq_received && !req->rq_bytes_sent) { | 849 | if (req->rq_reply_bytes_recvd && !req->rq_bytes_sent) { |
| 846 | err = req->rq_received; | 850 | err = req->rq_reply_bytes_recvd; |
| 847 | goto out_unlock; | 851 | goto out_unlock; |
| 848 | } | 852 | } |
| 849 | if (!xprt->ops->reserve_xprt(task)) | 853 | if (!xprt->ops->reserve_xprt(task)) |
| @@ -855,7 +859,7 @@ out_unlock: | |||
| 855 | 859 | ||
| 856 | void xprt_end_transmit(struct rpc_task *task) | 860 | void xprt_end_transmit(struct rpc_task *task) |
| 857 | { | 861 | { |
| 858 | xprt_release_write(task->tk_xprt, task); | 862 | xprt_release_write(task->tk_rqstp->rq_xprt, task); |
| 859 | } | 863 | } |
| 860 | 864 | ||
| 861 | /** | 865 | /** |
| @@ -872,8 +876,11 @@ void xprt_transmit(struct rpc_task *task) | |||
| 872 | 876 | ||
| 873 | dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); | 877 | dprintk("RPC: %5u xprt_transmit(%u)\n", task->tk_pid, req->rq_slen); |
| 874 | 878 | ||
| 875 | if (!req->rq_received) { | 879 | if (!req->rq_reply_bytes_recvd) { |
| 876 | if (list_empty(&req->rq_list)) { | 880 | if (list_empty(&req->rq_list) && rpc_reply_expected(task)) { |
| 881 | /* | ||
| 882 | * Add to the list only if we're expecting a reply | ||
| 883 | */ | ||
| 877 | spin_lock_bh(&xprt->transport_lock); | 884 | spin_lock_bh(&xprt->transport_lock); |
| 878 | /* Update the softirq receive buffer */ | 885 | /* Update the softirq receive buffer */ |
| 879 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, | 886 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, |
| @@ -908,8 +915,13 @@ void xprt_transmit(struct rpc_task *task) | |||
| 908 | /* Don't race with disconnect */ | 915 | /* Don't race with disconnect */ |
| 909 | if (!xprt_connected(xprt)) | 916 | if (!xprt_connected(xprt)) |
| 910 | task->tk_status = -ENOTCONN; | 917 | task->tk_status = -ENOTCONN; |
| 911 | else if (!req->rq_received) | 918 | else if (!req->rq_reply_bytes_recvd && rpc_reply_expected(task)) { |
| 919 | /* | ||
| 920 | * Sleep on the pending queue since | ||
| 921 | * we're expecting a reply. | ||
| 922 | */ | ||
| 912 | rpc_sleep_on(&xprt->pending, task, xprt_timer); | 923 | rpc_sleep_on(&xprt->pending, task, xprt_timer); |
| 924 | } | ||
| 913 | spin_unlock_bh(&xprt->transport_lock); | 925 | spin_unlock_bh(&xprt->transport_lock); |
| 914 | } | 926 | } |
| 915 | 927 | ||
| @@ -982,11 +994,17 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) | |||
| 982 | */ | 994 | */ |
| 983 | void xprt_release(struct rpc_task *task) | 995 | void xprt_release(struct rpc_task *task) |
| 984 | { | 996 | { |
| 985 | struct rpc_xprt *xprt = task->tk_xprt; | 997 | struct rpc_xprt *xprt; |
| 986 | struct rpc_rqst *req; | 998 | struct rpc_rqst *req; |
| 999 | int is_bc_request; | ||
| 987 | 1000 | ||
| 988 | if (!(req = task->tk_rqstp)) | 1001 | if (!(req = task->tk_rqstp)) |
| 989 | return; | 1002 | return; |
| 1003 | |||
| 1004 | /* Preallocated backchannel request? */ | ||
| 1005 | is_bc_request = bc_prealloc(req); | ||
| 1006 | |||
| 1007 | xprt = req->rq_xprt; | ||
| 990 | rpc_count_iostats(task); | 1008 | rpc_count_iostats(task); |
| 991 | spin_lock_bh(&xprt->transport_lock); | 1009 | spin_lock_bh(&xprt->transport_lock); |
| 992 | xprt->ops->release_xprt(xprt, task); | 1010 | xprt->ops->release_xprt(xprt, task); |
| @@ -999,10 +1017,19 @@ void xprt_release(struct rpc_task *task) | |||
| 999 | mod_timer(&xprt->timer, | 1017 | mod_timer(&xprt->timer, |
| 1000 | xprt->last_used + xprt->idle_timeout); | 1018 | xprt->last_used + xprt->idle_timeout); |
| 1001 | spin_unlock_bh(&xprt->transport_lock); | 1019 | spin_unlock_bh(&xprt->transport_lock); |
| 1002 | xprt->ops->buf_free(req->rq_buffer); | 1020 | if (!bc_prealloc(req)) |
| 1021 | xprt->ops->buf_free(req->rq_buffer); | ||
| 1003 | task->tk_rqstp = NULL; | 1022 | task->tk_rqstp = NULL; |
| 1004 | if (req->rq_release_snd_buf) | 1023 | if (req->rq_release_snd_buf) |
| 1005 | req->rq_release_snd_buf(req); | 1024 | req->rq_release_snd_buf(req); |
| 1025 | |||
| 1026 | /* | ||
| 1027 | * Early exit if this is a backchannel preallocated request. | ||
| 1028 | * There is no need to have it added to the RPC slot list. | ||
| 1029 | */ | ||
| 1030 | if (is_bc_request) | ||
| 1031 | return; | ||
| 1032 | |||
| 1006 | memset(req, 0, sizeof(*req)); /* mark unused */ | 1033 | memset(req, 0, sizeof(*req)); /* mark unused */ |
| 1007 | 1034 | ||
| 1008 | dprintk("RPC: %5u release request %p\n", task->tk_pid, req); | 1035 | dprintk("RPC: %5u release request %p\n", task->tk_pid, req); |
| @@ -1049,6 +1076,11 @@ found: | |||
| 1049 | 1076 | ||
| 1050 | INIT_LIST_HEAD(&xprt->free); | 1077 | INIT_LIST_HEAD(&xprt->free); |
| 1051 | INIT_LIST_HEAD(&xprt->recv); | 1078 | INIT_LIST_HEAD(&xprt->recv); |
| 1079 | #if defined(CONFIG_NFS_V4_1) | ||
| 1080 | spin_lock_init(&xprt->bc_pa_lock); | ||
| 1081 | INIT_LIST_HEAD(&xprt->bc_pa_list); | ||
| 1082 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1083 | |||
| 1052 | INIT_WORK(&xprt->task_cleanup, xprt_autoclose); | 1084 | INIT_WORK(&xprt->task_cleanup, xprt_autoclose); |
| 1053 | setup_timer(&xprt->timer, xprt_init_autodisconnect, | 1085 | setup_timer(&xprt->timer, xprt_init_autodisconnect, |
| 1054 | (unsigned long)xprt); | 1086 | (unsigned long)xprt); |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 42a6f9f20285..9e884383134f 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | |||
| @@ -397,14 +397,14 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt, | |||
| 397 | if (!ch) | 397 | if (!ch) |
| 398 | return 0; | 398 | return 0; |
| 399 | 399 | ||
| 400 | /* Allocate temporary reply and chunk maps */ | ||
| 401 | rpl_map = svc_rdma_get_req_map(); | ||
| 402 | chl_map = svc_rdma_get_req_map(); | ||
| 403 | |||
| 404 | svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count); | 400 | svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count); |
| 405 | if (ch_count > RPCSVC_MAXPAGES) | 401 | if (ch_count > RPCSVC_MAXPAGES) |
| 406 | return -EINVAL; | 402 | return -EINVAL; |
| 407 | 403 | ||
| 404 | /* Allocate temporary reply and chunk maps */ | ||
| 405 | rpl_map = svc_rdma_get_req_map(); | ||
| 406 | chl_map = svc_rdma_get_req_map(); | ||
| 407 | |||
| 408 | if (!xprt->sc_frmr_pg_list_len) | 408 | if (!xprt->sc_frmr_pg_list_len) |
| 409 | sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp, | 409 | sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp, |
| 410 | rpl_map, chl_map, ch_count, | 410 | rpl_map, chl_map, ch_count, |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 6c2d61586551..83c73c4d017a 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -34,6 +34,9 @@ | |||
| 34 | #include <linux/sunrpc/sched.h> | 34 | #include <linux/sunrpc/sched.h> |
| 35 | #include <linux/sunrpc/xprtsock.h> | 35 | #include <linux/sunrpc/xprtsock.h> |
| 36 | #include <linux/file.h> | 36 | #include <linux/file.h> |
| 37 | #ifdef CONFIG_NFS_V4_1 | ||
| 38 | #include <linux/sunrpc/bc_xprt.h> | ||
| 39 | #endif | ||
| 37 | 40 | ||
| 38 | #include <net/sock.h> | 41 | #include <net/sock.h> |
| 39 | #include <net/checksum.h> | 42 | #include <net/checksum.h> |
| @@ -270,6 +273,13 @@ struct sock_xprt { | |||
| 270 | #define TCP_RCV_COPY_FRAGHDR (1UL << 1) | 273 | #define TCP_RCV_COPY_FRAGHDR (1UL << 1) |
| 271 | #define TCP_RCV_COPY_XID (1UL << 2) | 274 | #define TCP_RCV_COPY_XID (1UL << 2) |
| 272 | #define TCP_RCV_COPY_DATA (1UL << 3) | 275 | #define TCP_RCV_COPY_DATA (1UL << 3) |
| 276 | #define TCP_RCV_READ_CALLDIR (1UL << 4) | ||
| 277 | #define TCP_RCV_COPY_CALLDIR (1UL << 5) | ||
| 278 | |||
| 279 | /* | ||
| 280 | * TCP RPC flags | ||
| 281 | */ | ||
| 282 | #define TCP_RPC_REPLY (1UL << 6) | ||
| 273 | 283 | ||
| 274 | static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) | 284 | static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) |
| 275 | { | 285 | { |
| @@ -956,7 +966,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea | |||
| 956 | transport->tcp_offset = 0; | 966 | transport->tcp_offset = 0; |
| 957 | 967 | ||
| 958 | /* Sanity check of the record length */ | 968 | /* Sanity check of the record length */ |
| 959 | if (unlikely(transport->tcp_reclen < 4)) { | 969 | if (unlikely(transport->tcp_reclen < 8)) { |
| 960 | dprintk("RPC: invalid TCP record fragment length\n"); | 970 | dprintk("RPC: invalid TCP record fragment length\n"); |
| 961 | xprt_force_disconnect(xprt); | 971 | xprt_force_disconnect(xprt); |
| 962 | return; | 972 | return; |
| @@ -991,33 +1001,77 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, struct xdr_skb_r | |||
| 991 | if (used != len) | 1001 | if (used != len) |
| 992 | return; | 1002 | return; |
| 993 | transport->tcp_flags &= ~TCP_RCV_COPY_XID; | 1003 | transport->tcp_flags &= ~TCP_RCV_COPY_XID; |
| 994 | transport->tcp_flags |= TCP_RCV_COPY_DATA; | 1004 | transport->tcp_flags |= TCP_RCV_READ_CALLDIR; |
| 995 | transport->tcp_copied = 4; | 1005 | transport->tcp_copied = 4; |
| 996 | dprintk("RPC: reading reply for XID %08x\n", | 1006 | dprintk("RPC: reading %s XID %08x\n", |
| 1007 | (transport->tcp_flags & TCP_RPC_REPLY) ? "reply for" | ||
| 1008 | : "request with", | ||
| 997 | ntohl(transport->tcp_xid)); | 1009 | ntohl(transport->tcp_xid)); |
| 998 | xs_tcp_check_fraghdr(transport); | 1010 | xs_tcp_check_fraghdr(transport); |
| 999 | } | 1011 | } |
| 1000 | 1012 | ||
| 1001 | static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) | 1013 | static inline void xs_tcp_read_calldir(struct sock_xprt *transport, |
| 1014 | struct xdr_skb_reader *desc) | ||
| 1002 | { | 1015 | { |
| 1003 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 1016 | size_t len, used; |
| 1004 | struct rpc_rqst *req; | 1017 | u32 offset; |
| 1018 | __be32 calldir; | ||
| 1019 | |||
| 1020 | /* | ||
| 1021 | * We want transport->tcp_offset to be 8 at the end of this routine | ||
| 1022 | * (4 bytes for the xid and 4 bytes for the call/reply flag). | ||
| 1023 | * When this function is called for the first time, | ||
| 1024 | * transport->tcp_offset is 4 (after having already read the xid). | ||
| 1025 | */ | ||
| 1026 | offset = transport->tcp_offset - sizeof(transport->tcp_xid); | ||
| 1027 | len = sizeof(calldir) - offset; | ||
| 1028 | dprintk("RPC: reading CALL/REPLY flag (%Zu bytes)\n", len); | ||
| 1029 | used = xdr_skb_read_bits(desc, &calldir, len); | ||
| 1030 | transport->tcp_offset += used; | ||
| 1031 | if (used != len) | ||
| 1032 | return; | ||
| 1033 | transport->tcp_flags &= ~TCP_RCV_READ_CALLDIR; | ||
| 1034 | transport->tcp_flags |= TCP_RCV_COPY_CALLDIR; | ||
| 1035 | transport->tcp_flags |= TCP_RCV_COPY_DATA; | ||
| 1036 | /* | ||
| 1037 | * We don't yet have the XDR buffer, so we will write the calldir | ||
| 1038 | * out after we get the buffer from the 'struct rpc_rqst' | ||
| 1039 | */ | ||
| 1040 | if (ntohl(calldir) == RPC_REPLY) | ||
| 1041 | transport->tcp_flags |= TCP_RPC_REPLY; | ||
| 1042 | else | ||
| 1043 | transport->tcp_flags &= ~TCP_RPC_REPLY; | ||
| 1044 | dprintk("RPC: reading %s CALL/REPLY flag %08x\n", | ||
| 1045 | (transport->tcp_flags & TCP_RPC_REPLY) ? | ||
| 1046 | "reply for" : "request with", calldir); | ||
| 1047 | xs_tcp_check_fraghdr(transport); | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | static inline void xs_tcp_read_common(struct rpc_xprt *xprt, | ||
| 1051 | struct xdr_skb_reader *desc, | ||
| 1052 | struct rpc_rqst *req) | ||
| 1053 | { | ||
| 1054 | struct sock_xprt *transport = | ||
| 1055 | container_of(xprt, struct sock_xprt, xprt); | ||
| 1005 | struct xdr_buf *rcvbuf; | 1056 | struct xdr_buf *rcvbuf; |
| 1006 | size_t len; | 1057 | size_t len; |
| 1007 | ssize_t r; | 1058 | ssize_t r; |
| 1008 | 1059 | ||
| 1009 | /* Find and lock the request corresponding to this xid */ | 1060 | rcvbuf = &req->rq_private_buf; |
| 1010 | spin_lock(&xprt->transport_lock); | 1061 | |
| 1011 | req = xprt_lookup_rqst(xprt, transport->tcp_xid); | 1062 | if (transport->tcp_flags & TCP_RCV_COPY_CALLDIR) { |
| 1012 | if (!req) { | 1063 | /* |
| 1013 | transport->tcp_flags &= ~TCP_RCV_COPY_DATA; | 1064 | * Save the RPC direction in the XDR buffer |
| 1014 | dprintk("RPC: XID %08x request not found!\n", | 1065 | */ |
| 1015 | ntohl(transport->tcp_xid)); | 1066 | __be32 calldir = transport->tcp_flags & TCP_RPC_REPLY ? |
| 1016 | spin_unlock(&xprt->transport_lock); | 1067 | htonl(RPC_REPLY) : 0; |
| 1017 | return; | 1068 | |
| 1069 | memcpy(rcvbuf->head[0].iov_base + transport->tcp_copied, | ||
| 1070 | &calldir, sizeof(calldir)); | ||
| 1071 | transport->tcp_copied += sizeof(calldir); | ||
| 1072 | transport->tcp_flags &= ~TCP_RCV_COPY_CALLDIR; | ||
| 1018 | } | 1073 | } |
| 1019 | 1074 | ||
| 1020 | rcvbuf = &req->rq_private_buf; | ||
| 1021 | len = desc->count; | 1075 | len = desc->count; |
| 1022 | if (len > transport->tcp_reclen - transport->tcp_offset) { | 1076 | if (len > transport->tcp_reclen - transport->tcp_offset) { |
| 1023 | struct xdr_skb_reader my_desc; | 1077 | struct xdr_skb_reader my_desc; |
| @@ -1054,7 +1108,7 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea | |||
| 1054 | "tcp_offset = %u, tcp_reclen = %u\n", | 1108 | "tcp_offset = %u, tcp_reclen = %u\n", |
| 1055 | xprt, transport->tcp_copied, | 1109 | xprt, transport->tcp_copied, |
| 1056 | transport->tcp_offset, transport->tcp_reclen); | 1110 | transport->tcp_offset, transport->tcp_reclen); |
| 1057 | goto out; | 1111 | return; |
| 1058 | } | 1112 | } |
| 1059 | 1113 | ||
| 1060 | dprintk("RPC: XID %08x read %Zd bytes\n", | 1114 | dprintk("RPC: XID %08x read %Zd bytes\n", |
| @@ -1070,11 +1124,125 @@ static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_rea | |||
| 1070 | transport->tcp_flags &= ~TCP_RCV_COPY_DATA; | 1124 | transport->tcp_flags &= ~TCP_RCV_COPY_DATA; |
| 1071 | } | 1125 | } |
| 1072 | 1126 | ||
| 1073 | out: | 1127 | return; |
| 1128 | } | ||
| 1129 | |||
| 1130 | /* | ||
| 1131 | * Finds the request corresponding to the RPC xid and invokes the common | ||
| 1132 | * tcp read code to read the data. | ||
| 1133 | */ | ||
| 1134 | static inline int xs_tcp_read_reply(struct rpc_xprt *xprt, | ||
| 1135 | struct xdr_skb_reader *desc) | ||
| 1136 | { | ||
| 1137 | struct sock_xprt *transport = | ||
| 1138 | container_of(xprt, struct sock_xprt, xprt); | ||
| 1139 | struct rpc_rqst *req; | ||
| 1140 | |||
| 1141 | dprintk("RPC: read reply XID %08x\n", ntohl(transport->tcp_xid)); | ||
| 1142 | |||
| 1143 | /* Find and lock the request corresponding to this xid */ | ||
| 1144 | spin_lock(&xprt->transport_lock); | ||
| 1145 | req = xprt_lookup_rqst(xprt, transport->tcp_xid); | ||
| 1146 | if (!req) { | ||
| 1147 | dprintk("RPC: XID %08x request not found!\n", | ||
| 1148 | ntohl(transport->tcp_xid)); | ||
| 1149 | spin_unlock(&xprt->transport_lock); | ||
| 1150 | return -1; | ||
| 1151 | } | ||
| 1152 | |||
| 1153 | xs_tcp_read_common(xprt, desc, req); | ||
| 1154 | |||
| 1074 | if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) | 1155 | if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) |
| 1075 | xprt_complete_rqst(req->rq_task, transport->tcp_copied); | 1156 | xprt_complete_rqst(req->rq_task, transport->tcp_copied); |
| 1157 | |||
| 1076 | spin_unlock(&xprt->transport_lock); | 1158 | spin_unlock(&xprt->transport_lock); |
| 1077 | xs_tcp_check_fraghdr(transport); | 1159 | return 0; |
| 1160 | } | ||
| 1161 | |||
| 1162 | #if defined(CONFIG_NFS_V4_1) | ||
| 1163 | /* | ||
| 1164 | * Obtains an rpc_rqst previously allocated and invokes the common | ||
| 1165 | * tcp read code to read the data. The result is placed in the callback | ||
| 1166 | * queue. | ||
| 1167 | * If we're unable to obtain the rpc_rqst we schedule the closing of the | ||
| 1168 | * connection and return -1. | ||
| 1169 | */ | ||
| 1170 | static inline int xs_tcp_read_callback(struct rpc_xprt *xprt, | ||
| 1171 | struct xdr_skb_reader *desc) | ||
| 1172 | { | ||
| 1173 | struct sock_xprt *transport = | ||
| 1174 | container_of(xprt, struct sock_xprt, xprt); | ||
| 1175 | struct rpc_rqst *req; | ||
| 1176 | |||
| 1177 | req = xprt_alloc_bc_request(xprt); | ||
| 1178 | if (req == NULL) { | ||
| 1179 | printk(KERN_WARNING "Callback slot table overflowed\n"); | ||
| 1180 | xprt_force_disconnect(xprt); | ||
| 1181 | return -1; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | req->rq_xid = transport->tcp_xid; | ||
| 1185 | dprintk("RPC: read callback XID %08x\n", ntohl(req->rq_xid)); | ||
| 1186 | xs_tcp_read_common(xprt, desc, req); | ||
| 1187 | |||
| 1188 | if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) { | ||
| 1189 | struct svc_serv *bc_serv = xprt->bc_serv; | ||
| 1190 | |||
| 1191 | /* | ||
| 1192 | * Add callback request to callback list. The callback | ||
| 1193 | * service sleeps on the sv_cb_waitq waiting for new | ||
| 1194 | * requests. Wake it up after adding enqueing the | ||
| 1195 | * request. | ||
| 1196 | */ | ||
| 1197 | dprintk("RPC: add callback request to list\n"); | ||
| 1198 | spin_lock(&bc_serv->sv_cb_lock); | ||
| 1199 | list_add(&req->rq_bc_list, &bc_serv->sv_cb_list); | ||
| 1200 | spin_unlock(&bc_serv->sv_cb_lock); | ||
| 1201 | wake_up(&bc_serv->sv_cb_waitq); | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | req->rq_private_buf.len = transport->tcp_copied; | ||
| 1205 | |||
| 1206 | return 0; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | static inline int _xs_tcp_read_data(struct rpc_xprt *xprt, | ||
| 1210 | struct xdr_skb_reader *desc) | ||
| 1211 | { | ||
| 1212 | struct sock_xprt *transport = | ||
| 1213 | container_of(xprt, struct sock_xprt, xprt); | ||
| 1214 | |||
| 1215 | return (transport->tcp_flags & TCP_RPC_REPLY) ? | ||
| 1216 | xs_tcp_read_reply(xprt, desc) : | ||
| 1217 | xs_tcp_read_callback(xprt, desc); | ||
| 1218 | } | ||
| 1219 | #else | ||
| 1220 | static inline int _xs_tcp_read_data(struct rpc_xprt *xprt, | ||
| 1221 | struct xdr_skb_reader *desc) | ||
| 1222 | { | ||
| 1223 | return xs_tcp_read_reply(xprt, desc); | ||
| 1224 | } | ||
| 1225 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 1226 | |||
| 1227 | /* | ||
| 1228 | * Read data off the transport. This can be either an RPC_CALL or an | ||
| 1229 | * RPC_REPLY. Relay the processing to helper functions. | ||
| 1230 | */ | ||
| 1231 | static void xs_tcp_read_data(struct rpc_xprt *xprt, | ||
| 1232 | struct xdr_skb_reader *desc) | ||
| 1233 | { | ||
| 1234 | struct sock_xprt *transport = | ||
| 1235 | container_of(xprt, struct sock_xprt, xprt); | ||
| 1236 | |||
| 1237 | if (_xs_tcp_read_data(xprt, desc) == 0) | ||
| 1238 | xs_tcp_check_fraghdr(transport); | ||
| 1239 | else { | ||
| 1240 | /* | ||
| 1241 | * The transport_lock protects the request handling. | ||
| 1242 | * There's no need to hold it to update the tcp_flags. | ||
| 1243 | */ | ||
| 1244 | transport->tcp_flags &= ~TCP_RCV_COPY_DATA; | ||
| 1245 | } | ||
| 1078 | } | 1246 | } |
| 1079 | 1247 | ||
| 1080 | static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_skb_reader *desc) | 1248 | static inline void xs_tcp_read_discard(struct sock_xprt *transport, struct xdr_skb_reader *desc) |
| @@ -1114,9 +1282,14 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns | |||
| 1114 | xs_tcp_read_xid(transport, &desc); | 1282 | xs_tcp_read_xid(transport, &desc); |
| 1115 | continue; | 1283 | continue; |
| 1116 | } | 1284 | } |
| 1285 | /* Read in the call/reply flag */ | ||
| 1286 | if (transport->tcp_flags & TCP_RCV_READ_CALLDIR) { | ||
| 1287 | xs_tcp_read_calldir(transport, &desc); | ||
| 1288 | continue; | ||
| 1289 | } | ||
| 1117 | /* Read in the request data */ | 1290 | /* Read in the request data */ |
| 1118 | if (transport->tcp_flags & TCP_RCV_COPY_DATA) { | 1291 | if (transport->tcp_flags & TCP_RCV_COPY_DATA) { |
| 1119 | xs_tcp_read_request(xprt, &desc); | 1292 | xs_tcp_read_data(xprt, &desc); |
| 1120 | continue; | 1293 | continue; |
| 1121 | } | 1294 | } |
| 1122 | /* Skip over any trailing bytes on short reads */ | 1295 | /* Skip over any trailing bytes on short reads */ |
| @@ -1792,6 +1965,7 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt, | |||
| 1792 | */ | 1965 | */ |
| 1793 | set_bit(XPRT_CONNECTION_CLOSE, &xprt->state); | 1966 | set_bit(XPRT_CONNECTION_CLOSE, &xprt->state); |
| 1794 | xprt_force_disconnect(xprt); | 1967 | xprt_force_disconnect(xprt); |
| 1968 | break; | ||
| 1795 | case -ECONNREFUSED: | 1969 | case -ECONNREFUSED: |
| 1796 | case -ECONNRESET: | 1970 | case -ECONNRESET: |
| 1797 | case -ENETUNREACH: | 1971 | case -ENETUNREACH: |
| @@ -2010,6 +2184,9 @@ static struct rpc_xprt_ops xs_tcp_ops = { | |||
| 2010 | .buf_free = rpc_free, | 2184 | .buf_free = rpc_free, |
| 2011 | .send_request = xs_tcp_send_request, | 2185 | .send_request = xs_tcp_send_request, |
| 2012 | .set_retrans_timeout = xprt_set_retrans_timeout_def, | 2186 | .set_retrans_timeout = xprt_set_retrans_timeout_def, |
| 2187 | #if defined(CONFIG_NFS_V4_1) | ||
| 2188 | .release_request = bc_release_request, | ||
| 2189 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 2013 | .close = xs_tcp_close, | 2190 | .close = xs_tcp_close, |
| 2014 | .destroy = xs_destroy, | 2191 | .destroy = xs_destroy, |
| 2015 | .print_stats = xs_tcp_print_stats, | 2192 | .print_stats = xs_tcp_print_stats, |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 24168560ebae..241bddd0b4f1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -1687,13 +1687,52 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
| 1687 | if (err) | 1687 | if (err) |
| 1688 | goto out_rtnl; | 1688 | goto out_rtnl; |
| 1689 | 1689 | ||
| 1690 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 1690 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
| 1691 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { | 1691 | if (err) |
| 1692 | err = -EINVAL; | ||
| 1693 | goto out; | 1692 | goto out; |
| 1693 | |||
| 1694 | /* validate settings */ | ||
| 1695 | err = 0; | ||
| 1696 | |||
| 1697 | switch (dev->ieee80211_ptr->iftype) { | ||
| 1698 | case NL80211_IFTYPE_AP: | ||
| 1699 | case NL80211_IFTYPE_AP_VLAN: | ||
| 1700 | /* disallow mesh-specific things */ | ||
| 1701 | if (params.plink_action) | ||
| 1702 | err = -EINVAL; | ||
| 1703 | break; | ||
| 1704 | case NL80211_IFTYPE_STATION: | ||
| 1705 | /* disallow everything but AUTHORIZED flag */ | ||
| 1706 | if (params.plink_action) | ||
| 1707 | err = -EINVAL; | ||
| 1708 | if (params.vlan) | ||
| 1709 | err = -EINVAL; | ||
| 1710 | if (params.supported_rates) | ||
| 1711 | err = -EINVAL; | ||
| 1712 | if (params.ht_capa) | ||
| 1713 | err = -EINVAL; | ||
| 1714 | if (params.listen_interval >= 0) | ||
| 1715 | err = -EINVAL; | ||
| 1716 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
| 1717 | err = -EINVAL; | ||
| 1718 | break; | ||
| 1719 | case NL80211_IFTYPE_MESH_POINT: | ||
| 1720 | /* disallow things mesh doesn't support */ | ||
| 1721 | if (params.vlan) | ||
| 1722 | err = -EINVAL; | ||
| 1723 | if (params.ht_capa) | ||
| 1724 | err = -EINVAL; | ||
| 1725 | if (params.listen_interval >= 0) | ||
| 1726 | err = -EINVAL; | ||
| 1727 | if (params.supported_rates) | ||
| 1728 | err = -EINVAL; | ||
| 1729 | if (params.sta_flags_mask) | ||
| 1730 | err = -EINVAL; | ||
| 1731 | break; | ||
| 1732 | default: | ||
| 1733 | err = -EINVAL; | ||
| 1694 | } | 1734 | } |
| 1695 | 1735 | ||
| 1696 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | ||
| 1697 | if (err) | 1736 | if (err) |
| 1698 | goto out; | 1737 | goto out; |
| 1699 | 1738 | ||
| @@ -1728,9 +1767,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
| 1728 | if (!info->attrs[NL80211_ATTR_MAC]) | 1767 | if (!info->attrs[NL80211_ATTR_MAC]) |
| 1729 | return -EINVAL; | 1768 | return -EINVAL; |
| 1730 | 1769 | ||
| 1731 | if (!info->attrs[NL80211_ATTR_STA_AID]) | ||
| 1732 | return -EINVAL; | ||
| 1733 | |||
| 1734 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | 1770 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) |
| 1735 | return -EINVAL; | 1771 | return -EINVAL; |
| 1736 | 1772 | ||
| @@ -1745,9 +1781,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
| 1745 | params.listen_interval = | 1781 | params.listen_interval = |
| 1746 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 1782 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); |
| 1747 | 1783 | ||
| 1748 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | 1784 | if (info->attrs[NL80211_ATTR_STA_AID]) { |
| 1749 | if (!params.aid || params.aid > IEEE80211_MAX_AID) | 1785 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); |
| 1750 | return -EINVAL; | 1786 | if (!params.aid || params.aid > IEEE80211_MAX_AID) |
| 1787 | return -EINVAL; | ||
| 1788 | } | ||
| 1751 | 1789 | ||
| 1752 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 1790 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
| 1753 | params.ht_capa = | 1791 | params.ht_capa = |
| @@ -1762,13 +1800,39 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
| 1762 | if (err) | 1800 | if (err) |
| 1763 | goto out_rtnl; | 1801 | goto out_rtnl; |
| 1764 | 1802 | ||
| 1765 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 1803 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
| 1766 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { | 1804 | if (err) |
| 1767 | err = -EINVAL; | ||
| 1768 | goto out; | 1805 | goto out; |
| 1806 | |||
| 1807 | /* validate settings */ | ||
| 1808 | err = 0; | ||
| 1809 | |||
| 1810 | switch (dev->ieee80211_ptr->iftype) { | ||
| 1811 | case NL80211_IFTYPE_AP: | ||
| 1812 | case NL80211_IFTYPE_AP_VLAN: | ||
| 1813 | /* all ok but must have AID */ | ||
| 1814 | if (!params.aid) | ||
| 1815 | err = -EINVAL; | ||
| 1816 | break; | ||
| 1817 | case NL80211_IFTYPE_MESH_POINT: | ||
| 1818 | /* disallow things mesh doesn't support */ | ||
| 1819 | if (params.vlan) | ||
| 1820 | err = -EINVAL; | ||
| 1821 | if (params.aid) | ||
| 1822 | err = -EINVAL; | ||
| 1823 | if (params.ht_capa) | ||
| 1824 | err = -EINVAL; | ||
| 1825 | if (params.listen_interval >= 0) | ||
| 1826 | err = -EINVAL; | ||
| 1827 | if (params.supported_rates) | ||
| 1828 | err = -EINVAL; | ||
| 1829 | if (params.sta_flags_mask) | ||
| 1830 | err = -EINVAL; | ||
| 1831 | break; | ||
| 1832 | default: | ||
| 1833 | err = -EINVAL; | ||
| 1769 | } | 1834 | } |
| 1770 | 1835 | ||
| 1771 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | ||
| 1772 | if (err) | 1836 | if (err) |
| 1773 | goto out; | 1837 | goto out; |
| 1774 | 1838 | ||
| @@ -1812,7 +1876,8 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
| 1812 | goto out_rtnl; | 1876 | goto out_rtnl; |
| 1813 | 1877 | ||
| 1814 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 1878 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
| 1815 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { | 1879 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
| 1880 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
| 1816 | err = -EINVAL; | 1881 | err = -EINVAL; |
| 1817 | goto out; | 1882 | goto out; |
| 1818 | } | 1883 | } |
