PID Namespace 内の reboot システムコール
lxc-devel ML をなんとなく眺めていたら "On any recent kernel, reboot syscall from inside a non-init pid-ns will not reboot the host." なんて書いてありました.ほほぅ.
というわけで調べてみると kernel/sys.c にありました.
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg) { struct pid_namespace *pid_ns = task_active_pid_ns(current); char buffer[256]; int ret = 0; /* We only trust the superuser with rebooting the system. */ if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT)) return -EPERM; /* For safety, we require "magic" arguments. */ if (magic1 != LINUX_REBOOT_MAGIC1 || (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && magic2 != LINUX_REBOOT_MAGIC2B && magic2 != LINUX_REBOOT_MAGIC2C)) return -EINVAL; /* * If pid namespaces are enabled and the current task is in a child * pid_namespace, the command is handled by reboot_pid_ns() which will * call do_exit(). */ ret = reboot_pid_ns(pid_ns, cmd); /* ←ここ!! */ if (ret) return ret; /* Instead of trying to make the power_off code look like * halt when pm_power_off is not set do it the easy way. */ if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) cmd = LINUX_REBOOT_CMD_HALT; mutex_lock(&reboot_mutex); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: kernel_restart(NULL); break; : (略)
reboot_pid_ns って関数がキモですね.pid_ns 内にいる時は,この関数内で然るべき処理をやって,このシステムコールはここで終わり,そうでないなら,普通に reboot の処理へ,ということでしょうね.
reboot_pid_ns() はというと,kernel/pid_namespace.c 内にあって,こんな感じ.
int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd) { if (pid_ns == &init_pid_ns) /* ←親環境 (システムの init) の PID 名前空間だったらココでは何もしない */ return 0; switch (cmd) { case LINUX_REBOOT_CMD_RESTART2: case LINUX_REBOOT_CMD_RESTART: pid_ns->reboot = SIGHUP; break; case LINUX_REBOOT_CMD_POWER_OFF: case LINUX_REBOOT_CMD_HALT: pid_ns->reboot = SIGINT; break; default: return -EINVAL; } read_lock(&tasklist_lock); force_sig(SIGKILL, pid_ns->child_reaper); read_unlock(&tasklist_lock); do_exit(0); /* Not reached */ return 0; }
今,init_pid_ns の PID 名前空間 (つまりシステムの init と同じ PID 名前空間) にいれば,この関数は何もせずに return 0 しますね.それ以外の PID 名前空間に入れば,pid_ns->reboot にシグナルを設定して,force_sig で,多分今の名前空間のプロセスたちに SIGKILL を送るのでしょうね.
このコミット] で入ったようですね.Linux 3.4 以降のようです.
へー :-D