ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

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

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)的一些定义和参数设置。具体来说,这段代码涉及到以下内容:

  1. Socket 优先级设置:这部分代码定义了一个静态整数变量so_priority,用于表示套接字(socket)的优先级,当希望网络适配器(NIC)执行优化的数据包处理或过滤时使用。非零值表示通用优化的需求。通过将其定义为模块参数,可以允许不同的 NIC 实现使用不同的值。

  2. 模块参数定义:使用宏module_param定义了一个模块参数so_priority,类型为整数,访问权限为 0644(即读写权限)。同时,使用宏MODULE_PARM_DESC对参数进行了描述,说明了该参数的含义。

  3. 锁依赖性设置:当编译配置中启用了调试锁分配(CONFIG_DEBUG_LOCK_ALLOC)时,这部分代码定义了用于锁依赖性的关键类(lock class key),以便在锁依赖性检测时区分 nvme-tcp 模块的套接字使用和用户空间套接字 API 使用。具体来说,定义了两个锁依赖性关键类:nvme_tcp_sk_key和nvme_tcp_slock_key。

综上所述,这段代码主要涉及到网络模块中套接字优先级的设置以及在调试锁分配情况下为锁依赖性设置的一些内容。

nvme_tcp_reclassify_socket

staticvoidnvme_tcp_reclassify_socket(structsocket*sock){structsock*sk=sock->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),以用于可能的锁依赖性追踪。

