首页 > *nix应用编程, *nix技术, UbuntuKylin > 快速重启Linux

快速重启Linux

2013年10月7日 发表评论 阅读评论 153 次浏览

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/2351http://lenky.info/?p=2351


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以或书面等方式告知,本站将及时删除相关内容或链接。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.