存储课程学习笔记8_spdk的安装以及简单demo测试

已经对相关的基础概念有一定的了解,比如裸盘,文件系统,读写相关裸盘,裸盘挂载使用,内核插入文件系统的方式,相关操作io的库或者函数(io_uring, readv,writev, mmap等),以及用户态文件系统fuse。

接下来对spdk进行了解。

0:总结

1:对spdk进行安装以及demo测试。

2:对宏观上spdk控制磁盘的架构和方案进行认识。

3:基于已经能通过spdk对磁盘进行访问的功能,后续按需按业务就得思考了(如何有效管理磁盘?)。

1:了解相关的文件系统

分布式文件系统一般提供了网络接口,对文件进行索引。

io的读写性能,硬件已经不是瓶颈,软件有一定限制,可以用spdk。
在这里插入图片描述

文件系统的最底层,其实是操作磁盘,各种类型的磁盘性能已经提升,性能瓶颈就在软件,有了spdk。

类似dpdk接管网卡,提升网络性能,spdk接管磁盘,提升磁盘io读写性能。

2:spdk的环境搭建。

vfio ===》/dev/vfio/vfio 内核有个vfio模块, 有个vfio设备文件 然后用户层操作vfio接口交互(libvfio-user)。

uio ====》/sys/class/uio 使用spdk启动后绑定磁盘后可以看到。 (可以深入uio的交互逻辑以及相关其他详细信息)

ubuntu@ubuntu:/dev$ ls nvme
nvme0         nvme0n1       nvme-fabrics  
ubuntu@ubuntu:/dev$ su
root@ubuntu:/dev# cd /home/ubuntu/spdk/spdk/
root@ubuntu:/home/ubuntu/spdk/spdk# ./scripts/setup.sh 
0000:03:00.0 (15ad 07f0): nvme -> uio_pci_generic

#查看uio设备编号和地址的关系 
root@ubuntu:/home/ubuntu/spdk/spdk# ls -l /sys/class/uio/uio*/device
lrwxrwxrwx 1 root root 0 Sep 11 03:52 /sys/class/uio/uio0/device -> ../../../0000:03:00.0

root@ubuntu:/sys/class/uio/uio0# ll
...
lrwxrwxrwx 1 root root    0 Sep 11 03:52 device -> ../../../0000:03:00.0/

#可以查看已经绑定的地址  这里显示的是大页内存的情况
root@ubuntu:/home/ubuntu/spdk/spdk# ./scripts/setup.sh status 
Hugepages
node     hugesize     free /  total
node0   1048576kB        0 /      0
node0      2048kB     1024 /   1024

Type                      BDF             Vendor Device NUMA    Driver           Device     Block devices
NVMe                      0000:03:00.0    15ad   07f0   unknown uio_pci_generic  -          -

3:安装spdk并支持fio模块

 $ git clone https://github.com/spdk/spdk.git
 $ cd spdk
 $ git submodule update --init
 $ ./scripts/pkgdep.sh   #涉及pip相关下载  需要换源 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
 $ ./configure --with-fio=/path/to/fio/repo   #fio安装可执行目录  root@ubuntu:/home/ubuntu/spdk/spdk# ./configure --with-fio=/home/ubuntu/uring/fio-fio-3.37
 $ make
 $ ./script/setup.sh

#遇到问题   Failed to connect to github.com port 443 after 21094 ms: Connection refused
#是代理问题导致 可以设置 首先查看网络代理端口  设置 -> 网络和Internet -> 代理
#如果开了代理 则
ubuntu@ubuntu:~/uring/fio-fio-3.37$ git config --global http.proxy 127.0.0.1:7888
ubuntu@ubuntu:~/uring/fio-fio-3.37$ git config --global https.proxy 127.0.0.1:7888
ubuntu@ubuntu:~/uring/fio-fio-3.37$ git config --list   #-l
#关闭上面的代理设置 
ubuntu@ubuntu:~/uring/fio-fio-3.37$ git config --global --unset http.proxy
ubuntu@ubuntu:~/uring/fio-fio-3.37$ git config --global --unset https.proxy

#如果安装过程中,有其他问题 大多数是网络不够好的原因,多试几次就好
root@ubuntu:/home/ubuntu/spdk/spdk# ./configure --with-fio=/home/ubuntu/uring/fio-fio-3.37
Using default SPDK env in /home/ubuntu/spdk/spdk/lib/env_dpdk
Using default DPDK in /home/ubuntu/spdk/spdk/dpdk/build
Configuring ISA-L (logfile: /home/ubuntu/spdk/spdk/.spdk-isal.log)...done.
Configuring ISA-L-crypto (logfile: /home/ubuntu/spdk/spdk/.spdk-isal-crypto.log)...done.
Creating mk/config.mk...done.
Creating mk/cc.flags.mk...done.
Type 'make' to build.
root@ubuntu:/home/ubuntu/spdk/spdk# make

#安装后启动 接管了虚拟机新增的nvme磁盘 这里注意这个地址
root@ubuntu:/home/ubuntu/spdk/spdk# ./scripts/setup.sh 
0000:03:00.0 (15ad 07f0): nvme -> uio_pci_generic

4:了解spdk下提供的相关脚本手动管理。

应该参考官网文档进行了解,SPDK: Storage Performance Development Kit

1:需要了解 build目录下生成的相关bin可执行文件的功能。

2:了解script目录下提供的相关脚本(需要对架构,以及函数调用的流程进行了解)。

#我可以理解未vhost就是spdk中对各种设备的一个虚拟化适配层(实现零拷贝,支持多种设备)
#手动对流程进行了解  启动一个vhost
root@ubuntu:/home/ubuntu/spdk/spdk/build/bin# ./vhost -c ../examples/hello_bdev.json 
[2024-09-11 04:19:13.990166] Starting SPDK v24.09-pre / DPDK 24.03.0 initialization...
[2024-09-11 04:19:13.990285] [ DPDK EAL parameters: vhost --no-shconf -c 0x1 --huge-unlink --no-telemetry --log-level=lib.eal:6 --log-level=lib.cryptodev:5 --log-level=user1:6 --iova-mode=pa --base-virtaddr=0x200000000000 --match-allocations --file-prefix=spdk_pid26150 ]
[2024-09-11 04:19:14.141607] app.c: 909:spdk_app_start: *NOTICE*: Total cores available: 1
[2024-09-11 04:19:14.209328] reactor.c: 943:reactor_run: *NOTICE*: Reactor started on core 0


#使用脚本进行观察 vhost实际上是server端  这里连接要对应 显示不一样
root@ubuntu:/home/ubuntu/spdk/spdk# ./scripts/spdkcli.py 
SPDK CLI v0.1

/bdevs> ls
o- bdevs .......................................................................................... [...]
  o- aio ..................................................................................... [Bdevs: 0]
  o- error ................................................................................... [Bdevs: 0]
  o- iscsi ................................................................................... [Bdevs: 0]
  o- logical_volume .......................................................................... [Bdevs: 0]
  o- malloc .................................................................................. [Bdevs: 0]
  o- null .................................................................................... [Bdevs: 0]
  o- nvme .................................................................................... [Bdevs: 1]
  | o- Nvme0n1 .......................... [11fd19c0-3da8-2017-000c-296beb492b8c, Size=20.0G, Not claimed]
  o- raid_volume ............................................................................. [Bdevs: 0]
  o- rbd ..................................................................................... [Bdevs: 0]
  o- split_disk .............................................................................. [Bdevs: 0]
  o- uring ................................................................................... [Bdevs: 0]
  o- virtioblk_disk .......................................................................... [Bdevs: 0]
  o- virtioscsi_disk ......................................................................... [Bdevs: 0]
/bdevs> /bdevs> exit

#spdk 对很多的控制接口的管理都是通过rpc  可以通过脚本查看以及创建,涉及相关的模块及流程
root@ubuntu:/home/ubuntu/spdk/spdk# 

#按默认启动一个新的vhost  
root@ubuntu:/home/ubuntu/spdk/spdk/build/bin# ./vhost -S /var/tmp -m 0x3
[2024-09-11 04:37:39.894391] Starting SPDK v24.09-pre / DPDK 24.03.0 initialization...
[2024-09-11 04:37:39.894598] [ DPDK EAL parameters: vhost --no-shconf -c 0x3 --huge-unlink --no-telemetry --log-level=lib.eal:6 --log-level=lib.cryptodev:5 --log-level=user1:6 --iova-mode=pa --base-virtaddr=0x200000000000 --match-allocations --file-prefix=spdk_pid26210 ]
[2024-09-11 04:37:40.032618] app.c: 909:spdk_app_start: *NOTICE*: Total cores available: 2
[2024-09-11 04:37:40.079872] reactor.c: 943:reactor_run: *NOTICE*: Reactor started on core 1
[2024-09-11 04:37:40.080050] reactor.c: 943:reactor_run: *NOTICE*: Reactor started on core 0

