diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2015-01-13 11:03:28 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2015-01-15 15:01:47 -0500 |
commit | 61edbcb7c7f4efb65df4ad793d007237f9fa311f (patch) | |
tree | fc0bc3b1ff1b5f1ad72bda0f4165faecb418c1e7 /net | |
parent | e54524111f51eac1900cf91aca3d38a92a6b11c0 (diff) |
svcrdma: rc_position sanity checking
An RPC/RDMA client may send large RPC arguments via a read
list. This is a list of scatter/gather elements which convey
RPC call arguments too large to fit in a small RDMA SEND.
Each entry in the read list has a "position" field, whose value is
the byte offset in the XDR stream where the data in that entry is to
be inserted. Entries which share the same "position" value make up
the same RPC argument. The receiver inserts entries with the same
position field value in list order into the XDR stream.
Currently the Linux NFS/RDMA server cannot handle receiving read
chunks in more than one position, mostly because no current client
sends read lists with elements in more than one position. As a
sanity check, ensure that all received chunks have the same
"rc_position."
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index c3aebc1bf0a6..a67dd1a081dd 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | |||
@@ -365,6 +365,7 @@ static int rdma_read_chunks(struct svcxprt_rdma *xprt, | |||
365 | int page_no, ret; | 365 | int page_no, ret; |
366 | struct rpcrdma_read_chunk *ch; | 366 | struct rpcrdma_read_chunk *ch; |
367 | u32 handle, page_offset, byte_count; | 367 | u32 handle, page_offset, byte_count; |
368 | u32 position; | ||
368 | u64 rs_offset; | 369 | u64 rs_offset; |
369 | bool last; | 370 | bool last; |
370 | 371 | ||
@@ -389,10 +390,17 @@ static int rdma_read_chunks(struct svcxprt_rdma *xprt, | |||
389 | head->arg.len = rqstp->rq_arg.len; | 390 | head->arg.len = rqstp->rq_arg.len; |
390 | head->arg.buflen = rqstp->rq_arg.buflen; | 391 | head->arg.buflen = rqstp->rq_arg.buflen; |
391 | 392 | ||
392 | page_no = 0; page_offset = 0; | 393 | ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0]; |
393 | for (ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0]; | 394 | position = be32_to_cpu(ch->rc_position); |
394 | ch->rc_discrim != 0; ch++) { | 395 | |
395 | handle = be32_to_cpu(ch->rc_target.rs_handle); | 396 | ret = 0; |
397 | page_no = 0; | ||
398 | page_offset = 0; | ||
399 | for (; ch->rc_discrim != xdr_zero; ch++) { | ||
400 | if (be32_to_cpu(ch->rc_position) != position) | ||
401 | goto err; | ||
402 | |||
403 | handle = be32_to_cpu(ch->rc_target.rs_handle), | ||
396 | byte_count = be32_to_cpu(ch->rc_target.rs_length); | 404 | byte_count = be32_to_cpu(ch->rc_target.rs_length); |
397 | xdr_decode_hyper((__be32 *)&ch->rc_target.rs_offset, | 405 | xdr_decode_hyper((__be32 *)&ch->rc_target.rs_offset, |
398 | &rs_offset); | 406 | &rs_offset); |