NFS client fixes for Linux 5.0
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 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEnZ5MQTpR7cLU7KEp18tUv7ClQOsFAlxCH1kACgkQ18tUv7Cl QOs4rBAAymqyhUzNgap1TX/KezFxqii7CVMVabrA5eGN+ZXbSVAZkwy7BMZWwVIp tEvD7lxWtF11x7bQDw7Xz+ruBCjLdD0RQIFnlBpVKqsRy9oSRA4PsgSbuIFaw+gX Bun4Z0xmOCPF7knRv6gQonArEZfHeokIIN8AtSBtWVByaOrnZwgDkNTIub8akpUl FQlzgq7lTydVzNcju2ImBeubU7KgFEu0F2Zub5z/iR+F2Mx/bAju8Q4YeVlPyD8U QJoIBlXAvgK8LK4bZCh40zPeEt0TMWXnW7o0JHgVQ0g6VbT+hp17I7fz91xEazye qbjpIJIjv5daEv0REM8t5ZCZB3tEatVjb4EQWXp0gJYb0l5E3I/O+7MO44n4uMYx s3UTxzM6NjwCtlgmn4tYUj+vEIExQHUUnwOl02e5iEa7bqNNY75ehAhj5Rh7iQBH H4b+OVuqc608q87rNePdK1LRyh0/u1cDI1kDAQoIP2omlb5hJQGk0Nuz9G2BodIj rP0x7nV+ykOXZtr6TR+RvaksL1W39PzVKYA0aL+e2gbcv4YO+Oq1phvNKwRWPM4a g08r/kvifS5h6/Jq8Wmn83f1vAOX7Sf23RtEoj+t9hc4S4JbsV2iYK3PY3eWbSYE Oz0Vt4gvBBJ+0rHJ10BsQ7686OQkyMKpIlvmx6O5mWVlthovbJM= =6Nzz -----END PGP SIGNATURE----- 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()
This commit is contained in:
Коммит
b0efca46b5
|
@ -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;
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
/* 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,7 +2339,8 @@ 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);
|
||||||
req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p);
|
if (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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 @@
|
||||||
#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,
|
||||||
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,
|
||||||
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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче