存储课程学习笔记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.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  -          -

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

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.rhkb.cn/news/422154.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nlohmann::json中有中文时调用dump转string抛出异常的问题

问题描述 Winodows下C开发想使用一个json库&#xff0c;使用的nlohmann::json&#xff0c;但是遇到json中使用中文时&#xff0c;转成string&#xff0c;会抛出异常。 nlohmann::json contentJson;contentJson["chinese"] "哈哈哈";std::string test con…

前端算法(持续更新)

1、最大的钻石 1楼到n楼的每层电梯口都放着一个钻石&#xff0c;钻石大小不一。你从电梯1楼到n楼&#xff0c;每层楼电梯门都会打开一次&#xff0c;只能拿一次钻石&#xff0c;问怎样才能最大的钻石&#xff1f; 解题思路&#xff1a; 这是一个经典的动态规划问题&#xff…

让人眼前一亮的软件测试简历,收不到面试邀请算我输

不知道大家的简历是不是都写成下面这样 根据需求文档进行需求分析 熟悉业务流程&#xff0c;明确测试点 根据测试点设计测试用例 参与评审测试用例 提交和回归跟踪缺陷&#xff0c;确认修复完成之后关闭Bug 通过使用Fiddler进行抓包分析并定位前后端Bug 使用简单的SQL语…

git一个项目关联多个远程仓库

一行代码就行&#xff1a; git remote set-url origin [想要关联的远程仓库地址]想要关联哪个就切换哪个 或者不用每次切换&#xff0c;集中管理&#xff1a; Git->Manage Remotes 点击“”&#xff0c;填入Name和想要关联的远程库地址 每次push时执行命令 git push [为…

美团OC感想

OC感想 晚上十点拿到美团意向了 到家事业部。&#xff0c;日常实习没过&#xff0c;暑期实习没过&#xff0c;秋招终于意向了&#xff0c;晚上十点发的&#xff0c;整整激动到一点才睡着&#xff0c;不仅因为这是秋招的第一个意向&#xff0c;更因为这是我一直心心念念想去的地…

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录 [web][极客大挑战 2019]Http 考点&#xff1a;Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点&#xff1a;弱密码字典爆破 四种方法&#xff1a; [web][极客大挑战 2019]Http 考点&#xff1a;Referer协议、UA协议、X-Forwarded-For协议 访问…

五款知名国内外OA系统厂商盘点,优缺点一目了然!

本文将推荐五款知名的OA系统&#xff0c;助力企业选型&#xff01; OA 系统就像是企业办公的智慧枢纽。它整合了流程审批、文档管理、沟通协作等多种功能&#xff0c;让企业的日常办公更加高效有序。就好比一个多功能的办公工具箱&#xff0c;为企业提供各种实用的工具。 然而…

研1日记9

1.理解conv1d和conv2d a. 1和2处理的数据不同&#xff0c;1维数据和图像 b. 例如x输入形状为(32,19,512)时&#xff0c;卷积公式是针对512的&#xff0c;而19应该变换为参数中指定的输出通道。 2.“SE块”&#xff08;Squeeze-and-Excitation Block&#xff09;它可以帮助模…

jenkins工具的介绍和gitlab安装

使用方式 替代手动&#xff0c;自动化拉取、集成、构建、测试&#xff1b;是CI/CD持续集成、持续部署主流开发模式中重要工具&#xff1b;必须组件 jenkins-gitlab&#xff0c;代码公共仓库服务器&#xff08;至少6G内存&#xff09;&#xff1b;jenkins-server&#xff0c;需…

无人机视角-道路目标检测数据集 航拍 8600张 voc yolo

数据集名称&#xff1a; 无人机视角-道路目标检测数据集 数据集规模&#xff1a; 图像数量&#xff1a;8600张拍摄方式&#xff1a;航拍&#xff08;使用无人机拍摄&#xff09;标注格式&#xff1a;支持VOC和YOLO格式 数据集内容&#xff1a; 该数据集由无人机从空中拍摄的…

网络安全架构师

