多看看spdk代码学习
多看看spdk代码学习
- 还是干货直接上代码
- 简易讲解
- 详细讲解一下这份代码
还是干货直接上代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <stdbool.h>
#include <pthread.h>
#include <spdk/nvme.h>
#define MAX_CONTROLLERS 16
static struct spdk_nvme_ctrlr *g_controllers[MAX_CONTROLLERS];
static int g_num_controllers = 0;
static void
ctrlr_init_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,struct spdk_nvme_ctrlr_opts *opts)
{printf("Initializing controller %!s(MISSING)\n", trid->traddr);
}
static void
ctrlr_attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
{printf("Attached to controller %!s(MISSING)\n", trid->traddr);g_controllers[g_num_controllers++] = ctrlr;
}
static void
ctrlr_detach_cb(void *cb_ctx, struct spdk_nvme_ctrlr *ctrlr)
{printf("Detached from controller %!s(MISSING)\n", spdk_nvme_ctrlr_get_trid(ctrlr)->traddr);
}
static void
sigint_handler(int signal)
{int i;printf("Caught signal %!d(MISSING)\n", signal);for (i = 0; i < g_num_controllers; i++) {spdk_nvme_detach(g_controllers[i]);}spdk_nvme_cleanup();exit(0);
}
int main(int argc, char **argv)
{struct spdk_env_opts opts;struct spdk_env_opts_init(&opts);opts.name = "helloworld";opts.core_mask = "0x1";opts.shm_id = 0;spdk_env_init(&opts);struct spdk_nvme_transport_id trid = { 0 };const char *address = "0000:04:00.0";trid.trtype = SPDK_NVME_TRANSPORT_PCIE;trid.adrfam = SPDK_NVMF_ADRFAM_IPV4;strncpy(trid.traddr, address, sizeof(trid.traddr));struct spdk_nvme_ctrlr_opts ctrlr_opts;struct spdk_nvme_ctrlr_opts_set_defaults(&ctrlr_opts);ctrlr_opts.num_io_queues = 4;ctrlr_opts.use_cmb_sqs = true;struct spdk_nvme_probe_ctx *probe_ctx;probe_ctx = spdk_nvme_connect_async(&trid, &ctrlr_opts, sizeof(ctrlr_opts),ctrlr_init_cb, ctrlr_attach_cb, ctrlr_detach_cb);if (probe_ctx == NULL) {printf("Failed to connect to NVMe controller\n");exit(1);}signal(SIGINT, sigint_handler);while (true) {spdk_nvme_probe_poll_async(probe_ctx);usleep(1000);}return 0;
}
简易讲解
这个代码的作用是连接到一个NVMe SSD,并且打印出一些连接的信息。它的执行流程如下:
- 初始化SPDK环境。
- 定义NVMe控制器的传输ID和选项。
- 定义NVMe控制器连接的回调函数。
- 连接到NVMe控制器。
- 注册SIGINT信号处理函数。
- 循环调用spdk_nvme_probe_poll_async函数,等待NVMe控制器连接。
- 注销SPDK环境。
在这个代码中,我们使用了以下的NVMe相关函数:
- spdk_nvme_connect_async:异步连接到NVMe控制器。
- spdk_nvme_ctrlr_opts_set_defaults:设置NVMe控制器选项的默认值。
- spdk_nvme_probe_poll_async:异步探测NVMe控制器。
- spdk_nvme_detach:断开与NVMe SSD的连接。
- signal:注册信号处理函数。
这个代码演示了如何使用SPDK的NVMe模块连接到NVMe SSD,并且可以扩展它来执行更复杂的操作。在实际的应用程序中,我们可以根据需要修改这个代码,比如读取数据、使用多个队列、使用多个命名空间等。
详细讲解一下这份代码
首先,我们需要了解一下NVMe(Non-Volatile Memory Express)是什么
。NVMe是一个通用的高速输入/输出接口,用于连接Flash和其他非易失性存储器设备。它被设计为一种高效、低延迟的接口,可以满足需要高速数据传输的应用程序的需求。NVMe是一种标准化接口,它提供了一个统一的命令集和控制器接口,可以让软件开发人员更容易地访问和管理存储设备。
那么,这份代码的作用是什么呢?它的主要功能是连接到一个NVMe SSD,并且打印出一些连接的信息。具体的执行流程如下:
- 初始化SPDK环境。
这一步非常简单,只需要调用spdk_env_init函数即可。当然,我们也可以通过spdk_env_opts_init函数来设置环境选项。 - 定义NVMe控制器的传输ID和选项。
在这个代码中,我们定义了一个struct spdk_nvme_transport_id类型的变量trid,用于指定NVMe SSD的传输ID。同时,我们也定义了一个struct spdk_nvme_ctrlr_opts类型的变量ctrlr_opts,用于设置NVMe控制器的选项,比如队列数量、命名空间等。 - 定义NVMe控制器连接的回调函数。
在这个代码中,我们定义了三个回调函数,分别是ctrlr_init_cb、ctrlr_attach_cb和ctrlr_detach_cb。这些回调函数会在NVMe控制器连接的不同阶段被调用,我们可以在这些回调函数中实现一些自定义的逻辑。 - 连接到NVMe控制器。
通过调用spdk_nvme_connect_async函数,我们可以异步地连接到NVMe控制器。这个函数会返回一个指向spdk_nvme_probe_ctx类型的结构体的指针,我们可以在之后的异步操作中使用这个结构体。 - 注册SIGINT信号处理函数。
我们可以通过调用signal函数来注册信号处理函数,这里我们注册了SIGINT信号的处理函数。 - 循环调用spdk_nvme_probe_poll_async函数,等待NVMe控制器连接。
在这个代码中,我们使用了一个循环来等待NVMe控制器的连接,这个循环中调用了spdk_nvme_probe_poll_async函数。这个函数会异步地探测NVMe控制器,如果探测到了NVMe控制器,就会调用之前定义的回调函数。我们可以在这些回调函数中实现一些自定义的逻辑,比如读取数据、使用多个队列、使用多个命名空间等。 - 注销SPDK环境。
当程序退出时,我们需要调用spdk_nvme_cleanup函数来注销SPDK环境。
这份代码涉及到了一些SPDK NVMe模块的API,比如spdk_nvme_connect_async、spdk_nvme_probe_poll_async、spdk_nvme_detach等。如果你想深入了解这些API的使用方法,可以参考SPDK官方文档。
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习