不过通常一个reactor只有一个thread,在spdk应用中,更多的是注册多个poller而不是注册多个thread。 Io_device 和 io_channel在thread中也是非常重要的概念。它们的实现都在thread.c中,io_device是设备的抽象,io_channel是对该设备通道的抽象。一个线程可以创建多个io_channel . io_channel只能和一个io_device绑定,并...
再结合代码分析,rbd模块加载时会将创建io_channel的接口bdev_rbd_create_cb向外注册,rbd bdev在创建rbd bdev时默认做bdev_examine,这个流程会创建一次io_channel,然后销毁。在将rbd bdev attach到nvmf subsystem时,会调用创建io_channel接口,因为nvmf_tgt有8个线程,所以会调用8次创建io_channel接口,但disk->main_t...
spdk_io_channel_destroy_cb destroy_cb; // io_channel销毁的回调函数 }; 虽然io_channel看起来是很简单的结构体,实际上在创建一个io_device的时候,会要求使用者传入一个io_channel_ctx的大小作为调用的参数,而在给io_channel分配内存的时候,除了分配本身io_channel结构体的大小外,还会额外分配一个io_channel_c...
在今天的代码中,任何指针都是指针,其唯一性仅基于其内存地址,并且spdk_io_channel是与特定spdk_io_device. 线程抽象提供了一些函数,用于将消息发送到任何其他线程,逐个向所有线程发送消息,以及将消息发送到给定io_device存在io_channel的所有线程。 最关键的是,线程抽象实际上并没有生成任何自己的系统...
vhost线程在操作相同NVMe控制器下的namespace时,不同的vhost线程会申请不同的IO Channel(实际对应NVMe Queue Pair,作用类似虚拟机IO环),并且每个线程都会轮循各自申请的IO Channel中的响应消息。例如图中reactor_0会向NVMe控制器申请QueuePair1,并在轮循过程中注册对该QueuePair的poller函数(负责从中取响应);reactor...
具体的I/O读和写的信息都会在这个数据结构中被保存,以及涉及的Buffer、Bdev Channel等相关资源,后期需要结合高级的存储特性像逻辑卷、流量控制等都需要在I/O数据结构这里有相关的标识符和额外的属性。具体可以参考SPDK源码中的struct spdk_bdev_io结构体。
其他如数据读写的API,其第一个参数都是打开设备API返回的指针,第二个参数是一个IO通路(channel),IO通路与硬件的队列相对应,第三到第五个参数则是数据缓冲区、访问的位置和数据的长度,这几个参数跟Linux的read和write函数很像。最后两个参数是回调函数及其参数,这个参数与SPDK异步处理相关。
(4)数据路径的无锁化机制:在I/O路径上采用io_channel技术,避免采用锁机制,能降低时延和提升性能。 对于类似NVMe的多队列设备,SPDK提供一个I/O channel的概念 (即thread和device的一个mapping关系),封装在SPDK_vhost_blk_session结构中。不同的thread 操作同一个device应该拥有不同的I/O channel,每个I/O channel...
_io_channel {3structspdk_thread *thread;//绑定的线程4structio_device *dev;//绑定的io_device5uint32_tref;//io_channel引用计数6uint32_t destroy_ref;//destroy前被引用的次数7TAILQ_ENTRY(spdk_io_channel) tailq;//io_channel 队列头8spdk_io_channel_destroy_cb destroy_cb;//io_channel销毁的...
在lib/thread.c和include/spdk/thread.h中:spdk_thread和spdk_poller,spdk_io_device和spdk_io_channel定义如下: structspdk_thread{ // Tail queue declarations. 队列头 TAILQ_HEAD(, spdk_io_channel) io_channels; //描述前一个和下一个元素的结构体 ...