diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/sunrpc/clnt.c | 29 | ||||
| -rw-r--r-- | net/sunrpc/xprtsock.c | 28 |
2 files changed, 38 insertions, 19 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index dab09dac8fc7..f09b7db2c492 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -750,14 +750,16 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client); | |||
| 750 | /* | 750 | /* |
| 751 | * Free an RPC client | 751 | * Free an RPC client |
| 752 | */ | 752 | */ |
| 753 | static void | 753 | static struct rpc_clnt * |
| 754 | rpc_free_client(struct rpc_clnt *clnt) | 754 | rpc_free_client(struct rpc_clnt *clnt) |
| 755 | { | 755 | { |
| 756 | struct rpc_clnt *parent = NULL; | ||
| 757 | |||
| 756 | dprintk_rcu("RPC: destroying %s client for %s\n", | 758 | dprintk_rcu("RPC: destroying %s client for %s\n", |
| 757 | clnt->cl_program->name, | 759 | clnt->cl_program->name, |
| 758 | rcu_dereference(clnt->cl_xprt)->servername); | 760 | rcu_dereference(clnt->cl_xprt)->servername); |
| 759 | if (clnt->cl_parent != clnt) | 761 | if (clnt->cl_parent != clnt) |
| 760 | rpc_release_client(clnt->cl_parent); | 762 | parent = clnt->cl_parent; |
| 761 | rpc_clnt_remove_pipedir(clnt); | 763 | rpc_clnt_remove_pipedir(clnt); |
| 762 | rpc_unregister_client(clnt); | 764 | rpc_unregister_client(clnt); |
| 763 | rpc_free_iostats(clnt->cl_metrics); | 765 | rpc_free_iostats(clnt->cl_metrics); |
| @@ -766,18 +768,17 @@ rpc_free_client(struct rpc_clnt *clnt) | |||
| 766 | rpciod_down(); | 768 | rpciod_down(); |
| 767 | rpc_free_clid(clnt); | 769 | rpc_free_clid(clnt); |
| 768 | kfree(clnt); | 770 | kfree(clnt); |
| 771 | return parent; | ||
| 769 | } | 772 | } |
| 770 | 773 | ||
| 771 | /* | 774 | /* |
| 772 | * Free an RPC client | 775 | * Free an RPC client |
| 773 | */ | 776 | */ |
| 774 | static void | 777 | static struct rpc_clnt * |
| 775 | rpc_free_auth(struct rpc_clnt *clnt) | 778 | rpc_free_auth(struct rpc_clnt *clnt) |
| 776 | { | 779 | { |
| 777 | if (clnt->cl_auth == NULL) { | 780 | if (clnt->cl_auth == NULL) |
| 778 | rpc_free_client(clnt); | 781 | return rpc_free_client(clnt); |
| 779 | return; | ||
| 780 | } | ||
| 781 | 782 | ||
| 782 | /* | 783 | /* |
| 783 | * Note: RPCSEC_GSS may need to send NULL RPC calls in order to | 784 | * Note: RPCSEC_GSS may need to send NULL RPC calls in order to |
| @@ -788,7 +789,8 @@ rpc_free_auth(struct rpc_clnt *clnt) | |||
| 788 | rpcauth_release(clnt->cl_auth); | 789 | rpcauth_release(clnt->cl_auth); |
| 789 | clnt->cl_auth = NULL; | 790 | clnt->cl_auth = NULL; |
| 790 | if (atomic_dec_and_test(&clnt->cl_count)) | 791 | if (atomic_dec_and_test(&clnt->cl_count)) |
| 791 | rpc_free_client(clnt); | 792 | return rpc_free_client(clnt); |
| 793 | return NULL; | ||
| 792 | } | 794 | } |
| 793 | 795 | ||
| 794 | /* | 796 | /* |
| @@ -799,10 +801,13 @@ rpc_release_client(struct rpc_clnt *clnt) | |||
| 799 | { | 801 | { |
| 800 | dprintk("RPC: rpc_release_client(%p)\n", clnt); | 802 | dprintk("RPC: rpc_release_client(%p)\n", clnt); |
| 801 | 803 | ||
| 802 | if (list_empty(&clnt->cl_tasks)) | 804 | do { |
| 803 | wake_up(&destroy_wait); | 805 | if (list_empty(&clnt->cl_tasks)) |
| 804 | if (atomic_dec_and_test(&clnt->cl_count)) | 806 | wake_up(&destroy_wait); |
| 805 | rpc_free_auth(clnt); | 807 | if (!atomic_dec_and_test(&clnt->cl_count)) |
| 808 | break; | ||
| 809 | clnt = rpc_free_auth(clnt); | ||
| 810 | } while (clnt != NULL); | ||
| 806 | } | 811 | } |
| 807 | EXPORT_SYMBOL_GPL(rpc_release_client); | 812 | EXPORT_SYMBOL_GPL(rpc_release_client); |
| 808 | 813 | ||
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 17c88928b7db..dd9d295813cf 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -393,8 +393,10 @@ static int xs_send_kvec(struct socket *sock, struct sockaddr *addr, int addrlen, | |||
| 393 | return kernel_sendmsg(sock, &msg, NULL, 0, 0); | 393 | return kernel_sendmsg(sock, &msg, NULL, 0, 0); |
| 394 | } | 394 | } |
| 395 | 395 | ||
| 396 | static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned int base, int more) | 396 | static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned int base, int more, bool zerocopy) |
| 397 | { | 397 | { |
| 398 | ssize_t (*do_sendpage)(struct socket *sock, struct page *page, | ||
| 399 | int offset, size_t size, int flags); | ||
| 398 | struct page **ppage; | 400 | struct page **ppage; |
| 399 | unsigned int remainder; | 401 | unsigned int remainder; |
| 400 | int err, sent = 0; | 402 | int err, sent = 0; |
| @@ -403,6 +405,9 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i | |||
| 403 | base += xdr->page_base; | 405 | base += xdr->page_base; |
| 404 | ppage = xdr->pages + (base >> PAGE_SHIFT); | 406 | ppage = xdr->pages + (base >> PAGE_SHIFT); |
| 405 | base &= ~PAGE_MASK; | 407 | base &= ~PAGE_MASK; |
| 408 | do_sendpage = sock->ops->sendpage; | ||
| 409 | if (!zerocopy) | ||
| 410 | do_sendpage = sock_no_sendpage; | ||
| 406 | for(;;) { | 411 | for(;;) { |
| 407 | unsigned int len = min_t(unsigned int, PAGE_SIZE - base, remainder); | 412 | unsigned int len = min_t(unsigned int, PAGE_SIZE - base, remainder); |
| 408 | int flags = XS_SENDMSG_FLAGS; | 413 | int flags = XS_SENDMSG_FLAGS; |
| @@ -410,7 +415,7 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i | |||
| 410 | remainder -= len; | 415 | remainder -= len; |
| 411 | if (remainder != 0 || more) | 416 | if (remainder != 0 || more) |
| 412 | flags |= MSG_MORE; | 417 | flags |= MSG_MORE; |
| 413 | err = sock->ops->sendpage(sock, *ppage, base, len, flags); | 418 | err = do_sendpage(sock, *ppage, base, len, flags); |
| 414 | if (remainder == 0 || err != len) | 419 | if (remainder == 0 || err != len) |
| 415 | break; | 420 | break; |
| 416 | sent += err; | 421 | sent += err; |
| @@ -431,9 +436,10 @@ static int xs_send_pagedata(struct socket *sock, struct xdr_buf *xdr, unsigned i | |||
| 431 | * @addrlen: UDP only -- length of destination address | 436 | * @addrlen: UDP only -- length of destination address |
| 432 | * @xdr: buffer containing this request | 437 | * @xdr: buffer containing this request |
| 433 | * @base: starting position in the buffer | 438 | * @base: starting position in the buffer |
| 439 | * @zerocopy: true if it is safe to use sendpage() | ||
| 434 | * | 440 | * |
| 435 | */ | 441 | */ |
| 436 | static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base) | 442 | static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, struct xdr_buf *xdr, unsigned int base, bool zerocopy) |
| 437 | { | 443 | { |
| 438 | unsigned int remainder = xdr->len - base; | 444 | unsigned int remainder = xdr->len - base; |
| 439 | int err, sent = 0; | 445 | int err, sent = 0; |
| @@ -461,7 +467,7 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen, | |||
| 461 | if (base < xdr->page_len) { | 467 | if (base < xdr->page_len) { |
| 462 | unsigned int len = xdr->page_len - base; | 468 | unsigned int len = xdr->page_len - base; |
| 463 | remainder -= len; | 469 | remainder -= len; |
| 464 | err = xs_send_pagedata(sock, xdr, base, remainder != 0); | 470 | err = xs_send_pagedata(sock, xdr, base, remainder != 0, zerocopy); |
| 465 | if (remainder == 0 || err != len) | 471 | if (remainder == 0 || err != len) |
| 466 | goto out; | 472 | goto out; |
| 467 | sent += err; | 473 | sent += err; |
| @@ -564,7 +570,7 @@ static int xs_local_send_request(struct rpc_task *task) | |||
| 564 | req->rq_svec->iov_base, req->rq_svec->iov_len); | 570 | req->rq_svec->iov_base, req->rq_svec->iov_len); |
| 565 | 571 | ||
| 566 | status = xs_sendpages(transport->sock, NULL, 0, | 572 | status = xs_sendpages(transport->sock, NULL, 0, |
| 567 | xdr, req->rq_bytes_sent); | 573 | xdr, req->rq_bytes_sent, true); |
| 568 | dprintk("RPC: %s(%u) = %d\n", | 574 | dprintk("RPC: %s(%u) = %d\n", |
| 569 | __func__, xdr->len - req->rq_bytes_sent, status); | 575 | __func__, xdr->len - req->rq_bytes_sent, status); |
| 570 | if (likely(status >= 0)) { | 576 | if (likely(status >= 0)) { |
| @@ -620,7 +626,7 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
| 620 | status = xs_sendpages(transport->sock, | 626 | status = xs_sendpages(transport->sock, |
| 621 | xs_addr(xprt), | 627 | xs_addr(xprt), |
| 622 | xprt->addrlen, xdr, | 628 | xprt->addrlen, xdr, |
| 623 | req->rq_bytes_sent); | 629 | req->rq_bytes_sent, true); |
| 624 | 630 | ||
| 625 | dprintk("RPC: xs_udp_send_request(%u) = %d\n", | 631 | dprintk("RPC: xs_udp_send_request(%u) = %d\n", |
| 626 | xdr->len - req->rq_bytes_sent, status); | 632 | xdr->len - req->rq_bytes_sent, status); |
| @@ -693,6 +699,7 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
| 693 | struct rpc_xprt *xprt = req->rq_xprt; | 699 | struct rpc_xprt *xprt = req->rq_xprt; |
| 694 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 700 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); |
| 695 | struct xdr_buf *xdr = &req->rq_snd_buf; | 701 | struct xdr_buf *xdr = &req->rq_snd_buf; |
| 702 | bool zerocopy = true; | ||
| 696 | int status; | 703 | int status; |
| 697 | 704 | ||
| 698 | xs_encode_stream_record_marker(&req->rq_snd_buf); | 705 | xs_encode_stream_record_marker(&req->rq_snd_buf); |
| @@ -700,13 +707,20 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
| 700 | xs_pktdump("packet data:", | 707 | xs_pktdump("packet data:", |
| 701 | req->rq_svec->iov_base, | 708 | req->rq_svec->iov_base, |
| 702 | req->rq_svec->iov_len); | 709 | req->rq_svec->iov_len); |
| 710 | /* Don't use zero copy if this is a resend. If the RPC call | ||
| 711 | * completes while the socket holds a reference to the pages, | ||
| 712 | * then we may end up resending corrupted data. | ||
| 713 | */ | ||
| 714 | if (task->tk_flags & RPC_TASK_SENT) | ||
| 715 | zerocopy = false; | ||
| 703 | 716 | ||
| 704 | /* Continue transmitting the packet/record. We must be careful | 717 | /* Continue transmitting the packet/record. We must be careful |
| 705 | * to cope with writespace callbacks arriving _after_ we have | 718 | * to cope with writespace callbacks arriving _after_ we have |
| 706 | * called sendmsg(). */ | 719 | * called sendmsg(). */ |
| 707 | while (1) { | 720 | while (1) { |
| 708 | status = xs_sendpages(transport->sock, | 721 | status = xs_sendpages(transport->sock, |
| 709 | NULL, 0, xdr, req->rq_bytes_sent); | 722 | NULL, 0, xdr, req->rq_bytes_sent, |
| 723 | zerocopy); | ||
| 710 | 724 | ||
| 711 | dprintk("RPC: xs_tcp_send_request(%u) = %d\n", | 725 | dprintk("RPC: xs_tcp_send_request(%u) = %d\n", |
| 712 | xdr->len - req->rq_bytes_sent, status); | 726 | xdr->len - req->rq_bytes_sent, status); |
