⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 verbs.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
					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, &param);		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, &param);		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 + -