#使用rpc.py创建一个 bdev
root@ubuntu:/home/ubuntu/spdk/spdk# ./scripts/rpc.py -h  
root@ubuntu:/home/ubuntu/spdk/spdk# ./scripts/rpc.py bdev_malloc_create 64 512 -b Malloc0
Malloc0
root@ubuntu:/home/ubuntu/spdk/spdk# ./scripts/spdkcli.py ls
o- / ............................................................................... [...]
  o- bdevs ......................................................................... [...]
  | o- aio .................................................................... [Bdevs: 0]
  | o- error .................................................................. [Bdevs: 0]
  | o- iscsi .................................................................. [Bdevs: 0]
  | o- logical_volume ......................................................... [Bdevs: 0]
  | o- malloc ................................................................. [Bdevs: 1]
  | | o- Malloc0 ......... [9fb50102-4c6c-414f-9675-336ac2408f1c, Size=64.0M, Not claimed]
  | o- null ................................................................... [Bdevs: 0]
  | o- nvme ................................................................... [Bdevs: 0]
  | o- raid_volume ............................................................ [Bdevs: 0]
  | o- rbd .................................................................... [Bdevs: 0]
  | o- split_disk ............................................................. [Bdevs: 0]
  | o- uring .................................................................. [Bdevs: 0]
  | o- virtioblk_disk ......................................................... [Bdevs: 0]
  | o- virtioscsi_disk ........................................................ [Bdevs: 0]
  o- lvol_stores ........................................................ [Lvol stores: 0]
  o- vhost ......................................................................... [...]
    o- block ....................................................................... [...]
    o- scsi ........................................................................ [...]
    
#继续创建一个vhost  并给vhost分配位置  
#理解  vhost是一个适配层  可以适配所有的,target属于真正的目标磁盘,进行管理。
./scripts/spdkcli.py ls
./scripts/rpc.py bdev_malloc_create 64 512 -b Malloc0
./scripts/spdkcli.py ls
netstat -anop|grep vhost
./scripts/rpc.py vhost_create_scsi_controller --cpumask 0x1 vhost.0
netstat -anop|grep vhost
./scripts/spdkcli.py ls
./scripts/rpc.py vhost_scsi_controller_add_target vhost.0 1 Malloc0
./scripts/spdkcli.py ls
./scripts/rpc.py vhost_scsi_controller_add_target vhost.0 0 Malloc0

#上面的测试需要基于一个vhost启动去做连接
^Croot@ubuntu:/home/ubuntu/spdk/spdk/build/bin# ./vhost -S /var/tmp -m 0x3
[2024-09-11 04:37:39.894391] Starting SPDK v24.09-pre / DPDK 24.03.0 initialization...
[2024-09-11 04:37:39.894598] [ DPDK EAL parameters: vhost --no-shconf -c 0x3 --huge-unlink --no-telemetry --log-level=lib.eal:6 --log-level=lib.cryptodev:5 --log-level=user1:6 --iova-mode=pa --base-virtaddr=0x200000000000 --match-allocations --file-prefix=spdk_pid26210 ]
[2024-09-11 04:37:40.032618] app.c: 909:spdk_app_start: *NOTICE*: Total cores available: 2
[2024-09-11 04:37:40.079872] reactor.c: 943:reactor_run: *NOTICE*: Reactor started on core 1
[2024-09-11 04:37:40.080050] reactor.c: 943:reactor_run: *NOTICE*: Reactor started on core 0

VHOST_CONFIG: (/var/tmp/vhost.0) logging feature is disabled in async copy mode
VHOST_CONFIG: (/var/tmp/vhost.0) vhost-user server: socket created, fd: 226
VHOST_CONFIG: (/var/tmp/vhost.0) binding succeeded

在这里插入图片描述

创建一个vhost,可以看到已经新创建了一个socket,以及在目录层级中也能看到。 分配vhost,还未进行

在这里插入图片描述

vhost_scsi_controller_add_target 创建一个target,并与逻辑单元进行关联。

这里创建了两个

在这里插入图片描述

相关接口就属于业务流程了,待研究相关流程接口。

可以看到,接管磁盘,可以在用户层自己做磁盘的控制。

5:运行自带的example

可以看到 使用bdev的方式操作磁盘,读写已经成功。

