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。最后,如果成功处理了接收请求,则更新队列头,并确保在更新完成后再写入门铃寄存器,然后释放队列的锁。

相关推荐
Eloudy4 天前
国内加速 docker pull 下载 docker images,特别是 nvidia 的cuda image
docker·gpu·rdma
tiantianuser8 天前
NVME-oF IP 设计12 : Capsule是胶囊?
rdma·高速传输·roce v2·nvme of
tiantianuser8 天前
NVME-oF IP 设计14 : 简介NVMe oF IP特点
网络存储·rdma·高速存储·高速传输·nvme of
Eloudy8 天前
全文笔记 - GPU-Initiated Networking for NCCL
gpu·rdma
liuyunshengsir9 天前
perftest 工具集ib_write_bw中的 RDMA Write 带宽测试工具手册
网络·rdma
Eloudy9 天前
Holoscan Sensor Bridge 入门指南(Getting Started)
gpu·fpga·rdma
tiantianuser11 天前
NVME-oF IP 设计10:设计目标是什么?
rdma·高速传输·cmac·roce v2·nvme of
tiantianuser11 天前
NVME-oF IP 设计11 : 控制面与数据面干什么用?
网络协议·rdma·高速传输·roce v2·nvme of
Eloudy11 天前
ubuntu 22.04安装 Mellanox 的 MFT 工具包
rdma
mounter62512 天前
高性能网络技术演进与创新探索:RDMA、eBPF/XDP 深度解析及 LSF/MM/BPF 2023 专题演讲
linux·ebpf·linux kernel·kernel·rdma·xdp