Merge tag 'nfs-for-5.8-3' of git://git.linux-nfs.org/projects/anna/linux-nfs into...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 17 Jul 2020 23:37:52 +0000 (16:37 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 17 Jul 2020 23:37:52 +0000 (16:37 -0700)
Pull NFS client fixes from Anna Schumaker:
 "A few more NFS client bugfixes for Linux 5.8:

  NFS:
   - Fix interrupted slots by using the SEQUENCE operation

  SUNRPC:
   - revert d03727b248d0 to fix unkillable IOs

  xprtrdma:
   - Fix double-free in rpcrdma_ep_create()
   - Fix recursion into rpcrdma_xprt_disconnect()
   - Fix return code from rpcrdma_xprt_connect()
   - Fix handling of connect errors
   - Fix incorrect header size calculations"

* tag 'nfs-for-5.8-3' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  SUNRPC reverting d03727b248d0 ("NFSv4 fix CLOSE not waiting for direct IO compeletion")
  xprtrdma: fix incorrect header size calculations
  NFS: Fix interrupted slots by sending a solo SEQUENCE operation
  xprtrdma: Fix handling of connect errors
  xprtrdma: Fix return code from rpcrdma_xprt_connect()
  xprtrdma: Fix recursion into rpcrdma_xprt_disconnect()
  xprtrdma: Fix double-free in rpcrdma_ep_create()

fs/nfs/direct.c
fs/nfs/file.c
fs/nfs/nfs4proc.c
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtrdma/verbs.c

