diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2016-03-01 13:06:56 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2016-03-01 16:06:40 -0500 |
commit | a0544c946dfdba9d93ad9030e7bb6db1961d45c1 (patch) | |
tree | ece78f7c4261b364bde8b5009a41992881ada3c0 | |
parent | f3ea53fb3bc3908b6e9ef39e53a75b55df7f78f8 (diff) |
svcrdma: Hook up the logic to return ERR_CHUNK
RFC 5666 Section 4.2 states:
> When the peer detects an RPC-over-RDMA header version that it does
> not support (currently this document defines only version 1), it
> replies with an error code of ERR_VERS, and provides the low and
> high inclusive version numbers it does, in fact, support.
And:
> When other decoding errors are detected in the header or chunks,
> either an RPC decode error MAY be returned or the RPC/RDMA error
> code ERR_CHUNK MUST be returned.
The Linux NFS server does throw ERR_VERS when a client sends it
a request whose rdma_version is not "one." But it does not return
ERR_CHUNK when a header decoding error occurs. It just drops the
request.
To improve protocol extensibility, it should reject invalid values
in the rdma_proc field instead of treating them all like RDMA_MSG.
Otherwise clients can't detect when the server doesn't support
new rdma_proc values.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: Devesh Sharma <devesh.sharma@broadcom.com>
Tested-by: Devesh Sharma <devesh.sharma@broadcom.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_marshal.c | 55 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 4 |
2 files changed, 46 insertions, 13 deletions
diff --git a/net/sunrpc/xprtrdma/svc_rdma_marshal.c b/net/sunrpc/xprtrdma/svc_rdma_marshal.c index b9ce01f6af90..765bca47c74d 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_marshal.c +++ b/net/sunrpc/xprtrdma/svc_rdma_marshal.c | |||
@@ -148,22 +148,41 @@ static __be32 *decode_reply_array(__be32 *va, __be32 *vaend) | |||
148 | int svc_rdma_xdr_decode_req(struct rpcrdma_msg *rmsgp, struct svc_rqst *rqstp) | 148 | int svc_rdma_xdr_decode_req(struct rpcrdma_msg *rmsgp, struct svc_rqst *rqstp) |
149 | { | 149 | { |
150 | __be32 *va, *vaend; | 150 | __be32 *va, *vaend; |
151 | unsigned int len; | ||
151 | u32 hdr_len; | 152 | u32 hdr_len; |
152 | 153 | ||
153 | /* Verify that there's enough bytes for header + something */ | 154 | /* Verify that there's enough bytes for header + something */ |
154 | if (rqstp->rq_arg.len <= RPCRDMA_HDRLEN_MIN) { | 155 | if (rqstp->rq_arg.len <= RPCRDMA_HDRLEN_ERR) { |
155 | dprintk("svcrdma: header too short = %d\n", | 156 | dprintk("svcrdma: header too short = %d\n", |
156 | rqstp->rq_arg.len); | 157 | rqstp->rq_arg.len); |
157 | return -EINVAL; | 158 | return -EINVAL; |
158 | } | 159 | } |
159 | 160 | ||
160 | if (rmsgp->rm_vers != rpcrdma_version) | 161 | if (rmsgp->rm_vers != rpcrdma_version) { |
162 | dprintk("%s: bad version %u\n", __func__, | ||
163 | be32_to_cpu(rmsgp->rm_vers)); | ||
161 | return -EPROTONOSUPPORT; | 164 | return -EPROTONOSUPPORT; |
165 | } | ||
162 | 166 | ||
163 | /* Pull in the extra for the padded case and bump our pointer */ | 167 | switch (be32_to_cpu(rmsgp->rm_type)) { |
164 | if (rmsgp->rm_type == rdma_msgp) { | 168 | case RDMA_MSG: |
165 | int hdrlen; | 169 | case RDMA_NOMSG: |
166 | 170 | break; | |
171 | |||
172 | case RDMA_DONE: | ||
173 | /* Just drop it */ | ||
174 | dprintk("svcrdma: dropping RDMA_DONE message\n"); | ||
175 | return 0; | ||
176 | |||
177 | case RDMA_ERROR: | ||
178 | /* Possible if this is a backchannel reply. | ||
179 | * XXX: We should cancel this XID, though. | ||
180 | */ | ||
181 | dprintk("svcrdma: dropping RDMA_ERROR message\n"); | ||
182 | return 0; | ||
183 | |||
184 | case RDMA_MSGP: | ||
185 | /* Pull in the extra for the padded case, bump our pointer */ | ||
167 | rmsgp->rm_body.rm_padded.rm_align = | 186 | rmsgp->rm_body.rm_padded.rm_align = |
168 | be32_to_cpu(rmsgp->rm_body.rm_padded.rm_align); | 187 | be32_to_cpu(rmsgp->rm_body.rm_padded.rm_align); |
169 | rmsgp->rm_body.rm_padded.rm_thresh = | 188 | rmsgp->rm_body.rm_padded.rm_thresh = |
@@ -171,11 +190,15 @@ int svc_rdma_xdr_decode_req(struct rpcrdma_msg *rmsgp, struct svc_rqst *rqstp) | |||
171 | 190 | ||
172 | va = &rmsgp->rm_body.rm_padded.rm_pempty[4]; | 191 | va = &rmsgp->rm_body.rm_padded.rm_pempty[4]; |
173 | rqstp->rq_arg.head[0].iov_base = va; | 192 | rqstp->rq_arg.head[0].iov_base = va; |
174 | hdrlen = (u32)((unsigned long)va - (unsigned long)rmsgp); | 193 | len = (u32)((unsigned long)va - (unsigned long)rmsgp); |
175 | rqstp->rq_arg.head[0].iov_len -= hdrlen; | 194 | rqstp->rq_arg.head[0].iov_len -= len; |
176 | if (hdrlen > rqstp->rq_arg.len) | 195 | if (len > rqstp->rq_arg.len) |
177 | return -EINVAL; | 196 | return -EINVAL; |
178 | return hdrlen; | 197 | return len; |
198 | default: | ||
199 | dprintk("svcrdma: bad rdma procedure (%u)\n", | ||
200 | be32_to_cpu(rmsgp->rm_type)); | ||
201 | return -EINVAL; | ||
179 | } | 202 | } |
180 | 203 | ||
181 | /* The chunk list may contain either a read chunk list or a write | 204 | /* The chunk list may contain either a read chunk list or a write |
@@ -184,14 +207,20 @@ int svc_rdma_xdr_decode_req(struct rpcrdma_msg *rmsgp, struct svc_rqst *rqstp) | |||
184 | va = &rmsgp->rm_body.rm_chunks[0]; | 207 | va = &rmsgp->rm_body.rm_chunks[0]; |
185 | vaend = (__be32 *)((unsigned long)rmsgp + rqstp->rq_arg.len); | 208 | vaend = (__be32 *)((unsigned long)rmsgp + rqstp->rq_arg.len); |
186 | va = decode_read_list(va, vaend); | 209 | va = decode_read_list(va, vaend); |
187 | if (!va) | 210 | if (!va) { |
211 | dprintk("svcrdma: failed to decode read list\n"); | ||
188 | return -EINVAL; | 212 | return -EINVAL; |
213 | } | ||
189 | va = decode_write_list(va, vaend); | 214 | va = decode_write_list(va, vaend); |
190 | if (!va) | 215 | if (!va) { |
216 | dprintk("svcrdma: failed to decode write list\n"); | ||
191 | return -EINVAL; | 217 | return -EINVAL; |
218 | } | ||
192 | va = decode_reply_array(va, vaend); | 219 | va = decode_reply_array(va, vaend); |
193 | if (!va) | 220 | if (!va) { |
221 | dprintk("svcrdma: failed to decode reply chunk\n"); | ||
194 | return -EINVAL; | 222 | return -EINVAL; |
223 | } | ||
195 | 224 | ||
196 | rqstp->rq_arg.head[0].iov_base = va; | 225 | rqstp->rq_arg.head[0].iov_base = va; |
197 | hdr_len = (unsigned long)va - (unsigned long)rmsgp; | 226 | hdr_len = (unsigned long)va - (unsigned long)rmsgp; |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 8f68cb6d89fe..f8b840b17c02 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | |||
@@ -657,6 +657,8 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp) | |||
657 | ret = svc_rdma_xdr_decode_req(rmsgp, rqstp); | 657 | ret = svc_rdma_xdr_decode_req(rmsgp, rqstp); |
658 | if (ret < 0) | 658 | if (ret < 0) |
659 | goto out_err; | 659 | goto out_err; |
660 | if (ret == 0) | ||
661 | goto out_drop; | ||
660 | rqstp->rq_xprt_hlen = ret; | 662 | rqstp->rq_xprt_hlen = ret; |
661 | 663 | ||
662 | if (svc_rdma_is_backchannel_reply(xprt, rmsgp)) { | 664 | if (svc_rdma_is_backchannel_reply(xprt, rmsgp)) { |
@@ -710,6 +712,8 @@ out_err: | |||
710 | defer: | 712 | defer: |
711 | return 0; | 713 | return 0; |
712 | 714 | ||
715 | out_drop: | ||
716 | svc_rdma_put_context(ctxt, 1); | ||
713 | repost: | 717 | repost: |
714 | return svc_rdma_repost_recv(rdma_xprt, GFP_KERNEL); | 718 | return svc_rdma_repost_recv(rdma_xprt, GFP_KERNEL); |
715 | } | 719 | } |