NVMe Linux驱动系列一:host端[tcp.c]<86>

发布时间:2026/10/27 9:24:18
NVMe Linux驱动系列一:host端[tcp.c]<86> Define/* Define the socket priority to use for connections were it is desirable * that the NIC consider performing optimized packet processing or filtering. * A non-zero value being sufficient to indicate general consideration of any * possible optimization. Making it a module param allows for alternative * values that may be unique for some NIC implementations. */staticintso_priority;module_param(so_priority,int,0644);MODULE_PARM_DESC(so_priority,nvme tcp socket optimize priority);#ifdefCONFIG_DEBUG_LOCK_ALLOC/* lockdep can detect a circular dependency of the form * sk_lock - mmap_lock (page fault) - fs locks - sk_lock * because dependencies are tracked for both nvme-tcp and user contexts. Using * a separate class prevents lockdep from conflating nvme-tcp socket use with * user-space socket API use. */staticstructlock_class_keynvme_tcp_sk_key[2];staticstructlock_class_keynvme_tcp_slock_key[2];以上代码是关于Linux内核中的网络模块network module的一些定义和参数设置。具体来说这段代码涉及到以下内容Socket 优先级设置这部分代码定义了一个静态整数变量so_priority用于表示套接字socket的优先级当希望网络适配器NIC执行优化的数据包处理或过滤时使用。非零值表示通用优化的需求。通过将其定义为模块参数可以允许不同的 NIC 实现使用不同的值。模块参数定义使用宏module_param定义了一个模块参数so_priority类型为整数访问权限为 0644即读写权限。同时使用宏MODULE_PARM_DESC对参数进行了描述说明了该参数的含义。锁依赖性设置当编译配置中启用了调试锁分配CONFIG_DEBUG_LOCK_ALLOC时这部分代码定义了用于锁依赖性的关键类lock class key以便在锁依赖性检测时区分 nvme-tcp 模块的套接字使用和用户空间套接字 API 使用。具体来说定义了两个锁依赖性关键类nvme_tcp_sk_key和nvme_tcp_slock_key。综上所述这段代码主要涉及到网络模块中套接字优先级的设置以及在调试锁分配情况下为锁依赖性设置的一些内容。nvme_tcp_reclassify_socketstaticvoidnvme_tcp_reclassify_socket(structsocket*sock){structsock*sksock-sk;if(WARN_ON_ONCE(!sock_allow_reclassification(sk)))return;switch(sk-sk_family){caseAF_INET:sock_lock_init_class_and_name(sk,slock-AF_INET-NVME,nvme_tcp_slock_key[0],sk_lock-AF_INET-NVME,nvme_tcp_sk_key[0]);break;caseAF_INET6:sock_lock_init_class_and_name(sk,slock-AF_INET6-NVME,nvme_tcp_slock_key[1],sk_lock-AF_INET6-NVME,nvme_tcp_sk_key[1]);break;default:WARN_ON_ONCE(1);}}#elsestaticvoidnvme_tcp_reclassify_socket(structsocket*sock){}#endif这段代码是一个在 nvme-tcp 模块中的函数用于对套接字socket进行重新分类reclassify。具体来说这个函数根据套接字的地址族address family来初始化锁lock以用于可能的锁依赖性追踪。以下是代码的解释函数nvme_tcp_reclassify_socket这是一个用于重新分类套接字的函数。参数struct socket *sock函数接受一个指向socket结构的指针作为参数表示要重新分类的套接字。if语句首先使用WARN_ON_ONCE宏来检查是否允许对套接字进行重新分类。如果不允许则直接返回不进行后续操作。switch语句接下来根据套接字的地址族address family存储在sk-sk_family中进行分类操作。case AF_INET如果套接字的地址族是 IPv4AF_INET则使用sock_lock_init_class_and_name函数初始化锁并设置特定的锁类别和名称以及与锁相关的关键类。这里使用了nvme_tcp_slock_key[0]和nvme_tcp_sk_key[0]。case AF_INET6如果套接字的地址族是 IPv6AF_INET6则同样使用sock_lock_init_class_and_name函数初始化锁但是设置不同的锁类别和名称以及不同的关键类。这里使用了nvme_tcp_slock_key[1]和nvme_tcp_sk_key[1]。default如果地址族既不是 IPv4 也不是 IPv6发出警告但不执行其他操作。如果代码被编译配置中的CONFIG_DEBUG_LOCK_ALLOC宏定义启用那么函数将进行套接字的重新分类操作。否则如果没有启用该宏定义函数体为空。总之这段代码主要用于在 nvme-tcp 模块中为套接字设置锁的类别和名称以便在调试情况下追踪锁依赖性。nvme_tcp_send_stateenumnvme_tcp_send_state{NVME_TCP_SEND_CMD_PDU0,NVME_TCP_SEND_H2C_PDU,NVME_TCP_SEND_DATA,NVME_TCP_SEND_DDGST,};这段代码定义了一个枚举类型enum nvme_tcp_send_state该枚举类型表示了 nvme-tcp 发送过程中的不同状态。具体来说它定义了以下四个状态NVME_TCP_SEND_CMD_PDU表示发送命令CommandPDUProtocol Data Unit协议数据单元的状态。NVME_TCP_SEND_H2C_PDU表示发送主机到控制器Host-to-ControllerH2CPDU 的状态。NVME_TCP_SEND_DATA表示发送数据的状态。NVME_TCP_SEND_DDGST表示发送数据完整性校验Data Digest的状态。这些状态往往用于描述 NVMe over TCP 协议中数据传输的各个阶段例如在发送 NVMe 命令到远程控制器、发送数据块或校验等方面。枚举类型的使用可以提高代码的可读性使得在程序中更方便地引用这些不同的状态。每个状态都被赋予了一个整数值从 0 开始用于在代码中表示和比较不同的状态。nvme_tcp_requeststructnvme_tcp_request{structnvme_requestreq;void*pdu;structnvme_tcp_queue*queue;u32 data_len;u32 pdu_len;u32 pdu_sent;u32 h2cdata_left;u32 h2cdata_offset;u16 ttag;__le16 status;structlist_headentry;structllist_nodelentry;__le32 ddgst;structbio*curr_bio;structiov_iteriter;/* send state */size_toffset;size_tdata_sent;enumnvme_tcp_send_statestate;};这段代码定义了一个名为struct nvme_tcp_request的数据结构用于表示 NVMe over TCP 协议中的请求信息。该结构体包含了多个成员每个成员存储了与请求相关的不同属性和状态。以下是对结构体成员的解释struct nvme_request req;包含 NVMe 命令请求信息的结构体。void *pdu;指向协议数据单元PDU的指针。struct nvme_tcp_queue *queue;指向 NVMe over TCP 队列的指针用于跟踪请求所属的队列。u32 data_len;数据的长度。u32 pdu_len;PDU 的长度。u32 pdu_sent;已发送的 PDU 长度。u32 h2cdata_left;待发送的主机到控制器数据长度。u32 h2cdata_offset;主机到控制器数据的偏移量。u16 ttag;传输标签用于唯一标识请求。__le16 status;状态码表示请求的状态。struct list_head entry;用于将请求添加到链表中的链表头。struct llist_node lentry;用于将请求添加到锁-free链表中的链表节点。__le32 ddgst;数据完整性校验的值。struct bio *curr_bio;指向当前正在处理的生物bio结构的指针。struct iov_iter iter;用于在请求中迭代访问 I/O 向量iov的迭代器。size_t offset;数据传输的偏移量。size_t data_sent;已发送的数据长度。enum nvme_tcp_send_state state;枚举类型表示发送状态之前提到的 nvme-tcp 发送状态。这个数据结构用于在 NVMe over TCP 协议的实现中存储和跟踪请求的各种信息和状态。根据这些成员可以追踪请求的各个阶段包括数据传输、状态等。nvme_tcp_queue_flagsenumnvme_tcp_queue_flags{NVME_TCP_Q_ALLOCATED0,NVME_TCP_Q_LIVE1,NVME_TCP_Q_POLLING2,};这段代码定义了一个名为enum nvme_tcp_queue_flags的枚举类型用于表示 NVMe over TCP 队列的不同标志flags。这些标志用于在代码中标识队列的状态或特性。以下是对枚举成员的解释NVME_TCP_Q_ALLOCATED表示队列已经被分配。这个标志可能在队列对象被分配内存后设置。NVME_TCP_Q_LIVE表示队列正在运行“live”。这个标志可能在队列已经启动并处于运行状态时设置。NVME_TCP_Q_POLLING表示队列正在使用轮询方式polling处理请求。这可能是一种处理请求的方法其中不使用中断而是通过循环查询的方式来检查是否有新的请求需要处理。这些标志通常用于控制和跟踪队列的状态以及在代码中根据需要执行不同的逻辑。在 NVMe over TCP 协议的实现中队列是一个关键的组件用于管理请求的排队和处理。这些标志可用于在队列的生命周期中确定其状态和行为。nvme_tcp_recv_stateenumnvme_tcp_recv_state{NVME_TCP_RECV_PDU0,NVME_TCP_RECV_DATA,NVME_TCP_RECV_DDGST,};这段代码定义了一个名为enum nvme_tcp_recv_state的枚举类型用于表示在 NVMe over TCP 协议中接收数据时可能的不同状态。具体来说它定义了以下三个状态NVME_TCP_RECV_PDU表示接收协议数据单元PDU的状态。NVME_TCP_RECV_DATA表示接收数据的状态。NVME_TCP_RECV_DDGST表示接收数据完整性校验Data Digest的状态。这些状态描述了在 NVMe over TCP 协议中数据传输的各个阶段例如接收协议消息、接收数据块以及校验等方面。通过使用这些枚举状态可以更清晰地表达接收数据的不同阶段从而提高代码的可读性并有助于在程序中引用和处理不同的接收状态。每个状态都被赋予了一个整数值从 0 开始用于在代码中表示和比较不同的状态。nvme_tcp_queuestructnvme_tcp_ctrl;structnvme_tcp_queue{structsocket*sock;structwork_structio_work;intio_cpu;structmutexqueue_lock;structmutexsend_mutex;structllist_headreq_list;structlist_headsend_list;/* recv state */void*pdu;intpdu_remaining;intpdu_offset;size_tdata_remaining;size_tddgst_remaining;unsignedintnr_cqe;/* send state */structnvme_tcp_request*request;u32 maxh2cdata;size_tcmnd_capsule_len;structnvme_tcp_ctrl*ctrl;unsignedlongflags;bool rd_enabled;bool hdr_digest;bool data_digest;structahash_request*rcv_hash;structahash_request*snd_hash;__le32 exp_ddgst;__le32 recv_ddgst;structpage_frag_cachepf_cache;void(*state_change)(structsock*);void(*data_ready)(structsock*);void(*write_space)(structsock*);};这段代码定义了一个名为struct nvme_tcp_queue的数据结构用于表示 NVMe over TCP 协议中的队列信息。这个结构体包含了多个成员每个成员存储了与队列相关的不同属性和状态。以下是对结构体成员的解释struct socket *sock;指向套接字socket的指针用于与远程端进行通信。struct work_struct io_work;用于处理异步 I/O 的工作结构。int io_cpu;表示用于 I/O 处理的 CPU 核心。struct mutex queue_lock;用于保护队列操作的互斥锁。struct mutex send_mutex;用于保护发送操作的互斥锁。struct llist_head req_list;链接请求的锁-free链表头。struct list_head send_list;链接已发送请求的链表头。void *pdu;指向协议数据单元PDU的指针。int pdu_remaining;PDU 剩余的字节数。int pdu_offset;PDU 的偏移量。size_t data_remaining;数据剩余的字节数。size_t ddgst_remaining;数据完整性校验Data Digest剩余的字节数。unsigned int nr_cqe;完成队列项CQE的数量。struct nvme_tcp_request *request;指向当前请求的指针。u32 maxh2cdata;最大主机到控制器数据长度。size_t cmnd_capsule_len;命令胶囊的长度。struct nvme_tcp_ctrl *ctrl;指向 NVMe over TCP 控制器的指针。unsigned long flags;标志位表示队列的状态。bool rd_enabled;表示是否启用读取Read。bool hdr_digest;是否启用协议头的数据完整性校验。bool data_digest;是否启用数据的数据完整性校验。struct ahash_request *rcv_hash;接收数据的哈希请求。struct ahash_request *snd_hash;发送数据的哈希请求。__le32 exp_ddgst;期望的数据完整性校验值。__le32 recv_ddgst;接收到的数据完整性校验值。struct page_frag_cache pf_cache;页面碎片缓存。函数指针成员state_change、data_ready和write_space是函数指针用于在不同的事件发生时调用相应的函数。这个数据结构用于在 NVMe over TCP 协议的实现中存储和管理队列的信息和状态。队列在协议中起着重要作用用于管理请求的处理和排队以及与远程端的通信。nvme_tcp_ctrlstructnvme_tcp_ctrl{/* read only in the hot path */structnvme_tcp_queue*queues;structblk_mq_tag_settag_set;/* other member variables */structlist_headlist;structblk_mq_tag_setadmin_tag_set;structsockaddr_storageaddr;structsockaddr_storagesrc_addr;structnvme_ctrlctrl;structwork_structerr_work;structdelayed_workconnect_work;structnvme_tcp_requestasync_req;u32 io_queues[HCTX_MAX_TYPES];};这段代码定义了一个名为struct nvme_tcp_ctrl的数据结构用于表示 NVMe over TCP 控制器的信息。这个结构体包含了多个成员每个成员存储了与控制器相关的不同属性和状态。以下是对结构体成员的解释struct nvme_tcp_queue *queues;指向 NVMe over TCP 队列数组的指针。struct blk_mq_tag_set tag_set;用于管理多队列blk-mq的标签集。struct list_head list;用于将控制器添加到链表中的链表头。struct blk_mq_tag_set admin_tag_set;管理管理队列Admin Queue的标签集。struct sockaddr_storage addr;存储控制器的地址信息。struct sockaddr_storage src_addr;存储源地址信息。struct nvme_ctrl ctrl;NVMe 控制器的基本信息。struct work_struct err_work;用于处理错误的工作结构。struct delayed_work connect_work;用于处理连接的延迟工作结构。struct nvme_tcp_request async_req;异步请求。u32 io_queues[HCTX_MAX_TYPES];输入/输出队列的数量按类型进行索引。这个数据结构用于在 NVMe over TCP 协议的实现中存储和管理控制器的信息和状态。控制器是 NVMe 设备的核心部分它管理着设备的各种操作和状态。在这个结构中包含了与控制器相关的队列、标签集、地址信息、工作结构等信息以便协议的实现能够进行管理和处理。nvme_tcp_ctrl_list nvme_tcp_ctrl_mutex nvme_tcp_wq nvme_tcp_mq_ops nvme_tcp_admin_mq_opsstaticLIST_HEAD(nvme_tcp_ctrl_list);staticDEFINE_MUTEX(nvme_tcp_ctrl_mutex);staticstructworkqueue_struct*nvme_tcp_wq;staticconststructblk_mq_opsnvme_tcp_mq_ops;staticconststructblk_mq_opsnvme_tcp_admin_mq_ops;staticintnvme_tcp_try_send(structnvme_tcp_queue*queue);这段代码定义了一些全局变量和函数声明用于在 NVMe over TCP 协议实现中使用。以下是对这些内容的解释static LIST_HEAD(nvme_tcp_ctrl_list);定义了一个链表头nvme_tcp_ctrl_list用于存储 NVMe over TCP 控制器的列表。static DEFINE_MUTEX(nvme_tcp_ctrl_mutex);定义了一个互斥锁nvme_tcp_ctrl_mutex用于对 NVMe over TCP 控制器的操作进行同步。static struct workqueue_struct *nvme_tcp_wq;定义了一个指向工作队列的指针nvme_tcp_wq用于处理工作任务。static const struct blk_mq_ops nvme_tcp_mq_ops;定义了一个块多队列操作结构体nvme_tcp_mq_ops用于 NVMe over TCP 队列的操作。static const struct blk_mq_ops nvme_tcp_admin_mq_ops;类似地定义了一个用于管理队列Admin Queue的块多队列操作结构体nvme_tcp_admin_mq_ops。static int nvme_tcp_try_send(struct nvme_tcp_queue *queue);函数声明表示尝试发送数据到 NVMe over TCP 队列的函数。函数接受一个指向 NVMe over TCP 队列的指针作为参数。这些全局变量和函数声明通常在 NVMe over TCP 协议的实现中用于管理和操作控制器、队列、工作队列等关键组件。它们提供了实现协议所需的基本功能和数据结构。to_tcp_ctrlstaticinlinestructnvme_tcp_ctrl*to_tcp_ctrl(structnvme_ctrl*ctrl){returncontainer_of(ctrl,structnvme_tcp_ctrl,ctrl);}这段代码定义了一个静态内联函数to_tcp_ctrl用于将一个指向 NVMe 控制器结构体struct nvme_ctrl的指针转换为对应的 NVMe over TCP 控制器结构体struct nvme_tcp_ctrl的指针。这种转换使用了宏container_of它是一种用于通过结构体的成员指针获取整个结构体的技术。以下是这个函数的解释static inline struct nvme_tcp_ctrl *to_tcp_ctrl(struct nvme_ctrl *ctrl)定义了一个内联函数将传入的 NVMe 控制器结构体指针转换为对应的 NVMe over TCP 控制器结构体指针。return container_of(ctrl, struct nvme_tcp_ctrl, ctrl);使用container_of宏将ctrl指针转换为其父结构体struct nvme_tcp_ctrl的指针。这里ctrl是在struct nvme_tcp_ctrl结构体内作为成员存在的。这个函数在协议实现中可能用于从 NVMe 控制器结构体指针中获取对应的 NVMe over TCP 控制器结构体指针以便进行 NVMe over TCP 特定的操作和访问。nvme_tcp_queue_idstaticinlineintnvme_tcp_queue_id(structnvme_tcp_queue*queue){returnqueue-queue-ctrl-queues;}这段代码定义了一个静态内联函数nvme_tcp_queue_id用于计算给定 NVMe over TCP 队列指针在其控制器队列数组中的索引ID。这种计算基于指针的减法操作其中queue-ctrl-queues是指向队列数组的指针。以下是这个函数的解释static inline int nvme_tcp_queue_id(struct nvme_tcp_queue *queue)定义了一个内联函数用于计算给定 NVMe over TCP 队列指针在其控制器队列数组中的索引。return queue - queue-ctrl-queues;使用指针的减法操作计算队列指针queue相对于队列数组起始地址queue-ctrl-queues的偏移量从而得到队列在数组中的索引。这个函数可能在 NVMe over TCP 协议实现中用于确定给定队列的唯一标识以便在数组中进行索引访问。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询