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

news2024/11/25 16:00:31

已经对相关的基础概念有一定的了解,比如裸盘,文件系统,读写相关裸盘,裸盘挂载使用,内核插入文件系统的方式,相关操作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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2124982.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

张驰咨询:打造精益生产高手的摇篮,企业竞争力倍增器!

精益生产培训机构在推动企业转型升级、提升竞争力方面发挥着不可替代的作用。它们通过系统化的培训&#xff0c;将精益生产的核心理念、工具和方法传授给企业及其员工&#xff0c;助力企业实现生产效率的飞跃、成本的有效控制以及产品质量的显著提升。 一、精益生产培训机构的作…

一文搞懂Maven的使用:下载、配置、阿里云私服、IDEA配置

Maven是什么&#xff1f; Maven是一个项目管理工具&#xff0c;其核心是一个项目对象模型&#xff08;POM&#xff1a;Project Object Model&#xff09;&#xff0c;通过这个模型可以管理项目的构建、报告和文档。Maven还包含了一套标准的集合、项目生命周期、依赖管理系统以…

代码随想录算法训练营第27天|455. 分发饼干、376. 摆动序列、53. 最大子数组和

目录 455. 分发饼干&#xff08;总出问题&#xff0c;需要多次写&#xff09;1、题目描述2、思路3、code4、复杂度分析5、超级无敌一句话总结 376. 摆动序列1、题目描述2、思路4、复杂度分析 53. 最大子数组和1、题目描述2、思路3、code4、复杂度分析 455. 分发饼干&#xff08…

无人机之伯努利定律

无人机的伯努利定律是解释无人机飞行原理的关键理论之一&#xff0c;它主要阐述了流体&#xff08;如空气&#xff09;在流动过程中速度与压力之间的关系。以下是对无人机伯努利定律的详细解释&#xff1a; 一、伯努利定律的基本原理 伯努利定律是流体力学中的一个基本原理&am…

初识时序数据库InfluxDB

最近项目开发中,需要记录时间序列的日志信息,InfluxDB 刚好契合。于是准备研究一下,发现已经有整理很好的文档,以下两篇觉得很好,入门开发可以参考一下。 因为项目是用C#开发的,因此,简单介绍一下C#开发中,InfluxDB的API使用。 1.简介 InfluxDB是一个由InfluxData开发…

18、Gemini-Pentest-v1

难度 中 &#xff08;个人认为是高&#xff09; 目标 root权限 一个flag 靶机启动环境为VMware kali 192.168.152.56 靶机 192.168.152.64 信息收集 突破点大概就是web端了 web测试 访问主页直接就是目录遍历 不过进去后是一个正常的网页 简单的试了几个弱口令无果继续信息…

什么是HTTPS协议?

HTTPS协议&#xff08;Hypertext Transfer Protocol Secure&#xff09;即安全超文本传输协议&#xff0c;是互联网上进行安全通信的一种重要协议。它是在HTTP&#xff08;Hypertext Transfer Protocol&#xff09;协议的基础上增加了安全性的要求&#xff0c;通过SSL&#xff…

ffmpeg面向对象-rtsp拉流相关对象

目录 1.AVFormatContext类。1.1 概述1.2 构造函数1.3 oopc的继承实现 2. AVInputFormat 类。2.1 多态的实现 3.所用设计模式3.1模板模式3.2 工厂模式&#xff1f; 3.3 rtsp拉流建链 4.this指针5.小结6.rtsp拉流流程 1.AVFormatContext类。 1.1 概述 用户看到的是AVFormatCont…

精益管理|Toyota Kata 是什么意思?

丰田套路是一种培养持续改进习惯的系统方法&#xff0c;也是精益管理&#xff08;CLMP&#xff09;中的一套方法。“Toyota Kata”一词来自精益专家 Mike Rother 的管理书籍《Toyota Kata&#xff1a;Managing People for Improvement, Adaptiveness, and Superior Results》。…

2024/9/11 小型PLC典型应用2:伺服canlink配置、指令、应用

