📄 verbs.c
字号:
break; default: break; } } rpcrdma_deregister_internal(ia, buf->rb_send_bufs[i]->rl_handle, &buf->rb_send_bufs[i]->rl_iov); kfree(buf->rb_send_bufs[i]); } } kfree(buf->rb_pool);}/* * Get a set of request/reply buffers. * * Reply buffer (if needed) is attached to send buffer upon return. * Rule: * rb_send_index and rb_recv_index MUST always be pointing to the * *next* available buffer (non-NULL). They are incremented after * removing buffers, and decremented *before* returning them. */struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *buffers){ struct rpcrdma_req *req; unsigned long flags; spin_lock_irqsave(&buffers->rb_lock, flags); if (buffers->rb_send_index == buffers->rb_max_requests) { spin_unlock_irqrestore(&buffers->rb_lock, flags); dprintk("RPC: %s: out of request buffers\n", __func__); return ((struct rpcrdma_req *)NULL); } req = buffers->rb_send_bufs[buffers->rb_send_index]; if (buffers->rb_send_index < buffers->rb_recv_index) { dprintk("RPC: %s: %d extra receives outstanding (ok)\n", __func__, buffers->rb_recv_index - buffers->rb_send_index); req->rl_reply = NULL; } else { req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index]; buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL; } buffers->rb_send_bufs[buffers->rb_send_index++] = NULL; if (!list_empty(&buffers->rb_mws)) { int i = RPCRDMA_MAX_SEGS - 1; do { struct rpcrdma_mw *r; r = list_entry(buffers->rb_mws.next, struct rpcrdma_mw, mw_list); list_del(&r->mw_list); req->rl_segments[i].mr_chunk.rl_mw = r; } while (--i >= 0); } spin_unlock_irqrestore(&buffers->rb_lock, flags); return req;}/* * Put request/reply buffers back into pool. * Pre-decrement counter/array index. */voidrpcrdma_buffer_put(struct rpcrdma_req *req){ struct rpcrdma_buffer *buffers = req->rl_buffer; struct rpcrdma_ia *ia = rdmab_to_ia(buffers); int i; unsigned long flags; BUG_ON(req->rl_nchunks != 0); spin_lock_irqsave(&buffers->rb_lock, flags); buffers->rb_send_bufs[--buffers->rb_send_index] = req; req->rl_niovs = 0; if (req->rl_reply) { buffers->rb_recv_bufs[--buffers->rb_recv_index] = req->rl_reply; init_waitqueue_head(&req->rl_reply->rr_unbind); req->rl_reply->rr_func = NULL; req->rl_reply = NULL; } switch (ia->ri_memreg_strategy) { case RPCRDMA_MTHCAFMR: case RPCRDMA_MEMWINDOWS_ASYNC: case RPCRDMA_MEMWINDOWS: /* * Cycle mw's back in reverse order, and "spin" them. * This delays and scrambles reuse as much as possible. */ i = 1; do { struct rpcrdma_mw **mw; mw = &req->rl_segments[i].mr_chunk.rl_mw; list_add_tail(&(*mw)->mw_list, &buffers->rb_mws); *mw = NULL; } while (++i < RPCRDMA_MAX_SEGS); list_add_tail(&req->rl_segments[0].mr_chunk.rl_mw->mw_list, &buffers->rb_mws); req->rl_segments[0].mr_chunk.rl_mw = NULL; break; default: break; } spin_unlock_irqrestore(&buffers->rb_lock, flags);}/* * Recover reply buffers from pool. * This happens when recovering from error conditions. * Post-increment counter/array index. */voidrpcrdma_recv_buffer_get(struct rpcrdma_req *req){ struct rpcrdma_buffer *buffers = req->rl_buffer; unsigned long flags; if (req->rl_iov.length == 0) /* special case xprt_rdma_allocate() */ buffers = ((struct rpcrdma_req *) buffers)->rl_buffer; spin_lock_irqsave(&buffers->rb_lock, flags); if (buffers->rb_recv_index < buffers->rb_max_requests) { req->rl_reply = buffers->rb_recv_bufs[buffers->rb_recv_index]; buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL; } spin_unlock_irqrestore(&buffers->rb_lock, flags);}/* * Put reply buffers back into pool when not attached to * request. This happens in error conditions, and when * aborting unbinds. Pre-decrement counter/array index. */voidrpcrdma_recv_buffer_put(struct rpcrdma_rep *rep){ struct rpcrdma_buffer *buffers = rep->rr_buffer; unsigned long flags; rep->rr_func = NULL; spin_lock_irqsave(&buffers->rb_lock, flags); buffers->rb_recv_bufs[--buffers->rb_recv_index] = rep; spin_unlock_irqrestore(&buffers->rb_lock, flags);}/* * Wrappers for internal-use kmalloc memory registration, used by buffer code. */intrpcrdma_register_internal(struct rpcrdma_ia *ia, void *va, int len, struct ib_mr **mrp, struct ib_sge *iov){ struct ib_phys_buf ipb; struct ib_mr *mr; int rc; /* * All memory passed here was kmalloc'ed, therefore phys-contiguous. */ iov->addr = ib_dma_map_single(ia->ri_id->device, va, len, DMA_BIDIRECTIONAL); iov->length = len; if (ia->ri_bind_mem != NULL) { *mrp = NULL; iov->lkey = ia->ri_bind_mem->lkey; return 0; } ipb.addr = iov->addr; ipb.size = iov->length; mr = ib_reg_phys_mr(ia->ri_pd, &ipb, 1, IB_ACCESS_LOCAL_WRITE, &iov->addr); dprintk("RPC: %s: phys convert: 0x%llx " "registered 0x%llx length %d\n", __func__, (unsigned long long)ipb.addr, (unsigned long long)iov->addr, len); if (IS_ERR(mr)) { *mrp = NULL; rc = PTR_ERR(mr); dprintk("RPC: %s: failed with %i\n", __func__, rc); } else { *mrp = mr; iov->lkey = mr->lkey; rc = 0; } return rc;}intrpcrdma_deregister_internal(struct rpcrdma_ia *ia, struct ib_mr *mr, struct ib_sge *iov){ int rc; ib_dma_unmap_single(ia->ri_id->device, iov->addr, iov->length, DMA_BIDIRECTIONAL); if (NULL == mr) return 0; rc = ib_dereg_mr(mr); if (rc) dprintk("RPC: %s: ib_dereg_mr failed %i\n", __func__, rc); return rc;}/* * Wrappers for chunk registration, shared by read/write chunk code. */static voidrpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, int writing){ seg->mr_dir = writing ? DMA_FROM_DEVICE : DMA_TO_DEVICE; seg->mr_dmalen = seg->mr_len; if (seg->mr_page) seg->mr_dma = ib_dma_map_page(ia->ri_id->device, seg->mr_page, offset_in_page(seg->mr_offset), seg->mr_dmalen, seg->mr_dir); else seg->mr_dma = ib_dma_map_single(ia->ri_id->device, seg->mr_offset, seg->mr_dmalen, seg->mr_dir);}static voidrpcrdma_unmap_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg){ if (seg->mr_page) ib_dma_unmap_page(ia->ri_id->device, seg->mr_dma, seg->mr_dmalen, seg->mr_dir); else ib_dma_unmap_single(ia->ri_id->device, seg->mr_dma, seg->mr_dmalen, seg->mr_dir);}intrpcrdma_register_external(struct rpcrdma_mr_seg *seg, int nsegs, int writing, struct rpcrdma_xprt *r_xprt){ struct rpcrdma_ia *ia = &r_xprt->rx_ia; int mem_priv = (writing ? IB_ACCESS_REMOTE_WRITE : IB_ACCESS_REMOTE_READ); struct rpcrdma_mr_seg *seg1 = seg; int i; int rc = 0; switch (ia->ri_memreg_strategy) {#if RPCRDMA_PERSISTENT_REGISTRATION case RPCRDMA_ALLPHYSICAL: rpcrdma_map_one(ia, seg, writing); seg->mr_rkey = ia->ri_bind_mem->rkey; seg->mr_base = seg->mr_dma; seg->mr_nsegs = 1; nsegs = 1; break;#endif /* Registration using fast memory registration */ case RPCRDMA_MTHCAFMR: { u64 physaddrs[RPCRDMA_MAX_DATA_SEGS]; int len, pageoff = offset_in_page(seg->mr_offset); seg1->mr_offset -= pageoff; /* start of page */ seg1->mr_len += pageoff; len = -pageoff; if (nsegs > RPCRDMA_MAX_DATA_SEGS) nsegs = RPCRDMA_MAX_DATA_SEGS; for (i = 0; i < nsegs;) { rpcrdma_map_one(ia, seg, writing); physaddrs[i] = seg->mr_dma; len += seg->mr_len; ++seg; ++i; /* Check for holes */ if ((i < nsegs && offset_in_page(seg->mr_offset)) || offset_in_page((seg-1)->mr_offset+(seg-1)->mr_len)) break; } nsegs = i; rc = ib_map_phys_fmr(seg1->mr_chunk.rl_mw->r.fmr, physaddrs, nsegs, seg1->mr_dma); if (rc) { dprintk("RPC: %s: failed ib_map_phys_fmr " "%u@0x%llx+%i (%d)... status %i\n", __func__, len, (unsigned long long)seg1->mr_dma, pageoff, nsegs, rc); while (nsegs--) rpcrdma_unmap_one(ia, --seg); } else { seg1->mr_rkey = seg1->mr_chunk.rl_mw->r.fmr->rkey; seg1->mr_base = seg1->mr_dma + pageoff; seg1->mr_nsegs = nsegs; seg1->mr_len = len; } } break; /* Registration using memory windows */ case RPCRDMA_MEMWINDOWS_ASYNC: case RPCRDMA_MEMWINDOWS: { struct ib_mw_bind param; rpcrdma_map_one(ia, seg, writing); param.mr = ia->ri_bind_mem; param.wr_id = 0ULL; /* no send cookie */ param.addr = seg->mr_dma; param.length = seg->mr_len; param.send_flags = 0; param.mw_access_flags = mem_priv; DECR_CQCOUNT(&r_xprt->rx_ep); rc = ib_bind_mw(ia->ri_id->qp, seg->mr_chunk.rl_mw->r.mw, ¶m); if (rc) { dprintk("RPC: %s: failed ib_bind_mw " "%u@0x%llx status %i\n", __func__, seg->mr_len, (unsigned long long)seg->mr_dma, rc); rpcrdma_unmap_one(ia, seg); } else { seg->mr_rkey = seg->mr_chunk.rl_mw->r.mw->rkey; seg->mr_base = param.addr; seg->mr_nsegs = 1; nsegs = 1; } } break; /* Default registration each time */ default: { struct ib_phys_buf ipb[RPCRDMA_MAX_DATA_SEGS]; int len = 0; if (nsegs > RPCRDMA_MAX_DATA_SEGS) nsegs = RPCRDMA_MAX_DATA_SEGS; for (i = 0; i < nsegs;) { rpcrdma_map_one(ia, seg, writing); ipb[i].addr = seg->mr_dma; ipb[i].size = seg->mr_len; len += seg->mr_len; ++seg; ++i; /* Check for holes */ if ((i < nsegs && offset_in_page(seg->mr_offset)) || offset_in_page((seg-1)->mr_offset+(seg-1)->mr_len)) break; } nsegs = i; seg1->mr_base = seg1->mr_dma; seg1->mr_chunk.rl_mr = ib_reg_phys_mr(ia->ri_pd, ipb, nsegs, mem_priv, &seg1->mr_base); if (IS_ERR(seg1->mr_chunk.rl_mr)) { rc = PTR_ERR(seg1->mr_chunk.rl_mr); dprintk("RPC: %s: failed ib_reg_phys_mr " "%u@0x%llx (%d)... status %i\n", __func__, len, (unsigned long long)seg1->mr_dma, nsegs, rc); while (nsegs--) rpcrdma_unmap_one(ia, --seg); } else { seg1->mr_rkey = seg1->mr_chunk.rl_mr->rkey; seg1->mr_nsegs = nsegs; seg1->mr_len = len; } } break; } if (rc) return -1; return nsegs;}intrpcrdma_deregister_external(struct rpcrdma_mr_seg *seg, struct rpcrdma_xprt *r_xprt, void *r){ struct rpcrdma_ia *ia = &r_xprt->rx_ia; struct rpcrdma_mr_seg *seg1 = seg; int nsegs = seg->mr_nsegs, rc; switch (ia->ri_memreg_strategy) {#if RPCRDMA_PERSISTENT_REGISTRATION case RPCRDMA_ALLPHYSICAL: BUG_ON(nsegs != 1); rpcrdma_unmap_one(ia, seg); rc = 0; break;#endif case RPCRDMA_MTHCAFMR: { LIST_HEAD(l); list_add(&seg->mr_chunk.rl_mw->r.fmr->list, &l); rc = ib_unmap_fmr(&l); while (seg1->mr_nsegs--) rpcrdma_unmap_one(ia, seg++); } if (rc) dprintk("RPC: %s: failed ib_unmap_fmr," " status %i\n", __func__, rc); break; case RPCRDMA_MEMWINDOWS_ASYNC: case RPCRDMA_MEMWINDOWS: { struct ib_mw_bind param; BUG_ON(nsegs != 1); param.mr = ia->ri_bind_mem; param.addr = 0ULL; /* unbind */ param.length = 0; param.mw_access_flags = 0; if (r) { param.wr_id = (u64) (unsigned long) r; param.send_flags = IB_SEND_SIGNALED; INIT_CQCOUNT(&r_xprt->rx_ep); } else { param.wr_id = 0ULL; param.send_flags = 0; DECR_CQCOUNT(&r_xprt->rx_ep); } rc = ib_bind_mw(ia->ri_id->qp, seg->mr_chunk.rl_mw->r.mw, ¶m); rpcrdma_unmap_one(ia, seg); } if (rc) dprintk("RPC: %s: failed ib_(un)bind_mw," " status %i\n", __func__, rc); else r = NULL; /* will upcall on completion */ break; default: rc = ib_dereg_mr(seg1->mr_chunk.rl_mr); seg1->mr_chunk.rl_mr = NULL; while (seg1->mr_nsegs--) rpcrdma_unmap_one(ia, seg++); if (rc) dprintk("RPC: %s: failed ib_dereg_mr," " status %i\n", __func__, rc); break; } if (r) { struct rpcrdma_rep *rep = r; void (*func)(struct rpcrdma_rep *) = rep->rr_func; rep->rr_func = NULL; func(rep); /* dereg done, callback now */ } return nsegs;}/* * Prepost any receive buffer, then post send. * * Receive buffer is donated to hardware, reclaimed upon recv completion. */intrpcrdma_ep_post(struct rpcrdma_ia *ia, struct rpcrdma_ep *ep, struct rpcrdma_req *req){ struct ib_send_wr send_wr, *send_wr_fail; struct rpcrdma_rep *rep = req->rl_reply; int rc; if (rep) { rc = rpcrdma_ep_post_recv(ia, ep, rep); if (rc) goto out; req->rl_reply = NULL; } send_wr.next = NULL; send_wr.wr_id = 0ULL; /* no send cookie */ send_wr.sg_list = req->rl_send_iov; send_wr.num_sge = req->rl_niovs; send_wr.opcode = IB_WR_SEND; send_wr.imm_data = 0; if (send_wr.num_sge == 4) /* no need to sync any pad (constant) */ ib_dma_sync_single_for_device(ia->ri_id->device, req->rl_send_iov[3].addr, req->rl_send_iov[3].length, DMA_TO_DEVICE); ib_dma_sync_single_for_device(ia->ri_id->device, req->rl_send_iov[1].addr, req->rl_send_iov[1].length, DMA_TO_DEVICE); ib_dma_sync_single_for_device(ia->ri_id->device, req->rl_send_iov[0].addr, req->rl_send_iov[0].length, DMA_TO_DEVICE); if (DECR_CQCOUNT(ep) > 0) send_wr.send_flags = 0; else { /* Provider must take a send completion every now and then */ INIT_CQCOUNT(ep); send_wr.send_flags = IB_SEND_SIGNALED; } rc = ib_post_send(ia->ri_id->qp, &send_wr, &send_wr_fail); if (rc) dprintk("RPC: %s: ib_post_send returned %i\n", __func__, rc);out: return rc;}/* * (Re)post a receive buffer. */intrpcrdma_ep_post_recv(struct rpcrdma_ia *ia, struct rpcrdma_ep *ep, struct rpcrdma_rep *rep){ struct ib_recv_wr recv_wr, *recv_wr_fail; int rc; recv_wr.next = NULL; recv_wr.wr_id = (u64) (unsigned long) rep; recv_wr.sg_list = &rep->rr_iov; recv_wr.num_sge = 1; ib_dma_sync_single_for_cpu(ia->ri_id->device, rep->rr_iov.addr, rep->rr_iov.length, DMA_BIDIRECTIONAL); DECR_CQCOUNT(ep); rc = ib_post_recv(ia->ri_id->qp, &recv_wr, &recv_wr_fail); if (rc) dprintk("RPC: %s: ib_post_recv returned %i\n", __func__, rc); return rc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -