aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2017-02-07 11:58:32 -0500
committerJ. Bruce Fields <bfields@redhat.com>2017-02-08 14:41:57 -0500
commit647e18e3bd0308b38d5341fc08cd70ed1ce28a71 (patch)
treeba5c0b0238432a9fb80aeb5192f13425aaeb88b7
parent98fc21d3bfd55a36ce9eb7b32d1ce146f0d1696d (diff)
svcrdma: Clean up RPC-over-RDMA Call header decoder
Replace C structure-based XDR decoding with pointer arithmetic. Pointer arithmetic is considered more portable. Rename the "decode" functions. Nothing is decoded here, they perform only transport header sanity checking. Use existing XDR naming conventions to help readability. Straight-line the hot path: - relocate the dprintk call sites out of line - remove unnecessary byte-swapping - reduce count of conditional branches Deprecate RDMA_MSGP. It's not properly spec'd by RFC5666, and therefore never used by any V1 client. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_marshal.c232
1 files changed, 79 insertions, 153 deletions
diff --git a/net/sunrpc/xprtrdma/svc_rdma_marshal.c b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
index c7d15b1126ce..1c4aabf0f657 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_marshal.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_marshal.c
@@ -1,4 +1,5 @@
1/* 1/*
2 * Copyright (c) 2016 Oracle. All rights reserved.
2 * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved. 3 * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
3 * 4 *
4 * This software is available to you under a choice of one of two 5 * This software is available to you under a choice of one of two
@@ -47,102 +48,43 @@
47 48
48#define RPCDBG_FACILITY RPCDBG_SVCXPRT 49#define RPCDBG_FACILITY RPCDBG_SVCXPRT
49 50
50/* 51static __be32 *xdr_check_read_list(__be32 *p, __be32 *end)
51 * Decodes a read chunk list. The expected format is as follows:
52 * descrim : xdr_one
53 * position : __be32 offset into XDR stream
54 * handle : __be32 RKEY
55 * . . .
56 * end-of-list: xdr_zero
57 */
58static __be32 *decode_read_list(__be32 *va, __be32 *vaend)
59{ 52{
60 struct rpcrdma_read_chunk *ch = (struct rpcrdma_read_chunk *)va; 53 __be32 *next;
61 54
62 while (ch->rc_discrim != xdr_zero) { 55 while (*p++ != xdr_zero) {
63 if (((unsigned long)ch + sizeof(struct rpcrdma_read_chunk)) > 56 next = p + rpcrdma_readchunk_maxsz - 1;
64 (unsigned long)vaend) { 57 if (next > end)
65 dprintk("svcrdma: vaend=%p, ch=%p\n", vaend, ch);
66 return NULL; 58 return NULL;
67 } 59 p = next;
68 ch++;
69 } 60 }
70 return &ch->rc_position; 61 return p;
71} 62}
72 63
73/* 64static __be32 *xdr_check_write_list(__be32 *p, __be32 *end)
74 * Decodes a write chunk list. The expected format is as follows:
75 * descrim : xdr_one
76 * nchunks : <count>
77 * handle : __be32 RKEY ---+
78 * length : __be32 <len of segment> |
79 * offset : remove va + <count>
80 * . . . |
81 * ---+
82 */
83static __be32 *decode_write_list(__be32 *va, __be32 *vaend)
84{ 65{
85 unsigned long start, end; 66 __be32 *next;
86 int nchunks;
87
88 struct rpcrdma_write_array *ary =
89 (struct rpcrdma_write_array *)va;
90
91 /* Check for not write-array */
92 if (ary->wc_discrim == xdr_zero)
93 return &ary->wc_nchunks;
94 67
95 if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) > 68 while (*p++ != xdr_zero) {
96 (unsigned long)vaend) { 69 next = p + 1 + be32_to_cpup(p) * rpcrdma_segment_maxsz;
97 dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend); 70 if (next > end)
98 return NULL; 71 return NULL;
99 } 72 p = next;
100 nchunks = be32_to_cpu(ary->wc_nchunks);
101
102 start = (unsigned long)&ary->wc_array[0];
103 end = (unsigned long)vaend;
104 if (nchunks < 0 ||
105 nchunks > (SIZE_MAX - start) / sizeof(struct rpcrdma_write_chunk) ||
106 (start + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > end) {
107 dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
108 ary, nchunks, vaend);
109 return NULL;
110 } 73 }
111 /* 74 return p;
112 * rs_length is the 2nd 4B field in wc_target and taking its
113 * address skips the list terminator
114 */
115 return &ary->wc_array[nchunks].wc_target.rs_length;
116} 75}
117 76
118static __be32 *decode_reply_array(__be32 *va, __be32 *vaend) 77static __be32 *xdr_check_reply_chunk(__be32 *p, __be32 *end)
119{ 78{
120 unsigned long start, end; 79 __be32 *next;
121 int nchunks; 80
122 struct rpcrdma_write_array *ary = 81 if (*p++ != xdr_zero) {
123 (struct rpcrdma_write_array *)va; 82 next = p + 1 + be32_to_cpup(p) * rpcrdma_segment_maxsz;
124 83 if (next > end)
125 /* Check for no reply-array */ 84 return NULL;
126 if (ary->wc_discrim == xdr_zero) 85 p = next;
127 return &ary->wc_nchunks;
128
129 if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
130 (unsigned long)vaend) {
131 dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
132 return NULL;
133 }
134 nchunks = be32_to_cpu(ary->wc_nchunks);
135
136 start = (unsigned long)&ary->wc_array[0];
137 end = (unsigned long)vaend;
138 if (nchunks < 0 ||
139 nchunks > (SIZE_MAX - start) / sizeof(struct rpcrdma_write_chunk) ||
140 (start + (sizeof(struct rpcrdma_write_chunk) * nchunks)) > end) {
141 dprintk("svcrdma: ary=%p, wc_nchunks=%d, vaend=%p\n",
142 ary, nchunks, vaend);
143 return NULL;
144 } 86 }
145 return (__be32 *)&ary->wc_array[nchunks]; 87 return p;
146} 88}
147 89
148/** 90/**
@@ -158,87 +100,71 @@ static __be32 *decode_reply_array(__be32 *va, __be32 *vaend)
158 */ 100 */
159int svc_rdma_xdr_decode_req(struct xdr_buf *rq_arg) 101int svc_rdma_xdr_decode_req(struct xdr_buf *rq_arg)
160{ 102{
161 struct rpcrdma_msg *rmsgp; 103 __be32 *p, *end, *rdma_argp;
162 __be32 *va, *vaend; 104 unsigned int hdr_len;
163 unsigned int len;
164 u32 hdr_len;
165 105
166 /* Verify that there's enough bytes for header + something */ 106 /* Verify that there's enough bytes for header + something */
167 if (rq_arg->len <= RPCRDMA_HDRLEN_ERR) { 107 if (rq_arg->len <= RPCRDMA_HDRLEN_ERR)
168 dprintk("svcrdma: header too short = %d\n", 108 goto out_short;
169 rq_arg->len);
170 return -EINVAL;
171 }
172 109
173 rmsgp = (struct rpcrdma_msg *)rq_arg->head[0].iov_base; 110 rdma_argp = rq_arg->head[0].iov_base;
174 if (rmsgp->rm_vers != rpcrdma_version) { 111 if (*(rdma_argp + 1) != rpcrdma_version)
175 dprintk("%s: bad version %u\n", __func__, 112 goto out_version;
176 be32_to_cpu(rmsgp->rm_vers));
177 return -EPROTONOSUPPORT;
178 }
179 113
180 switch (be32_to_cpu(rmsgp->rm_type)) { 114 switch (*(rdma_argp + 3)) {
181 case RDMA_MSG: 115 case rdma_msg:
182 case RDMA_NOMSG: 116 case rdma_nomsg:
183 break; 117 break;
184 118
185 case RDMA_DONE: 119 case rdma_done:
186 /* Just drop it */ 120 goto out_drop;
187 dprintk("svcrdma: dropping RDMA_DONE message\n");
188 return 0;
189
190 case RDMA_ERROR:
191 /* Possible if this is a backchannel reply.
192 * XXX: We should cancel this XID, though.
193 */
194 dprintk("svcrdma: dropping RDMA_ERROR message\n");
195 return 0;
196
197 case RDMA_MSGP:
198 /* Pull in the extra for the padded case, bump our pointer */
199 rmsgp->rm_body.rm_padded.rm_align =
200 be32_to_cpu(rmsgp->rm_body.rm_padded.rm_align);
201 rmsgp->rm_body.rm_padded.rm_thresh =
202 be32_to_cpu(rmsgp->rm_body.rm_padded.rm_thresh);
203
204 va = &rmsgp->rm_body.rm_padded.rm_pempty[4];
205 rq_arg->head[0].iov_base = va;
206 len = (u32)((unsigned long)va - (unsigned long)rmsgp);
207 rq_arg->head[0].iov_len -= len;
208 if (len > rq_arg->len)
209 return -EINVAL;
210 return len;
211 default:
212 dprintk("svcrdma: bad rdma procedure (%u)\n",
213 be32_to_cpu(rmsgp->rm_type));
214 return -EINVAL;
215 }
216 121
217 /* The chunk list may contain either a read chunk list or a write 122 case rdma_error:
218 * chunk list and a reply chunk list. 123 goto out_drop;
219 */ 124
220 va = &rmsgp->rm_body.rm_chunks[0]; 125 default:
221 vaend = (__be32 *)((unsigned long)rmsgp + rq_arg->len); 126 goto out_proc;
222 va = decode_read_list(va, vaend);
223 if (!va) {
224 dprintk("svcrdma: failed to decode read list\n");
225 return -EINVAL;
226 }
227 va = decode_write_list(va, vaend);
228 if (!va) {
229 dprintk("svcrdma: failed to decode write list\n");
230 return -EINVAL;
231 }
232 va = decode_reply_array(va, vaend);
233 if (!va) {
234 dprintk("svcrdma: failed to decode reply chunk\n");
235 return -EINVAL;
236 } 127 }
237 128
238 rq_arg->head[0].iov_base = va; 129 end = (__be32 *)((unsigned long)rdma_argp + rq_arg->len);
239 hdr_len = (unsigned long)va - (unsigned long)rmsgp; 130 p = xdr_check_read_list(rdma_argp + 4, end);
131 if (!p)
132 goto out_inval;
133 p = xdr_check_write_list(p, end);
134 if (!p)
135 goto out_inval;
136 p = xdr_check_reply_chunk(p, end);
137 if (!p)
138 goto out_inval;
139 if (p > end)
140 goto out_inval;
141
142 rq_arg->head[0].iov_base = p;
143 hdr_len = (unsigned long)p - (unsigned long)rdma_argp;
240 rq_arg->head[0].iov_len -= hdr_len; 144 rq_arg->head[0].iov_len -= hdr_len;
241 return hdr_len; 145 return hdr_len;
146
147out_short:
148 dprintk("svcrdma: header too short = %d\n", rq_arg->len);
149 return -EINVAL;
150
151out_version:
152 dprintk("svcrdma: bad xprt version: %u\n",
153 be32_to_cpup(rdma_argp + 1));
154 return -EPROTONOSUPPORT;
155
156out_drop:
157 dprintk("svcrdma: dropping RDMA_DONE/ERROR message\n");
158 return 0;
159
160out_proc:
161 dprintk("svcrdma: bad rdma procedure (%u)\n",
162 be32_to_cpup(rdma_argp + 3));
163 return -EINVAL;
164
165out_inval:
166 dprintk("svcrdma: failed to parse transport header\n");
167 return -EINVAL;
242} 168}
243 169
244int svc_rdma_xdr_encode_error(struct svcxprt_rdma *xprt, 170int svc_rdma_xdr_encode_error(struct svcxprt_rdma *xprt,