下面这个指令需要设置伺服的急停方式&#xff08;例如&#xff1a;惯性停机、急停等等&#xff09; 通讯故障步骤排查 1&#xff1a;接线问题 2&#xff1a;配置问题&#xff08;波特率.....&#xff09;

安卓13允许app启动服务 android13允许应用启动服务 无法启动服务 Background start not allowed: service

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.编译6.彩蛋1.前言 android13应用启动服务,有些应用会被禁止启动服务,开启的服务会失败,这是高版本的android的特性,我们需要更改下frameworks的代码。 2.问题分析 查看下logcat信息 B…

百元榜哪个牌子的蓝牙耳机最好用?四大闭眼入高性价比耳机推荐!

蓝牙耳机的普及率在近年来越来越高&#xff0c;行业发展十分迅猛&#xff01;在很多好的品牌涌现的同时&#xff0c;也有很多的品牌质量不过关&#xff0c;货不对版&#xff0c;使得很多的人以为&#xff0c;百元的就没有好用蓝牙耳机&#xff0c;不少小伙伴在选择蓝牙耳机的时…

N-152基于java贪吃蛇游戏5

开发工具eclipse,jdk1.8 文档截图&#xff1a; N-152基于java贪吃蛇游戏5

抽象工厂模式abstract factory

此篇为学习笔记&#xff0c;原文链接 https://refactoringguru.cn/design-patterns/abstract-factory 它能创建一系列相关的对象&#xff0c; 而无需指定其具体类。抽象工厂提供了一个接口&#xff0c; 可用于创建每个系列产品的对象。 优点 你可以确保同一工厂生成的产品相…

2024/9/10黑马头条跟学笔记(六)

D6 1.今日学习内容 1.1需求分析 点击下架之后&#xff0c;app端显示以下架 耦合&#xff0c;没技术点&#xff0c;不用&#xff0c;咱用kafka&#xff0c;流量削峰&#xff0c;异步调用&#xff0c;解耦 为什么要学&#xff1f; 面时提问 2.kafka概述 rabbitMQ&#xff0c;…

C#基础:字段的初始化,特性,类的继承和多态基础demo

目录 一、字段 1.认识字段和属性 2.初始化字段 二、特性 1.特性的基础 2.特性的自定义和使用 三、继承 1.多继承 2.重写父类和增加子类方法 四、多态 一、字段 1.认识字段和属性 public class Test { public int field //我是字段public int property { get; set; …

建议AI大模型小白必看的学习教程!!

逼自己两周刷完 AI大模型(白嫖) LLM大模型自用资料&#xff0c;以及学习路线整理 整理了我入门大模型的学习路线和自用资料&#xff0c;在全民LLM时期&#xff0c;多输入一些就多一重安全感。建议先对LLM全貌有了解&#xff0c;然后自顶向下去学习。前置知识是nlp基础如transf…

Vue3.5正式上线,有哪些新特性和用法?

9月1日&#xff0c; Vue 3.5 正式发布了&#xff01; 此次要版本不包含重大更改&#xff0c;并且包括内部改进和有用的新功能。我们将在这篇博文中介绍一些亮点 - 有关更改和新功能的完整列表&#xff0c;请参阅 GitHub 上的完整更新日志。 1. Props 解构 在vue3.5 之前&#…

C语言14--作用域与存储期

作用域基本概念 C语言中&#xff0c;标识符都有一定的可见范围&#xff0c;这些可见范围保证了标识符只能在一个有限的区域内使用&#xff0c;这个可见范围&#xff0c;被称为作用域&#xff08;scope&#xff09;。 软件开发中&#xff0c;尽量缩小标识符的作用域是一项基本原…

细致刨析JDBC ③ 高级篇

目录 一、JDBC优化及工具类封装 1.现有问题 2.JDBC工具类封装V1.0 3.ThreadLocal 4.JDBC工具类封装V2.0 二、DAO封装及BaseDAO工具类 1.BaseDAO概念 2.BaseDao层代码实现 ① BaseDao层——通用的修改方法 ② 通用的查询方法 ③ 单行查询方法优化 三、事务 1、事务回顾 2.JDBC中…