目录表
Hotplug原理
Hotplug即热插拔,在新版本OpenWRT
上,hotplug
,coldplug
与watchdog
等被集成到全新的Procd系统中。
Procd是OpenWRT
下新的预初始化,初始化,热插拔和事件系统。在openwrt
中, procd
作为 init
进程会处理许多事情, 其中就包括 hotplug
。procd
本身并不知道如何处理hotplug
事件,也没有必要知道,因为它只实现机制,而不实现策略。事件的处理是由配置文件决定的,这些配置文件即所谓的rules
.。老版本下独立的hotplug2
在r36987
被移除了。所以下面我们要介绍的就是新版本下Hotplug
的机制。
要了解Hotplug
运行的整个过程,首先得了解procd
系统的工作流程。才能从全局了解hotplug
是如何工作的。在这里我们重点介绍与hotplug
相关的procd
启动过程。
Procd启动过程分析
preinit()函数
void
preinit(void)
{
char *init[] = { "/bin/sh", "/etc/preinit", NULL };
char *plug[] = { "/sbin/procd", "-h", "/etc/hotplug-preinit.json", NULL };
LOG("- preinit -\n");
plugd_proc.cb = plugd_proc_cb;
plugd_proc.pid = fork();
if (!plugd_proc.pid) {
execvp(plug[0], plug);
ERROR("Failed to start plugd\n");
exit(-1);
}
if (plugd_proc.pid <= 0) {
ERROR("Failed to start new plugd instance\n");
return;
}
uloop_process_add(&plugd_proc);
setenv("PREINIT", "1", 1);
preinit_proc.cb = spawn_procd;
preinit_proc.pid = fork();
if (!preinit_proc.pid) {
execvp(init[0], init);
ERROR("Failed to start preinit\n");
exit(-1);
}
if (preinit_proc.pid <= 0) {
ERROR("Failed to start new preinit instance\n");
return;
}
uloop_process_add(&preinit_proc);
DEBUG(4, "Launched preinit instance, pid=%d\n", (int) preinit_proc.pid);
}
-
创建子进程执行
/etc/preinit
脚本,此时PREINI
T环境变量被设置为1,主进程同时使用uloop_process_add()
把/etc/preinit
子进程加入uloop
进行监控,当/etc/preinit
执行结束时回调plugd_proc_cb()
函数把监控/etc/preinit
进程对应对象中pid
属性设置为0,表示/etc/preinit
已执行完成。 -
创建子进程执行
/sbin/procd -h /etc/hotplug-preinit.json
,主进程同时使用uloop_process_add()
把/sbin/procd
子进程加入uloop
进行监控,当/sbin/procd
进程结束时回调spawn_procd()
函数。 -
spawn_procd()
函数繁衍后继真正使用的/sbin/procd
进程,从/tmp/debuglevel
读出debug
级别并设置到环境变量DBGLVL
中,把watchdog fd
设置到环境变量WDTFD
中,最后调用execvp()
繁衍/sbin/procd
进程。
procd进程
在这里我们主要分析procd
的五个状态,分别为 STATE_EARLY
、STATE_INIT
、STATE_RUNNING
、STATE_SHUTDOWN
、STATE_HALT
,这5个状态将按顺序变化,当前状态保存在全局变量state
中,可通过procd_state_next()
函数使用状态发生变化。
static void state_enter(void)
{
char ubus_cmd[] = "/sbin/ubusd";
switch (state) {
case STATE_EARLY:
LOG("- early -\n");
watchdog_init(0);
hotplug("/etc/hotplug.json");
procd_coldplug();
break;
case STATE_INIT:
// try to reopen incase the wdt was not available before coldplug
watchdog_init(0);
LOG("- ubus -\n");
procd_connect_ubus();
LOG("- init -\n");
service_init();
service_start_early("ubus", ubus_cmd);
procd_inittab();
procd_inittab_run("respawn");
procd_inittab_run("askconsole");
procd_inittab_run("askfirst");
procd_inittab_run("sysinit");
break;
case STATE_RUNNING:
LOG("- init complete -\n");
break;
case STATE_SHUTDOWN:
LOG("- shutdown -\n");
procd_inittab_run("shutdown");
sync();
break;
case STATE_HALT:
LOG("- reboot -\n");
reboot(reboot_event);
bre