<!-- Related_Searches_Area_And_Overlays_Begin --><!-- MAIN_COLUMN_CONTAINER_BEGIN -->
<!-- MAIN_COLUMN_CONTENT_BEGIN -->
随着计算机系统变得更快更好,系统重新启动时间也需要跟上发展。实际上,随着系统的处理器速度、存储容量和资源性能变得更加先进和复杂,重新启动的时间竟变长了。虽然更长的重新启动时间对每个人来说只是一种刺激,但它对生产系统的影响是至关重要的,因为更长的重新启动时间意味着正常运行时间的减少。除了影响系统对其用户的可用性之外,更长的重新启动时间对内核和系统软件开发者来说是一个主要的瓶颈,因为他们每天都要多次重新启动他们的机器。
当系统有很多松散分布的 SCSI 总线或者 ECC 校验的物理内存时,重新启动时间特别长。测试结果显示,重新启动过程中大部分时间消耗在固件(firmware)阶段,在此阶段,连接到系统的设备被识别出来并被初始化(要深入了解,请查看本文的 参考资料部分)。自然,大部分试图减少重新启动时间的努力都瞄准重新启动过程的这个阶段。其中一项努力带来了 kexec 的发展,kexec 是一个可用于 x86 平台上 Linux 内核的功能部件。使用 kexec,您可以直接重新启动到另一个内核,不再必须通过固件和引导装载程序阶段。跳过序列中最长的部分大大减少了重新启动时间。
Linux 中的引导概述
要理解 kexec,需要先具备 Linux 中引导过程的知识。Linux 中的引导过程有两个阶段:引导装载程序阶段和内核阶段。
引导装载程序阶段主要包括硬件阶段、固件阶段、第一级引导装载程序和第二级引导装载程序。引导过程从硬件加电启动开始。一些初始化工作完成后,控制转到固件。固件在一些体系结构中也称为“BIOS”,它去检测系统上的各种设备,包括内存控制器、存储设备、总线桥和其他硬件。固件基于设置将控制移交给一个最小化的引导装载程序,即大家所知的主引导记录(master boot record),这个主引导记录可能在磁盘驱动器上,或者在可移动媒体上,或者在网络上。将控制移交给操作系统的实际工作由第二阶段引导装载程序(通常被简单地认为是“引导装载器(boot loader)” )执行。这个引导装载程序让用户可以选择要装载的内核,将内核和相关参数装载到内存,初始化内核,设置需要的环境变量,并最终“运行”内核。
引导的下一个阶段是 内核阶段,此时内核已经获得控制权。它设置需要的数据结构,检测当前在系统上的设备,装载需要的设备驱动程序,并初始化设备。引导过程的最后阶段包括用户级初始化。在这个阶段,内核检查文件系统的完整性,挂载文件系统,设置交换分区(或者交换文件),启动系统服务,设置系统终端,并完成所有其他设置。
在系统重新启动时,引导装载阶段之前要先关闭先前正在运行的系统。这涉及到停止运行的进程,将高速缓冲存储器内容写回到磁盘,?载文件系统,然后执行硬件的重启。在本文的 参考资料部分,您可以找到对 Linux 中引导过程以及常见的引导相关概念的极好的描述。
回页首
kexec 概述
kexec 是 Linux 内核的一个补丁,让您可以从当前正在运行的内核直接引导到一个新内核。在上面描述的引导序列中,kexec 跳过了整个引导装载程序阶段(第一部分)并直接跳转到我们希望引导到的内核。不再有硬件的重启,不再有固件操作,不再涉及引导装载程序。完全避开了引导序列中最弱的一环 -- 固件。这一功能部件带来的最大益处在于,系统现在可以极其快速地重新启动。对企业级系统而言,kexec 大大减少了重新启动引起的系统宕机时间。对内核和系统软件开发者而言,kexec 帮助您在开发和测试成果时可以迅速重新启动系统,而不必每次都要再经历耗时的固件阶段。
kexec 补丁是 Eric Biederman 的作品,这个项目仍处在积极的开发之中(查看 参考资料部分以深入了解此项目以及如何对它做出贡献)。
显然,由于这个功能部件涉及到操作系统如此多的敏感部分,需要特别细心以使其始终正确工作。对 kexec 来说,最大的挑战在于,在 Linux 中,要重新引导到的新内核需要位于内存中与当前正在运行的内核相同的位置。仍然在当前内核的上下文中运行时,用新内核去替换内存中现有的内核,这是件困难的工作。另一个大问题是,系统中设备的状态。固件总是将设备初始化(或重启)到已知的“sane”状态。kexec 绕过固件阶段的事实,意味着设备的状态是不可靠的。
本文接下来的几节将向您展示如何征服这些挑战,并展示如何实现到新内核的直接引导。注意,当前 kexec 只能用于 x86 32 位平台。尽管将 kexec 移植到其他平台的工作正在进行,但是还没有可以用的代码版本。因此,后面几节中的所有技术细节都只特定于 x86 平台。
回页首
使用 kexec
Kexec 有两个组件。第一个是用户空间组件,叫做“kexec-tools”。第二个是真正的内核补丁。这两部分实现 kexec 的两个主要操作:将新内核装载到内存并重新启动到它。可以容易地获得一个启用 kexec 的内核。只需要下载 kexec-tools 包和特定内核的补丁(见 参考资料部分的链接),编译 kexec-tools 包以得到 kexec工具,并将特定内核的补丁加入到内核树中并重装启动到它。当然,您在编译内核时要确保选中 CONFIG_KEXEC
选项。
如上所述,kexec 的使用包括(1)将重新启动到的内核装载到内核中,然后(2)真正重新启动到它。装载内核的语法如下:
kexec -l <kernel-image> --append="<command-line-options>"
在这里, <kernel-image>
是您想要重新启动后的内核文件, <command-line-options>
容纳的是需要传递到新内核的命令行参数。由于错误的命令行选项可能会在重新启动时引发问题,所以,确保合法值传递到重新启动的内核的安全方法是传递 /proc/cmdline
的内容。
例如,如果您希望重新启动的内核映像是 /boot/bzImage, /proc/cmdline
的内容是 "root=/dev/hda1"
,那么装载内核的命令将是:
kexec -l /boot/bzImage -append="root=/dev/hda1"
然后,为了真正重新启动已装载的内核,只需要输入:
kexec -e
系统将立即重新启动。不同于正常的重新启动过程,在重新启动之前,kexec 不去执行彻底停止系统。需要您在尝试进行 kexec 重新启动之前去杀死所有应用程序并?载文件系统。
回页首
kexec
的魔力
在 kexec 的发展过程中,最大的挑战之一来自于这样一个事实:Linux 内核要从内存中固定的地址运行。也就是说,新内核需要安放于当前内核正在运行的位置。在 x86 系统上,内核位于物理地址 0x100000(虚拟地址为 0xc0000000,也叫做 PAGE_OFFSET
)。用新内核覆盖旧内核的工作分三个阶段完成:
- 将新内核拷贝到内核中。
- 将这个内核映像移到动态内核内存中。
- 将这个映像拷贝到真正的目标位置(覆盖当前内核),然后启动新内核。
前两个阶段在内核的“装载”期间完成。第一个任务是解释内核映像文件的内容。Kexec-tools 已经被编译,因此,理论上您可以装载并引导任何(甚至是非-Linux 的)内核。当前,只能引导到 elf32 格式的内核映像。这个文件被解析,内核“段(segments)”被装载到缓存中。这些段根据代码的自然类型进行分类。例如,在使用常见的“bzImage”内核文件格式的情况下,典型的段是针对 16 位内核代码、32 位内核代码和初始 RAM 磁盘代码的段。用于追踪这些段的结构体被称为 kexec_segment
,是一个相当简单的结构体:
清单 1. kexec_segment 结构体
struct kexec_segment {
void *buf;
size_t bufsz;
void *mem;
size_t memsz;
};
|
结构体的前两个元素指向用户空间缓存和它的大小,接下来两个元素指明了段的最终目标位置和它的大小。
一旦特定内核文件格式的(kernel-file format-specific)模块将映像装载到用户内存,映像就会被 sys_kexec
系统调用转移到动态内核内存。这个系统调用给每个从用户空间传递而来的段分配动态内核页,并将段拷贝到这些内核页上。
kexec 还分配了一个用来存储汇编代码的小存根(small stub)的内核页,称为 reboot_code_buffer
。这个存根完成用将要重新启动到的内核来覆盖当前内核并跳转到它的实际工作。 reboot_code_buffer
是惟一的存留在其最终存放位置的缓存。换句话说,它从它最初装载到的位置开始执行。为此,在启用了 MMU 的系统上,驻留这些代码的页被 一致映射(identity mapped)。简单说,这需要用相同的物理和虚拟地址在 init_mm
(内核的页表结构体)中创建一个页表条目。必须这样做才能在重新启动操作中访问这一代码段,如接下来将要论述的。
关于 reboot_code_buffer
、各种段以及其他细节的信息通过使用 kimage
结构来保持:
清单 2. kimage 结构体
struct kimage {
kimage_entry_t head;
kimage_entry_t *entry;
kimage_entry_t *last_entry;
unsigned long destination;
unsigned long offset;
unsigned long start;
struct page *reboot_code_pages;
unsigned long nr_segments;
struct kexec_segment segment[KEXEC_SEGMENT_MAX+1];
struct list_head dest_pages;
struct list_head unuseable_pages;
};
|
当前,这个结构体中最重要的部分是指向容纳映像的内核内存中缓存的 segment[KEXEC_SEGMENT_MAX+1]
元素,和指向重新启动过程中使用的汇编存根的 reboot_code_pages
。
一旦内核映像被装载,系统就可以重新启动到它。使用 kexec -e
命令来开始真正重新启动到新内核。这个命令实际上是用 sys_reboot
系统调用来通知内核执行重新启动,但是使用了一个特别的 - LINUX_REBOOT_CMD_KEXEC
标志。
重新启动的系统调用遇到这个特别的标志后,将控制权移交给 machine_kexec()
函数。 machine_kexec()
执行的动作完全针对特定体系结构。在当前的 x86 实现中,动作的序列如下:
- 从当前进程的
mm struct
切换到使用内核的 init_mm
结构体,以访问一致映射的 reboot_code_buffer
。
- 停止 apics 并禁用中断。
- 将汇编存根代码拷贝到您在装载内核映像时分配的
reboot_code_buffer
中。此汇编代码可以在 relocate_new_kernel
例程中找到。
- 将内核数据段(
__KERNEL_DS
)值装载到段寄存器,并使用 GDT 和 IDT 无效。
- 跳转到
reboot_code_buffer
中的代码,将一些重要的信息以参数的形式传递给新内核,比如容纳有内核映像的源/目的地址的间接页,新内核的起始地址, reboot_code_buffer
页的地址,以及一个标明系统是否启用了物理地址扩展(physical address extension,PAE)的标志。
汇编存根代码执行下面的操作:
- 自栈中读取参数,并将它们存储到寄存器中,然后禁用中断。
- 使用以参数形式传递给自己的页地址,在页的末端设置一个栈。
- 将新内核映像的起始地址存储到栈中,以使得存根代码的返回自动将系统引导到新的内核映像。
- 设置 cr0 寄存器的适当位来禁用内存分页。
- 将页目录基址寄存器 cr4 重设为 0。
- 清空快表(Translation Lookaside Buffers,TLB)。
- 将所有内核映像页拷贝到最终目标页。
- 再次清空 TLB。
- 将除了栈指针寄存器 esp(因为它指向容纳新内核起始地址的栈)以外的所有寄存器重设为 0。
- 自存根代码“返回”。自动将系统引导到新内核。
这一系列工作完成后,新内核获得控制权,然后系统正常引导起来。
回页首
kexec 的益处
要求高可用性的系统,以及需要不断重新启动系统的内核开发人员,都将受益于 kexec。因为 kexec 跳过了系统重新启动过程中最耗时的部分(也就是固件阶段),所以重新启动变得非常快,可用性得到了提高。
kexec 在宕机转储(crash dump)工具中也得到了令人关注的应用。Linux Kernel Crash Dumps(LKCD)项目(查看 参考资料中的链接)使用 kexec 开发了一种不同的转储机制。在系统出错或者用户转储开始时,系统内存映像被压缩并转储到可用的空闲内存页中。接下来,系统使用 kexec 重新启动到另一个内核。新内核会被告知转储存储在何处,并防止任何进程使用那些内存区域。随后,内存转储可以写出到磁盘分区或者通过网络写到另一台机器。
这一设计的关键在于这样一个事实,通过避开重新启动过程中的固件阶段,LKCD 可以防止物理内存内容被固件清除掉。在宕机的时候,LKCD 也不需要依赖于一个不可靠的磁盘或者网络设备驱动器来将内存映像写出到目标位置。当重新启动执行,系统处于可靠状态后,转储通过正常的系统设备驱动器写出到目标位置。
回页首
kexec 的发展趋势
Kexec 当前只能用于 x86 32 位平台。使其可以应用于 PPC 64 和 AMD 64 等其他体系结构的平台将会有所帮助。而且,更好地与关机(shutdown)接口集成,以方便地终止进程、停止设备和?载文件系统,将使它更便于普通用户使用。
您可以为 kexec 的开发做出贡献。开始时请在一个测试用的系统上尝试 kexec。您还可以加入到“fastboot”邮件列表中,所有关于项目的技术讨论都在那里进行(查看 参考资料中的链接)。
<!-- CMA ID: 21958 --><!-- Site ID: 10 --><!-- XSLT stylesheet used to transform this file: dw-article-6.0-beta.xsl -->
参考资料
关于作者
Hariprasad Nellitheertha 在位于班加罗尔(Bangalore,印度)的 IBM India Software Labs 的 Linux Technology Center 工作。Hari 当前正致力于 LKCD(Linux Kernel Crash Dumps)项目,以前曾致力于 OS/2 内核和文件系统的工作。可以通过 nharipra@in.ibm.com 与 Hari 联系。
相关推荐
Kexec 是一项重要的 Linux 内核技术,它允许在不重启硬件的情况下加载新的内核版本。这项技术最初由 Simon Horman 和 Magnus Damm 在 VALinux Systems Japan K.K. 开发,并在 2007 年的 Linux.Conf.Au 大会上进行了...
它的主要优点在于能够快速地进行系统重启或者灾难恢复,因为省去了传统的硬件初始化过程。这对于系统维护、故障排查以及性能测试等领域具有重要意义。kexec-tools则是实现kexec功能的用户空间工具,包括了kexec加载...
* kexec:使用kexec工具来快速重启Linux内核。 Linux内核故障排除: Linux内核故障排除是诊断和修复Linux内核中的错误和故障的技术,包括: * dmesg:使用dmesg命令来查看Linux内核的日志信息。 * syslog:使用...
kexec工具的核心是kexec内核函数,它将新内核的映像加载到内存中,然后跳转执行新内核,从而实现快速重启。这种机制跳过了常规的BIOS或UEFI引导流程,减少了启动时间,提高了系统的响应速度。kexec分为两种模式:...
当系统准备进行kexec重启时,首先会调用`kexec`命令加载新内核的映像和相关设备树到内存中。然后,系统会保存当前内核的状态,包括页表、中断处理程序等,以便在新内核启动后恢复。最后,执行软重启,新内核接管系统...
kexec能够在内核级别进行快速重启,允许系统立即运行一个新内核,而无需完成完整的系统重启流程。这种方法能够显著减少从关闭旧内核到加载新内核的总时间。此外,kexec还支持并行设备初始化,这有助于进一步提高启动...
- **Kexec**:Kexec是一种快速重启内核的技术,能够在几毫秒内切换到一个新的内核镜像,极大地缩短了重启时间。 - **Kdump**:Kdump是一种崩溃转储技术,可以在系统崩溃后收集重要的调试信息,对于分析系统故障原因...
在Firmware和Bootloader阶段,为了缩短启动时间,可以采用Kexec工具,它允许在不重启硬件的情况下重新启动内核,从而实现快速加载。此外,也可以在内核命令行中加入reboot=soft参数来跳过Firmware阶段。对于正常启动...
- **Linux kdump/kexec支持**:简化了Linux虚拟机的内核转储过程,提高了故障诊断和恢复的效率。 ##### 7. 非屏蔽中断(NMI)支持 - **NMI支持**:当Linux虚拟机失去响应时,可以通过NMI与其交互,帮助进行故障排除。...
它利用**kexec**系统调用来快速启动另一个内核(通常称为dump-capturekernel),以便在不破坏原有内核数据的情况下捕获核心内存映像。捕获的核心内存映像可以存储在`/proc/vmcore`文件中,之后可通过专门的工具进行...
- **kexec快速加载**:kdump利用kexec技术快速加载一个备用内核,该内核负责捕获崩溃内核的状态并将其写入转储文件。 - **内存转储**:崩溃内核将内存状态复制到预留的`crashkernel`空间,然后由新内核将这些数据...
内核中的Kexec功能也得到了加强,支持不通过引导加载器的快速重启。这意味着系统可以在不完全关闭的情况下,迅速重新启动到另一个内核,大大减少了启动时间。此外,Kdump功能的引入提供了一种基于Kexec的系统崩溃...
kexec是一种在Linux内核中用于快速启动新内核的技术,它允许系统在不完全关闭当前内核的情况下加载并启动另一个内核。 1. **kexec技术**: kexec是一种系统重启机制,它允许一个正在运行的操作系统内核加载并启动另...
kexec-hardboot补丁是内核中的一个重要组件,它扩展了kexec功能,这是一种快速启动技术,允许系统在不完全关闭的情况下加载新的内核。在Android设备上,kexec-hardboot可以用于在保持数据完整性的前提下,实现更快的...
- **kexec选项**:用于快速重启的配置。 - **RCU选项**:读取复制更新机制的设置。 - **ACPI选项**:电源管理和热插拔设备支持。 - **SCSI选项**:小型计算机系统接口的配置。 - **PCI选项**:外围组件互连标准的...
- **Kexec**: Kexec 是一种内核级技术,允许在当前内核之上加载另一个内核,而无需重启。 - **Kdump**: 当系统崩溃时,kdump 使用 kexec 加载一个“次级”内核,该内核负责收集转储数据。 ##### 11. Kdump 安装 **...
“kexec-bin”可能是Bootloader中的一个组件或者工具,用于在Linux内核之间切换,例如在系统升级时,新内核可以通过kexec快速加载,而无需完全重启设备。kexec技术允许已经运行的Linux内核直接加载另一个内核映像,...
kexec是一种在Linux内核中直接加载另一个内核的技术,无需经过完整的系统关闭和重启过程。这在调试、升级或热切换内核时非常有用。在Bootloader源代码中,kexec-mod可能是一个补丁或模块,用于支持这种快速内核切换...
Runnix 利用 kexec 实现快速切换到不同的 Linux 发行版或内核版本。 ### 2. syslinux syslinux 是一个用于引导软盘、硬盘和 CD-ROM 上的 Linux 的引导加载程序。它支持多种文件系统,并且可以在 BIOS 或 UEFI 模式...