|
@@ -190,6 +190,28 @@ rpcrdma_receive_worker(struct work_struct *work)
|
|
|
rpcrdma_reply_handler(rep);
|
|
|
}
|
|
|
|
|
|
+/* Perform basic sanity checking to avoid using garbage
|
|
|
+ * to update the credit grant value.
|
|
|
+ */
|
|
|
+static void
|
|
|
+rpcrdma_update_granted_credits(struct rpcrdma_rep *rep)
|
|
|
+{
|
|
|
+ struct rpcrdma_msg *rmsgp = rdmab_to_msg(rep->rr_rdmabuf);
|
|
|
+ struct rpcrdma_buffer *buffer = &rep->rr_rxprt->rx_buf;
|
|
|
+ u32 credits;
|
|
|
+
|
|
|
+ if (rep->rr_len < RPCRDMA_HDRLEN_ERR)
|
|
|
+ return;
|
|
|
+
|
|
|
+ credits = be32_to_cpu(rmsgp->rm_credit);
|
|
|
+ if (credits == 0)
|
|
|
+ credits = 1; /* don't deadlock */
|
|
|
+ else if (credits > buffer->rb_max_requests)
|
|
|
+ credits = buffer->rb_max_requests;
|
|
|
+
|
|
|
+ atomic_set(&buffer->rb_credits, credits);
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
rpcrdma_recvcq_process_wc(struct ib_wc *wc)
|
|
|
{
|
|
@@ -211,7 +233,8 @@ rpcrdma_recvcq_process_wc(struct ib_wc *wc)
|
|
|
ib_dma_sync_single_for_cpu(rep->rr_device,
|
|
|
rdmab_addr(rep->rr_rdmabuf),
|
|
|
rep->rr_len, DMA_FROM_DEVICE);
|
|
|
- prefetch(rdmab_to_msg(rep->rr_rdmabuf));
|
|
|
+
|
|
|
+ rpcrdma_update_granted_credits(rep);
|
|
|
|
|
|
out_schedule:
|
|
|
queue_work(rpcrdma_receive_wq, &rep->rr_work);
|
|
@@ -330,6 +353,7 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
|
|
|
connected:
|
|
|
dprintk("RPC: %s: %sconnected\n",
|
|
|
__func__, connstate > 0 ? "" : "dis");
|
|
|
+ atomic_set(&xprt->rx_buf.rb_credits, 1);
|
|
|
ep->rep_connected = connstate;
|
|
|
rpcrdma_conn_func(ep);
|
|
|
wake_up_all(&ep->rep_connect_wait);
|
|
@@ -943,6 +967,7 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt)
|
|
|
buf->rb_max_requests = r_xprt->rx_data.max_requests;
|
|
|
buf->rb_bc_srv_max_requests = 0;
|
|
|
spin_lock_init(&buf->rb_lock);
|
|
|
+ atomic_set(&buf->rb_credits, 1);
|
|
|
|
|
|
rc = ia->ri_ops->ro_init(r_xprt);
|
|
|
if (rc)
|