diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-11-12 18:04:04 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-11-19 12:03:20 -0500 |
commit | 093a1468b6edb0e568be7311b8d2228d205702db (patch) | |
tree | ab0b360d7cdea38af56ca8e2e029c1e892b29e7f /net | |
parent | 6d0ba0432a5e10bc714ba9c5adc460e726e5fbb4 (diff) |
SUNRPC: Fix locking around callback channel reply receive
Both xprt_lookup_rqst() and xprt_complete_rqst() require that you
take the transport lock in order to avoid races with xprt_transmit().
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Cc: stable@vger.kernel.org
Reviewed-by: Jeff Layton <jlayton@primarydata.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/svcsock.c | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 3f959c681885..f9c052d508f0 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -1019,17 +1019,12 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
1019 | xid = *p++; | 1019 | xid = *p++; |
1020 | calldir = *p; | 1020 | calldir = *p; |
1021 | 1021 | ||
1022 | if (bc_xprt) | 1022 | if (!bc_xprt) |
1023 | req = xprt_lookup_rqst(bc_xprt, xid); | ||
1024 | |||
1025 | if (!req) { | ||
1026 | printk(KERN_NOTICE | ||
1027 | "%s: Got unrecognized reply: " | ||
1028 | "calldir 0x%x xpt_bc_xprt %p xid %08x\n", | ||
1029 | __func__, ntohl(calldir), | ||
1030 | bc_xprt, ntohl(xid)); | ||
1031 | return -EAGAIN; | 1023 | return -EAGAIN; |
1032 | } | 1024 | spin_lock_bh(&bc_xprt->transport_lock); |
1025 | req = xprt_lookup_rqst(bc_xprt, xid); | ||
1026 | if (!req) | ||
1027 | goto unlock_notfound; | ||
1033 | 1028 | ||
1034 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf)); | 1029 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf)); |
1035 | /* | 1030 | /* |
@@ -1040,11 +1035,21 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
1040 | dst = &req->rq_private_buf.head[0]; | 1035 | dst = &req->rq_private_buf.head[0]; |
1041 | src = &rqstp->rq_arg.head[0]; | 1036 | src = &rqstp->rq_arg.head[0]; |
1042 | if (dst->iov_len < src->iov_len) | 1037 | if (dst->iov_len < src->iov_len) |
1043 | return -EAGAIN; /* whatever; just giving up. */ | 1038 | goto unlock_eagain; /* whatever; just giving up. */ |
1044 | memcpy(dst->iov_base, src->iov_base, src->iov_len); | 1039 | memcpy(dst->iov_base, src->iov_base, src->iov_len); |
1045 | xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); | 1040 | xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); |
1046 | rqstp->rq_arg.len = 0; | 1041 | rqstp->rq_arg.len = 0; |
1042 | spin_unlock_bh(&bc_xprt->transport_lock); | ||
1047 | return 0; | 1043 | return 0; |
1044 | unlock_notfound: | ||
1045 | printk(KERN_NOTICE | ||
1046 | "%s: Got unrecognized reply: " | ||
1047 | "calldir 0x%x xpt_bc_xprt %p xid %08x\n", | ||
1048 | __func__, ntohl(calldir), | ||
1049 | bc_xprt, ntohl(xid)); | ||
1050 | unlock_eagain: | ||
1051 | spin_unlock_bh(&bc_xprt->transport_lock); | ||
1052 | return -EAGAIN; | ||
1048 | } | 1053 | } |
1049 | 1054 | ||
1050 | static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) | 1055 | static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) |