diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-19 16:27:38 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-19 16:27:38 -0500 |
commit | b0efca46b57071e4c281034f04d2b56edf79843d (patch) | |
tree | 93d04cfe9cb1bba4ecc694aca73887a32d9e9e47 | |
parent | 4d5f6e0201bc568c0758ed3f77a06648ec9fd482 (diff) | |
parent | deaa5c96c2f7e8b934088a1e70a0fe8797bd1149 (diff) |
Merge tag 'nfs-for-5.0-2' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client fixes from Anna Schumaker:
"These are mostly fixes for SUNRPC bugs, with a single v4.2
copy_file_range() fix mixed in.
Stable bugfixes:
- Fix TCP receive code on archs with flush_dcache_page()
Other bugfixes:
- Fix error code in rpcrdma_buffer_create()
- Fix a double free in rpcrdma_send_ctxs_create()
- Fix kernel BUG at kernel/cred.c:825
- Fix unnecessary retry in nfs42_proc_copy_file_range()
- Ensure rq_bytes_sent is reset before request transmission
- Ensure we respect the RPCSEC_GSS sequence number limit
- Address Kerberos performance/behavior regression"
* tag 'nfs-for-5.0-2' of git://git.linux-nfs.org/projects/anna/linux-nfs:
SUNRPC: Address Kerberos performance/behavior regression
SUNRPC: Ensure we respect the RPCSEC_GSS sequence number limit
SUNRPC: Ensure rq_bytes_sent is reset before request transmission
NFSv4.2 fix unnecessary retry in nfs4_copy_file_range
sunrpc: kernel BUG at kernel/cred.c:825!
SUNRPC: Fix TCP receive code on archs with flush_dcache_page()
xprtrdma: Double free in rpcrdma_sendctxs_create()
xprtrdma: Fix error code in rpcrdma_buffer_create()
-rw-r--r-- | fs/nfs/nfs4file.c | 8 | ||||
-rw-r--r-- | net/sunrpc/auth.c | 3 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 12 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 20 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 3 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/verbs.c | 10 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 22 |
7 files changed, 53 insertions, 25 deletions
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 46d691ba04bc..45b2322e092d 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -133,15 +133,9 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, | |||
133 | struct file *file_out, loff_t pos_out, | 133 | struct file *file_out, loff_t pos_out, |
134 | size_t count, unsigned int flags) | 134 | size_t count, unsigned int flags) |
135 | { | 135 | { |
136 | ssize_t ret; | ||
137 | |||
138 | if (file_inode(file_in) == file_inode(file_out)) | 136 | if (file_inode(file_in) == file_inode(file_out)) |
139 | return -EINVAL; | 137 | return -EINVAL; |
140 | retry: | 138 | return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); |
141 | ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); | ||
142 | if (ret == -EAGAIN) | ||
143 | goto retry; | ||
144 | return ret; | ||
145 | } | 139 | } |
146 | 140 | ||
147 | static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) | 141 | static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 1ff9768f5456..f3023bbc0b7f 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -41,6 +41,9 @@ static unsigned long number_cred_unused; | |||
41 | 41 | ||
42 | static struct cred machine_cred = { | 42 | static struct cred machine_cred = { |
43 | .usage = ATOMIC_INIT(1), | 43 | .usage = ATOMIC_INIT(1), |
44 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
45 | .magic = CRED_MAGIC, | ||
46 | #endif | ||
44 | }; | 47 | }; |
45 | 48 | ||
46 | /* | 49 | /* |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index dc86713b32b6..1531b0219344 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -1549,8 +1549,10 @@ gss_marshal(struct rpc_task *task, __be32 *p) | |||
1549 | cred_len = p++; | 1549 | cred_len = p++; |
1550 | 1550 | ||
1551 | spin_lock(&ctx->gc_seq_lock); | 1551 | spin_lock(&ctx->gc_seq_lock); |
1552 | req->rq_seqno = ctx->gc_seq++; | 1552 | req->rq_seqno = (ctx->gc_seq < MAXSEQ) ? ctx->gc_seq++ : MAXSEQ; |
1553 | spin_unlock(&ctx->gc_seq_lock); | 1553 | spin_unlock(&ctx->gc_seq_lock); |
1554 | if (req->rq_seqno == MAXSEQ) | ||
1555 | goto out_expired; | ||
1554 | 1556 | ||
1555 | *p++ = htonl((u32) RPC_GSS_VERSION); | 1557 | *p++ = htonl((u32) RPC_GSS_VERSION); |
1556 | *p++ = htonl((u32) ctx->gc_proc); | 1558 | *p++ = htonl((u32) ctx->gc_proc); |
@@ -1572,14 +1574,18 @@ gss_marshal(struct rpc_task *task, __be32 *p) | |||
1572 | mic.data = (u8 *)(p + 1); | 1574 | mic.data = (u8 *)(p + 1); |
1573 | maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); | 1575 | maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); |
1574 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) { | 1576 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) { |
1575 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 1577 | goto out_expired; |
1576 | } else if (maj_stat != 0) { | 1578 | } else if (maj_stat != 0) { |
1577 | printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); | 1579 | pr_warn("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); |
1580 | task->tk_status = -EIO; | ||
1578 | goto out_put_ctx; | 1581 | goto out_put_ctx; |
1579 | } | 1582 | } |
1580 | p = xdr_encode_opaque(p, NULL, mic.len); | 1583 | p = xdr_encode_opaque(p, NULL, mic.len); |
1581 | gss_put_ctx(ctx); | 1584 | gss_put_ctx(ctx); |
1582 | return p; | 1585 | return p; |
1586 | out_expired: | ||
1587 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | ||
1588 | task->tk_status = -EKEYEXPIRED; | ||
1583 | out_put_ctx: | 1589 | out_put_ctx: |
1584 | gss_put_ctx(ctx); | 1590 | gss_put_ctx(ctx); |
1585 | return NULL; | 1591 | return NULL; |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 71d9599b5816..d7ec6132c046 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -1739,14 +1739,10 @@ rpc_xdr_encode(struct rpc_task *task) | |||
1739 | xdr_buf_init(&req->rq_rcv_buf, | 1739 | xdr_buf_init(&req->rq_rcv_buf, |
1740 | req->rq_rbuffer, | 1740 | req->rq_rbuffer, |
1741 | req->rq_rcvsize); | 1741 | req->rq_rcvsize); |
1742 | req->rq_bytes_sent = 0; | ||
1743 | 1742 | ||
1744 | p = rpc_encode_header(task); | 1743 | p = rpc_encode_header(task); |
1745 | if (p == NULL) { | 1744 | if (p == NULL) |
1746 | printk(KERN_INFO "RPC: couldn't encode RPC header, exit EIO\n"); | ||
1747 | rpc_exit(task, -EIO); | ||
1748 | return; | 1745 | return; |
1749 | } | ||
1750 | 1746 | ||
1751 | encode = task->tk_msg.rpc_proc->p_encode; | 1747 | encode = task->tk_msg.rpc_proc->p_encode; |
1752 | if (encode == NULL) | 1748 | if (encode == NULL) |
@@ -1771,10 +1767,17 @@ call_encode(struct rpc_task *task) | |||
1771 | /* Did the encode result in an error condition? */ | 1767 | /* Did the encode result in an error condition? */ |
1772 | if (task->tk_status != 0) { | 1768 | if (task->tk_status != 0) { |
1773 | /* Was the error nonfatal? */ | 1769 | /* Was the error nonfatal? */ |
1774 | if (task->tk_status == -EAGAIN || task->tk_status == -ENOMEM) | 1770 | switch (task->tk_status) { |
1771 | case -EAGAIN: | ||
1772 | case -ENOMEM: | ||
1775 | rpc_delay(task, HZ >> 4); | 1773 | rpc_delay(task, HZ >> 4); |
1776 | else | 1774 | break; |
1775 | case -EKEYEXPIRED: | ||
1776 | task->tk_action = call_refresh; | ||
1777 | break; | ||
1778 | default: | ||
1777 | rpc_exit(task, task->tk_status); | 1779 | rpc_exit(task, task->tk_status); |
1780 | } | ||
1778 | return; | 1781 | return; |
1779 | } | 1782 | } |
1780 | 1783 | ||
@@ -2336,7 +2339,8 @@ rpc_encode_header(struct rpc_task *task) | |||
2336 | *p++ = htonl(clnt->cl_vers); /* program version */ | 2339 | *p++ = htonl(clnt->cl_vers); /* program version */ |
2337 | *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ | 2340 | *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ |
2338 | p = rpcauth_marshcred(task, p); | 2341 | p = rpcauth_marshcred(task, p); |
2339 | req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); | 2342 | if (p) |
2343 | req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); | ||
2340 | return p; | 2344 | return p; |
2341 | } | 2345 | } |
2342 | 2346 | ||
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 73547d17d3c6..f1ec2110efeb 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -1151,6 +1151,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task) | |||
1151 | struct rpc_xprt *xprt = req->rq_xprt; | 1151 | struct rpc_xprt *xprt = req->rq_xprt; |
1152 | 1152 | ||
1153 | if (xprt_request_need_enqueue_transmit(task, req)) { | 1153 | if (xprt_request_need_enqueue_transmit(task, req)) { |
1154 | req->rq_bytes_sent = 0; | ||
1154 | spin_lock(&xprt->queue_lock); | 1155 | spin_lock(&xprt->queue_lock); |
1155 | /* | 1156 | /* |
1156 | * Requests that carry congestion control credits are added | 1157 | * Requests that carry congestion control credits are added |
@@ -1177,7 +1178,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task) | |||
1177 | INIT_LIST_HEAD(&req->rq_xmit2); | 1178 | INIT_LIST_HEAD(&req->rq_xmit2); |
1178 | goto out; | 1179 | goto out; |
1179 | } | 1180 | } |
1180 | } else { | 1181 | } else if (!req->rq_seqno) { |
1181 | list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { | 1182 | list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { |
1182 | if (pos->rq_task->tk_owner != task->tk_owner) | 1183 | if (pos->rq_task->tk_owner != task->tk_owner) |
1183 | continue; | 1184 | continue; |
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 7749a2bf6887..4994e75945b8 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
@@ -845,17 +845,13 @@ static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt) | |||
845 | for (i = 0; i <= buf->rb_sc_last; i++) { | 845 | for (i = 0; i <= buf->rb_sc_last; i++) { |
846 | sc = rpcrdma_sendctx_create(&r_xprt->rx_ia); | 846 | sc = rpcrdma_sendctx_create(&r_xprt->rx_ia); |
847 | if (!sc) | 847 | if (!sc) |
848 | goto out_destroy; | 848 | return -ENOMEM; |
849 | 849 | ||
850 | sc->sc_xprt = r_xprt; | 850 | sc->sc_xprt = r_xprt; |
851 | buf->rb_sc_ctxs[i] = sc; | 851 | buf->rb_sc_ctxs[i] = sc; |
852 | } | 852 | } |
853 | 853 | ||
854 | return 0; | 854 | return 0; |
855 | |||
856 | out_destroy: | ||
857 | rpcrdma_sendctxs_destroy(buf); | ||
858 | return -ENOMEM; | ||
859 | } | 855 | } |
860 | 856 | ||
861 | /* The sendctx queue is not guaranteed to have a size that is a | 857 | /* The sendctx queue is not guaranteed to have a size that is a |
@@ -1113,8 +1109,10 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) | |||
1113 | WQ_MEM_RECLAIM | WQ_HIGHPRI, | 1109 | WQ_MEM_RECLAIM | WQ_HIGHPRI, |
1114 | 0, | 1110 | 0, |
1115 | r_xprt->rx_xprt.address_strings[RPC_DISPLAY_ADDR]); | 1111 | r_xprt->rx_xprt.address_strings[RPC_DISPLAY_ADDR]); |
1116 | if (!buf->rb_completion_wq) | 1112 | if (!buf->rb_completion_wq) { |
1113 | rc = -ENOMEM; | ||
1117 | goto out; | 1114 | goto out; |
1115 | } | ||
1118 | 1116 | ||
1119 | return 0; | 1117 | return 0; |
1120 | out: | 1118 | out: |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 13559e6a460b..7754aa3e434f 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <net/udp.h> | 48 | #include <net/udp.h> |
49 | #include <net/tcp.h> | 49 | #include <net/tcp.h> |
50 | #include <linux/bvec.h> | 50 | #include <linux/bvec.h> |
51 | #include <linux/highmem.h> | ||
51 | #include <linux/uio.h> | 52 | #include <linux/uio.h> |
52 | 53 | ||
53 | #include <trace/events/sunrpc.h> | 54 | #include <trace/events/sunrpc.h> |
@@ -376,6 +377,26 @@ xs_read_discard(struct socket *sock, struct msghdr *msg, int flags, | |||
376 | return sock_recvmsg(sock, msg, flags); | 377 | return sock_recvmsg(sock, msg, flags); |
377 | } | 378 | } |
378 | 379 | ||
380 | #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE | ||
381 | static void | ||
382 | xs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek) | ||
383 | { | ||
384 | struct bvec_iter bi = { | ||
385 | .bi_size = count, | ||
386 | }; | ||
387 | struct bio_vec bv; | ||
388 | |||
389 | bvec_iter_advance(bvec, &bi, seek & PAGE_MASK); | ||
390 | for_each_bvec(bv, bvec, bi, bi) | ||
391 | flush_dcache_page(bv.bv_page); | ||
392 | } | ||
393 | #else | ||
394 | static inline void | ||
395 | xs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek) | ||
396 | { | ||
397 | } | ||
398 | #endif | ||
399 | |||
379 | static ssize_t | 400 | static ssize_t |
380 | xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, | 401 | xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, |
381 | struct xdr_buf *buf, size_t count, size_t seek, size_t *read) | 402 | struct xdr_buf *buf, size_t count, size_t seek, size_t *read) |
@@ -409,6 +430,7 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, | |||
409 | seek + buf->page_base); | 430 | seek + buf->page_base); |
410 | if (ret <= 0) | 431 | if (ret <= 0) |
411 | goto sock_err; | 432 | goto sock_err; |
433 | xs_flush_bvec(buf->bvec, ret, seek + buf->page_base); | ||
412 | offset += ret - buf->page_base; | 434 | offset += ret - buf->page_base; |
413 | if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) | 435 | if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) |
414 | goto out; | 436 | goto out; |