root@ubuntu:/home/ubuntu/spdk/spdk/build/examples# ./hello_bdev --json hello_bdev.json 
[2024-09-11 05:12:00.875144] Starting SPDK v24.09-pre / DPDK 24.03.0 initialization...
[2024-09-11 05:12:00.876148] [ DPDK EAL parameters: hello_bdev --no-shconf -c 0x1 --huge-unlink --no-telemetry --log-level=lib.eal:6 --log-level=lib.cryptodev:5 --log-level=user1:6 --iova-mode=pa --base-virtaddr=0x200000000000 --match-allocations --file-prefix=spdk_pid26425 ]
[2024-09-11 05:12:01.011770] app.c: 909:spdk_app_start: *NOTICE*: Total cores available: 1
[2024-09-11 05:12:01.067633] reactor.c: 943:reactor_run: *NOTICE*: Reactor started on core 0
[2024-09-11 05:12:01.222992] hello_bdev.c: 222:hello_start: *NOTICE*: Successfully started the application
[2024-09-11 05:12:01.223091] hello_bdev.c: 231:hello_start: *NOTICE*: Opening the bdev Malloc0
[2024-09-11 05:12:01.223107] bdev.c:8114:bdev_open_ext: *NOTICE*: Currently unable to find bdev with name: Malloc0
[2024-09-11 05:12:01.223118] hello_bdev.c: 235:hello_start: *ERROR*: Could not open bdev: Malloc0
[2024-09-11 05:12:01.223129] app.c:1053:spdk_app_stop: *WARNING*: spdk_app_stop'd on non-zero
[2024-09-11 05:12:01.346120] hello_bdev.c: 309:main: *ERROR*: ERROR starting application
root@ubuntu:/home/ubuntu/spdk/spdk/build/examples# ./hello_bdev --json hello_bdev.json -b Nvme0n1
[2024-09-11 05:12:55.397512] Starting SPDK v24.09-pre / DPDK 24.03.0 initialization...
[2024-09-11 05:12:55.398311] [ DPDK EAL parameters: hello_bdev --no-shconf -c 0x1 --huge-unlink --no-telemetry --log-level=lib.eal:6 --log-level=lib.cryptodev:5 --log-level=user1:6 --iova-mode=pa --base-virtaddr=0x200000000000 --match-allocations --file-prefix=spdk_pid26428 ]
[2024-09-11 05:12:55.533299] app.c: 909:spdk_app_start: *NOTICE*: Total cores available: 1
[2024-09-11 05:12:55.589472] reactor.c: 943:reactor_run: *NOTICE*: Reactor started on core 0
[2024-09-11 05:12:55.730733] hello_bdev.c: 222:hello_start: *NOTICE*: Successfully started the application
[2024-09-11 05:12:55.730872] hello_bdev.c: 231:hello_start: *NOTICE*: Opening the bdev Nvme0n1
[2024-09-11 05:12:55.730907] hello_bdev.c: 244:hello_start: *NOTICE*: Opening io channel
[2024-09-11 05:12:55.731352] hello_bdev.c: 138:hello_write: *NOTICE*: Writing to the bdev
[2024-09-11 05:12:55.760169] hello_bdev.c: 117:write_complete: *NOTICE*: bdev io write completed successfully
[2024-09-11 05:12:55.760365] hello_bdev.c:  84:hello_read: *NOTICE*: Reading io
[2024-09-11 05:12:55.760924] hello_bdev.c:  65:read_complete: *NOTICE*: Read string from bdev : Hello World!

[2024-09-11 05:12:55.760977] hello_bdev.c:  74:read_complete: *NOTICE*: Stopping app

6:spdk提供的两种测试fio性能方式。

可以这样理解吗:nvme直接与磁盘进行通信交互,bdev是基于各种磁盘类型协议进行过封装,支持nvme类型的设备。

#spdk提供两种测试方式 可以使用fio测试其他方式读写磁盘的能力
#1:bdev  LD_PRELOAD hook的方式  dpdk提供了两种方式 spdk/spdk/build/fio/目录下
#使用bdev进行测试时 注意bdev.fio脚本  用到json文件 按rpc进行通信。 注意其中设置的
root@ubuntu:/home/ubuntu/spdk/fio_script# LD_PRELOAD=/home/ubuntu/spdk/spdk/build/fio/spdk_bdev /home/ubuntu/uring/fio-fio-3.37/fio bdev.fio 
test: (g=0): rw=randwrite, bs=(R) 16.0KiB-16.0KiB, (W) 16.0KiB-16.0KiB, (T) 16.0KiB-16.0KiB, ioengine=spdk_bdev, iodepth=64
fio-3.37
...
Run status group 0 (all jobs):
  WRITE: bw=2027MiB/s (2126MB/s), 2027MiB/s-2027MiB/s (2126MB/s-2126MB/s), io=19.8GiB (21.3GB), run=10001-10001msec
