作者 三角板
給SSD Fans原創(chuàng)投稿技術(shù)或市場文章,拿>=100元稿費。
以前只知道DPDK,最近聽說SPDK,深入研究了一把。
Dpdk依賴UIO技術(shù),見如下網(wǎng)址:
http://www.cnblogs.com/kb342/p/5168197.html
舉個例子說明一下UIO技術(shù),做過vxworks的工程師都知道,vxworks沒有用戶空間和內(nèi)核空間的概念,所有的任務(wù)(進程或者線程)都跑在一個用戶空間,調(diào)試時候可以直接敲函數(shù)讀寫寄存器;到了linux里面一般都用創(chuàng)建芯片寄存器ioremap空間向?qū)?yīng)的proc文件實現(xiàn)對寄存器狀態(tài)的讀寫配置。Intel利用其在X86平臺(還有pcie)領(lǐng)域的巨大優(yōu)勢,專門寫了一個通用的驅(qū)動來簡化統(tǒng)一實現(xiàn)這個功能(UIO驅(qū)動加eal層),這就是UIO技術(shù)。猜測也正是因為如此,spdk只能跑在X86架構(gòu)的服務(wù)器平臺上。當然這僅僅是個簡單的例子,方便大家了解,其實不僅僅是intel,各大公司比如華為都有內(nèi)部這樣一套統(tǒng)一的內(nèi)核和用戶通信調(diào)試接口提高效率。
SPDK依賴于dpdk,編譯步驟如下:
下載spdk
git clone https://github.com/spdk/spdk.git
下載dpdk
Spdk代碼下載后默認有一個dpdk的空文件夾用來存放dpdk源碼
在spdk目錄下如下操作:

提示用git submodule update –init命令下載dpdk
編譯dpdk
進入dpdk目錄
輸入如下命令
make install T=x86_64-native-linuxapp-gcc DESTDIR=.
需要說明的是dpdk有自身一套很智能的安裝和配置接口,這里直接手動操作,具體配置方法后續(xù)說明。
4. 安裝相關(guān)編譯工具和依賴庫
進入spdk/目錄,執(zhí)行pkgdep.sh腳本,自動下載安裝相關(guān)依賴文件。
編譯spdk
進入spdk目錄執(zhí)行make DPDK_DIR=./dpdk/x86_64-native-linuxapp-gcc
編譯通過。
dpdk配置
見如下網(wǎng)址http://blog.csdn.net/fjssharpsword/article/details/50946110
建議用自帶的選擇配置模式進行如下操作(可以和步驟3一起完成):
安裝UIO驅(qū)動(Insert IGB UIO module);
Setup hugepage mappings for non-NUMA systems 輸入64或128;
Bind Ethernet device to IGB UIO module;
Display current Ethernet device settings;
Run test application(非必要操作)
配置spdk
Spdk目錄下執(zhí)行如下命令s/setup.sh
執(zhí)行測試程序spdk/example/nvme/目錄下相關(guān)測試命令

本測試例子是寫入一個數(shù)據(jù)后做回讀測試,詳見代碼。
最后不要忘記在安裝調(diào)試spdk包的時候插上nvme ssd。
內(nèi)核代碼層次
Nvme相關(guān)的api文件存在于libnvme目錄下的C文件中,看文件名稱就知道各個層次對應(yīng)的接口函數(shù):
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層次是工作在底層的統(tǒng)一抽象層次,類似于hal層次,獲取設(shè)備的寄存器IO地址空間和中斷等傳遞給用戶層設(shè)備,用mmap實現(xiàn)。
每個request處理完之后的觸發(fā)的的cpl處理回調(diào)函數(shù)是從qpair這個結(jié)構(gòu)體中傳遞過去的,見nvme_pcie_ctrlr_create_io_qpair, nvme_pcie_qpair_construct, nvme_pcie_qpair_process_completions
uio驅(qū)動可以參見內(nèi)核的/driver/uio 目錄,直接創(chuàng)建一個字符設(shè)備接口作為用戶和內(nèi)核態(tài)的信息交換接口,可以直接看uio.c的代碼,其他的是針對各種特定設(shè)備的uio驅(qū)動。
Dpdk的igb_uio驅(qū)動代碼文件在如下位置:dpdkliblibrte_eallinuxappigb_uio,可以查看源碼,具體的實現(xiàn)機制如下網(wǎng)址有詳細介紹。
igb_uio ————————> http://blog.csdn.net/weijitao/article/details/52949454
Eal層代碼位置spdkdpdkliblibrte_eal 這個里面創(chuàng)建了內(nèi)核和用戶態(tài)的信息交換機制,代碼比較復(fù)雜,不太容易讀。
Dpdk ———————-> http://dpdk.org/doc/guides/prog_guide/env_abstraction_layer.html
eal層次代碼比較復(fù)雜,目前還沒有完全理出來。
Eal中的相關(guān)thread:eal_intr_thread_main ,eal_thread_loop,hpet_msb_inc等用來完成數(shù)據(jù)傳遞和狀態(tài)同步等。
Eal層次獲取PCI信息是靠解析sysfs的節(jié)點實現(xiàn)的,獲取信息后傳遞給用戶態(tài)的driver,見eal_pci.c
簡單來說SPDK的實現(xiàn)道理如下:通過UIO這個的驅(qū)動接口,僅僅將驅(qū)動中共性的一部分放在內(nèi)核態(tài)實現(xiàn),eal層次通過解析sysfs的相關(guān)節(jié)點獲取設(shè)備信息(bar,function等)傳遞給用戶態(tài)的設(shè)備模型,之后eal層次用mmap建立內(nèi)核和用戶空間的數(shù)據(jù)傳遞通道和同步機制,實現(xiàn)了驅(qū)動的用戶態(tài)功能實現(xiàn)。
Spdk提供了多種存儲接口(scsi,nvme等)不同層次的操作接口,可以供用戶直接調(diào)用完成設(shè)備識別,控制,數(shù)據(jù)傳輸?shù)取?/div>






