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

ops/2024/10/21 9:46:09/

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

接下来对spdk进行了解。

0:总结

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

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

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

1:了解相关的文件系统

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

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

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

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

spdk_26">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.0root@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 /   1024Type                      BDF             Vendor Device NUMA    Driver           Device     Block devices
NVMe                      0000:03:00.0    15ad   07f0   unknown uio_pci_generic  -          -

spdkfio_60">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

spdk_97">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 0VHOST_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

spdkfio_251">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) { //timeoutreturn false;}return true;
}

http://www.ppmy.cn/ops/109783.html

相关文章

MFC工控项目实例之十四模拟量信号名称从文件读写

承接专栏《MFC工控项目实例之十三从文件读写板卡信号名称》 在BoardTest.cpp文件中添加代码 int m_CountGetCurSel_AD[16];//索引号 UINT m_CountComboID_AD[16]//控件ID号{IDC_COMBO33,IDC_COMBO34,IDC_COMBO35,IDC_COMBO36,IDC_COMBO37,IDC_COMBO38,IDC_COMBO39,IDC_COMBO40…

springboot体会BIO(阻塞式IO)

使用springboot体会阻塞式IO 大致的思路为&#xff1a; 创建一个socket服务端&#xff0c;监听socket通道&#xff0c;并打印出socket通道中的内容。 创建两个socket客户端&#xff0c;向socket服务端写入消息。 1.创建服务端 public class RedisServer {public static void m…

基于YOLOv10的光伏板缺陷检测系统

基于YOLOv10的光伏板缺陷检测系统 (价格90) 包含 [鸟落, 干净, 破裂, 灰尘] 4个类 通过PYQT构建UI界面&#xff0c;包含图片检测&#xff0c;视频检测&#xff0c;摄像头实时检测。 &#xff08;该系统可以根据数据训练出的yolov10的权重文件&#xff0c;运用在其…

Redis、memcache、MongoDB 对比

1. 数据结构和存储方式 Redis Redis 是一个开源的内存数据库&#xff0c;支持丰富的数据结构。它的数据类型包括&#xff1a; 字符串&#xff08;String&#xff09;哈希&#xff08;Hash&#xff09;列表&#xff08;List&#xff09;集合&#xff08;Set&#xff09;有序集…

设计模式之装饰器模式:让对象功能扩展更优雅的艺术

一、什么是装饰器模式 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff08;Structural Pattern&#xff09;&#xff0c;它允许用户通过一种灵活的方式来动态地给一个对象添加一些额外的职责。就增加功能来说&#xff0c;装饰器模式相比使用…

Android系列基础知识总结

四大组件 Activity Activity生命周期 不同场景下Activity生命周期的变化过程 启动Activity&#xff1a; onCreate()—>onStart()—>onResume()&#xff0c;Activity进入运行状态。Activity退居后台&#xff1a; 当前Activity转到新的Activity界面或按Home键回到主屏&a…

HTTP 协议的工作过程

当我们在浏览器输入一个网址&#xff0c;此时浏览器就会给对应的服务器发送一个 HTTP 请求&#xff0c;对应的服务器收到这个请求之后&#xff0c;经过计算处理&#xff0c;就会返回一个 HTTP 响应。并且当我们访问一个网站时&#xff0c;可能涉及不止一次的 HTTP 请求和响应的…

电气设备或电气线路故障引起的火灾主要特征

1 主要特征 电气火灾是由电气设备或电气线路故障引起的火灾。这类火灾具有一定的特殊性&#xff0c;主要特征如下&#xff1a; 1&#xff09;突发性强 突发性&#xff1a;电气火灾往往在没有明显征兆的情况下突然发生&#xff0c;不易被及时察觉。 瞬间爆发&#xff1a;由于…