快速重启Linux
A rapidreboot-tool for Ubuntu based on kexec-tools and python.
https://github.com/lenky0401/rapidreboot
已经捣鼓kdump的时候,整过一个kexec的家伙,主要也就是在旧内核oops时,用它启动一个新内核,从而在新内核里执行dump工作,保存旧内核的oops信息,以便问题排查。
旧内核里直接启动新内核,这可以跳过机器硬件自检,从而节约一些开机时间,因此kexec的新用法就是快速重启Linux,以我当前所用的Ubuntu为例。
首先需要内核打开对应的选项,Ubuntu已经打开了:
lenky@Ubuntu:~$ cat /boot/config-`uname -r` | grep KEXEC
CONFIG_KEXEC=y
CONFIG_KEXEC_JUMP=y
其次,需要应用层工具kexec-tools,默认没有安装,Ubuntu里需要执行如下命令进行安装:
lenky@Ubuntu:~$ sudo apt-get install kexec-tools
有了上面两个支持,做快速重启的步骤就是两步:
1,加载内核:
lenky@Ubuntu:~$ sudo kexec -l /boot/vmlinuz-`uname -r` –initrd=/boot/initrd.img-`uname -r` –append=”`cat /proc/cmdline`”
2,执行重启:
lenky@Ubuntu:~$ sudo kexec -e
当然,如果每次快速重启都需要自己去敲上面这两个命令,未免太麻烦了点。不过别当心,kexec工具包已经替我们做了相关工作,只要我们打开对应的选项,那么在进行任意普通的重启操作(不管是命令行执行reboot或是gnome界面里点击重启按钮)时,实际执行的都是快速重启。
这个选项就是配置文件/etc/default/kexec里的“LOAD_KEXEC=true”:
lenky@Ubuntu:~$ cat /etc/default/kexec # Defaults for kexec initscript # sourced by /etc/init.d/kexec and /etc/init.d/kexec-load # Load a kexec kernel (true/false) LOAD_KEXEC=true # Kernel and initrd image KERNEL_IMAGE="/vmlinuz" INITRD="/initrd.img" # If empty, use current /proc/cmdline APPEND="" # Load the default kernel from grub config (true/false) USE_GRUB_CONFIG=false
快速重启也有个麻烦点,那就是你点重启无法经过grub了,那么也就无法选择进入其他操作系统(如果你有装的话)了,你可以将其改为“LOAD_KEXEC=false”来进行关闭。
下面解释一下LOAD_KEXEC选项是如何作用的。这涉及到另外两个脚本:
lenky@Ubuntu:~$ ls /etc/rc6.d/*kexec* -l lrwxrwxrwx 1 root root 20 9月 24 17:13 /etc/rc6.d/K18kexec-load -> ../init.d/kexec-load lrwxrwxrwx 1 root root 15 9月 24 17:13 /etc/rc6.d/S85kexec -> ../init.d/kexec lenky@Ubuntu:~$ cat /etc/rc6.d/K18kexec-load #! /bin/sh ### BEGIN INIT INFO # Provides: kexec-load # Required-Start: # Required-Stop: $local_fs $remote_fs kexec # Should-Stop: autofs # Default-Start: # Default-Stop: 6 # Short-Description: Load kernel image with kexec # Description: ### END INIT INFO PATH=/sbin:/bin:/usr/sbin:/usr/bin NOKEXECFILE=/tmp/no-kexec-reboot . /lib/lsb/init-functions test -r /etc/default/kexec && . /etc/default/kexec process_grub_entry() { initrd_image= while read command args; do if [ "$command" = "linux" ]; then echo "$args" | while read kernel append; do echo KERNEL_IMAGE=\"${kernel}\" echo APPEND=\"${append}\" done elif [ "$command" = "initrd" ]; then initrd_image=${args} fi done echo INITRD=\"$initrd_image\" } get_grub_kernel() { test -f /boot/grub/grub.cfg || return data=$(cat /boot/grub/grub.cfg) default=$(echo "$data" | awk '/^set default/ {print $2}' | cut -d'"' -f2) if [ -z "$default" ]; then default=0 fi start_offset=$((default + 1)) end_offset=$((default + 2)) # grub entries start with "menuentry" commands. Get the line # numbers that surround the first entry offsets=$(echo "$data" | grep -n ^menuentry | cut -d: -f1) begin=$(echo "$offsets" | tail -n+$start_offset | head -n1) end=$(echo "$offsets" | tail -n+$end_offset | head -n1) # If this is the last entry, we need to read to the end of the file # or to the end of boot entry section if [ -z "$end" ]; then numlines=$(echo "$data" | tail --lines=+$begin | grep -n "^### END" | head -1 | cut -d: -f1) end=$((begin + numlines - 1)) fi length=$((end - begin)) entry=$(echo "$data" | tail -n+$begin | head -n$length) eval $(echo "$entry" | process_grub_entry) } do_stop () { test "$LOAD_KEXEC" = "true" || exit 0 test -x /sbin/kexec || exit 0 test "x`cat /sys/kernel/kexec_loaded`y" = "x1y" && exit 0 if [ -f $NOKEXECFILE ] then /bin/rm -f $NOKEXECFILE exit 0 fi test "$USE_GRUB_CONFIG" = "true" && get_grub_kernel REAL_APPEND="$APPEND" test -z "$REAL_APPEND" && REAL_APPEND="`cat /proc/cmdline`" log_action_begin_msg "Loading new kernel image into memory" if [ -z "$INITRD" ] then kexec -l "$KERNEL_IMAGE" --append="$REAL_APPEND" else kexec -l "$KERNEL_IMAGE" --initrd="$INITRD" --append="$REAL_APPEND" fi log_action_end_msg $? } case "$1" in start) # No-op ;; restart|reload|force-reload) echo "Error: argument '$1' not supported" >&2 exit 3 ;; stop) do_stop ;; *) echo "Usage: $0 start|stop" >&2 exit 3 ;; esac exit 0 lenky@Ubuntu:~$ cat /etc/rc6.d/S85kexec #! /bin/sh ### BEGIN INIT INFO # Provides: kexec # Required-Start: # Required-Stop: reboot # X-Stop-After: umountroot # Default-Start: # Default-Stop: 6 # Short-Description: Execute the kexec -e command to reboot system # Description: ### END INIT INFO PATH=/sbin:/bin . /lib/lsb/init-functions test -r /etc/default/kexec && . /etc/default/kexec do_stop () { test "x`cat /sys/kernel/kexec_loaded`y" = "x1y" || exit 0 test -x /sbin/kexec || exit 0 log_action_msg "Will now restart with kexec" kexec -e log_failure_msg "kexec failed" } case "$1" in start) # No-op ;; restart|reload|force-reload) echo "Error: argument '$1' not supported" >&2 exit 3 ;; stop) do_stop ;; *) echo "Usage: $0 start|stop" >&2 exit 3 ;; esac exit 0
在进行runlevel切换时,Linux就会自动执行对应的脚本,对于runlevel 6有一点特殊,它的K开头或S开头的脚本都会带上stop参数。在脚本K18kexec-load里,选项LOAD_KEXEC用来控制是否要加载新内核,为true则加载,否则直接exit退出。在脚本S85kexec里,通过读取/sys/kernel/kexec_loaded判断是否已经加载新内核,如果加载了则启动新内核,进行快速重启,否则走原有重启流程。这样,最终的结果就是:LOAD_KEXEC选项控制了是否启动快速重启。
转载请保留地址:http://lenky.info/archives/2013/10/07/2351 或 http://lenky.info/?p=2351
备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。
法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以或书面等方式告知,本站将及时删除相关内容或链接。