spdk的信号处理流程

SPDK可以正常响应操作系统的下电流程以及Ctrl+c命令,意味着它可以正确处理 信号.
由于SPDK内部有元数据需要刷到盘上保存,因此正常的处理信号非常重要,关系到下次启动后是否能够正常恢复元数据.
此处的元数据主要指的是Blobstore下盘保存的部分,包括Superblobk部分,以及用于下次恢复的几个位图.
SPDK可以通过spdk-kill-instance RPC命令正常的退出进程.
spdk-kill-instance
这个RPC的核心处理,其实就是对spdk自己的进程 发送一个指定的信号.

root@e610-c:/home/brandon/spdk-dev# ./scripts/rpc.py -s 1.1.1.4 -p 5000 spdk_kill_instance --help
usage: rpc.py [options] spdk_kill_instance [-h] sig_name

positional arguments:
  sig_name    signal will be sent to server.

options:
  -h, --help  show this help message and exit

支持的sig_name包括:
	        {"SIGINT",	SIGINT},
		{"SIGTERM",	SIGTERM},
		{"SIGQUIT",	SIGQUIT},
		{"SIGHUP",	SIGHUP},
		{"SIGKILL",	SIGKILL},
		{"SIGUSR1",	SIGUSR1},

其中SIGKILL类似于shell命令 kill - 9 回直接导致进程退出而不会做任何处理.
常见的SIGTERM或者SIGQUIT,会触发spdk走正常的进程退出流程.
1,信号的注册
注册的位置在:
图片.png
其中spdk_app_start是每个spdk应用必然要调用的接口,不管是spdk_tgt还是支持nvmf协议的nvmf_tgt.
spdk_app_start实际运行在appthread上,即0号线程上. 当给进程发送sig的时候,由0号线程捕捉到并进__shutdown_signal处理函数.
2,信号的处理
图片.png
1,从spdk_subsystem_fini开始,处理完之后处理下一个子系统spdk_subsystem_fini_next.
2,每个子系统的都带回调函数进去,最后处理spdk_reactors_stop
3,子系统是个纯内存结构,根据加载的子系统进行反向的处理.
以bdev子系统为例:
1,首先找到子系统的fini接口是否注册,如果注册就调用.

subsystem_fini_next():
        while (g_next_subsystem) {
		if (g_next_subsystem->fini) {
			g_next_subsystem->fini();
			return;
		}
		g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
	}

注册子系统的ini,一般通过这个结构注册,以bdev为例:

bdev.c:
static struct spdk_subsystem g_spdk_subsystem_bdev = {
	.name = "bdev",
	.init = bdev_subsystem_initialize,
	.fini = bdev_subsystem_finish,
	.write_config_json = bdev_subsystem_config_json,
};


其注册的就是bdev_subsystem_finish函数,其他的子系统由iSCSI,NBD,accel,sock等等.
4,bdev的退出流程:
图片.png
bdev分为2种,一种是必须以其他bdev作为basebdev的设备(如lvol,raid, ocf),一种是直接可以创建操作的bdev(nvme bdev,malloc bdev,null设备等 )
所有的bev都会注册 module_fini 接口,进行该bdev的unregister操作,如果内部有依赖,需要内部处理,比如LVS上如果有lvol,需要先将lvol的bdev unregister之后,再unregiser LVS,这个流程在LVS内部保证.
以lvs(lvolstor为例):由于lvolstore是必须依赖其他bdev的设备,所以他会注册:

.fini_start = vbdev_lvs_fini_start,
static struct spdk_bdev_module g_lvol_if = {
	.name = "lvol",
	.module_init = vbdev_lvs_init,
	.fini_start = vbdev_lvs_fini_start,
	.async_fini_start = true,
	.examine_disk = vbdev_lvs_examine,
	.get_ctx_size = vbdev_lvs_get_ctx_size,

};

5, lvs的退出流程
图片.png
总的来说,就是将每个lvs的内存位图都刷到盘上,保证下次上电直接取位图就可以恢复,不用全盘扫描恢复.
lvs流程走完之后,会寻找下一个subsystem的处理.直到所有subsystem处理完.

欢迎电邮leipang09@gmail.com讨论

# SPDK  信号 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×