Commit 95e20af9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client bugfixes from Anna Schumaker:
 "Three NFS over RDMA fixes for bugs Chuck found that can be hit during
  device removal:

   - Fix create_qp crash on device unload

   - Fix completion wait during device removal

   - Fix oops in receive handler after device removal"

* tag 'nfs-for-5.5-2' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  xprtrdma: Fix oops in Receive handler after device removal
  xprtrdma: Fix completion wait during device removal
  xprtrdma: Fix create_qp crash on device unload
parents 452424cd 671c450b
Loading
Loading
Loading
Loading
+22 −7
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@
static void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt,
				       struct rpcrdma_sendctx *sc);
static void rpcrdma_reqs_reset(struct rpcrdma_xprt *r_xprt);
static void rpcrdma_reps_destroy(struct rpcrdma_buffer *buf);
static void rpcrdma_reps_unmap(struct rpcrdma_xprt *r_xprt);
static void rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt);
static void rpcrdma_mrs_destroy(struct rpcrdma_xprt *r_xprt);
static struct rpcrdma_regbuf *
@@ -244,6 +244,7 @@ rpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
			ia->ri_id->device->name,
			rpcrdma_addrstr(r_xprt), rpcrdma_portstr(r_xprt));
#endif
		init_completion(&ia->ri_remove_done);
		set_bit(RPCRDMA_IAF_REMOVING, &ia->ri_flags);
		ep->rep_connected = -ENODEV;
		xprt_force_disconnect(xprt);
@@ -297,7 +298,6 @@ rpcrdma_create_id(struct rpcrdma_xprt *xprt, struct rpcrdma_ia *ia)
	int rc;

	init_completion(&ia->ri_done);
	init_completion(&ia->ri_remove_done);

	id = rdma_create_id(xprt->rx_xprt.xprt_net, rpcrdma_cm_event_handler,
			    xprt, RDMA_PS_TCP, IB_QPT_RC);
@@ -421,7 +421,7 @@ rpcrdma_ia_remove(struct rpcrdma_ia *ia)
	/* The ULP is responsible for ensuring all DMA
	 * mappings and MRs are gone.
	 */
	rpcrdma_reps_destroy(buf);
	rpcrdma_reps_unmap(r_xprt);
	list_for_each_entry(req, &buf->rb_allreqs, rl_all) {
		rpcrdma_regbuf_dma_unmap(req->rl_rdmabuf);
		rpcrdma_regbuf_dma_unmap(req->rl_sendbuf);
@@ -599,6 +599,7 @@ static int rpcrdma_ep_recreate_xprt(struct rpcrdma_xprt *r_xprt,
				    struct ib_qp_init_attr *qp_init_attr)
{
	struct rpcrdma_ia *ia = &r_xprt->rx_ia;
	struct rpcrdma_ep *ep = &r_xprt->rx_ep;
	int rc, err;

	trace_xprtrdma_reinsert(r_xprt);
@@ -613,6 +614,7 @@ static int rpcrdma_ep_recreate_xprt(struct rpcrdma_xprt *r_xprt,
		pr_err("rpcrdma: rpcrdma_ep_create returned %d\n", err);
		goto out2;
	}
	memcpy(qp_init_attr, &ep->rep_attr, sizeof(*qp_init_attr));

	rc = -ENETUNREACH;
	err = rdma_create_qp(ia->ri_id, ia->ri_pd, qp_init_attr);
@@ -1090,6 +1092,7 @@ static struct rpcrdma_rep *rpcrdma_rep_create(struct rpcrdma_xprt *r_xprt,
	rep->rr_recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov;
	rep->rr_recv_wr.num_sge = 1;
	rep->rr_temp = temp;
	list_add(&rep->rr_all, &r_xprt->rx_buf.rb_all_reps);
	return rep;

out_free:
@@ -1100,6 +1103,7 @@ out:

static void rpcrdma_rep_destroy(struct rpcrdma_rep *rep)
{
	list_del(&rep->rr_all);
	rpcrdma_regbuf_free(rep->rr_rdmabuf);
	kfree(rep);
}
@@ -1118,10 +1122,16 @@ static struct rpcrdma_rep *rpcrdma_rep_get_locked(struct rpcrdma_buffer *buf)
static void rpcrdma_rep_put(struct rpcrdma_buffer *buf,
			    struct rpcrdma_rep *rep)
{
	if (!rep->rr_temp)
	llist_add(&rep->rr_node, &buf->rb_free_reps);
	else
		rpcrdma_rep_destroy(rep);
}

static void rpcrdma_reps_unmap(struct rpcrdma_xprt *r_xprt)
{
	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
	struct rpcrdma_rep *rep;

	list_for_each_entry(rep, &buf->rb_all_reps, rr_all)
		rpcrdma_regbuf_dma_unmap(rep->rr_rdmabuf);
}

static void rpcrdma_reps_destroy(struct rpcrdma_buffer *buf)
@@ -1152,6 +1162,7 @@ int rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)

	INIT_LIST_HEAD(&buf->rb_send_bufs);
	INIT_LIST_HEAD(&buf->rb_allreqs);
	INIT_LIST_HEAD(&buf->rb_all_reps);

	rc = -ENOMEM;
	for (i = 0; i < buf->rb_max_requests; i++) {
@@ -1504,6 +1515,10 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, bool temp)
	wr = NULL;
	while (needed) {
		rep = rpcrdma_rep_get_locked(buf);
		if (rep && rep->rr_temp) {
			rpcrdma_rep_destroy(rep);
			continue;
		}
		if (!rep)
			rep = rpcrdma_rep_create(r_xprt, temp);
		if (!rep)
+2 −0
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ struct rpcrdma_rep {
	struct xdr_stream	rr_stream;
	struct llist_node	rr_node;
	struct ib_recv_wr	rr_recv_wr;
	struct list_head	rr_all;
};

/* To reduce the rate at which a transport invokes ib_post_recv
@@ -368,6 +369,7 @@ struct rpcrdma_buffer {

	struct list_head	rb_allreqs;
	struct list_head	rb_all_mrs;
	struct list_head	rb_all_reps;

	struct llist_head	rb_free_reps;