aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/xprtsock.c52
1 files changed, 49 insertions, 3 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index e18596146013..8975c10591c3 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -270,6 +270,12 @@ struct sock_xprt {
270#define TCP_RCV_COPY_FRAGHDR (1UL << 1) 270#define TCP_RCV_COPY_FRAGHDR (1UL << 1)
271#define TCP_RCV_COPY_XID (1UL << 2) 271#define TCP_RCV_COPY_XID (1UL << 2)
272#define TCP_RCV_COPY_DATA (1UL << 3) 272#define TCP_RCV_COPY_DATA (1UL << 3)
273#define TCP_RCV_COPY_CALLDIR (1UL << 4)
274
275/*
276 * TCP RPC flags
277 */
278#define TCP_RPC_REPLY (1UL << 5)
273 279
274static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) 280static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt)
275{ 281{
@@ -956,7 +962,7 @@ static inline void xs_tcp_read_fraghdr(struct rpc_xprt *xprt, struct xdr_skb_rea
956 transport->tcp_offset = 0; 962 transport->tcp_offset = 0;
957 963
958 /* Sanity check of the record length */ 964 /* Sanity check of the record length */
959 if (unlikely(transport->tcp_reclen < 4)) { 965 if (unlikely(transport->tcp_reclen < 8)) {
960 dprintk("RPC: invalid TCP record fragment length\n"); 966 dprintk("RPC: invalid TCP record fragment length\n");
961 xprt_force_disconnect(xprt); 967 xprt_force_disconnect(xprt);
962 return; 968 return;
@@ -991,13 +997,48 @@ static inline void xs_tcp_read_xid(struct sock_xprt *transport, struct xdr_skb_r
991 if (used != len) 997 if (used != len)
992 return; 998 return;
993 transport->tcp_flags &= ~TCP_RCV_COPY_XID; 999 transport->tcp_flags &= ~TCP_RCV_COPY_XID;
994 transport->tcp_flags |= TCP_RCV_COPY_DATA; 1000 transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
995 transport->tcp_copied = 4; 1001 transport->tcp_copied = 4;
996 dprintk("RPC: reading reply for XID %08x\n", 1002 dprintk("RPC: reading %s XID %08x\n",
1003 (transport->tcp_flags & TCP_RPC_REPLY) ? "reply for"
1004 : "request with",
997 ntohl(transport->tcp_xid)); 1005 ntohl(transport->tcp_xid));
998 xs_tcp_check_fraghdr(transport); 1006 xs_tcp_check_fraghdr(transport);
999} 1007}
1000 1008
1009static inline void xs_tcp_read_calldir(struct sock_xprt *transport,
1010 struct xdr_skb_reader *desc)
1011{
1012 size_t len, used;
1013 u32 offset;
1014 __be32 calldir;
1015
1016 /*
1017 * We want transport->tcp_offset to be 8 at the end of this routine
1018 * (4 bytes for the xid and 4 bytes for the call/reply flag).
1019 * When this function is called for the first time,
1020 * transport->tcp_offset is 4 (after having already read the xid).
1021 */
1022 offset = transport->tcp_offset - sizeof(transport->tcp_xid);
1023 len = sizeof(calldir) - offset;
1024 dprintk("RPC: reading CALL/REPLY flag (%Zu bytes)\n", len);
1025 used = xdr_skb_read_bits(desc, &calldir, len);
1026 transport->tcp_offset += used;
1027 if (used != len)
1028 return;
1029 transport->tcp_flags &= ~TCP_RCV_COPY_CALLDIR;
1030 transport->tcp_flags |= TCP_RCV_COPY_DATA;
1031 transport->tcp_copied += 4;
1032 if (ntohl(calldir) == RPC_REPLY)
1033 transport->tcp_flags |= TCP_RPC_REPLY;
1034 else
1035 transport->tcp_flags &= ~TCP_RPC_REPLY;
1036 dprintk("RPC: reading %s CALL/REPLY flag %08x\n",
1037 (transport->tcp_flags & TCP_RPC_REPLY) ?
1038 "reply for" : "request with", calldir);
1039 xs_tcp_check_fraghdr(transport);
1040}
1041
1001static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) 1042static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_reader *desc)
1002{ 1043{
1003 struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 1044 struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
@@ -1114,6 +1155,11 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns
1114 xs_tcp_read_xid(transport, &desc); 1155 xs_tcp_read_xid(transport, &desc);
1115 continue; 1156 continue;
1116 } 1157 }
1158 /* Read in the call/reply flag */
1159 if (transport->tcp_flags & TCP_RCV_COPY_CALLDIR) {
1160 xs_tcp_read_calldir(transport, &desc);
1161 continue;
1162 }
1117 /* Read in the request data */ 1163 /* Read in the request data */
1118 if (transport->tcp_flags & TCP_RCV_COPY_DATA) { 1164 if (transport->tcp_flags & TCP_RCV_COPY_DATA) {
1119 xs_tcp_read_request(xprt, &desc); 1165 xs_tcp_read_request(xprt, &desc);