RDMA内核态函数ib_post_recv()源码分析

接上文,上文分析了内核rdma向发送队列添加发送请求的函数ib_post_send,本文分析一下向接收队列添加接收请求的函数ib_post_recv。其实函数调用流程与上文类似,不再重复说明,可参考链接。
函数调用过程

最终会调用到这个函数

下面是这个函数的完整代码

c 复制代码
int mlx5_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
		      const struct ib_recv_wr **bad_wr, bool drain)
{
	struct mlx5_ib_qp *qp = to_mqp(ibqp);
	struct mlx5_wqe_data_seg *scat;
	struct mlx5_rwqe_sig *sig;
	struct mlx5_ib_dev *dev = to_mdev(ibqp->device);
	struct mlx5_core_dev *mdev = dev->mdev;
	unsigned long flags;
	int err = 0;
	int nreq;
	int ind;
	int i;

	if (unlikely(mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR &&
		     !drain)) {
		*bad_wr = wr;
		return -EIO;
	}

	if (qp->type == IB_QPT_GSI)
		return mlx5_ib_gsi_post_recv(ibqp, wr, bad_wr);

	spin_lock_irqsave(&qp->rq.lock, flags);

	ind = qp->rq.head & (qp->rq.wqe_cnt - 1);

	for (nreq = 0; wr; nreq++, wr = wr->next) {
		if (mlx5_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) {
			err = -ENOMEM;
			*bad_wr = wr;
			goto out;
		}

		if (unlikely(wr->num_sge > qp->rq.max_gs)) {
			err = -EINVAL;
			*bad_wr = wr;
			goto out;
		}

		scat = mlx5_frag_buf_get_wqe(&qp->rq.fbc, ind);
		if (qp->flags_en & MLX5_QP_FLAG_SIGNATURE)
			scat++;

		for (i = 0; i < wr->num_sge; i++)
			set_data_ptr_seg(scat + i, wr->sg_list + i);

		if (i < qp->rq.max_gs) {
			scat[i].byte_count = 0;
			scat[i].lkey       = cpu_to_be32(MLX5_INVALID_LKEY);
			scat[i].addr       = 0;
		}

		if (qp->flags_en & MLX5_QP_FLAG_SIGNATURE) {
			sig = (struct mlx5_rwqe_sig *)scat;
			set_sig_seg(sig, qp->rq.max_gs);
		}

		qp->rq.wrid[ind] = wr->wr_id;

		ind = (ind + 1) & (qp->rq.wqe_cnt - 1);
	}

out:
	if (likely(nreq)) {
		qp->rq.head += nreq;

		/* Make sure that descriptors are written before
		 * doorbell record.
		 */
		wmb();

		*qp->db.db = cpu_to_be32(qp->rq.head & 0xffff);
	}

	spin_unlock_irqrestore(&qp->rq.lock, flags);

	return err;
}

然后介绍一下这个函数:

1.参数。ibqp:指向一个IB队列对(Queue Pair)结构体的指针,表示待操作的队列对。

wr:指向接收请求工作请求(Work Request)链表的指针,即待投递的接收请求。

bad_wr:指向指针的指针,用于指示投递失败的工作请求。

drain:一个布尔值,指示是否需要在设备处于内部错误状态时尝试清空队列。

2.函数从ibqp中获取到对应的mlx5_ib_qp结构体,并获取其所属的设备和设备对象。如果设备处于内部错误状态且不需要排空队列,则函数将返回错误并将bad_wr指向当前的工作请求,否则继续执行。如果队列类型为GSI(General Services Interface),则调用特定的函数处理接收请求,并返回。然后,函数获取队列的锁,并初始化一些变量。

3.接着,遍历接收请求链表,依次处理每个接收请求:

检查队列是否溢出,如果溢出则返回错误。检查接收请求中的散射-聚集元素(Scatter-Gather Elements,SGE)数量是否超过队列的最大值,如果超过则返回错误。为接收请求获取一个WQE(Work Queue Element)缓冲区,并填充数据段。如果启用了数据完整性校验,则设置签名段。将接收请求的ID写入队列的WQE中。更新索引以指向下一个WQE。最后,如果成功处理了接收请求,则更新队列头,并确保在更新完成后再写入门铃寄存器,然后释放队列的锁。

相关推荐
论文复现现场1 天前
8卡 A100 服务器哪里租?NVLink、RDMA 与 NCCL 验收指南
linux·服务器·php·分布式训练·rdma·nvlink·nccl
gwf2162 天前
RDMA事件与异步通知机制:CMA事件与设备事件深度解析
驱动开发·linux内核·rdma·rdma_cm·异构计算·异步事件·cve分析
cyf313 天前
RDMA 写操作带宽性能建模与参数敏感性分析
性能优化·rdma·rocev2
gwf2164 天前
QP状态机详解:Reset→Init→RTR→RTS与建链握手过程
性能调优·rdma·qp状态机·linux内核驱动·ib_modify_qp·cm建链·irdma
cyf314 天前
RDMA数据传输原理深入解读
udp·rdma·rocev2·bth·pertest
gwf2166 天前
Completion Queue(CQ)与中断处理:轮询、中断聚合与错误码 —— 面向AI集群的驱动级深度剖析
驱动开发·性能调优·pcie·rdma·ai集群·中断聚合·cq
gwf2167 天前
内核RDMA子系统(ib_core)架构与核心数据结构:从驱动视角解构数据通路
linux内核·rdma·网卡驱动·mlx5·gpudirect·ib_core·内核架构
gwf2169 天前
Verbs性能优化实战:Inline/Signaled/批处理/NUMA亲和全攻略
rdma·numa·io_uring·内核驱动·mlx5·verbs·hugepage
业余程序员plus10 天前
RDMA-HCA-Mellanox网卡UAR与门铃 (二)
rdma·mellanox·wqe·mmio·doorbell·uar·blueflame
业余程序员plus10 天前
RDMA-HCA-Mellanox网卡架构与初始化 (一)
pcie·rdma·hca·icm·mellanox·mlx5·command queue