Commit 98ef77d1 authored by Chuck Lever's avatar Chuck Lever Committed by Anna Schumaker

xprtrdma: Send Queue size grows after a reconnect

Eli Dorfman reports that after a series of idle disconnects, an
RPC/RDMA transport becomes unusable (rdma_create_qp returns
-ENOMEM). Problem was tracked down to increasing Send Queue size
after each reconnect.

The rdma_create_qp() API does not promise to leave its @qp_init_attr
parameter unaltered. In fact, some drivers do modify one or more of
its fields. Thus our calls to rdma_create_qp must use a fresh copy
of ib_qp_init_attr each time.

This fix is appropriate for kernels dating back to late 2007, though
it will have to be adapted, as the connect code has changed over the
years.
Reported-by: default avatarEli Dorfman <eli@vastdata.com>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent f9e1afe0
...@@ -606,10 +606,10 @@ void rpcrdma_ep_destroy(struct rpcrdma_xprt *r_xprt) ...@@ -606,10 +606,10 @@ void rpcrdma_ep_destroy(struct rpcrdma_xprt *r_xprt)
* Unlike a normal reconnection, a fresh PD and a new set * Unlike a normal reconnection, a fresh PD and a new set
* of MRs and buffers is needed. * of MRs and buffers is needed.
*/ */
static int static int rpcrdma_ep_recreate_xprt(struct rpcrdma_xprt *r_xprt,
rpcrdma_ep_recreate_xprt(struct rpcrdma_xprt *r_xprt, struct ib_qp_init_attr *qp_init_attr)
struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
{ {
struct rpcrdma_ia *ia = &r_xprt->rx_ia;
int rc, err; int rc, err;
trace_xprtrdma_reinsert(r_xprt); trace_xprtrdma_reinsert(r_xprt);
...@@ -626,7 +626,7 @@ rpcrdma_ep_recreate_xprt(struct rpcrdma_xprt *r_xprt, ...@@ -626,7 +626,7 @@ rpcrdma_ep_recreate_xprt(struct rpcrdma_xprt *r_xprt,
} }
rc = -ENETUNREACH; rc = -ENETUNREACH;
err = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr); err = rdma_create_qp(ia->ri_id, ia->ri_pd, qp_init_attr);
if (err) { if (err) {
pr_err("rpcrdma: rdma_create_qp returned %d\n", err); pr_err("rpcrdma: rdma_create_qp returned %d\n", err);
goto out3; goto out3;
...@@ -643,16 +643,16 @@ rpcrdma_ep_recreate_xprt(struct rpcrdma_xprt *r_xprt, ...@@ -643,16 +643,16 @@ rpcrdma_ep_recreate_xprt(struct rpcrdma_xprt *r_xprt,
return rc; return rc;
} }
static int static int rpcrdma_ep_reconnect(struct rpcrdma_xprt *r_xprt,
rpcrdma_ep_reconnect(struct rpcrdma_xprt *r_xprt, struct rpcrdma_ep *ep, struct ib_qp_init_attr *qp_init_attr)
struct rpcrdma_ia *ia)
{ {
struct rpcrdma_ia *ia = &r_xprt->rx_ia;
struct rdma_cm_id *id, *old; struct rdma_cm_id *id, *old;
int err, rc; int err, rc;
trace_xprtrdma_reconnect(r_xprt); trace_xprtrdma_reconnect(r_xprt);
rpcrdma_ep_disconnect(ep, ia); rpcrdma_ep_disconnect(&r_xprt->rx_ep, ia);
rc = -EHOSTUNREACH; rc = -EHOSTUNREACH;
id = rpcrdma_create_id(r_xprt, ia); id = rpcrdma_create_id(r_xprt, ia);
...@@ -674,7 +674,7 @@ rpcrdma_ep_reconnect(struct rpcrdma_xprt *r_xprt, struct rpcrdma_ep *ep, ...@@ -674,7 +674,7 @@ rpcrdma_ep_reconnect(struct rpcrdma_xprt *r_xprt, struct rpcrdma_ep *ep,
goto out_destroy; goto out_destroy;
} }
err = rdma_create_qp(id, ia->ri_pd, &ep->rep_attr); err = rdma_create_qp(id, ia->ri_pd, qp_init_attr);
if (err) if (err)
goto out_destroy; goto out_destroy;
...@@ -699,25 +699,27 @@ rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) ...@@ -699,25 +699,27 @@ rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
struct rpcrdma_xprt *r_xprt = container_of(ia, struct rpcrdma_xprt, struct rpcrdma_xprt *r_xprt = container_of(ia, struct rpcrdma_xprt,
rx_ia); rx_ia);
struct rpc_xprt *xprt = &r_xprt->rx_xprt; struct rpc_xprt *xprt = &r_xprt->rx_xprt;
struct ib_qp_init_attr qp_init_attr;
int rc; int rc;
retry: retry:
memcpy(&qp_init_attr, &ep->rep_attr, sizeof(qp_init_attr));
switch (ep->rep_connected) { switch (ep->rep_connected) {
case 0: case 0:
dprintk("RPC: %s: connecting...\n", __func__); dprintk("RPC: %s: connecting...\n", __func__);
rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr); rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &qp_init_attr);
if (rc) { if (rc) {
rc = -ENETUNREACH; rc = -ENETUNREACH;
goto out_noupdate; goto out_noupdate;
} }
break; break;
case -ENODEV: case -ENODEV:
rc = rpcrdma_ep_recreate_xprt(r_xprt, ep, ia); rc = rpcrdma_ep_recreate_xprt(r_xprt, &qp_init_attr);
if (rc) if (rc)
goto out_noupdate; goto out_noupdate;
break; break;
default: default:
rc = rpcrdma_ep_reconnect(r_xprt, ep, ia); rc = rpcrdma_ep_reconnect(r_xprt, &qp_init_attr);
if (rc) if (rc)
goto out; goto out;
} }
......
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