#2: nvme  spdk中用于专门与nvme通信
root@ubuntu:/home/ubuntu/spdk/fio_script# LD_PRELOAD=/home/ubuntu/spdk/spdk/build/fio/spdk_nvme /home/ubuntu/uring/fio-fio-3.37/fio nvme.fio 
test: (g=0): rw=randwrite, bs=(R) 16.0KiB-16.0KiB, (W) 16.0KiB-16.0KiB, (T) 16.0KiB-16.0KiB, ioengine=spdk, iodepth=64
fio-3.37
...
Run status group 0 (all jobs):
  WRITE: bw=817MiB/s (857MB/s), 817MiB/s-817MiB/s (857MB/s-857MB/s), io=8175MiB (8572MB), run=10001-10001msec

对比各种测试方式下的性能差异  以及spdk_nvme 和 spdk_bdev的区别

7:实现一个example进行理解。

7.1 了解几种访问磁盘的方式

1:可以直接通过spdk 的nvme模块,直接与nvme设备进行交互管理。

2:可以通过bdev模块,实现与nvme设备的交互。

3:基于bdev之上,使用blob/blobstore实现与磁盘进行交互。

4:与nvme设备最底层的交互实际上还是PCie总线,nvme是基于pcie的协议封装,spdk管理dbev,blob/blobstore等模块的方式,采用rpc的方式。

在这里插入图片描述

参考如图:bdev,blob,blobstore等创建,删除,查询的管理 用的rpc。

bdev是一个适配层封装吧,blob底层实际上也用bdev再调用。

在这里插入图片描述

7.2 理解一个blob的demo

1:参考spdk下的example下的demo了解概念最合适,以及新增demo的方式参考example。

2:blob的整个管理使用的是rpc,所以这里的顺序流程,一直使用回调函数获取到执行结果后继续。

3:自己的demo下,可以不放在example目录下去编译,只需要修改对应makefile下的SPDK_ROOT_DIR 参数为spdk实际目录。

7.2.1 确定环境的正确,实现入口

首先环境运行起来 参考example,自己写入口,修改makefile进行测试

#include <stdio.h>
#include <spdk/event.h> 


static void example_entry(void *ctx)
{
	printf("example_entry ====> \n");
}

 int main(int argc, char *argv[]) {

	if (argc < 2) {
		return -1;
	}

	struct spdk_app_opts opts= {0};
	spdk_app_opts_init(&opts, sizeof(opts));
	opts.name = "blob_example";
	opts.json_config_file = argv[1];

	printf("spdk_set_thread --> \n");

	// zfs_ctx_t *ctx = calloc(1, sizeof(zfs_ctx_t));
	//启动spdk应用程序
	spdk_app_start(&opts, example_entry, NULL);

	spdk_app_fini();

	// free(ctx);

	return 0;
}

运行显示

root@ubuntu:/home/ubuntu/storage/spdk_one_example# ls
blob_example.c  hello_blob.json  Makefile
root@ubuntu:/home/ubuntu/storage/spdk_one_example# make
root@ubuntu:/home/ubuntu/storage/spdk_one_example# ./blob_example hello_blob.json 
spdk_set_thread --> 
[2024-09-08 03:28:36.621006] Starting SPDK v24.09-pre / DPDK 24.03.0 initialization...
[2024-09-08 03:28:36.621185] [ DPDK EAL parameters: blob_example --no-shconf -c 0x1 --huge-unlink --no-telemetry --log-level=lib.eal:6 --log-level=lib.cryptodev:5 --log-level=user1:6 --iova-mode=pa --base-virtaddr=0x200000000000 --match-allocations --file-prefix=spdk_pid3536 ]
[2024-09-08 03:28:36.759565] app.c: 909:spdk_app_start: *NOTICE*: Total cores available: 1
[2024-09-08 03:28:36.807677] reactor.c: 943:reactor_run: *NOTICE*: Reactor started on core 0
example_entry ====> 
7.2.2 相关接口调用测试

依次通过回到函数创建:

创建bdev =》创建blobstore=>创建真正blob ==>真正对blob的创建,删除,修改,读,写等

#include <stdio.h>
#include <spdk/event.h> 

#include <spdk/env.h>
#include <spdk/blob.h>
#include <spdk/bdev.h>
#include <spdk/blob_bdev.h>
static void example_spdk_bdev_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
				     void *event_ctx) {
	printf("example_spdk_bdev_cb blobstore create success\n");
}

static void example_spdk__bdev_open_blob_complete(void *arg, struct spdk_blob *blb, int bserrno) {
	printf("example_spdk__bdev_open_blob_complete blobstore create success\n");
	//最后就是读写操作了 对blob的真正操作 获取空闲大小  设置大小  读写操作  以及相关释放操作。
}


