diff options
Diffstat (limited to 'net/sunrpc/xprtsock.c')
-rw-r--r-- | net/sunrpc/xprtsock.c | 52 |
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 | ||
274 | static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) | 280 | static 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 | ||
1009 | static 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 | |||
1001 | static inline void xs_tcp_read_request(struct rpc_xprt *xprt, struct xdr_skb_reader *desc) | 1042 | static 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); |