Skip to content

Commit 647e18e

Browse files
chuckleverJ. Bruce Fields
authored andcommitted
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>
1 parent 98fc21d commit 647e18e

File tree

1 file changed

+79
-153
lines changed

1 file changed

+79
-153
lines changed

net/sunrpc/xprtrdma/svc_rdma_marshal.c

Lines changed: 79 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/*
2+
* Copyright (c) 2016 Oracle. All rights reserved.
23
* Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved.
34
*
45
* This software is available to you under a choice of one of two
@@ -47,102 +48,43 @@
4748

4849
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
4950

50-
/*
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-
*/
58-
static __be32 *decode_read_list(__be32 *va, __be32 *vaend)
51+
static __be32 *xdr_check_read_list(__be32 *p, __be32 *end)
5952
{
60-
struct rpcrdma_read_chunk *ch = (struct rpcrdma_read_chunk *)va;
53+
__be32 *next;
6154

62-
while (ch->rc_discrim != xdr_zero) {
63-
if (((unsigned long)ch + sizeof(struct rpcrdma_read_chunk)) >
64-
(unsigned long)vaend) {
65-
dprintk("svcrdma: vaend=%p, ch=%p\n", vaend, ch);
55+
while (*p++ != xdr_zero) {
56+
next = p + rpcrdma_readchunk_maxsz - 1;
57+
if (next > end)
6658
return NULL;
67-
}
68-
ch++;
59+
p = next;
6960
}
70-
return &ch->rc_position;
61+
return p;
7162
}
7263

73-
/*
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-
*/
83-
static __be32 *decode_write_list(__be32 *va, __be32 *vaend)
64+
static __be32 *xdr_check_write_list(__be32 *p, __be32 *end)
8465
{
85-
unsigned long start, end;
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;
66+
__be32 *next;
9467

95-
if ((unsigned long)ary + sizeof(struct rpcrdma_write_array) >
96-
(unsigned long)vaend) {
97-
dprintk("svcrdma: ary=%p, vaend=%p\n", ary, vaend);
98-
return NULL;
99-
}
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;
68+
while (*p++ != xdr_zero) {
69+
next = p + 1 + be32_to_cpup(p) * rpcrdma_segment_maxsz;
70+
if (next > end)
71+
return NULL;
72+
p = next;
11073
}
111-
/*
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;
74+
return p;
11675
}
11776

118-
static __be32 *decode_reply_array(__be32 *va, __be32 *vaend)
77+
static __be32 *xdr_check_reply_chunk(__be32 *p, __be32 *end)
11978
{
120-
unsigned long start, end;
121-
int nchunks;
122-
struct rpcrdma_write_array *ary =
123-
(struct rpcrdma_write_array *)va;
124-
125-
/* Check for no reply-array */
126-
if (ary->wc_discrim == xdr_zero)
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;
79+
__be32 *next;
80+
81+
if (*p++ != xdr_zero) {
82+
next = p + 1 + be32_to_cpup(p) * rpcrdma_segment_maxsz;
83+
if (next > end)
84+
return NULL;
85+
p = next;
14486
}
145-
return (__be32 *)&ary->wc_array[nchunks];
87+
return p;
14688
}
14789

14890
/**
@@ -158,87 +100,71 @@ static __be32 *decode_reply_array(__be32 *va, __be32 *vaend)
158100
*/
159101
int svc_rdma_xdr_decode_req(struct xdr_buf *rq_arg)
160102
{
161-
struct rpcrdma_msg *rmsgp;
162-
__be32 *va, *vaend;
163-
unsigned int len;
164-
u32 hdr_len;
103+
__be32 *p, *end, *rdma_argp;
104+
unsigned int hdr_len;
165105

166106
/* Verify that there's enough bytes for header + something */
167-
if (rq_arg->len <= RPCRDMA_HDRLEN_ERR) {
168-
dprintk("svcrdma: header too short = %d\n",
169-
rq_arg->len);
170-
return -EINVAL;
171-
}
107+
if (rq_arg->len <= RPCRDMA_HDRLEN_ERR)
108+
goto out_short;
172109

173-
rmsgp = (struct rpcrdma_msg *)rq_arg->head[0].iov_base;
174-
if (rmsgp->rm_vers != rpcrdma_version) {
175-
dprintk("%s: bad version %u\n", __func__,
176-
be32_to_cpu(rmsgp->rm_vers));
177-
return -EPROTONOSUPPORT;
178-
}
110+
rdma_argp = rq_arg->head[0].iov_base;
111+
if (*(rdma_argp + 1) != rpcrdma_version)
112+
goto out_version;
179113

180-
switch (be32_to_cpu(rmsgp->rm_type)) {
181-
case RDMA_MSG:
182-
case RDMA_NOMSG:
114+
switch (*(rdma_argp + 3)) {
115+
case rdma_msg:
116+
case rdma_nomsg:
183117
break;
184118

185-
case RDMA_DONE:
186-
/* Just drop it */
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-
}
119+
case rdma_done:
120+
goto out_drop;
216121

217-
/* The chunk list may contain either a read chunk list or a write
218-
* chunk list and a reply chunk list.
219-
*/
220-
va = &rmsgp->rm_body.rm_chunks[0];
221-
vaend = (__be32 *)((unsigned long)rmsgp + rq_arg->len);
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;
122+
case rdma_error:
123+
goto out_drop;
124+
125+
default:
126+
goto out_proc;
236127
}
237128

238-
rq_arg->head[0].iov_base = va;
239-
hdr_len = (unsigned long)va - (unsigned long)rmsgp;
129+
end = (__be32 *)((unsigned long)rdma_argp + rq_arg->len);
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;
240144
rq_arg->head[0].iov_len -= hdr_len;
241145
return hdr_len;
146+
147+
out_short:
148+
dprintk("svcrdma: header too short = %d\n", rq_arg->len);
149+
return -EINVAL;
150+
151+
out_version:
152+
dprintk("svcrdma: bad xprt version: %u\n",
153+
be32_to_cpup(rdma_argp + 1));
154+
return -EPROTONOSUPPORT;
155+
156+
out_drop:
157+
dprintk("svcrdma: dropping RDMA_DONE/ERROR message\n");
158+
return 0;
159+
160+
out_proc:
161+
dprintk("svcrdma: bad rdma procedure (%u)\n",
162+
be32_to_cpup(rdma_argp + 3));
163+
return -EINVAL;
164+
165+
out_inval:
166+
dprintk("svcrdma: failed to parse transport header\n");
167+
return -EINVAL;
242168
}
243169

244170
int svc_rdma_xdr_encode_error(struct svcxprt_rdma *xprt,

0 commit comments

Comments
 (0)