以下是代码的解释:

  1. 函数nvme_tcp_reclassify_socket:这是一个用于重新分类套接字的函数。

  2. 参数struct socket *sock:函数接受一个指向socket结构的指针作为参数,表示要重新分类的套接字。

  3. if语句:首先使用WARN_ON_ONCE宏来检查是否允许对套接字进行重新分类。如果不允许,则直接返回,不进行后续操作。

  4. switch语句:接下来,根据套接字的地址族(address family,存储在sk->sk_family中)进行分类操作。

    • case AF_INET:如果套接字的地址族是 IPv4(AF_INET),则使用sock_lock_init_class_and_name函数初始化锁,并设置特定的锁类别和名称,以及与锁相关的关键类。这里使用了nvme_tcp_slock_key[0]和nvme_tcp_sk_key[0]。

    • case AF_INET6:如果套接字的地址族是 IPv6(AF_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_state

enumnvme_tcp_send_state{NVME_TCP_SEND_CMD_PDU=0,NVME_TCP_SEND_H2C_PDU,NVME_TCP_SEND_DATA,NVME_TCP_SEND_DDGST,};

这段代码定义了一个枚举类型enum nvme_tcp_send_state,该枚举类型表示了 nvme-tcp 发送过程中的不同状态。具体来说,它定义了以下四个状态:

  1. NVME_TCP_SEND_CMD_PDU:表示发送命令(Command)PDU(Protocol Data Unit,协议数据单元)的状态。

  2. NVME_TCP_SEND_H2C_PDU:表示发送主机到控制器(Host-to-Controller,H2C)PDU 的状态。

  3. NVME_TCP_SEND_DATA:表示发送数据的状态。

  4. NVME_TCP_SEND_DDGST:表示发送数据完整性校验(Data Digest)的状态。

这些状态往往用于描述 NVMe over TCP 协议中数据传输的各个阶段,例如在发送 NVMe 命令到远程控制器、发送数据块或校验等方面。枚举类型的使用可以提高代码的可读性,使得在程序中更方便地引用这些不同的状态。每个状态都被赋予了一个整数值(从 0 开始),用于在代码中表示和比较不同的状态。

nvme_tcp_request

structnvme_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 协议中的请求信息。该结构体包含了多个成员,每个成员存储了与请求相关的不同属性和状态。以下是对结构体成员的解释:

  1. struct nvme_request req;:包含 NVMe 命令请求信息的结构体。

  2. void *pdu;:指向协议数据单元(PDU)的指针。

  3. struct nvme_tcp_queue *queue;:指向 NVMe over TCP 队列的指针,用于跟踪请求所属的队列。

  4. u32 data_len;:数据的长度。

  5. u32 pdu_len;:PDU 的长度。

  6. u32 pdu_sent;:已发送的 PDU 长度。

  7. u32 h2cdata_left;:待发送的主机到控制器数据长度。

  8. u32 h2cdata_offset;:主机到控制器数据的偏移量。

  9. u16 ttag;:传输标签,用于唯一标识请求。

  10. __le16 status;:状态码,表示请求的状态。

  11. struct list_head entry;:用于将请求添加到链表中的链表头。

  12. struct llist_node lentry;:用于将请求添加到锁-free链表中的链表节点。

  13. __le32 ddgst;:数据完整性校验的值。

  14. struct bio *curr_bio;:指向当前正在处理的生物(bio)结构的指针。

  15. struct iov_iter iter;:用于在请求中迭代访问 I/O 向量(iov)的迭代器。

  16. size_t offset;:数据传输的偏移量。

  17. size_t data_sent;:已发送的数据长度。

  18. enum nvme_tcp_send_state state;:枚举类型,表示发送状态(之前提到的 nvme-tcp 发送状态)。

这个数据结构用于在 NVMe over TCP 协议的实现中存储和跟踪请求的各种信息和状态。根据这些成员,可以追踪请求的各个阶段,包括数据传输、状态等。

nvme_tcp_queue_flags

enumnvme_tcp_queue_flags{NVME_TCP_Q_ALLOCATED=0,NVME_TCP_Q_LIVE=1,NVME_TCP_Q_POLLING=2,};

这段代码定义了一个名为enum nvme_tcp_queue_flags的枚举类型,用于表示 NVMe over TCP 队列的不同标志(flags)。这些标志用于在代码中标识队列的状态或特性。以下是对枚举成员的解释:

  1. NVME_TCP_Q_ALLOCATED:表示队列已经被分配。这个标志可能在队列对象被分配内存后设置。

  2. NVME_TCP_Q_LIVE:表示队列正在运行(“live”)。这个标志可能在队列已经启动并处于运行状态时设置。

  3. NVME_TCP_Q_POLLING:表示队列正在使用轮询方式(polling)处理请求。这可能是一种处理请求的方法,其中不使用中断,而是通过循环查询的方式来检查是否有新的请求需要处理。

这些标志通常用于控制和跟踪队列的状态,以及在代码中根据需要执行不同的逻辑。在 NVMe over TCP 协议的实现中,队列是一个关键的组件,用于管理请求的排队和处理。这些标志可用于在队列的生命周期中确定其状态和行为。

nvme_tcp_recv_state

enumnvme_tcp_recv_state{NVME_TCP_RECV_PDU=0,NVME_TCP_RECV_DATA,NVME_TCP_RECV_DDGST,};

这段代码定义了一个名为enum nvme_tcp_recv_state的枚举类型,用于表示在 NVMe over TCP 协议中接收数据时可能的不同状态。具体来说,它定义了以下三个状态:

  1. NVME_TCP_RECV_PDU:表示接收协议数据单元(PDU)的状态。

  2. NVME_TCP_RECV_DATA:表示接收数据的状态。

  3. NVME_TCP_RECV_DDGST:表示接收数据完整性校验(Data Digest)的状态。

这些状态描述了在 NVMe over TCP 协议中数据传输的各个阶段,例如接收协议消息、接收数据块以及校验等方面。通过使用这些枚举状态,可以更清晰地表达接收数据的不同阶段,从而提高代码的可读性并有助于在程序中引用和处理不同的接收状态。每个状态都被赋予了一个整数值(从 0 开始),用于在代码中表示和比较不同的状态。

nvme_tcp_queue

structnvme_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 协议中的队列信息。这个结构体包含了多个成员,每个成员存储了与队列相关的不同属性和状态。以下是对结构体成员的解释:

  1. struct socket *sock;:指向套接字(socket)的指针,用于与远程端进行通信。

  2. struct work_struct io_work;:用于处理异步 I/O 的工作结构。

  3. int io_cpu;:表示用于 I/O 处理的 CPU 核心。

  4. struct mutex queue_lock;:用于保护队列操作的互斥锁。

  5. struct mutex send_mutex;:用于保护发送操作的互斥锁。

  6. struct llist_head req_list;:链接请求的锁-free链表头。

  7. struct list_head send_list;:链接已发送请求的链表头。

  8. void *pdu;:指向协议数据单元(PDU)的指针。

  9. int pdu_remaining;:PDU 剩余的字节数。

  10. int pdu_offset;:PDU 的偏移量。

  11. size_t data_remaining;:数据剩余的字节数。

  12. size_t ddgst_remaining;:数据完整性校验(Data Digest)剩余的字节数。

  13. unsigned int nr_cqe;:完成队列项(CQE)的数量。

  14. struct nvme_tcp_request *request;:指向当前请求的指针。

  15. u32 maxh2cdata;:最大主机到控制器数据长度。

  16. size_t cmnd_capsule_len;:命令胶囊的长度。

  17. struct nvme_tcp_ctrl *ctrl;:指向 NVMe over TCP 控制器的指针。

  18. unsigned long flags;:标志位,表示队列的状态。

  19. bool rd_enabled;:表示是否启用读取(Read)。

  20. bool hdr_digest;:是否启用协议头的数据完整性校验。

  21. bool data_digest;:是否启用数据的数据完整性校验。

  22. struct ahash_request *rcv_hash;:接收数据的哈希请求。

  23. struct ahash_request *snd_hash;:发送数据的哈希请求。

  24. __le32 exp_ddgst;:期望的数据完整性校验值。

  25. __le32 recv_ddgst;:接收到的数据完整性校验值。

  26. struct page_frag_cache pf_cache;:页面碎片缓存。

  27. 函数指针成员:state_change、data_ready和write_space是函数指针,用于在不同的事件发生时调用相应的函数。

这个数据结构用于在 NVMe over TCP 协议的实现中存储和管理队列的信息和状态。队列在协议中起着重要作用,用于管理请求的处理和排队,以及与远程端的通信。

nvme_tcp_ctrl

structnvme_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 控制器的信息。这个结构体包含了多个成员,每个成员存储了与控制器相关的不同属性和状态。以下是对结构体成员的解释:

  1. struct nvme_tcp_queue *queues;:指向 NVMe over TCP 队列数组的指针。

  2. struct blk_mq_tag_set tag_set;:用于管理多队列(blk-mq)的标签集。

  3. struct list_head list;:用于将控制器添加到链表中的链表头。

  4. struct blk_mq_tag_set admin_tag_set;:管理管理队列(Admin Queue)的标签集。

  5. struct sockaddr_storage addr;:存储控制器的地址信息。

  6. struct sockaddr_storage src_addr;:存储源地址信息。

  7. struct nvme_ctrl ctrl;:NVMe 控制器的基本信息。

  8. struct work_struct err_work;:用于处理错误的工作结构。

  9. struct delayed_work connect_work;:用于处理连接的延迟工作结构。

  10. struct nvme_tcp_request async_req;:异步请求。

  11. 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_ops

staticLIST_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 协议实现中使用。以下是对这些内容的解释:

  1. static LIST_HEAD(nvme_tcp_ctrl_list);:定义了一个链表头nvme_tcp_ctrl_list,用于存储 NVMe over TCP 控制器的列表。

  2. static DEFINE_MUTEX(nvme_tcp_ctrl_mutex);:定义了一个互斥锁nvme_tcp_ctrl_mutex,用于对 NVMe over TCP 控制器的操作进行同步。

  3. static struct workqueue_struct *nvme_tcp_wq;:定义了一个指向工作队列的指针nvme_tcp_wq,用于处理工作任务。

  4. static const struct blk_mq_ops nvme_tcp_mq_ops;:定义了一个块多队列操作结构体nvme_tcp_mq_ops,用于 NVMe over TCP 队列的操作。

  5. static const struct blk_mq_ops nvme_tcp_admin_mq_ops;:类似地,定义了一个用于管理队列(Admin Queue)的块多队列操作结构体nvme_tcp_admin_mq_ops。

  6. static int nvme_tcp_try_send(struct nvme_tcp_queue *queue);:函数声明,表示尝试发送数据到 NVMe over TCP 队列的函数。函数接受一个指向 NVMe over TCP 队列的指针作为参数。

这些全局变量和函数声明通常在 NVMe over TCP 协议的实现中用于管理和操作控制器、队列、工作队列等关键组件。它们提供了实现协议所需的基本功能和数据结构。

to_tcp_ctrl

staticinlinestructnvme_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_id

staticinlineintnvme_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 协议实现中用于确定给定队列的唯一标识,以便在数组中进行索引访问。

返回列表