Commit 6a70f89c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-5.8-3' of git://git.linux-nfs.org/projects/anna/linux-nfs into master

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 d03727b2 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 d03727b2 ("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()
parents 630c183b 65caafd0
...@@ -267,6 +267,8 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq) ...@@ -267,6 +267,8 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
{ {
struct inode *inode = dreq->inode; struct inode *inode = dreq->inode;
inode_dio_end(inode);
if (dreq->iocb) { if (dreq->iocb) {
long res = (long) dreq->error; long res = (long) dreq->error;
if (dreq->count != 0) { if (dreq->count != 0) {
...@@ -278,10 +280,7 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq) ...@@ -278,10 +280,7 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
complete(&dreq->completion); complete(&dreq->completion);
igrab(inode);
nfs_direct_req_release(dreq); nfs_direct_req_release(dreq);
inode_dio_end(inode);
iput(inode);
} }
static void nfs_direct_read_completion(struct nfs_pgio_header *hdr) 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, ...@@ -411,10 +410,8 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
* generic layer handle the completion. * generic layer handle the completion.
*/ */
if (requested_bytes == 0) { if (requested_bytes == 0) {
igrab(inode);
nfs_direct_req_release(dreq);
inode_dio_end(inode); inode_dio_end(inode);
iput(inode); nfs_direct_req_release(dreq);
return result < 0 ? result : -EIO; return result < 0 ? result : -EIO;
} }
...@@ -867,10 +864,8 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -867,10 +864,8 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
* generic layer handle the completion. * generic layer handle the completion.
*/ */
if (requested_bytes == 0) { if (requested_bytes == 0) {
igrab(inode);
nfs_direct_req_release(dreq);
inode_dio_end(inode); inode_dio_end(inode);
iput(inode); nfs_direct_req_release(dreq);
return result < 0 ? result : -EIO; return result < 0 ? result : -EIO;
} }
......
...@@ -83,7 +83,6 @@ nfs_file_release(struct inode *inode, struct file *filp) ...@@ -83,7 +83,6 @@ nfs_file_release(struct inode *inode, struct file *filp)
dprintk("NFS: release(%pD2)\n", filp); dprintk("NFS: release(%pD2)\n", filp);
nfs_inc_stats(inode, NFSIOS_VFSRELEASE); nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
inode_dio_wait(inode);
nfs_file_clear_open_context(filp); nfs_file_clear_open_context(filp);
return 0; return 0;
} }
......
...@@ -774,6 +774,14 @@ static void nfs4_slot_sequence_acked(struct nfs4_slot *slot, ...@@ -774,6 +774,14 @@ static void nfs4_slot_sequence_acked(struct nfs4_slot *slot,
slot->seq_nr_last_acked = seqnr; 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, static int nfs41_sequence_process(struct rpc_task *task,
struct nfs4_sequence_res *res) struct nfs4_sequence_res *res)
{ {
...@@ -790,6 +798,7 @@ static int nfs41_sequence_process(struct rpc_task *task, ...@@ -790,6 +798,7 @@ static int nfs41_sequence_process(struct rpc_task *task,
goto out; goto out;
session = slot->table->session; session = slot->table->session;
clp = session->clp;
trace_nfs4_sequence_done(session, res); trace_nfs4_sequence_done(session, res);
...@@ -804,7 +813,6 @@ static int nfs41_sequence_process(struct rpc_task *task, ...@@ -804,7 +813,6 @@ static int nfs41_sequence_process(struct rpc_task *task,
nfs4_slot_sequence_acked(slot, slot->seq_nr); nfs4_slot_sequence_acked(slot, slot->seq_nr);
/* Update the slot's sequence and clientid lease timer */ /* Update the slot's sequence and clientid lease timer */
slot->seq_done = 1; slot->seq_done = 1;
clp = session->clp;
do_renew_lease(clp, res->sr_timestamp); do_renew_lease(clp, res->sr_timestamp);
/* Check sequence flags */ /* Check sequence flags */
nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags, nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags,
...@@ -852,10 +860,18 @@ static int nfs41_sequence_process(struct rpc_task *task, ...@@ -852,10 +860,18 @@ static int nfs41_sequence_process(struct rpc_task *task,
/* /*
* Were one or more calls using this slot interrupted? * Were one or more calls using this slot interrupted?
* If the server never received the request, then our * 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) { if ((s32)(slot->seq_nr - slot->seq_nr_last_acked) > 1) {
slot->seq_nr--; 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; goto retry_nowait;
} }
/* /*
......
...@@ -71,7 +71,7 @@ static unsigned int rpcrdma_max_call_header_size(unsigned int maxsegs) ...@@ -71,7 +71,7 @@ static unsigned int rpcrdma_max_call_header_size(unsigned int maxsegs)
size = RPCRDMA_HDRLEN_MIN; size = RPCRDMA_HDRLEN_MIN;
/* Maximum Read list size */ /* Maximum Read list size */
size = maxsegs * rpcrdma_readchunk_maxsz * sizeof(__be32); size += maxsegs * rpcrdma_readchunk_maxsz * sizeof(__be32);
/* Minimal Read chunk size */ /* Minimal Read chunk size */
size += sizeof(__be32); /* segment count */ size += sizeof(__be32); /* segment count */
...@@ -94,7 +94,7 @@ static unsigned int rpcrdma_max_reply_header_size(unsigned int maxsegs) ...@@ -94,7 +94,7 @@ static unsigned int rpcrdma_max_reply_header_size(unsigned int maxsegs)
size = RPCRDMA_HDRLEN_MIN; size = RPCRDMA_HDRLEN_MIN;
/* Maximum Write list size */ /* Maximum Write list size */
size = sizeof(__be32); /* segment count */ size += sizeof(__be32); /* segment count */
size += maxsegs * rpcrdma_segment_maxsz * sizeof(__be32); size += maxsegs * rpcrdma_segment_maxsz * sizeof(__be32);
size += sizeof(__be32); /* list discriminator */ size += sizeof(__be32); /* list discriminator */
......
...@@ -249,6 +249,11 @@ xprt_rdma_connect_worker(struct work_struct *work) ...@@ -249,6 +249,11 @@ xprt_rdma_connect_worker(struct work_struct *work)
xprt->stat.connect_start; xprt->stat.connect_start;
xprt_set_connected(xprt); xprt_set_connected(xprt);
rc = -EAGAIN; 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); xprt_wake_pending_tasks(xprt, rc);
} }
......
...@@ -281,17 +281,19 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) ...@@ -281,17 +281,19 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
break; break;
case RDMA_CM_EVENT_CONNECT_ERROR: case RDMA_CM_EVENT_CONNECT_ERROR:
ep->re_connect_status = -ENOTCONN; ep->re_connect_status = -ENOTCONN;
goto disconnected; goto wake_connect_worker;
case RDMA_CM_EVENT_UNREACHABLE: case RDMA_CM_EVENT_UNREACHABLE:
ep->re_connect_status = -ENETUNREACH; ep->re_connect_status = -ENETUNREACH;
goto disconnected; goto wake_connect_worker;
case RDMA_CM_EVENT_REJECTED: case RDMA_CM_EVENT_REJECTED:
dprintk("rpcrdma: connection to %pISpc rejected: %s\n", dprintk("rpcrdma: connection to %pISpc rejected: %s\n",
sap, rdma_reject_msg(id, event->status)); sap, rdma_reject_msg(id, event->status));
ep->re_connect_status = -ECONNREFUSED; ep->re_connect_status = -ECONNREFUSED;
if (event->status == IB_CM_REJ_STALE_CONN) if (event->status == IB_CM_REJ_STALE_CONN)
ep->re_connect_status = -EAGAIN; ep->re_connect_status = -ENOTCONN;
goto disconnected; wake_connect_worker:
wake_up_all(&ep->re_connect_wait);
return 0;
case RDMA_CM_EVENT_DISCONNECTED: case RDMA_CM_EVENT_DISCONNECTED:
ep->re_connect_status = -ECONNABORTED; ep->re_connect_status = -ECONNABORTED;
disconnected: disconnected:
...@@ -400,14 +402,14 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt) ...@@ -400,14 +402,14 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
ep = kzalloc(sizeof(*ep), GFP_NOFS); ep = kzalloc(sizeof(*ep), GFP_NOFS);
if (!ep) if (!ep)
return -EAGAIN; return -ENOTCONN;
ep->re_xprt = &r_xprt->rx_xprt; ep->re_xprt = &r_xprt->rx_xprt;
kref_init(&ep->re_kref); kref_init(&ep->re_kref);
id = rpcrdma_create_id(r_xprt, ep); id = rpcrdma_create_id(r_xprt, ep);
if (IS_ERR(id)) { if (IS_ERR(id)) {
rc = PTR_ERR(id); kfree(ep);
goto out_free; return PTR_ERR(id);
} }
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
device = id->device; device = id->device;
...@@ -506,9 +508,6 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt) ...@@ -506,9 +508,6 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
out_destroy: out_destroy:
rpcrdma_ep_put(ep); rpcrdma_ep_put(ep);
rdma_destroy_id(id); rdma_destroy_id(id);
out_free:
kfree(ep);
r_xprt->rx_ep = NULL;
return rc; return rc;
} }
...@@ -524,8 +523,6 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt) ...@@ -524,8 +523,6 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt)
struct rpcrdma_ep *ep; struct rpcrdma_ep *ep;
int rc; int rc;
retry:
rpcrdma_xprt_disconnect(r_xprt);
rc = rpcrdma_ep_create(r_xprt); rc = rpcrdma_ep_create(r_xprt);
if (rc) if (rc)
return rc; return rc;
...@@ -540,10 +537,6 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt) ...@@ -540,10 +537,6 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt)
rpcrdma_ep_get(ep); rpcrdma_ep_get(ep);
rpcrdma_post_recvs(r_xprt, true); 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); rc = rdma_connect(ep->re_id, &ep->re_remote_cma);
if (rc) if (rc)
goto out; goto out;
...@@ -553,15 +546,19 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt) ...@@ -553,15 +546,19 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt)
wait_event_interruptible(ep->re_connect_wait, wait_event_interruptible(ep->re_connect_wait,
ep->re_connect_status != 0); ep->re_connect_status != 0);
if (ep->re_connect_status <= 0) { if (ep->re_connect_status <= 0) {
if (ep->re_connect_status == -EAGAIN)
goto retry;
rc = ep->re_connect_status; rc = ep->re_connect_status;
goto out; goto out;
} }
rc = rpcrdma_sendctxs_create(r_xprt);
if (rc) {
rc = -ENOTCONN;
goto out;
}
rc = rpcrdma_reqs_setup(r_xprt); rc = rpcrdma_reqs_setup(r_xprt);
if (rc) { if (rc) {
rpcrdma_xprt_disconnect(r_xprt); rc = -ENOTCONN;
goto out; goto out;
} }
rpcrdma_mrs_create(r_xprt); rpcrdma_mrs_create(r_xprt);
......
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