diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2019-02-15 18:14:27 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@hammerspace.com> | 2019-02-20 17:35:58 -0500 |
commit | e92053a52e68b841d1314ca04da7cbeb326ee1a0 (patch) | |
tree | 799a6840f095d2e0fae643f5095df742db20a021 /net/sunrpc/xprtsock.c | |
parent | ae0535515161d3a131f2acabb7b883e3f3d45235 (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.c | 43 |
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; |
459 | out: | 459 | out: |
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 | ||
485 | static void | ||
486 | xs_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 | |||
485 | static ssize_t | 493 | static ssize_t |
486 | xs_read_stream_request(struct sock_xprt *transport, struct msghdr *msg, | 494 | xs_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; |