深入研究SPDK

原创内容,转载请注明:  [http://www.ssdfans.com]  谢谢!

作者 三角板

 

以前只知道DPDK,最近听说SPDK,深入研究了一把。

Dpdk依赖UIO技术,见如下网址:

http://www.cnblogs.com/kb342/p/5168197.html

 

举个例子说明一下UIO技术,做过vxworks的工程师都知道,vxworks没有用户空间和内核空间的概念,所有的任务(进程或者线程)都跑在一个用户空间,调试时候可以直接敲函数读写寄存器;到了linux里面一般都用创建芯片寄存器ioremap空间向对应的proc文件实现对寄存器状态的读写配置。Intel利用其在X86平台(还有pcie)领域的巨大优势,专门写了一个通用的驱动来简化统一实现这个功能(UIO驱动加eal层),这就是UIO技术。猜测也正是因为如此,spdk只能跑在X86架构的服务器平台上。当然这仅仅是个简单的例子,方便大家了解,其实不仅仅是intel,各大公司比如华为都有内部这样一套统一的内核和用户通信调试接口提高效率。

 

SPDK依赖于dpdk,编译步骤如下:

  1. 下载spdk

    git clone https://github.com/spdk/spdk.git 

     

  2. 下载dpdk

    Spdk代码下载后默认有一个dpdk的空文件夹用来存放dpdk源码

    在spdk目录下如下操作:

    提示用git submodule update –init命令下载dpdk

     

  3. 编译dpdk

    进入dpdk目录

    输入如下命令

    make install T=x86_64-native-linuxapp-gcc DESTDIR=.  

    需要说明的是dpdk有自身一套很智能的安装和配置接口,这里直接手动操作,具体配置方法后续说明。

     

4. 安装相关编译工具和依赖库

进入spdk/script目录,执行pkgdep.sh脚本,自动下载安装相关依赖文件。

 

  1. 编译spdk

    进入spdk目录执行make DPDK_DIR=./dpdk/x86_64-native-linuxapp-gcc 

    编译通过。

     

  2. dpdk配置

    见如下网址http://blog.csdn.net/fjssharpsword/article/details/50946110

    建议用自带的选择配置模式进行如下操作(可以和步骤3一起完成):

    1. 安装UIO驱动(Insert IGB UIO module);
    2. Setup hugepage mappings for non-NUMA systems 输入64或128;
    3. Bind Ethernet device to IGB UIO module;
    4. Display current Ethernet device settings;
    5. Run test application(非必要操作)

       

  3. 配置spdk

    Spdk目录下执行如下命令scripts/setup.sh

     

  4. 执行测试程序spdk/example/nvme/目录下相关测试命令



本测试例子是写入一个数据后做回读测试,详见代码。

 

最后不要忘记在安装调试spdk包的时候插上nvme ssd。

 

内核代码层次

Nvme相关的api文件存在于\lib\nvme目录下的C文件中,看文件名称就知道各个层次对应的接口函数:

Nvme_ctrl, nvme_ns, nvme_qpair, nvme_transport, nvme_pcie等,nvme_transport其实是nvme_pcie层次的封装,详见

nvme_transport.c文件的宏定义如下如下:

 

 

#define TRANSPORT_PCIE(func_name, args)    case SPDK_NVME_TRANSPORT_PCIE: return nvme_pcie_ ## func_name args;

#ifdef SPDK_CONFIG_RDMA

#define TRANSPORT_FABRICS_RDMA(func_name, args)    case SPDK_NVME_TRANSPORT_RDMA: return nvme_rdma_ ## func_name args;

#define TRANSPORT_RDMA_AVAILABLE        true

#else

#define TRANSPORT_FABRICS_RDMA(func_name, args)    case SPDK_NVME_TRANSPORT_RDMA: SPDK_UNREACHABLE();

#define TRANSPORT_RDMA_AVAILABLE        false

#endif

#define NVME_TRANSPORT_CALL(trtype, func_name, args)     \

    do {                            \

        switch (trtype) {                \

        TRANSPORT_PCIE(func_name, args)            \

        TRANSPORT_FABRICS_RDMA(func_name, args)        \

        TRANSPORT_DEFAULT(trtype)            \

        }                        \

        SPDK_UNREACHABLE();                \

    } while (0)

 

 

Eal层次是工作在底层的统一抽象层次,类似于hal层次,获取设备的寄存器IO地址空间和中断等传递给用户层设备,用mmap实现。

 

每个request处理完之后的触发的的cpl处理回调函数是从qpair这个结构体中传递过去的,见nvme_pcie_ctrlr_create_io_qpair, nvme_pcie_qpair_construct, nvme_pcie_qpair_process_completions

 

uio驱动可以参见内核的/driver/uio 目录,直接创建一个字符设备接口作为用户和内核态的信息交换接口,可以直接看uio.c的代码,其他的是针对各种特定设备的uio驱动。

 

Dpdk的igb_uio驱动代码文件在如下位置:dpdk\lib\librte_eal\linuxapp\igb_uio,可以查看源码,具体的实现机制如下网址有详细介绍。

igb_uio ————————> http://blog.csdn.net/weijitao/article/details/52949454

 

Eal层代码位置spdk\dpdk\lib\librte_eal 这个里面创建了内核和用户态的信息交换机制,代码比较复杂,不太容易读。

Dpdk ———————-> http://dpdk.org/doc/guides/prog_guide/env_abstraction_layer.html

 

eal层次代码比较复杂,目前还没有完全理出来。

Eal中的相关thread:eal_intr_thread_main ,eal_thread_loop,hpet_msb_inc等用来完成数据传递和状态同步等。

Eal层次获取PCI信息是靠解析sysfs的节点实现的,获取信息后传递给用户态的driver,见eal_pci.c

 

简单来说SPDK的实现道理如下:通过UIO这个的驱动接口,仅仅将驱动中共性的一部分放在内核态实现,eal层次通过解析sysfs的相关节点获取设备信息(bar,function等)传递给用户态的设备模型,之后eal层次用mmap建立内核和用户空间的数据传递通道和同步机制,实现了驱动的用户态功能实现。

Spdk提供了多种存储接口(scsi,nvme等)不同层次的操作接口,可以供用户直接调用完成设备识别,控制,数据传输等。


 

分类目录 SSD.
扫一扫二维码或者微信搜索公众号ssdfans关注(添加朋友->点最下面的公众号->搜索ssdfans),可以经常看到SSD技术和产业的文章(SSD Fans只推送干货)。
ssdfans微信群介绍
技术讨论群 覆盖2000多位中国和世界华人圈SSD以及存储技术精英
固件、软件、测试群 固件、软件和测试技术讨论
异构计算群 讨论人工智能和GPU、FPGA、CPU异构计算
ASIC-FPGA群 芯片和FPGA硬件技术讨论群
闪存器件群 NAND、3D XPoint等固态存储介质技术讨论
企业级 企业级SSD、企业级存储
销售群 全国SSD供应商都在这里,砍砍价,会比某东便宜20%
工作求职群 存储行业换工作,发招聘,要关注各大公司招聘信息,赶快来
高管群 各大SSD相关存储公司高管和创始人、投资人

想加入这些群,请微信扫描下面二维码,或搜索nanoarchplus,加阿呆为微信好友,介绍你的昵称-单位-职务,注明群名,拉你进群。SSD业界需要什么帮助,也可以找阿呆聊。