aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/xprtsock.c
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@hammerspace.com>2019-02-15 18:14:27 -0500
committerTrond Myklebust <trond.myklebust@hammerspace.com>2019-02-20 17:35:58 -0500
commite92053a52e68b841d1314ca04da7cbeb326ee1a0 (patch)
tree799a6840f095d2e0fae643f5095df742db20a021 /net/sunrpc/xprtsock.c
parentae0535515161d3a131f2acabb7b883e3f3d45235 (diff)
SUNRPC: Handle zero length fragments correctly
A zero length fragment is really a bug, but let's ensure we don't go nuts when one turns up. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Diffstat (limited to 'net/sunrpc/xprtsock.c')
-rw-r--r--net/sunrpc/xprtsock.c43
1 files changed, 29 insertions, 14 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index ec0bb153c140..492cec3f1451 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -405,8 +405,8 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
405 size_t want, seek_init = seek, offset = 0; 405 size_t want, seek_init = seek, offset = 0;
406 ssize_t ret; 406 ssize_t ret;
407 407
408 if (seek < buf->head[0].iov_len) { 408 want = min_t(size_t, count, buf->head[0].iov_len);
409 want = min_t(size_t, count, buf->head[0].iov_len); 409 if (seek < want) {
410 ret = xs_read_kvec(sock, msg, flags, &buf->head[0], want, seek); 410 ret = xs_read_kvec(sock, msg, flags, &buf->head[0], want, seek);
411 if (ret <= 0) 411 if (ret <= 0)
412 goto sock_err; 412 goto sock_err;
@@ -417,8 +417,8 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
417 goto out; 417 goto out;
418 seek = 0; 418 seek = 0;
419 } else { 419 } else {
420 seek -= buf->head[0].iov_len; 420 seek -= want;
421 offset += buf->head[0].iov_len; 421 offset += want;
422 } 422 }
423 423
424 want = xs_alloc_sparse_pages(buf, 424 want = xs_alloc_sparse_pages(buf,
@@ -443,8 +443,8 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
443 offset += want; 443 offset += want;
444 } 444 }
445 445
446 if (seek < buf->tail[0].iov_len) { 446 want = min_t(size_t, count - offset, buf->tail[0].iov_len);
447 want = min_t(size_t, count - offset, buf->tail[0].iov_len); 447 if (seek < want) {
448 ret = xs_read_kvec(sock, msg, flags, &buf->tail[0], want, seek); 448 ret = xs_read_kvec(sock, msg, flags, &buf->tail[0], want, seek);
449 if (ret <= 0) 449 if (ret <= 0)
450 goto sock_err; 450 goto sock_err;
@@ -454,7 +454,7 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
454 if (ret != want) 454 if (ret != want)
455 goto out; 455 goto out;
456 } else 456 } else
457 offset += buf->tail[0].iov_len; 457 offset = seek_init;
458 ret = -EMSGSIZE; 458 ret = -EMSGSIZE;
459out: 459out:
460 *read = offset - seek_init; 460 *read = offset - seek_init;
@@ -482,6 +482,14 @@ xs_read_stream_request_done(struct sock_xprt *transport)
482 return transport->recv.fraghdr & cpu_to_be32(RPC_LAST_STREAM_FRAGMENT); 482 return transport->recv.fraghdr & cpu_to_be32(RPC_LAST_STREAM_FRAGMENT);
483} 483}
484 484
485static void
486xs_read_stream_check_eor(struct sock_xprt *transport,
487 struct msghdr *msg)
488{
489 if (xs_read_stream_request_done(transport))
490 msg->msg_flags |= MSG_EOR;
491}
492
485static ssize_t 493static ssize_t
486xs_read_stream_request(struct sock_xprt *transport, struct msghdr *msg, 494xs_read_stream_request(struct sock_xprt *transport, struct msghdr *msg,
487 int flags, struct rpc_rqst *req) 495 int flags, struct rpc_rqst *req)
@@ -493,17 +501,24 @@ xs_read_stream_request(struct sock_xprt *transport, struct msghdr *msg,
493 xs_read_header(transport, buf); 501 xs_read_header(transport, buf);
494 502
495 want = transport->recv.len - transport->recv.offset; 503 want = transport->recv.len - transport->recv.offset;
496 ret = xs_read_xdr_buf(transport->sock, msg, flags, buf, 504 if (want != 0) {
497 transport->recv.copied + want, transport->recv.copied, 505 ret = xs_read_xdr_buf(transport->sock, msg, flags, buf,
498 &read); 506 transport->recv.copied + want,
499 transport->recv.offset += read; 507 transport->recv.copied,
500 transport->recv.copied += read; 508 &read);
509 transport->recv.offset += read;
510 transport->recv.copied += read;
511 } else
512 read = 0;
513
501 if (transport->recv.offset == transport->recv.len) { 514 if (transport->recv.offset == transport->recv.len) {
502 if (xs_read_stream_request_done(transport)) 515 xs_read_stream_check_eor(transport, msg);
503 msg->msg_flags |= MSG_EOR;
504 return read; 516 return read;
505 } 517 }
506 518
519 if (want == 0)
520 return 0;
521
507 switch (ret) { 522 switch (ret) {
508 default: 523 default:
509 break; 524 break;