网络安全架构师负责构建全面的安全框架&#xff0c;以保护组织的数字资产免受侵害&#xff0c;确保组织在数字化转型的同时维持强大的安全防护。 摩根大通的网络安全运营副总裁兼安全架构总监Lester Nichols强调&#xff0c;成为网络安全架构师对现代企业至关重要&#xff0c;…

源代码防泄密软件的五大特点

在数据防泄密领域&#xff0c;深信达的SDC沙盒软件以其独特的技术和创新应用&#xff0c;为源代码安全提供了强有力的保护。特别是在源代码防泄密方面&#xff0c;SDC沙盒表现出色&#xff0c;其实现方式主要包括以下几个方面&#xff1a; 1. **内核级虚拟沙盒技术**&#xff1…

Vue | Vue深入浅出——Vue中的render函数详解

1.render函数 在编写vue单文件的大多数情况下&#xff0c;我们都是使用template模板来创建HTML。然而在一些条件判断比较复杂的场景下&#xff0c;使用JavaScript去描绘HTML的生成逻辑会显得更加的简洁直观。 使用Vue官网的例子来简单说明&#xff1a; 如果自己在开发的时候…

部署Apache网站

简易部署自己的apache网站 写在前面&#xff1a;先安装好mysql&#xff0c;再来搭建站点 1.安装php [rootlocalhost ~]# yum install php -y ##安装了php&#xff0c;默认会和apache结合工作2.创建文件编写php网页代码 [rootlocalhost ~]# vim /var/www/html/index.php ##创…

linux入门到实操-1 Linux概述、诞生过程、发行版本,如何安装?

教程来源&#xff1a;B站视频BV1WY4y1H7d3 3天搞定Linux&#xff0c;1天搞定Shell&#xff0c;清华学神带你通关_哔哩哔哩_bilibili 整理汇总的课程内容笔记和课程资料&#xff0c;供大家学习交流下载&#xff1a;夸克网盘分享 本文内容为完整笔记的入门篇 概述部分历史内容…

Day9 | Java框架 | SpringBoot

Day9 | Java框架 | SpringBoot SpringBoot简介入门程序概述起步依赖 基础配置配置文件格式&#xff1a;3种yaml语法规则yaml数据读取三种格式 多环境启动配置文件参数命令行参数多环境开发控制&#xff1a;Maven & SpringBoot 多环境兼容 配置文件分类&#xff1a;4种 整合…

【JUC】15-ThreadLocal线程局部变量

1. ThreadLocal ThreadLocal提供线程局部变量。每个线程在访问ThreadLocal实例的时候都有自己的、独立的变量副本。ThreadLocal实例通常是类中的私有静态字段&#xff0c;使用它的目的是希望将状态(用户ID或事务ID)与线程关联起来。 class Saler {ThreadLocal<Integer> …

MATLAB实现Dijkstra算法和Floyd算法

目录 1、文件功能介绍 2、代码执行效果展示 3、Dijkstra算法求图的单源最短路径 4、Dijkstra fullPath的更新逻辑 5、DIjkstra算法流程图 6、Floyd算法实现图的任意两点间最短路径 7、Floyd算法流程图 8、Floyd fullPath的更新逻辑&#xff08;非递归算法&#xff09; …

labview串口大数据量报错的一种解决思路(通过tcp进行写入和读取串口数据)

因为项目要求&#xff0c;用labview给客户开发了一个上位机&#xff0c;在现场给客户调试上位机时&#xff0c;发现了几种奇怪的现象 1&#xff1a;客户样件有两路串口&#xff0c;一路串口可以多字节进行发送数据&#xff0c;一路只能单字节发送数据&#xff0c;每次单字节数据…

Pygame中获取鼠标按键状态的方法

在《Pygame中获取鼠标位置的方法》中提到&#xff0c;可以通过鼠标事件和mouse模块中的函数获取鼠标位置&#xff0c;这两种方法同样适用于获取鼠标按键状态。 1 通过鼠标点击事件获取鼠标按键状态 通过鼠标点击事件获取鼠标按键状态的代码如图1所示。 图1 鼠标点击事件获取鼠…