index 3d113cf..1b79dd5 100644 (file)
@@ -267,6 +267,8 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
 {
        struct inode *inode = dreq->inode;
 
+       inode_dio_end(inode);
+
        if (dreq->iocb) {
                long res = (long) dreq->error;
                if (dreq->count != 0) {
@@ -278,10 +280,7 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
 
        complete(&dreq->completion);
 
-       igrab(inode);
        nfs_direct_req_release(dreq);
-       inode_dio_end(inode);
-       iput(inode);
 }
 
 static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
@@ -411,10 +410,8 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
         * generic layer handle the completion.
         */
        if (requested_bytes == 0) {
-               igrab(inode);
-               nfs_direct_req_release(dreq);
                inode_dio_end(inode);
-               iput(inode);
+               nfs_direct_req_release(dreq);
                return result < 0 ? result : -EIO;
        }
 
@@ -867,10 +864,8 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
         * generic layer handle the completion.
         */
        if (requested_bytes == 0) {
-               igrab(inode);
-               nfs_direct_req_release(dreq);
                inode_dio_end(inode);
-               iput(inode);
+               nfs_direct_req_release(dreq);
                return result < 0 ? result : -EIO;
        }
 
index ccd6c16..f96367a 100644 (file)
@@ -83,7 +83,6 @@ nfs_file_release(struct inode *inode, struct file *filp)
        dprintk("NFS: release(%pD2)\n", filp);
 
        nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
-       inode_dio_wait(inode);
        nfs_file_clear_open_context(filp);
        return 0;
 }
index e32717f..2e2dac2 100644 (file)
@@ -774,6 +774,14 @@ static void nfs4_slot_sequence_acked(struct nfs4_slot *slot,
        slot->seq_nr_last_acked = seqnr;
 }
 
+static void nfs4_probe_sequence(struct nfs_client *client, const struct cred *cred,
+                               struct nfs4_slot *slot)
+{
+       struct rpc_task *task = _nfs41_proc_sequence(client, cred, slot, true);
+       if (!IS_ERR(task))
+               rpc_put_task_async(task);
+}
+
 static int nfs41_sequence_process(struct rpc_task *task,
                struct nfs4_sequence_res *res)
 {
@@ -790,6 +798,7 @@ static int nfs41_sequence_process(struct rpc_task *task,
                goto out;
 
        session = slot->table->session;
+       clp = session->clp;
 
        trace_nfs4_sequence_done(session, res);
 
@@ -804,7 +813,6 @@ static int nfs41_sequence_process(struct rpc_task *task,
                nfs4_slot_sequence_acked(slot, slot->seq_nr);
                /* Update the slot's sequence and clientid lease timer */
                slot->seq_done = 1;
-               clp = session->clp;
                do_renew_lease(clp, res->sr_timestamp);
                /* Check sequence flags */
                nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags,
@@ -852,10 +860,18 @@ static int nfs41_sequence_process(struct rpc_task *task,
                /*
                 * Were one or more calls using this slot interrupted?
                 * If the server never received the request, then our
-                * transmitted slot sequence number may be too high.
+                * transmitted slot sequence number may be too high. However,
+                * if the server did receive the request then it might
+                * accidentally give us a reply with a mismatched operation.
+                * We can sort this out by sending a lone sequence operation
+                * to the server on the same slot.
                 */
                if ((s32)(slot->seq_nr - slot->seq_nr_last_acked) > 1) {
                        slot->seq_nr--;
+                       if (task->tk_msg.rpc_proc != &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE]) {
+                               nfs4_probe_sequence(clp, task->tk_msg.rpc_cred, slot);
+                               res->sr_slot = NULL;
+                       }
                        goto retry_nowait;
                }
                /*
index 935bbef..453bacc 100644 (file)
@@ -71,7 +71,7 @@ static unsigned int rpcrdma_max_call_header_size(unsigned int maxsegs)
        size = RPCRDMA_HDRLEN_MIN;
 
        /* Maximum Read list size */
-       size = maxsegs * rpcrdma_readchunk_maxsz * sizeof(__be32);
+       size += maxsegs * rpcrdma_readchunk_maxsz * sizeof(__be32);
 
        /* Minimal Read chunk size */
        size += sizeof(__be32); /* segment count */
@@ -94,7 +94,7 @@ static unsigned int rpcrdma_max_reply_header_size(unsigned int maxsegs)
        size = RPCRDMA_HDRLEN_MIN;
 
        /* Maximum Write list size */
-       size = sizeof(__be32);          /* segment count */
+       size += sizeof(__be32);         /* segment count */
        size += maxsegs * rpcrdma_segment_maxsz * sizeof(__be32);
        size += sizeof(__be32); /* list discriminator */
 
index 14165b6..053c8ab 100644 (file)
@@ -249,6 +249,11 @@ xprt_rdma_connect_worker(struct work_struct *work)
                                           xprt->stat.connect_start;
                xprt_set_connected(xprt);
                rc = -EAGAIN;
+       } else {
+               /* Force a call to xprt_rdma_close to clean up */
+               spin_lock(&xprt->transport_lock);
+               set_bit(XPRT_CLOSE_WAIT, &xprt->state);
+               spin_unlock(&xprt->transport_lock);
        }
        xprt_wake_pending_tasks(xprt, rc);
 }
index 2198c8e..75c6467 100644 (file)
@@ -281,17 +281,19 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
                break;
        case RDMA_CM_EVENT_CONNECT_ERROR:
                ep->re_connect_status = -ENOTCONN;
-               goto disconnected;
+               goto wake_connect_worker;
        case RDMA_CM_EVENT_UNREACHABLE:
                ep->re_connect_status = -ENETUNREACH;
-               goto disconnected;
+               goto wake_connect_worker;
        case RDMA_CM_EVENT_REJECTED:
                dprintk("rpcrdma: connection to %pISpc rejected: %s\n",
                        sap, rdma_reject_msg(id, event->status));
                ep->re_connect_status = -ECONNREFUSED;
                if (event->status == IB_CM_REJ_STALE_CONN)
-                       ep->re_connect_status = -EAGAIN;
-               goto disconnected;
+                       ep->re_connect_status = -ENOTCONN;
+wake_connect_worker:
+               wake_up_all(&ep->re_connect_wait);
+               return 0;
        case RDMA_CM_EVENT_DISCONNECTED:
                ep->re_connect_status = -ECONNABORTED;
 disconnected:
@@ -400,14 +402,14 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
 
        ep = kzalloc(sizeof(*ep), GFP_NOFS);
        if (!ep)
-               return -EAGAIN;
+               return -ENOTCONN;
        ep->re_xprt = &r_xprt->rx_xprt;
        kref_init(&ep->re_kref);
 
        id = rpcrdma_create_id(r_xprt, ep);
        if (IS_ERR(id)) {
-               rc = PTR_ERR(id);
-               goto out_free;
+               kfree(ep);
+               return PTR_ERR(id);
        }
        __module_get(THIS_MODULE);
        device = id->device;
@@ -506,9 +508,6 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
 out_destroy:
        rpcrdma_ep_put(ep);
        rdma_destroy_id(id);
-out_free:
-       kfree(ep);
-       r_xprt->rx_ep = NULL;
        return rc;
 }
 
@@ -524,8 +523,6 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt)
        struct rpcrdma_ep *ep;
        int rc;
 
-retry:
-       rpcrdma_xprt_disconnect(r_xprt);
        rc = rpcrdma_ep_create(r_xprt);
        if (rc)
                return rc;
@@ -540,10 +537,6 @@ retry:
        rpcrdma_ep_get(ep);
        rpcrdma_post_recvs(r_xprt, true);
 
-       rc = rpcrdma_sendctxs_create(r_xprt);
-       if (rc)
-               goto out;
-
        rc = rdma_connect(ep->re_id, &ep->re_remote_cma);
        if (rc)
                goto out;
@@ -553,15 +546,19 @@ retry:
        wait_event_interruptible(ep->re_connect_wait,
                                 ep->re_connect_status != 0);
        if (ep->re_connect_status <= 0) {
-               if (ep->re_connect_status == -EAGAIN)
-                       goto retry;
                rc = ep->re_connect_status;
                goto out;
        }
 
+       rc = rpcrdma_sendctxs_create(r_xprt);
+       if (rc) {
+               rc = -ENOTCONN;
+               goto out;
+       }
+
        rc = rpcrdma_reqs_setup(r_xprt);
        if (rc) {
-               rpcrdma_xprt_disconnect(r_xprt);
+               rc = -ENOTCONN;
                goto out;
        }
        rpcrdma_mrs_create(r_xprt);