Linux内核的__crash_kexec函数的作用,逐行对源码进行注释
时间: 2024-05-02 18:21:55 浏览: 254
__crash_kexec函数是Linux内核中的一个函数,用于在系统崩溃时进行重启。下面是对该函数的源码逐行注释:
```c
void __crash_kexec(struct pt_regs *regs)
{
struct resource *res;
unsigned long flags;
const char *s;
int i;
unsigned long kexec_flags = (unsigned long)panic_timeout;
```
定义了一些变量,其中kexec_flags存储了panic_timeout的值,该值会在后面被用于设置kexec的一些标志。
```c
if (regs) {
printk(KERN_EMERG "Kernel panic - not syncing: ");
print_modules();
print_ip_sym(regs->ip);
dump_trace(regs, NULL);
} else {
printk(KERN_EMERG "Kernel panic - not syncing: Attempted to kill init!\n");
}
```
如果regs不为NULL,说明系统崩溃的原因是一个内核错误,需要打印一些错误信息。否则,说明试图kill init进程导致崩溃,需要打印“Attempted to kill init!”的错误信息。
```c
/*
* We may have crashed before we've had a chance to initialize
* the console, so be prepared for this.
*/
console_lock();
if (console_may_schedule())
panic_print = 1;
console_unlock();
```
由于在发生崩溃之前,可能还没有初始化控制台,所以需要在这里进行初始化。
```c
smp_send_stop();
local_irq_disable();
local_fiq_disable();
```
停止其他CPU的调度,并禁用本地中断和快速中断。
```c
if (regs) {
bad_mode(regs);
dump_instr(regs, NULL);
}
```
如果regs不为NULL,说明有内核错误,需要调用bad_mode函数和dump_instr函数来打印一些错误信息。
```c
/* Stop the machine */
machine_shutdown();
```
停止机器运行。
```c
/*
* Save the panic record before unmapping the kernel memory,
* which we are about to do. This is necessary because the
* panic record is stored in kernel memory.
*/
save_panic(__FILE__, __LINE__, __func__, "Crash_kexec");
```
保存崩溃记录。
```c
/* Free all unused memory */
free_unused_memmap();
free_initmem();
free_initrd_mem();
free_all_bootmem();
free_all_pages();
```
释放所有未使用的内存。
```c
/*
* Turn off the caches to try to make sure that everything
* written so far is flushed to memory.
*/
flush_cache_all();
```
关闭缓存以确保所有写入的数据都被刷新到内存中。
```c
/*
* Unmap kernel memory.
*/
unmap_kernel_range((unsigned long)end, 0xffffffff - PAGE_OFFSET);
```
取消内核内存的映射。
```c
/* Release resources */
release_resource(&root_resource);
for (i = 0; i < MAX_IORESOURCES; i++)
release_resource(&ioport_resource[i]);
for (i = 0; i < MAX_RESOURCE_TYPE; i++) {
res = resource_list[i].next;
while (res != &resource_list[i]) {
release_resource(res);
res = res->next;
}
}
```
释放资源。
```c
/*
* Try to set up kexec to reboot into a crash kernel.
* If that fails, just reboot directly.
*/
flags = kexec_flags | KEXEC_RESTART;
s = "kexec";
if (kexec_load(flags, NULL, NULL) < 0) {
flags = kexec_flags | KEXEC_PRESERVE_RTC | KEXEC_ON_CRASH;
if (kexec_load(flags, NULL, NULL) < 0) {
s = "reboot";
panic_blink();
machine_restart(s);
}
}
```
尝试设置kexec以重启到一个崩溃内核。如果失败,则直接重启。
```c
/*
* If we get here, kexec has been set up successfully.
* Just jump to the new kernel.
*/
kexec_do_shutdown(s);
}
```
如果成功,则跳转到新内核。
阅读全文