Commit 673fdfe3f0630b03f3854d0361b1232f2e5ef7fb
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
Merge tag 'nfs-for-3.13-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes: - Stable fix for data corruption when retransmitting O_DIRECT writes - Stable fix for a deep recursion/stack overflow bug in rpc_release_client - Stable fix for infinite looping when mounting a NFSv4.x volume - Fix a typo in the nfs mount option parser - Allow pNFS layouts to be compiled into the kernel when NFSv4.1 is * tag 'nfs-for-3.13-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: nfs: fix pnfs Kconfig defaults NFS: correctly report misuse of "migration" mount option. nfs: don't retry detect_trunking with RPC_AUTH_UNIX more than once SUNRPC: Avoid deep recursion in rpc_release_client SUNRPC: Fix a data corruption issue when retransmitting RPC calls
Showing 5 changed files Side-by-side Diff
fs/nfs/Kconfig
... | ... | @@ -116,17 +116,17 @@ |
116 | 116 | config PNFS_FILE_LAYOUT |
117 | 117 | tristate |
118 | 118 | depends on NFS_V4_1 |
119 | - default m | |
119 | + default NFS_V4 | |
120 | 120 | |
121 | 121 | config PNFS_BLOCK |
122 | 122 | tristate |
123 | 123 | depends on NFS_V4_1 && BLK_DEV_DM |
124 | - default m | |
124 | + default NFS_V4 | |
125 | 125 | |
126 | 126 | config PNFS_OBJLAYOUT |
127 | 127 | tristate |
128 | 128 | depends on NFS_V4_1 && SCSI_OSD_ULD |
129 | - default m | |
129 | + default NFS_V4 | |
130 | 130 | |
131 | 131 | config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN |
132 | 132 | string "NFSv4.1 Implementation ID Domain" |
fs/nfs/nfs4state.c
... | ... | @@ -2093,10 +2093,15 @@ |
2093 | 2093 | nfs4_root_machine_cred(clp); |
2094 | 2094 | goto again; |
2095 | 2095 | } |
2096 | - if (i > 2) | |
2096 | + if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX) | |
2097 | 2097 | break; |
2098 | 2098 | case -NFS4ERR_CLID_INUSE: |
2099 | 2099 | case -NFS4ERR_WRONGSEC: |
2100 | + /* No point in retrying if we already used RPC_AUTH_UNIX */ | |
2101 | + if (clnt->cl_auth->au_flavor == RPC_AUTH_UNIX) { | |
2102 | + status = -EPERM; | |
2103 | + break; | |
2104 | + } | |
2100 | 2105 | clnt = rpc_clone_client_set_auth(clnt, RPC_AUTH_UNIX); |
2101 | 2106 | if (IS_ERR(clnt)) { |
2102 | 2107 | status = PTR_ERR(clnt); |
fs/nfs/super.c
... | ... | @@ -1614,7 +1614,7 @@ |
1614 | 1614 | goto out_minorversion_mismatch; |
1615 | 1615 | |
1616 | 1616 | if (mnt->options & NFS_OPTION_MIGRATION && |
1617 | - mnt->version != 4 && mnt->minorversion != 0) | |
1617 | + (mnt->version != 4 || mnt->minorversion != 0)) | |
1618 | 1618 | goto out_migration_misuse; |
1619 | 1619 | |
1620 | 1620 | /* |
net/sunrpc/clnt.c
... | ... | @@ -750,14 +750,16 @@ |
750 | 750 | /* |
751 | 751 | * Free an RPC client |
752 | 752 | */ |
753 | -static void | |
753 | +static struct rpc_clnt * | |
754 | 754 | rpc_free_client(struct rpc_clnt *clnt) |
755 | 755 | { |
756 | + struct rpc_clnt *parent = NULL; | |
757 | + | |
756 | 758 | dprintk_rcu("RPC: destroying %s client for %s\n", |
757 | 759 | clnt->cl_program->name, |
758 | 760 | rcu_dereference(clnt->cl_xprt)->servername); |
759 | 761 | if (clnt->cl_parent != clnt) |
760 | - rpc_release_client(clnt->cl_parent); | |
762 | + parent = clnt->cl_parent; | |
761 | 763 | rpc_clnt_remove_pipedir(clnt); |
762 | 764 | rpc_unregister_client(clnt); |
763 | 765 | rpc_free_iostats(clnt->cl_metrics); |
764 | 766 | |
765 | 767 | |
... | ... | @@ -766,18 +768,17 @@ |
766 | 768 | rpciod_down(); |
767 | 769 | rpc_free_clid(clnt); |
768 | 770 | kfree(clnt); |
771 | + return parent; | |
769 | 772 | } |
770 | 773 | |
771 | 774 | /* |
772 | 775 | * Free an RPC client |
773 | 776 | */ |
774 | -static void | |
777 | +static struct rpc_clnt * | |
775 | 778 | rpc_free_auth(struct rpc_clnt *clnt) |
776 | 779 | { |
777 | - if (clnt->cl_auth == NULL) { | |
778 | - rpc_free_client(clnt); | |
779 | - return; | |
780 | - } | |
780 | + if (clnt->cl_auth == NULL) | |
781 | + return rpc_free_client(clnt); | |
781 | 782 | |
782 | 783 | /* |
783 | 784 | * Note: RPCSEC_GSS may need to send NULL RPC calls in order to |
... | ... | @@ -788,7 +789,8 @@ |
788 | 789 | rpcauth_release(clnt->cl_auth); |
789 | 790 | clnt->cl_auth = NULL; |
790 | 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 @@ |
799 | 801 | { |
800 | 802 | dprintk("RPC: rpc_release_client(%p)\n", clnt); |
801 | 803 | |
802 | - if (list_empty(&clnt->cl_tasks)) | |
803 | - wake_up(&destroy_wait); | |
804 | - if (atomic_dec_and_test(&clnt->cl_count)) | |
805 | - rpc_free_auth(clnt); | |
804 | + do { | |
805 | + if (list_empty(&clnt->cl_tasks)) | |
806 | + wake_up(&destroy_wait); | |
807 | + if (!atomic_dec_and_test(&clnt->cl_count)) | |
808 | + break; | |
809 | + clnt = rpc_free_auth(clnt); | |
810 | + } while (clnt != NULL); | |
806 | 811 | } |
807 | 812 | EXPORT_SYMBOL_GPL(rpc_release_client); |
808 | 813 |
net/sunrpc/xprtsock.c
... | ... | @@ -393,8 +393,10 @@ |
393 | 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 | 400 | struct page **ppage; |
399 | 401 | unsigned int remainder; |
400 | 402 | int err, sent = 0; |
... | ... | @@ -403,6 +405,9 @@ |
403 | 405 | base += xdr->page_base; |
404 | 406 | ppage = xdr->pages + (base >> PAGE_SHIFT); |
405 | 407 | base &= ~PAGE_MASK; |
408 | + do_sendpage = sock->ops->sendpage; | |
409 | + if (!zerocopy) | |
410 | + do_sendpage = sock_no_sendpage; | |
406 | 411 | for(;;) { |
407 | 412 | unsigned int len = min_t(unsigned int, PAGE_SIZE - base, remainder); |
408 | 413 | int flags = XS_SENDMSG_FLAGS; |
... | ... | @@ -410,7 +415,7 @@ |
410 | 415 | remainder -= len; |
411 | 416 | if (remainder != 0 || more) |
412 | 417 | flags |= MSG_MORE; |
413 | - err = sock->ops->sendpage(sock, *ppage, base, len, flags); | |
418 | + err = do_sendpage(sock, *ppage, base, len, flags); | |
414 | 419 | if (remainder == 0 || err != len) |
415 | 420 | break; |
416 | 421 | sent += err; |
417 | 422 | |
... | ... | @@ -431,9 +436,10 @@ |
431 | 436 | * @addrlen: UDP only -- length of destination address |
432 | 437 | * @xdr: buffer containing this request |
433 | 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 | 444 | unsigned int remainder = xdr->len - base; |
439 | 445 | int err, sent = 0; |
... | ... | @@ -461,7 +467,7 @@ |
461 | 467 | if (base < xdr->page_len) { |
462 | 468 | unsigned int len = xdr->page_len - base; |
463 | 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 | 471 | if (remainder == 0 || err != len) |
466 | 472 | goto out; |
467 | 473 | sent += err; |
... | ... | @@ -564,7 +570,7 @@ |
564 | 570 | req->rq_svec->iov_base, req->rq_svec->iov_len); |
565 | 571 | |
566 | 572 | status = xs_sendpages(transport->sock, NULL, 0, |
567 | - xdr, req->rq_bytes_sent); | |
573 | + xdr, req->rq_bytes_sent, true); | |
568 | 574 | dprintk("RPC: %s(%u) = %d\n", |
569 | 575 | __func__, xdr->len - req->rq_bytes_sent, status); |
570 | 576 | if (likely(status >= 0)) { |
... | ... | @@ -620,7 +626,7 @@ |
620 | 626 | status = xs_sendpages(transport->sock, |
621 | 627 | xs_addr(xprt), |
622 | 628 | xprt->addrlen, xdr, |
623 | - req->rq_bytes_sent); | |
629 | + req->rq_bytes_sent, true); | |
624 | 630 | |
625 | 631 | dprintk("RPC: xs_udp_send_request(%u) = %d\n", |
626 | 632 | xdr->len - req->rq_bytes_sent, status); |
... | ... | @@ -693,6 +699,7 @@ |
693 | 699 | struct rpc_xprt *xprt = req->rq_xprt; |
694 | 700 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); |
695 | 701 | struct xdr_buf *xdr = &req->rq_snd_buf; |
702 | + bool zerocopy = true; | |
696 | 703 | int status; |
697 | 704 | |
698 | 705 | xs_encode_stream_record_marker(&req->rq_snd_buf); |
699 | 706 | |
... | ... | @@ -700,13 +707,20 @@ |
700 | 707 | xs_pktdump("packet data:", |
701 | 708 | req->rq_svec->iov_base, |
702 | 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 | 717 | /* Continue transmitting the packet/record. We must be careful |
705 | 718 | * to cope with writespace callbacks arriving _after_ we have |
706 | 719 | * called sendmsg(). */ |
707 | 720 | while (1) { |
708 | 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 | 725 | dprintk("RPC: xs_tcp_send_request(%u) = %d\n", |
712 | 726 | xdr->len - req->rq_bytes_sent, status); |