从内核崩溃调用用户空间应用程序

Calling user space application from kernel panic

提问人:RobertAA 提问时间:8/31/2023 最后编辑:0andriyRobertAA 更新时间:9/2/2023 访问量:106

问:

我需要一种方法来通知我的系统上的U-Boot发生内核崩溃,我已经配置了所有相关的应用程序,并且在手动启动时它可以正常工作。现在我需要自动执行此过程,以防发生内核崩溃,它应该更改 U-Boot 变量,为此我正在尝试使用函数但没有工作,调用此函数的结果是 0,但没有启动任何内容。我尝试在恐慌时创建一个文件,但也没有工作,文件没有被创建。 我已经隔离了与此相关的代码,并创建了一个内核模块来探测行为,在这个模块上,我只是调用并且运行良好,但是当我将代码移动到紧急函数时,没有任何反应。我读到了一些关于函数在 IRQ 处理程序中不起作用的内容,所以我也尝试过一个工人,但没有成功。这段代码是我最后一次尝试,任何帮助将不胜感激。fw_setenvcall_usermodehelper()touchcall_usermodehelper()call_usermodehelper()call_usermodehelper()

struct work_cont {
        struct work_struct real_work;
        char cmd[250];
};

static struct work_cont execwq;

void cmdexec_worker(struct work_struct *work)
{
    static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
    char *argv[] = { "/bin/touch", "/a.txt", NULL };
        // struct work_cont *c_ptr = container_of(work, struct work_cont, real_work);
        set_current_state(TASK_INTERRUPTIBLE);
    printk(KERN_ERR "Executing worker\n");
        call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);

        return;
}

void panic(const char *fmt, ...)
{
    schedule_work(&execwq.real_work);
...
}

static int __init setup_crash_kexec_post_notifiers(char *s)
{
        INIT_WORK(&execwq.real_work, cmdexec_worker);
...
}

加载内核模块手动工作,使用和不使用 worker。没有程序或脚本从panic函数工作,显示因此代码正在执行,但外部应用程序没有被调用。printk()

linux 内核 u-boot panic

评论

0赞 0andriy 9/1/2023
使用 ramoops、pstore 和类似的机制来实现这一点。
0赞 stark 9/1/2023
为什么不将变量默认为“panic has occurred”,并在干净关机/重新启动时将其更改为“no panic”?
0赞 0andriy 9/1/2023
@start,它可能会给出误报,例如,如果看门狗在设置正常启动标志之前重置设备(假设看门狗重置不被视为崩溃)。
0赞 sawdust 9/1/2023
你似乎没有意识到内核崩溃不是正常情况,你可以访问 rootfs 来加载和执行用户空间应用程序(可能需要与共享对象链接)来执行更多的 I/O。你期望许多系统功能是完整的和可用的,即使内核已经崩溃并基本上宣布系统不稳定。如果恐慌与rootfs有关怎么办?那么,如何访问程序的 rootfs?IMO 你需要重新考虑这个过于复杂的想法,这也使 U-Boot 的保存环境处于危险之中。
0赞 RobertAA 9/1/2023
@sawdust 你说得很对,你永远不应该做这样的事情,但我正在使用一个组装时无法物理访问的系统。因此,我需要一种方法来确保当某些东西崩溃时,系统能够自行恢复,并且就我所看到的而言,它应该更频繁地发生......这只是我发现的唯一方法,也许另一种选择会更好

答:

0赞 sawdust 9/2/2023 #1

从内核崩溃调用用户空间应用程序

你似乎没有意识到内核崩溃不是正常情况,你可以访问 rootfs 来加载和执行用户空间应用程序(可能需要与共享对象链接)来执行更多的 I/O。你期望许多系统功能是完整的和可用的,即使内核已经崩溃并基本上宣布系统不稳定。
如果恐慌与rootfs有关怎么办?那么,如何访问程序的 rootfs?这会导致无限的恐慌循环吗?IMO 您需要重新考虑这个过于复杂的方案,这也使 U-Boot 的保存环境面临风险。

我需要一种方法来通知我的系统上的U-Boot发生内核崩溃

所以你实际上有一个 XY 问题。

您为 Y 提出的解决方案让 U-Boot 简单地测试其环境变量之一,但要求内核执行不可能完成的任务,即启动用户程序以 (1) 读取文件(或原始扇区),(2) 修改内容并执行 CRC32 计算,然后 (3) 写回该内容。所有这些步骤都将在系统由于内核崩溃而不稳定时执行。请注意,如果启动了步骤 3 但未能成功完成,则 U-Boot 将不得不使用备份副本(如果可用)或恢复到环境的默认版本。

对于X来说,一个可能且更简单的解决方案(从内核的角度来看)是利用现有的内核功能。该系统可以构建为在发生崩溃时转储内存(也称为“核心”)。Ubuntu 文档将此功能描述为:

当发生内核崩溃时,内核依靠 kexec 机制在系统启动时分配的预留内存部分中快速重新启动内核的新实例(参见 xxx)。这允许现有内存区域保持不变,以便安全地将其内容复制到存储中。

现在,大部分新开发将在U-Boot端进行,U-Boot端必须确定是否编写了(新的)内核转储。


所以我需要一种方法来确保当出现崩溃时系统能够自行恢复......

然后,至少确保将CONFIG_PANIC_TIMEOUT更改为默认值 0 以外的值。

评论

0赞 RobertAA 9/5/2023
你说的似乎都是合理的。我不知道远程转储功能,这在这种情况下可能非常有用,所以我将研究如何生成远程内核转储,并从 uBoot 并使用 TFTP,检查该转储是否存在。我敢肯定,使用这种方法,我将能够恢复系统。谢谢!