Commit b0efca46 authored by Linus Torvalds's avatar Linus Torvalds

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()
parents 4d5f6e02 deaa5c96
...@@ -133,15 +133,9 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, ...@@ -133,15 +133,9 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out, struct file *file_out, loff_t pos_out,
size_t count, unsigned int flags) size_t count, unsigned int flags)
{ {
ssize_t ret;
if (file_inode(file_in) == file_inode(file_out)) if (file_inode(file_in) == file_inode(file_out))
return -EINVAL; return -EINVAL;
retry: return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
if (ret == -EAGAIN)
goto retry;
return ret;
} }
static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
......
...@@ -41,6 +41,9 @@ static unsigned long number_cred_unused; ...@@ -41,6 +41,9 @@ static unsigned long number_cred_unused;
static struct cred machine_cred = { static struct cred machine_cred = {
.usage = ATOMIC_INIT(1), .usage = ATOMIC_INIT(1),
#ifdef CONFIG_DEBUG_CREDENTIALS
.magic = CRED_MAGIC,
#endif
}; };
/* /*
......
...@@ -1549,8 +1549,10 @@ gss_marshal(struct rpc_task *task, __be32 *p) ...@@ -1549,8 +1549,10 @@ gss_marshal(struct rpc_task *task, __be32 *p)
cred_len = p++; cred_len = p++;
spin_lock(&ctx->gc_seq_lock); spin_lock(&ctx->gc_seq_lock);
req->rq_seqno = ctx->gc_seq++; req->rq_seqno = (ctx->gc_seq < MAXSEQ) ? ctx->gc_seq++ : MAXSEQ;
spin_unlock(&ctx->gc_seq_lock); spin_unlock(&ctx->gc_seq_lock);
if (req->rq_seqno == MAXSEQ)
goto out_expired;
*p++ = htonl((u32) RPC_GSS_VERSION); *p++ = htonl((u32) RPC_GSS_VERSION);
*p++ = htonl((u32) ctx->gc_proc); *p++ = htonl((u32) ctx->gc_proc);
...@@ -1572,14 +1574,18 @@ gss_marshal(struct rpc_task *task, __be32 *p) ...@@ -1572,14 +1574,18 @@ gss_marshal(struct rpc_task *task, __be32 *p)
mic.data = (u8 *)(p + 1); mic.data = (u8 *)(p + 1);
maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
if (maj_stat == GSS_S_CONTEXT_EXPIRED) { if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); goto out_expired;
} else if (maj_stat != 0) { } else if (maj_stat != 0) {
printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); pr_warn("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat);
task->tk_status = -EIO;
goto out_put_ctx; goto out_put_ctx;
} }
p = xdr_encode_opaque(p, NULL, mic.len); p = xdr_encode_opaque(p, NULL, mic.len);
gss_put_ctx(ctx); gss_put_ctx(ctx);
return p; return p;
out_expired:
clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
task->tk_status = -EKEYEXPIRED;
out_put_ctx: out_put_ctx:
gss_put_ctx(ctx); gss_put_ctx(ctx);
return NULL; return NULL;
......
...@@ -1739,14 +1739,10 @@ rpc_xdr_encode(struct rpc_task *task) ...@@ -1739,14 +1739,10 @@ rpc_xdr_encode(struct rpc_task *task)
xdr_buf_init(&req->rq_rcv_buf, xdr_buf_init(&req->rq_rcv_buf,
req->rq_rbuffer, req->rq_rbuffer,
req->rq_rcvsize); req->rq_rcvsize);
req->rq_bytes_sent = 0;
p = rpc_encode_header(task); p = rpc_encode_header(task);
if (p == NULL) { if (p == NULL)
printk(KERN_INFO "RPC: couldn't encode RPC header, exit EIO\n");
rpc_exit(task, -EIO);
return; return;
}
encode = task->tk_msg.rpc_proc->p_encode; encode = task->tk_msg.rpc_proc->p_encode;
if (encode == NULL) if (encode == NULL)
...@@ -1771,10 +1767,17 @@ call_encode(struct rpc_task *task) ...@@ -1771,10 +1767,17 @@ call_encode(struct rpc_task *task)
/* Did the encode result in an error condition? */ /* Did the encode result in an error condition? */
if (task->tk_status != 0) { if (task->tk_status != 0) {
/* Was the error nonfatal? */ /* Was the error nonfatal? */
if (task->tk_status == -EAGAIN || task->tk_status == -ENOMEM) switch (task->tk_status) {
case -EAGAIN:
case -ENOMEM:
rpc_delay(task, HZ >> 4); rpc_delay(task, HZ >> 4);
else break;
case -EKEYEXPIRED:
task->tk_action = call_refresh;
break;
default:
rpc_exit(task, task->tk_status); rpc_exit(task, task->tk_status);
}
return; return;
} }
...@@ -2336,6 +2339,7 @@ rpc_encode_header(struct rpc_task *task) ...@@ -2336,6 +2339,7 @@ rpc_encode_header(struct rpc_task *task)
*p++ = htonl(clnt->cl_vers); /* program version */ *p++ = htonl(clnt->cl_vers); /* program version */
*p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */ *p++ = htonl(task->tk_msg.rpc_proc->p_proc); /* procedure */
p = rpcauth_marshcred(task, p); p = rpcauth_marshcred(task, p);
if (p)
req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p); req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p);
return p; return p;
} }
......
...@@ -1151,6 +1151,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task) ...@@ -1151,6 +1151,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task)
struct rpc_xprt *xprt = req->rq_xprt; struct rpc_xprt *xprt = req->rq_xprt;
if (xprt_request_need_enqueue_transmit(task, req)) { if (xprt_request_need_enqueue_transmit(task, req)) {
req->rq_bytes_sent = 0;
spin_lock(&xprt->queue_lock); spin_lock(&xprt->queue_lock);
/* /*
* Requests that carry congestion control credits are added * Requests that carry congestion control credits are added
...@@ -1177,7 +1178,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task) ...@@ -1177,7 +1178,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task)
INIT_LIST_HEAD(&req->rq_xmit2); INIT_LIST_HEAD(&req->rq_xmit2);
goto out; goto out;
} }
} else { } else if (!req->rq_seqno) {
list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) { list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) {
if (pos->rq_task->tk_owner != task->tk_owner) if (pos->rq_task->tk_owner != task->tk_owner)
continue; continue;
......
...@@ -845,17 +845,13 @@ static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt) ...@@ -845,17 +845,13 @@ static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt)
for (i = 0; i <= buf->rb_sc_last; i++) { for (i = 0; i <= buf->rb_sc_last; i++) {
sc = rpcrdma_sendctx_create(&r_xprt->rx_ia); sc = rpcrdma_sendctx_create(&r_xprt->rx_ia);
if (!sc) if (!sc)
goto out_destroy; return -ENOMEM;
sc->sc_xprt = r_xprt; sc->sc_xprt = r_xprt;
buf->rb_sc_ctxs[i] = sc; buf->rb_sc_ctxs[i] = sc;
} }
return 0; return 0;
out_destroy:
rpcrdma_sendctxs_destroy(buf);
return -ENOMEM;
} }
/* The sendctx queue is not guaranteed to have a size that is a /* 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,8 +1109,10 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
WQ_MEM_RECLAIM | WQ_HIGHPRI, WQ_MEM_RECLAIM | WQ_HIGHPRI,
0, 0,
r_xprt->rx_xprt.address_strings[RPC_DISPLAY_ADDR]); r_xprt->rx_xprt.address_strings[RPC_DISPLAY_ADDR]);
if (!buf->rb_completion_wq) if (!buf->rb_completion_wq) {
rc = -ENOMEM;
goto out; goto out;
}
return 0; return 0;
out: out:
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include <net/udp.h> #include <net/udp.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <linux/bvec.h> #include <linux/bvec.h>
#include <linux/highmem.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <trace/events/sunrpc.h> #include <trace/events/sunrpc.h>
...@@ -376,6 +377,26 @@ xs_read_discard(struct socket *sock, struct msghdr *msg, int flags, ...@@ -376,6 +377,26 @@ xs_read_discard(struct socket *sock, struct msghdr *msg, int flags,
return sock_recvmsg(sock, msg, flags); return sock_recvmsg(sock, msg, flags);
} }
#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
static void
xs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek)
{
struct bvec_iter bi = {
.bi_size = count,
};
struct bio_vec bv;
bvec_iter_advance(bvec, &bi, seek & PAGE_MASK);
for_each_bvec(bv, bvec, bi, bi)
flush_dcache_page(bv.bv_page);
}
#else
static inline void
xs_flush_bvec(const struct bio_vec *bvec, size_t count, size_t seek)
{
}
#endif
static ssize_t static ssize_t
xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
struct xdr_buf *buf, size_t count, size_t seek, size_t *read) 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,6 +430,7 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
seek + buf->page_base); seek + buf->page_base);
if (ret <= 0) if (ret <= 0)
goto sock_err; goto sock_err;
xs_flush_bvec(buf->bvec, ret, seek + buf->page_base);
offset += ret - buf->page_base; offset += ret - buf->page_base;
if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC)) if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC))
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment