01
简介
02
SPDK BDEV模型
2.1 g_bdev_mgr
buf_small_pool: 小于8k数据的全局数据缓冲池,当数据大小小于8k时,会从该缓存池中获取buf,默认池大小为8191; buf_large_pool: 小于64k数据的全局数据缓冲池,当数据大小小于64k时,会从该缓冲池获取buf,默认池大小为1023; zero_buffer: 使用该缓冲区对设备进行填充补零操作; bdev_modules: 保存bdev模块的链式结构,如下图,是SPDK目前支持的模块;
bdevs: 保存bdev的链式结构,包含子系统所有的块设备;
bdev_names: 保存bdev名称的红黑树结构,方便使用名称对bdev快速检索;
2.2 spdk_bdev_mgmt_channel
per_thread_cache: 每个thread对接一个io_device只有唯一的io_channel,对应到该结构,代表了每个thread具有自己本地独立的spdk_bdev_io缓存池,初始化时会从全局结构bdev_io_pool中获取默认256个缓存单元;当进行IO时,会先该本地缓存池中获取,为空时,再从全局缓存池中获取;
need_buf_small: 将等待small buf的io进行排队等候;
need_buf_large: 将等待large buf的io进行排队等候;
shared_resources: 如果bdev使用了相同的后端设备,会使用同一个shared_resource,不同的后端设备对应不同shared_resource;
io_wait_queue: 将等待io元数据得io进行排队等候;
2.3 bdev子系统结构
如上图,bdev子系统会注册三类io设备:
g_bdev_mgr设备包括了bdev子系统全局的缓存池资源,对应得io_channel(spdk_bdev_mgmt_channel)会对thread局部资源进行管理。
SPDK中得每个bdev都会注册成io设备。
另外还有部分io设备会在模块中注册,对应io_channel会保存实际设备操作结构信息,对设备进行真正得IO。
03
自定义模块
3.1 模块接口
struct spdk_bdev_module {
const char *name;
bool async_init;
bool async_fini;
bool async_fini_start;
int (*module_init)(void);
void (*init_complete)(void);
void (*fini_start)(void);
void (*module_fini)(void);
int (*config_json)(struct spdk_json_write_ctx *w);
int (*get_ctx_size)(void);
void (*examine_config)(struct spdk_bdev *bdev);
void (*examine_disk)(struct spdk_bdev *bdev);
}
复制
name: 模块名称;
async_init: 标记模块得初始化过程是否是异步的;
async_fini: 标记模块卸载过程是否是异步的;
async_fini_start: 标记模块开始卸载的过程是否是异步的;
module_init: 模块初始化方法,必须实现;
init_complete: bdev子系统初始化完成后的模块回调方法;
fini_start: 模块开始反注册的回调方法;
config_json: 用于获取模块的配置信息;
get_ctx_size:获取模块上下文元数据的大小;
examine_config:当使用配置文件启动系统服务时,可能添加了一些vbdev(虚拟bdev),当bdev注册时,需要该回调检查该bdev是否被vbdev依赖,存在依赖时需要自动创建vbdev;
examine_disk:当bdev注册时,需要回调该方法检查bdev是否包含vbdev的元数据,存在则需要自动创建vbdev;
3.2 底层bdev(模块)接口
struct spdk_bdev_fn_table {
int (*destruct)(void *ctx);
void (*submit_request)(struct spdk_io_channel *ch, struct spdk_bdev_io *);
bool (*io_type_supported)(void *ctx, enum spdk_bdev_io_type);
struct spdk_io_channel *(*get_io_channel)(void *ctx);
int (*dump_info_json)(void *ctx, struct spdk_json_write_ctx *w);
void (*write_config_json)(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w);
uint64_t (*get_spin_time)(struct spdk_io_channel *ch);
void *(*get_module_ctx)(void *ctx);
int (*get_memory_domains)(void *ctx, struct spdk_memory_domain **domains, int array_size);
}
复制
destruct: bdev设备关闭回调;
submit_request: 向后端设备提交IO请求的方法;
io_type_supported: 查看底层bdev支持的方法;
get_io_channel:获取底层模块的io_channel;
dump_info_json:获取驱动的json信息;
write_config_json:获取bdev的json信息;
get_spin_time:获取io_channel的统计信息,供vtune工具调试使用;
get_memory_domains:提供给上层vbdev获取底层设备所使用的内存域;
04
io流程
a.从线程的本地缓存池获取IO结构;
b.本地缓存不足时会从全局缓存池获取IO结构;
c.对于某些IO,需要使用新的数据缓冲区时,按数据的大小从全局结构的small_pool和large_pool获取buffer,放入IO结构中;
d.从shared_resource中获取底层bdev的io_channel;
e.调用底层bdev的submit_request方法下发IO;
05
总结
06
参考文档
SPDK 应用编程框架
SPDK block device 及其编程的简单介绍