Merge tag 'nfs-for-5.0-2' of git://git.linux-nfs.org/projects/anna/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 19 Jan 2019 21:27:38 +0000 (09:27 +1200)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 19 Jan 2019 21:27:38 +0000 (09:27 +1200)
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()

fs/nfs/nfs4file.c
net/sunrpc/auth.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/clnt.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/verbs.c
net/sunrpc/xprtsock.c

index 46d691ba04bc8fdb38b28beca6eb445c50b7443a..45b2322e092d2455b508a8fdc00f5bde0b73c4e9 100644 (file)
@@ -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,
                                    size_t count, unsigned int flags)
 {
-       ssize_t ret;
-
        if (file_inode(file_in) == file_inode(file_out))
                return -EINVAL;
-retry:
-       ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
-       if (ret == -EAGAIN)
-               goto retry;
-       return ret;
+       return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
 }
 
 static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
index 1ff9768f545602dfa1d4db80c630321d4e86f6b8..f3023bbc0b7fcc292793fda4469e0c914b6ece93 100644 (file)
@@ -41,6 +41,9 @@ static unsigned long number_cred_unused;
 
 static struct cred machine_cred = {
        .usage = ATOMIC_INIT(1),
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       .magic = CRED_MAGIC,
+#endif
 };
 
 /*
index dc86713b32b6d832fe840e82332999af119c874c..1531b0219344d9e47a8dc33509355fefa9e05f5c 100644 (file)
@@ -1549,8 +1549,10 @@ gss_marshal(struct rpc_task *task, __be32 *p)
        cred_len = p++;
 
        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);
+       if (req->rq_seqno == MAXSEQ)
+               goto out_expired;
 
        *p++ = htonl((u32) RPC_GSS_VERSION);
        *p++ = htonl((u32) ctx->gc_proc);
@@ -1572,14 +1574,18 @@ gss_marshal(struct rpc_task *task, __be32 *p)
        mic.data = (u8 *)(p + 1);
        maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
        if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
-               clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
+               goto out_expired;
        } 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;
        }
        p = xdr_encode_opaque(p, NULL, mic.len);
        gss_put_ctx(ctx);
        return p;
+out_expired:
+       clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
+       task->tk_status = -EKEYEXPIRED;
 out_put_ctx:
        gss_put_ctx(ctx);
        return NULL;
index 71d9599b5816591bd12751703d8487a8dda688a4..d7ec6132c046ec409db057d6ace332ab620fa88b 100644 (file)
@@ -1739,14 +1739,10 @@ rpc_xdr_encode(struct rpc_task *task)
        xdr_buf_init(&req->rq_rcv_buf,
                     req->rq_rbuffer,
                     req->rq_rcvsize);
-       req->rq_bytes_sent = 0;
 
        p = rpc_encode_header(task);
-       if (p == NULL) {
-               printk(KERN_INFO "RPC: couldn't encode RPC header, exit EIO\n");
-               rpc_exit(task, -EIO);
+       if (p == NULL)
                return;
-       }
 
        encode = task->tk_msg.rpc_proc->p_encode;
        if (encode == NULL)
@@ -1771,10 +1767,17 @@ call_encode(struct rpc_task *task)
        /* Did the encode result in an error condition? */
        if (task->tk_status != 0) {
                /* 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);
-               else
+                       break;
+               case -EKEYEXPIRED:
+                       task->tk_action = call_refresh;
+                       break;
+               default:
                        rpc_exit(task, task->tk_status);
+               }
                return;
        }
 
@@ -2336,7 +2339,8 @@ rpc_encode_header(struct rpc_task *task)
        *p++ = htonl(clnt->cl_vers);    /* program version */
        *p++ = htonl(task->tk_msg.rpc_proc->p_proc);    /* procedure */
        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;
 }
 
index 73547d17d3c61a844c860c33acaff5259c81d54e..f1ec2110efebe6315523036bd11e30dbdf7c8de4 100644 (file)
@@ -1151,6 +1151,7 @@ xprt_request_enqueue_transmit(struct rpc_task *task)
        struct rpc_xprt *xprt = req->rq_xprt;
 
        if (xprt_request_need_enqueue_transmit(task, req)) {
+               req->rq_bytes_sent = 0;
                spin_lock(&xprt->queue_lock);
                /*
                 * 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);
                                goto out;
                        }
-               } else {
+               } else if (!req->rq_seqno) {
                        list_for_each_entry(pos, &xprt->xmit_queue, rq_xmit) {
                                if (pos->rq_task->tk_owner != task->tk_owner)
                                        continue;
index 7749a2bf6887764c0956ac404b53f055043c32c3..4994e75945b848c1dfba523e6a23cb2d45613ef5 100644 (file)
@@ -845,17 +845,13 @@ static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt)
        for (i = 0; i <= buf->rb_sc_last; i++) {
                sc = rpcrdma_sendctx_create(&r_xprt->rx_ia);
                if (!sc)
-                       goto out_destroy;
+                       return -ENOMEM;
 
                sc->sc_xprt = r_xprt;
                buf->rb_sc_ctxs[i] = sc;
        }
 
        return 0;
-
-out_destroy:
-       rpcrdma_sendctxs_destroy(buf);
-       return -ENOMEM;
 }
 
 /* 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,
                                                0,
                        r_xprt->rx_xprt.address_strings[RPC_DISPLAY_ADDR]);
-       if (!buf->rb_completion_wq)
+       if (!buf->rb_completion_wq) {
+               rc = -ENOMEM;
                goto out;
+       }
 
        return 0;
 out:
index 13559e6a460bc6f496a9e6dbc3cd5b7eaccad2e8..7754aa3e434f405711cfce8d9bdfece972dfc75c 100644 (file)
@@ -48,6 +48,7 @@
 #include <net/udp.h>
 #include <net/tcp.h>
 #include <linux/bvec.h>
+#include <linux/highmem.h>
 #include <linux/uio.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);
 }
 
+#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
 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)
@@ -409,6 +430,7 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
                                seek + buf->page_base);
                if (ret <= 0)
                        goto sock_err;
+               xs_flush_bvec(buf->bvec, ret, seek + buf->page_base);
                offset += ret - buf->page_base;
                if (offset == count || msg->msg_flags & (MSG_EOR|MSG_TRUNC))
                        goto out;