【C语言】linux内核ipoib模块 - ipoib_ib_handle_tx_wc

一、中文注释

这个函数是用来处理 Infiniband 设备在传输完成时的回调。该回调负责释放发送队列中的缓冲区并更新网络设备统计信息。

cpp 复制代码
static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
{
    // 通过net_device结构体获取私有数据结构
    struct ipoib_dev_priv *priv = ipoib_priv(dev);

    // 获取工作请求ID,这个ID在发送时被赋予,用于标识对应的缓冲区
    unsigned int wr_id = wc->wr_id;
    struct ipoib_tx_buf *tx_req;

    // 调试信息,输出完成的工作请求的ID和状态
    ipoib_dbg_data(priv, "send completion: id %d, status: %d\n",
               wr_id, wc->status);

    // 检查wr_id是否有效
    if (unlikely(wr_id >= priv->sendq_size)) {
        // 如果不是,打印警告信息
        ipoib_warn(priv, "send completion event with wrid %d (> %d)\n",
               wr_id, priv->sendq_size);
        return;
    }
    
    // 使用工作请求ID来获取发送队列中的缓冲区
    tx_req = &priv->tx_ring[wr_id];

    // 如果不是内联传输,就需要去除DMA映射
    if (!tx_req->is_inline)
        ipoib_dma_unmap_tx(priv, tx_req);

    // 更新网络设备的发送包统计信息
    ++dev->stats.tx_packets;
    dev->stats.tx_bytes += tx_req->skb->len;

    // 释放socket缓冲区
    dev_kfree_skb_any(tx_req->skb);
    tx_req->skb = NULL;

    // 更新发送尾部指针和未完成的发送计数
    ++priv->tx_tail;
    atomic_dec(&priv->tx_outstanding);

    // 如果网络队列停止了,并且未完成的发送数少于发送队列大小的一半,同时设备标记为"管理上行"则重新唤起网络队列
    if (unlikely(netif_queue_stopped(dev) &&
             (atomic_read(&priv->tx_outstanding) <= priv->sendq_size >> 1) &&
             test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)))
        netif_wake_queue(dev);

    // 如果完成状态不是成功且不是"刷新错误",那么会对QP状态进行验证和修复
    if (wc->status != IB_WC_SUCCESS &&
        wc->status != IB_WC_WR_FLUSH_ERR) {
        // 打印错误警告信息
        ipoib_warn(priv,
               "failed send event (status=%d, wrid=%d vend_err %#x)\n",
               wc->status, wr_id, wc->vendor_err);
        // 为QP验证工作分配内存
        struct ipoib_qp_state_validate *qp_work;
        qp_work = kzalloc(sizeof(*qp_work), GFP_ATOMIC);
        // 如果内存分配失败就直接返回
        if (!qp_work)
            return;

        // 初始化工作队列项并将它放到工作队列中去
        INIT_WORK(&qp_work->work, ipoib_qp_state_validate_work);
        qp_work->priv = priv;
        queue_work(priv->wq, &qp_work->work);
    }
}

该函数的作用是处理InfiniBand网络设备在发送数据完成后的清理工作。它检查完成状态,释放资源并更新发送队列状态,若发送失败则可能会尝试修复QP(Queue Pair)状态。

二、中文讲解

这个函数 ipoib_ib_handle_tx_wc 是处理IP-over-Infiniband(IPoIB)传输完成工作请求(Work Completion,WC)的函数,主要用于处理在IPoIB网络设备上完成发送操作的情况。这个函数是Linux内核中IPoIB模块的一部分,用来处理InfiniBand协议栈发送操作的完成事件。

下面将逐条中文解释该函数的逻辑:

