|
@@ -831,7 +831,21 @@ retry:
|
|
}
|
|
}
|
|
rc = ep->rep_connected;
|
|
rc = ep->rep_connected;
|
|
} else {
|
|
} else {
|
|
|
|
+ struct rpcrdma_xprt *r_xprt;
|
|
|
|
+ unsigned int extras;
|
|
|
|
+
|
|
dprintk("RPC: %s: connected\n", __func__);
|
|
dprintk("RPC: %s: connected\n", __func__);
|
|
|
|
+
|
|
|
|
+ r_xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
|
|
|
|
+ extras = r_xprt->rx_buf.rb_bc_srv_max_requests;
|
|
|
|
+
|
|
|
|
+ if (extras) {
|
|
|
|
+ rc = rpcrdma_ep_post_extra_recv(r_xprt, extras);
|
|
|
|
+ if (rc)
|
|
|
|
+ pr_warn("%s: rpcrdma_ep_post_extra_recv: %i\n",
|
|
|
|
+ __func__, rc);
|
|
|
|
+ rc = 0;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
out:
|
|
out:
|
|
@@ -868,20 +882,25 @@ rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static struct rpcrdma_req *
|
|
|
|
|
|
+struct rpcrdma_req *
|
|
rpcrdma_create_req(struct rpcrdma_xprt *r_xprt)
|
|
rpcrdma_create_req(struct rpcrdma_xprt *r_xprt)
|
|
{
|
|
{
|
|
|
|
+ struct rpcrdma_buffer *buffer = &r_xprt->rx_buf;
|
|
struct rpcrdma_req *req;
|
|
struct rpcrdma_req *req;
|
|
|
|
|
|
req = kzalloc(sizeof(*req), GFP_KERNEL);
|
|
req = kzalloc(sizeof(*req), GFP_KERNEL);
|
|
if (req == NULL)
|
|
if (req == NULL)
|
|
return ERR_PTR(-ENOMEM);
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
+ INIT_LIST_HEAD(&req->rl_free);
|
|
|
|
+ spin_lock(&buffer->rb_reqslock);
|
|
|
|
+ list_add(&req->rl_all, &buffer->rb_allreqs);
|
|
|
|
+ spin_unlock(&buffer->rb_reqslock);
|
|
req->rl_buffer = &r_xprt->rx_buf;
|
|
req->rl_buffer = &r_xprt->rx_buf;
|
|
return req;
|
|
return req;
|
|
}
|
|
}
|
|
|
|
|
|
-static struct rpcrdma_rep *
|
|
|
|
|
|
+struct rpcrdma_rep *
|
|
rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt)
|
|
rpcrdma_create_rep(struct rpcrdma_xprt *r_xprt)
|
|
{
|
|
{
|
|
struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
|
|
struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data;
|
|
@@ -920,6 +939,7 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
|
|
int i, rc;
|
|
int i, rc;
|
|
|
|
|
|
buf->rb_max_requests = r_xprt->rx_data.max_requests;
|
|
buf->rb_max_requests = r_xprt->rx_data.max_requests;
|
|
|
|
+ buf->rb_bc_srv_max_requests = 0;
|
|
spin_lock_init(&buf->rb_lock);
|
|
spin_lock_init(&buf->rb_lock);
|
|
|
|
|
|
rc = ia->ri_ops->ro_init(r_xprt);
|
|
rc = ia->ri_ops->ro_init(r_xprt);
|
|
@@ -927,6 +947,8 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
INIT_LIST_HEAD(&buf->rb_send_bufs);
|
|
INIT_LIST_HEAD(&buf->rb_send_bufs);
|
|
|
|
+ INIT_LIST_HEAD(&buf->rb_allreqs);
|
|
|
|
+ spin_lock_init(&buf->rb_reqslock);
|
|
for (i = 0; i < buf->rb_max_requests; i++) {
|
|
for (i = 0; i < buf->rb_max_requests; i++) {
|
|
struct rpcrdma_req *req;
|
|
struct rpcrdma_req *req;
|
|
|
|
|
|
@@ -937,6 +959,7 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
|
|
rc = PTR_ERR(req);
|
|
rc = PTR_ERR(req);
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
+ req->rl_backchannel = false;
|
|
list_add(&req->rl_free, &buf->rb_send_bufs);
|
|
list_add(&req->rl_free, &buf->rb_send_bufs);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -985,19 +1008,13 @@ rpcrdma_buffer_get_rep_locked(struct rpcrdma_buffer *buf)
|
|
static void
|
|
static void
|
|
rpcrdma_destroy_rep(struct rpcrdma_ia *ia, struct rpcrdma_rep *rep)
|
|
rpcrdma_destroy_rep(struct rpcrdma_ia *ia, struct rpcrdma_rep *rep)
|
|
{
|
|
{
|
|
- if (!rep)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
rpcrdma_free_regbuf(ia, rep->rr_rdmabuf);
|
|
rpcrdma_free_regbuf(ia, rep->rr_rdmabuf);
|
|
kfree(rep);
|
|
kfree(rep);
|
|
}
|
|
}
|
|
|
|
|
|
-static void
|
|
|
|
|
|
+void
|
|
rpcrdma_destroy_req(struct rpcrdma_ia *ia, struct rpcrdma_req *req)
|
|
rpcrdma_destroy_req(struct rpcrdma_ia *ia, struct rpcrdma_req *req)
|
|
{
|
|
{
|
|
- if (!req)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
rpcrdma_free_regbuf(ia, req->rl_sendbuf);
|
|
rpcrdma_free_regbuf(ia, req->rl_sendbuf);
|
|
rpcrdma_free_regbuf(ia, req->rl_rdmabuf);
|
|
rpcrdma_free_regbuf(ia, req->rl_rdmabuf);
|
|
kfree(req);
|
|
kfree(req);
|
|
@@ -1015,12 +1032,19 @@ rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
|
|
rpcrdma_destroy_rep(ia, rep);
|
|
rpcrdma_destroy_rep(ia, rep);
|
|
}
|
|
}
|
|
|
|
|
|
- while (!list_empty(&buf->rb_send_bufs)) {
|
|
|
|
|
|
+ spin_lock(&buf->rb_reqslock);
|
|
|
|
+ while (!list_empty(&buf->rb_allreqs)) {
|
|
struct rpcrdma_req *req;
|
|
struct rpcrdma_req *req;
|
|
|
|
|
|
- req = rpcrdma_buffer_get_req_locked(buf);
|
|
|
|
|
|
+ req = list_first_entry(&buf->rb_allreqs,
|
|
|
|
+ struct rpcrdma_req, rl_all);
|
|
|
|
+ list_del(&req->rl_all);
|
|
|
|
+
|
|
|
|
+ spin_unlock(&buf->rb_reqslock);
|
|
rpcrdma_destroy_req(ia, req);
|
|
rpcrdma_destroy_req(ia, req);
|
|
|
|
+ spin_lock(&buf->rb_reqslock);
|
|
}
|
|
}
|
|
|
|
+ spin_unlock(&buf->rb_reqslock);
|
|
|
|
|
|
ia->ri_ops->ro_destroy(buf);
|
|
ia->ri_ops->ro_destroy(buf);
|
|
}
|
|
}
|
|
@@ -1288,6 +1312,47 @@ rpcrdma_ep_post_recv(struct rpcrdma_ia *ia,
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * rpcrdma_ep_post_extra_recv - Post buffers for incoming backchannel requests
|
|
|
|
+ * @r_xprt: transport associated with these backchannel resources
|
|
|
|
+ * @min_reqs: minimum number of incoming requests expected
|
|
|
|
+ *
|
|
|
|
+ * Returns zero if all requested buffers were posted, or a negative errno.
|
|
|
|
+ */
|
|
|
|
+int
|
|
|
|
+rpcrdma_ep_post_extra_recv(struct rpcrdma_xprt *r_xprt, unsigned int count)
|
|
|
|
+{
|
|
|
|
+ struct rpcrdma_buffer *buffers = &r_xprt->rx_buf;
|
|
|
|
+ struct rpcrdma_ia *ia = &r_xprt->rx_ia;
|
|
|
|
+ struct rpcrdma_ep *ep = &r_xprt->rx_ep;
|
|
|
|
+ struct rpcrdma_rep *rep;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ int rc;
|
|
|
|
+
|
|
|
|
+ while (count--) {
|
|
|
|
+ spin_lock_irqsave(&buffers->rb_lock, flags);
|
|
|
|
+ if (list_empty(&buffers->rb_recv_bufs))
|
|
|
|
+ goto out_reqbuf;
|
|
|
|
+ rep = rpcrdma_buffer_get_rep_locked(buffers);
|
|
|
|
+ spin_unlock_irqrestore(&buffers->rb_lock, flags);
|
|
|
|
+
|
|
|
|
+ rc = rpcrdma_ep_post_recv(ia, ep, rep);
|
|
|
|
+ if (rc)
|
|
|
|
+ goto out_rc;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+out_reqbuf:
|
|
|
|
+ spin_unlock_irqrestore(&buffers->rb_lock, flags);
|
|
|
|
+ pr_warn("%s: no extra receive buffers\n", __func__);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+out_rc:
|
|
|
|
+ rpcrdma_recv_buffer_put(rep);
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
/* How many chunk list items fit within our inline buffers?
|
|
/* How many chunk list items fit within our inline buffers?
|
|
*/
|
|
*/
|
|
unsigned int
|
|
unsigned int
|