static void example_spdk_bdev_blob_create_cb(void *arg, spdk_blob_id blobid, int bserrno) 
{
	printf("example_spdk_bdev_blob_create_cb :%"PRIu64"\n", blobid);

	//blob创建后 
	struct spdk_blob_store *bs = arg;
	spdk_bs_open_blob(bs, blobid, example_spdk__bdev_open_blob_complete, NULL);
}


static void example_spdk_bdev_init_cb(void *arg, struct spdk_blob_store *bs,int bserrno) 
{
	printf("example_spdk_bdev_init_cb blobstore init success\n");
	spdk_bs_create_blob(bs, example_spdk_bdev_blob_create_cb, bs);
}

static void example_entry(void *ctx)
{
	printf("example_entry ====> \n");
	struct spdk_bs_dev *bsdev = NULL;
	const char * bdev_name = "Malloc0";   //这个名字和json配置文件中 bdev_malloc_create 中对应name关联
	int res = spdk_bdev_create_bs_dev_ext(bdev_name, example_spdk_bdev_cb, NULL, &bsdev);
	if (res != 0) {
		spdk_app_stop(-1);
		return ;
	}

	spdk_bs_init(bsdev, NULL, example_spdk_bdev_init_cb, NULL);
}

 int main(int argc, char *argv[]) {

	if (argc < 2) {
		return -1;
	}

	struct spdk_app_opts opts= {0};
	spdk_app_opts_init(&opts, sizeof(opts));
	opts.name = "blob_example";
	opts.json_config_file = argv[1];

	printf("spdk_set_thread --> \n");
	spdk_app_start(&opts, example_entry, NULL);
	spdk_app_fini();

	// free(ctx);
	return 0;
}

已经可以看到代码的调用流程。通过回调函数依次调用,但是实现后发现无法进行有效管理磁盘后续读写。

7.2.3 参考example下blob模块 实现磁盘读写

运行如下,可以看到已经正常写入并读成功。

root@ubuntu:/home/ubuntu/storage/spdk_one_example# ./blob_example hello_blob.json 
spdk_set_thread --> 
[2024-09-08 08:08:12.630916] Starting SPDK v24.09-pre / DPDK 24.03.0 initialization...
[2024-09-08 08:08:12.631057] [ DPDK EAL parameters: blob_example --no-shconf -c 0x1 --huge-unlink --no-telemetry --log-level=lib.eal:6 --log-level=lib.cryptodev:5 --log-level=user1:6 --iova-mode=pa --base-virtaddr=0x200000000000 --match-allocations --file-prefix=spdk_pid6132 ]
[2024-09-08 08:08:12.777323] app.c: 909:spdk_app_start: *NOTICE*: Total cores available: 1
[2024-09-08 08:08:12.836624] reactor.c: 943:reactor_run: *NOTICE*: Reactor started on core 0
example_entry ====> 
example_spdk_bdev_init_cb blobstore init success
example_spdk_bdev_blob_create_cb :4294967296
example_spdk__bdev_open_blob_complete blobstore create success
example_spdk__bdev_open_blob_complete free = 15
example_resize_complete blobstore create success
example_resize_complete total = 15
exp_file_write_complete 
Data written successfully.
read_data from blob :ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZa]ʆV 
exp_file_read_complete 
Data written successfully.

测试代码如下,只关注了流程,未考虑释放等。

这里注意,发现,blob在创建成功后,需要先进行resize等操作才能进行写入成功。

#include <stdio.h>
#include <spdk/event.h> 

#include <spdk/env.h>
#include <spdk/blob.h>
#include <spdk/bdev.h>
#include <spdk/blob_bdev.h>


//回调函数依次调用  有时候需要参数传递一些指针  这里定义必要的结构
struct temp_ctx_s{
	struct spdk_bs_dev *s_bsdev;
	struct spdk_blob_store *s_bs;
	spdk_blob_id s_blobid;
	struct spdk_blob * s_blob;
	struct spdk_io_channel* s_channel;

	uint64_t io_unit_size;

	uint8_t *write_buff;
	uint8_t *read_buff;
};
// struct temp_ctx_s *g_ctx;
static void example_spdk_bdev_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
				     void *event_ctx) {

	printf("example_spdk_bdev_cb blobstore create success\n");
	
}

static void delete_complete(void *arg1, int bserrno)
{

	if (bserrno) {
		printf("Error in delete completion: %d\n", (-bserrno));
		return;
	}

	// struct temp_ctx_s *m_ctx = arg1;
	//进行相关的释放动作 
}


