diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-16 15:28:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-16 15:28:18 -0400 |
commit | 465c209db83e2cdaeb4a52f4e107a9fc636704db (patch) | |
tree | 626cf4c456967059cac08b3297afc58e794fe61d | |
parent | a9c55d58bc36b5a0ef7021772fc2508e693ed534 (diff) | |
parent | 5e3863fd597eba8c6679de805681631b1aad9bdb (diff) |
Merge tag 'nfs-for-5.1-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust:
"Highlights include:
Bugfixes:
- Fix an Oops in SUNRPC back channel tracepoints
- Fix a SUNRPC client regression when handling oversized replies
- Fix the minimal size for SUNRPC reply buffer allocation
- rpc_decode_header() must always return a non-zero value on error
- Fix a typo in pnfs_update_layout()
Cleanup:
- Remove redundant check for the reply length in call_decode()"
* tag 'nfs-for-5.1-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
SUNRPC: Remove redundant check for the reply length in call_decode()
SUNRPC: Handle the SYSTEM_ERR rpc error
SUNRPC: rpc_decode_header() must always return a non-zero value on error
SUNRPC: Use the ENOTCONN error on socket disconnect
SUNRPC: Fix the minimal size for reply buffer allocation
SUNRPC: Fix a client regression when handling oversized replies
pNFS: Fix a typo in pnfs_update_layout
fix null pointer deref in tracepoints in back channel
-rw-r--r-- | fs/nfs/pnfs.c | 2 | ||||
-rw-r--r-- | include/trace/events/sunrpc.h | 6 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 32 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 2 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 2 |
5 files changed, 21 insertions, 23 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 8247bd1634cb..7066cd7c7aff 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1889,7 +1889,7 @@ lookup_again: | |||
1889 | atomic_read(&lo->plh_outstanding) != 0) { | 1889 | atomic_read(&lo->plh_outstanding) != 0) { |
1890 | spin_unlock(&ino->i_lock); | 1890 | spin_unlock(&ino->i_lock); |
1891 | lseg = ERR_PTR(wait_var_event_killable(&lo->plh_outstanding, | 1891 | lseg = ERR_PTR(wait_var_event_killable(&lo->plh_outstanding, |
1892 | atomic_read(&lo->plh_outstanding))); | 1892 | !atomic_read(&lo->plh_outstanding))); |
1893 | if (IS_ERR(lseg) || !list_empty(&lo->plh_segs)) | 1893 | if (IS_ERR(lseg) || !list_empty(&lo->plh_segs)) |
1894 | goto out_put_layout_hdr; | 1894 | goto out_put_layout_hdr; |
1895 | pnfs_put_layout_hdr(lo); | 1895 | pnfs_put_layout_hdr(lo); |
diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index 8451f30c6a0f..7e899e635d33 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h | |||
@@ -712,7 +712,8 @@ TRACE_EVENT(xprt_transmit, | |||
712 | 712 | ||
713 | TP_fast_assign( | 713 | TP_fast_assign( |
714 | __entry->task_id = rqst->rq_task->tk_pid; | 714 | __entry->task_id = rqst->rq_task->tk_pid; |
715 | __entry->client_id = rqst->rq_task->tk_client->cl_clid; | 715 | __entry->client_id = rqst->rq_task->tk_client ? |
716 | rqst->rq_task->tk_client->cl_clid : -1; | ||
716 | __entry->xid = be32_to_cpu(rqst->rq_xid); | 717 | __entry->xid = be32_to_cpu(rqst->rq_xid); |
717 | __entry->seqno = rqst->rq_seqno; | 718 | __entry->seqno = rqst->rq_seqno; |
718 | __entry->status = status; | 719 | __entry->status = status; |
@@ -742,7 +743,8 @@ TRACE_EVENT(xprt_enq_xmit, | |||
742 | 743 | ||
743 | TP_fast_assign( | 744 | TP_fast_assign( |
744 | __entry->task_id = task->tk_pid; | 745 | __entry->task_id = task->tk_pid; |
745 | __entry->client_id = task->tk_client->cl_clid; | 746 | __entry->client_id = task->tk_client ? |
747 | task->tk_client->cl_clid : -1; | ||
746 | __entry->xid = be32_to_cpu(task->tk_rqstp->rq_xid); | 748 | __entry->xid = be32_to_cpu(task->tk_rqstp->rq_xid); |
747 | __entry->seqno = task->tk_rqstp->rq_seqno; | 749 | __entry->seqno = task->tk_rqstp->rq_seqno; |
748 | __entry->stage = stage; | 750 | __entry->stage = stage; |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 4216fe33204a..228970e6e52b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -1730,7 +1730,12 @@ call_allocate(struct rpc_task *task) | |||
1730 | req->rq_callsize = RPC_CALLHDRSIZE + (auth->au_cslack << 1) + | 1730 | req->rq_callsize = RPC_CALLHDRSIZE + (auth->au_cslack << 1) + |
1731 | proc->p_arglen; | 1731 | proc->p_arglen; |
1732 | req->rq_callsize <<= 2; | 1732 | req->rq_callsize <<= 2; |
1733 | req->rq_rcvsize = RPC_REPHDRSIZE + auth->au_rslack + proc->p_replen; | 1733 | /* |
1734 | * Note: the reply buffer must at minimum allocate enough space | ||
1735 | * for the 'struct accepted_reply' from RFC5531. | ||
1736 | */ | ||
1737 | req->rq_rcvsize = RPC_REPHDRSIZE + auth->au_rslack + \ | ||
1738 | max_t(size_t, proc->p_replen, 2); | ||
1734 | req->rq_rcvsize <<= 2; | 1739 | req->rq_rcvsize <<= 2; |
1735 | 1740 | ||
1736 | status = xprt->ops->buf_alloc(task); | 1741 | status = xprt->ops->buf_alloc(task); |
@@ -2387,9 +2392,6 @@ call_decode(struct rpc_task *task) | |||
2387 | WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf, | 2392 | WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf, |
2388 | sizeof(req->rq_rcv_buf)) != 0); | 2393 | sizeof(req->rq_rcv_buf)) != 0); |
2389 | 2394 | ||
2390 | if (req->rq_rcv_buf.len < 12) | ||
2391 | goto out_retry; | ||
2392 | |||
2393 | xdr_init_decode(&xdr, &req->rq_rcv_buf, | 2395 | xdr_init_decode(&xdr, &req->rq_rcv_buf, |
2394 | req->rq_rcv_buf.head[0].iov_base, req); | 2396 | req->rq_rcv_buf.head[0].iov_base, req); |
2395 | switch (rpc_decode_header(task, &xdr)) { | 2397 | switch (rpc_decode_header(task, &xdr)) { |
@@ -2400,7 +2402,6 @@ call_decode(struct rpc_task *task) | |||
2400 | task->tk_pid, __func__, task->tk_status); | 2402 | task->tk_pid, __func__, task->tk_status); |
2401 | return; | 2403 | return; |
2402 | case -EAGAIN: | 2404 | case -EAGAIN: |
2403 | out_retry: | ||
2404 | task->tk_status = 0; | 2405 | task->tk_status = 0; |
2405 | /* Note: rpc_decode_header() may have freed the RPC slot */ | 2406 | /* Note: rpc_decode_header() may have freed the RPC slot */ |
2406 | if (task->tk_rqstp == req) { | 2407 | if (task->tk_rqstp == req) { |
@@ -2449,7 +2450,7 @@ static noinline int | |||
2449 | rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr) | 2450 | rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr) |
2450 | { | 2451 | { |
2451 | struct rpc_clnt *clnt = task->tk_client; | 2452 | struct rpc_clnt *clnt = task->tk_client; |
2452 | int error = -EACCES; | 2453 | int error; |
2453 | __be32 *p; | 2454 | __be32 *p; |
2454 | 2455 | ||
2455 | /* RFC-1014 says that the representation of XDR data must be a | 2456 | /* RFC-1014 says that the representation of XDR data must be a |
@@ -2458,7 +2459,7 @@ rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr) | |||
2458 | * undefined results | 2459 | * undefined results |
2459 | */ | 2460 | */ |
2460 | if (task->tk_rqstp->rq_rcv_buf.len & 3) | 2461 | if (task->tk_rqstp->rq_rcv_buf.len & 3) |
2461 | goto out_badlen; | 2462 | goto out_unparsable; |
2462 | 2463 | ||
2463 | p = xdr_inline_decode(xdr, 3 * sizeof(*p)); | 2464 | p = xdr_inline_decode(xdr, 3 * sizeof(*p)); |
2464 | if (!p) | 2465 | if (!p) |
@@ -2492,10 +2493,12 @@ rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr) | |||
2492 | error = -EOPNOTSUPP; | 2493 | error = -EOPNOTSUPP; |
2493 | goto out_err; | 2494 | goto out_err; |
2494 | case rpc_garbage_args: | 2495 | case rpc_garbage_args: |
2496 | case rpc_system_err: | ||
2495 | trace_rpc__garbage_args(task); | 2497 | trace_rpc__garbage_args(task); |
2498 | error = -EIO; | ||
2496 | break; | 2499 | break; |
2497 | default: | 2500 | default: |
2498 | trace_rpc__unparsable(task); | 2501 | goto out_unparsable; |
2499 | } | 2502 | } |
2500 | 2503 | ||
2501 | out_garbage: | 2504 | out_garbage: |
@@ -2509,11 +2512,6 @@ out_err: | |||
2509 | rpc_exit(task, error); | 2512 | rpc_exit(task, error); |
2510 | return error; | 2513 | return error; |
2511 | 2514 | ||
2512 | out_badlen: | ||
2513 | trace_rpc__unparsable(task); | ||
2514 | error = -EIO; | ||
2515 | goto out_err; | ||
2516 | |||
2517 | out_unparsable: | 2515 | out_unparsable: |
2518 | trace_rpc__unparsable(task); | 2516 | trace_rpc__unparsable(task); |
2519 | error = -EIO; | 2517 | error = -EIO; |
@@ -2524,6 +2522,7 @@ out_verifier: | |||
2524 | goto out_garbage; | 2522 | goto out_garbage; |
2525 | 2523 | ||
2526 | out_msg_denied: | 2524 | out_msg_denied: |
2525 | error = -EACCES; | ||
2527 | p = xdr_inline_decode(xdr, sizeof(*p)); | 2526 | p = xdr_inline_decode(xdr, sizeof(*p)); |
2528 | if (!p) | 2527 | if (!p) |
2529 | goto out_unparsable; | 2528 | goto out_unparsable; |
@@ -2535,9 +2534,7 @@ out_msg_denied: | |||
2535 | error = -EPROTONOSUPPORT; | 2534 | error = -EPROTONOSUPPORT; |
2536 | goto out_err; | 2535 | goto out_err; |
2537 | default: | 2536 | default: |
2538 | trace_rpc__unparsable(task); | 2537 | goto out_unparsable; |
2539 | error = -EIO; | ||
2540 | goto out_err; | ||
2541 | } | 2538 | } |
2542 | 2539 | ||
2543 | p = xdr_inline_decode(xdr, sizeof(*p)); | 2540 | p = xdr_inline_decode(xdr, sizeof(*p)); |
@@ -2572,8 +2569,7 @@ out_msg_denied: | |||
2572 | task->tk_xprt->servername); | 2569 | task->tk_xprt->servername); |
2573 | break; | 2570 | break; |
2574 | default: | 2571 | default: |
2575 | trace_rpc__unparsable(task); | 2572 | goto out_unparsable; |
2576 | error = -EIO; | ||
2577 | } | 2573 | } |
2578 | goto out_err; | 2574 | goto out_err; |
2579 | } | 2575 | } |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index e096c5a725df..d7117d241460 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -664,7 +664,7 @@ void xprt_disconnect_done(struct rpc_xprt *xprt) | |||
664 | spin_lock_bh(&xprt->transport_lock); | 664 | spin_lock_bh(&xprt->transport_lock); |
665 | xprt_clear_connected(xprt); | 665 | xprt_clear_connected(xprt); |
666 | xprt_clear_write_space_locked(xprt); | 666 | xprt_clear_write_space_locked(xprt); |
667 | xprt_wake_pending_tasks(xprt, -EAGAIN); | 667 | xprt_wake_pending_tasks(xprt, -ENOTCONN); |
668 | spin_unlock_bh(&xprt->transport_lock); | 668 | spin_unlock_bh(&xprt->transport_lock); |
669 | } | 669 | } |
670 | EXPORT_SYMBOL_GPL(xprt_disconnect_done); | 670 | EXPORT_SYMBOL_GPL(xprt_disconnect_done); |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 42f45d33dc56..9359539907ba 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -453,7 +453,7 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, | |||
453 | goto out; | 453 | goto out; |
454 | if (ret != want) | 454 | if (ret != want) |
455 | goto out; | 455 | goto out; |
456 | } else | 456 | } else if (offset < seek_init) |
457 | offset = seek_init; | 457 | offset = seek_init; |
458 | ret = -EMSGSIZE; | 458 | ret = -EMSGSIZE; |
459 | out: | 459 | out: |