cpp 复制代码
// 函数声明,接受一个网络设备和一个工作完成结构作为参数
static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) {
    // 从网络设备结构获取IPoIB设备私有数据
    struct ipoib_dev_priv *priv = ipoib_priv(dev);
    // 获取工作请求ID
    unsigned int wr_id = wc->wr_id;
    struct ipoib_tx_buf *tx_req;

    // 输出调试信息,包括工作请求ID和状态
    ipoib_dbg_data(priv, "send completion: id %d, status: %d\n", wr_id, wc->status);

    // 检查工作请求ID是否有效,如果不在发送队列范围内,打印警告并返回
    if (unlikely(wr_id >= priv->sendq_size)) {
        ipoib_warn(priv, "send completion event with wrid %d (> %d)\n", wr_id, priv->sendq_size);
        return;
    }

    // 获取对应工作请求ID的发送缓冲区
    tx_req = &priv->tx_ring[wr_id];

    // 如果发送请求并非内联的(数据不是和描述符一起发送的),则撤销DMA映射
    if (!tx_req->is_inline)
        ipoib_dma_unmap_tx(priv, tx_req);

    // 更新网络设备统计信息:增加发送的数据包和字节计数
    ++dev->stats.tx_packets;
    dev->stats.tx_bytes += tx_req->skb->len;

    // 释放对应的skb(socket缓冲区),并将指针置空
    dev_kfree_skb_any(tx_req->skb);
    tx_req->skb = NULL;

    // 增加发送队列尾部索引,表示处理了一个发送请求
    ++priv->tx_tail;
    // 原子减少正在处理的发送请求计数
    atomic_dec(&priv->tx_outstanding);

    // 如果网络队列停止,且未完成的发送请求数量小于发送队列大小的一半
    // 并且网络接口状态为上,那么重新启动网络队列
    if (unlikely(netif_queue_stopped(dev) &&
             (atomic_read(&priv->tx_outstanding) <= priv->sendq_size >> 1) &&
             test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)))
        netif_wake_queue(dev);

    // 如果工作完成状态非成功,并且不是因为刷新错误
    if (wc->status != IB_WC_SUCCESS && wc->status != IB_WC_WR_FLUSH_ERR) {
        struct ipoib_qp_state_validate *qp_work;
        // 打印警告,发送请求失败
        ipoib_warn(priv, "failed send event (status=%d, wrid=%d vend_err %#x)\n",
                   wc->status, wr_id, wc->vendor_err);
        // 为验证队列对状态分配工作并初始化
        qp_work = kzalloc(sizeof(*qp_work), GFP_ATOMIC);
        if (!qp_work)
            return;

        INIT_WORK(&qp_work->work, ipoib_qp_state_validate_work);
        qp_work->priv = priv;
        // 将验证工作加入到工作队列中
        queue_work(priv->wq, &qp_work->work);
    }
}

从代码可以看出,这个函数的主要作用是处理InfiniBand设备发送缓冲区完成工作事件,释放资源,更新统计数据,以及在发送操作失败时进行错误处理。

相关推荐
叫我龙翔13 分钟前
【计网】实现reactor反应堆模型 --- 多线程方案优化 ,OTOL方案
linux·运维·网络
mit6.82415 分钟前
[Docker#9] 存储卷 | Volume、Bind、Tmpfs | -v/mount | MySQL 灾难恢复 | 问题
linux·运维·docker·容器·架构
WangYaolove131433 分钟前
请解释Python中的装饰器是什么?如何使用它们?
linux·数据库·python
?crying1 小时前
蓝队基础4 -- 安全运营与监控
网络·安全·web安全
7yewh1 小时前
嵌入式硬件实战提升篇(一)-泰山派RK3566制作多功能小手机
linux·arm开发·驱动开发·嵌入式硬件·物联网·智能手机·硬件架构
茶颜悦色vv1 小时前
蓝队知识浅谈(中)
网络·web安全·网络安全
Xlbb.1 小时前
安全见闻6-9
网络·安全·web安全·网络安全
YRr YRr1 小时前
ubuntu ros 解决建完图后 保存的地图非常小的问题
linux·运维·ubuntu
脸ル粉嘟嘟2 小时前
常用命令之Linux&Oracle&Hive&Python
linux·hive·oracle
Wils0nEdwards2 小时前
Leetcode 整数转罗马数字
linux·python·leetcode