static void delete_blob(void *arg1, int bserrno)
{
	if (bserrno) {

		printf("Error in close completion: %d\n", (-bserrno));
		return;
	}

	struct temp_ctx_s *m_ctx = arg1;
	spdk_bs_delete_blob(m_ctx->s_bs, m_ctx->s_blobid,  delete_complete, m_ctx);
}


static void exp_file_read_complete(void *arg1, int bserrno) 
{
	printf("exp_file_read_complete \n");

	if (bserrno) {
        printf("Failed to read data: %d\n", (-bserrno));
        // 写入失败处理
        return;
    } else {
        printf("Data written successfully.\n");
        // 写入成功处理
    }

    struct temp_ctx_s *m_ctx = arg1;
    spdk_blob_close(m_ctx->s_blob, delete_blob, m_ctx);
}

// struct spdk_io_channel * g_channel;
// struct spdk_blob *g_blob;


static void exp_file_write_complete(void *arg1, int bserrno)
{
	printf("exp_file_write_complete \n");

	if (bserrno) {
        printf("Failed to write data: %d\n", (-bserrno));
        // 写入失败处理
        return;
    } 
    printf("Data written successfully.\n");
        // 写入成功处理

    struct temp_ctx_s *m_ctx = arg1;
	uint8_t *read_buff = spdk_malloc(m_ctx->io_unit_size, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
	if (read_buff == NULL)
	{
		printf("read_buff is null \n");
		return; 
	}
	spdk_blob_io_read(m_ctx->s_blob, m_ctx->s_channel , read_buff, 0, 1, exp_file_read_complete, m_ctx);
	printf("read_data from blob :%s \n", read_buff);

}

static void sync_complete(void *arg1, int bserrno)
{
	if (bserrno) {
		printf("sync_complete Error in sync callback: %d\n", (-bserrno));
		return;
	}
	struct temp_ctx_s *m_ctx = arg1;

	 uint8_t *write_buff = spdk_malloc(m_ctx->io_unit_size, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
	if (write_buff == NULL)
	{
		printf("write_buff is null \n");
		return; 
	}
	memset(write_buff, 0x5a, m_ctx->io_unit_size);
	m_ctx->s_channel = spdk_bs_alloc_io_channel(m_ctx->s_bs);
	
	spdk_blob_io_write(m_ctx->s_blob, m_ctx->s_channel , write_buff, 0, 1, exp_file_write_complete, m_ctx);
	

}
static void example_resize_complete(void *cb_arg, int bserrno)
{
	printf("example_resize_complete blobstore create success\n");
	struct temp_ctx_s *m_ctx = cb_arg;

	if (bserrno) {
		printf("example_resize_complete Error in blob resize: %d\n", (-bserrno));
		return;
	}
	uint64_t total = 0;
	total = spdk_blob_get_num_clusters(m_ctx->s_blob);

	printf("example_resize_complete total = %" PRIu64 "\n", total);

	spdk_blob_sync_md(m_ctx->s_blob, sync_complete, m_ctx); //进行同步相关数据 直接进行

}		

//最后就是读写操作了 对blob的真正管理
// char write_data[1024] = "Hello, SPDK! =======XXXXXXX"; // 写入的数据
// char read_data[1024] = {0}; // 用于存储读取的数据

static void example_spdk__bdev_open_blob_complete(void *arg, struct spdk_blob *blob, int bserrno) {
	printf("example_spdk__bdev_open_blob_complete blobstore create success\n");
	
	struct temp_ctx_s *m_ctx = arg;
	if (bserrno) {
		printf("example_spdk__bdev_open_blob_complete Error in open resize: %d\n", (-bserrno));
		return;
	}

	m_ctx->s_blob = blob;
	uint64_t free = 0;
	free = spdk_bs_free_cluster_count(m_ctx->s_bs);
	printf("example_spdk__bdev_open_blob_complete free = %" PRIu64 "\n", free);
	spdk_blob_resize(blob, free, example_resize_complete, m_ctx);

	// struct spdk_blob_store *bs = arg;
	// uint64_t io_unit_size = spdk_bs_get_io_unit_size(bs);
	// uint8_t *write_buff = spdk_malloc(io_unit_size, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
	// if (write_buff == NULL)
	// {
	// 	printf("write_buff is null \n");
	// 	return; 
	// }
	// memset(write_buff, 0x5a, io_unit_size);
	// // g_channel = spdk_bs_alloc_io_channel(bs);

	// g_ctx.bs = bs;
	// g_ctx.s_blob = blb;
	// g_ctx.io_unit_size = io_unit_size;
	// g_ctx.s_channel = spdk_bs_alloc_io_channel(bs);
	
	// spdk_blob_io_write(blb, g_ctx.s_channel , write_buff, 0, 1, exp_file_write_complete, NULL);
	
}

static void example_spdk_bdev_blob_create_cb(void *arg, spdk_blob_id blobid, int bserrno) 
{
	printf("example_spdk_bdev_blob_create_cb :%"PRIu64"\n", blobid);

	//blob创建后 
	struct temp_ctx_s *m_ctx = arg;

	if (bserrno) {
		printf("example_spdk_bdev_blob_create_cb Error in blob create callback: %d\n", (-bserrno));
		return;
	}
	m_ctx->s_blobid = blobid;
	spdk_bs_open_blob(m_ctx->s_bs, blobid, example_spdk__bdev_open_blob_complete, m_ctx);

}


static void example_spdk_bdev_init_cb(void *arg, struct spdk_blob_store *bs,int bserrno) 
{
	printf("example_spdk_bdev_init_cb blobstore init success\n");


	struct temp_ctx_s *m_ctx = arg;
	if (bserrno) {

		printf("example_spdk_bdev_init_cb Error initing the blobstore: %d\n", (-bserrno));
		return;
	}
	m_ctx->s_bs = bs;
	m_ctx->io_unit_size = spdk_bs_get_io_unit_size(bs);
	spdk_bs_create_blob(bs, example_spdk_bdev_blob_create_cb, m_ctx);
}

static void example_entry(void *ctx)
{
	printf("example_entry ====> \n");

	struct spdk_bs_dev *bsdev = NULL;

	const char * bdev_name = "Malloc0";   //这个名字和json配置文件中 bdev_malloc_create 中对应name关联
	int res = spdk_bdev_create_bs_dev_ext(bdev_name, example_spdk_bdev_cb, NULL, &bsdev);
	if (res != 0) {
		spdk_app_stop(-1);
		return ;
	}

	struct temp_ctx_s *m_ctx = ctx;
	spdk_bs_init(bsdev, NULL, example_spdk_bdev_init_cb, m_ctx);
}

 int main(int argc, char *argv[]) {

	if (argc < 2) {
		return -1;
	}

	struct spdk_app_opts opts= {0};
	spdk_app_opts_init(&opts, sizeof(opts));
	opts.name = "blob_example";
	opts.json_config_file = argv[1];

	printf("spdk_set_thread --> \n");

	//启动spdk应用程序

	struct temp_ctx_s *m_ctx = calloc(1, sizeof(struct temp_ctx_s));
	spdk_app_start(&opts, example_entry, m_ctx);

	spdk_app_fini();

	free(m_ctx);

	return 0;
}

上述流程可以发现,所有的操作都是顺序的,回调函数依次调用实现,异步的方案让我们无法实际有效管控。

7.2.4 把rpc异步调用方式改为同步

spdk已经提供了对应的接口和方案,也就是把相关操作放给特定的线程,等待执行完成。

借助spdk_thread_send_msg 放入线程 和spdk_thread_poll 指定轮询进行实现。

每次调用poller接口,实际上是在新的线程中调用,返回时即已经获取到反馈结果了。(参考example逻辑实现)

static int zvfs_env_setup(void) {
	struct spdk_env_opts opts;
	spdk_env_opts_init(&opts);

	if (spdk_env_init(&opts) != 0) {
		return -1;
	}

	spdk_log_set_print_level(SPDK_LOG_NOTICE);
	spdk_log_set_level(SPDK_LOG_NOTICE);
	spdk_log_open(NULL);

	spdk_thread_lib_init(NULL, 0);
	global_thread = spdk_thread_create("global", NULL);
	spdk_set_thread(global_thread);  //设置spdk工作线程 

	bool done = false;
	poller(global_thread, zvfs_json_load_fn, &done, &done);

	return 0;
}

//相关任务异步放入执行线程中 达到同步获取到结果
static const int POLLER_MAX_TIME = 100000;
static bool poller(struct spdk_thread *thread, spdk_msg_fn start_fn, void *ctx, bool *finished) {
	spdk_thread_send_msg(thread, start_fn, ctx);
	int poller_count = 0;
	do {
		spdk_thread_poll(thread, 0, 0);
		poller_count ++;
	} while (!(*finished) && poller_count < POLLER_MAX_TIME);

	
	if (!(*finished) && poller_count >= POLLER_MAX_TIME) { //timeout
		return false;
	}
	
	return true;
}
  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值