Как выполнить мягкую перезагрузку из немонолитного модуля ядра в области IRQ? - PullRequest
2 голосов
/ 16 марта 2012

Мне нужно перезагрузиться после обработки IRQ на земле ядра.

Я хочу вызвать двоичный файл /sbin/reboot, но у меня есть ограничения из-за области IRQ.

Код следует:

#define MY_IRQ_ID       42

void __init             rebootmodule_init(void) {
    request_any_context_irq(MY_IRQ_ID, rebootmodule_irq_handler, IRQF_TRIGGER_FALLING, "irq-name", NULL);
}

irqreturn_t             rebootmodule_irq_handler(int irq, void *dev_id) {
    my_reboot();
    return IRQ_HANDLED;
}

void                    my_reboot(void) {
    int                 ret;
    char                *argv[2], *envp[4];

    argv[0] = "/sbin/reboot";
    argv[1] = NULL;
    envp[0] = "HOME=/";
    envp[1] = "PWD=/";
    envp[2] = "PATH=/sbin";
    envp[3] = NULL;
    ret = call_usermodehelper(argv[0], argv, envp, 0);
    printk(KERN_INFO "trying to reboot (ret = %d)", ret);
}

Я вижу printk(...) при срабатывании IRQ, но у меня возникают ошибки, даже если я заменяю /sbin/reboot на /bin/rm /tmp/its-not-working.

Я проверял другим способомсделать перезагрузку, как mvBoardReset(), machine_halt(), arm_pm_restart(), pm_power_off(), kill(1, SIGTSTP), reboot(), handle_sysrq('b'), у меня всегда есть ошибки, которых у меня нет вне области IRQ.

Я действительно хочу позвонить /sbin/reboot, так как он выполняет чистую программную перезагрузку.

Спасибо за ваше время.

1 Ответ

5 голосов
/ 16 марта 2012

Просто идея: вы можете запустить поток ядра с помощью kthread_run(), перевести его в спящий режим с помощью wait_event(), разбудить его в обработчике IRQ с помощью wake_up(), выполнить свои действия (запустить /sbin/reboot или что вам нужно) в ветке ядра.Примерно так (полностью не проверено):

#define MY_IRQ_ID 42

static DECLARE_WAIT_QUEUE_HEAD(wq);
static volatile int showtime = 0;

void my_reboot(void) {
    int ret;
    char *argv[2], *envp[4];

    argv[0] = "/sbin/reboot";
    argv[1] = NULL;
    envp[0] = "HOME=/";
    envp[1] = "PWD=/";
    envp[2] = "PATH=/sbin";
    envp[3] = NULL;
    ret = call_usermodehelper(argv[0], argv, envp, 0);
    printk(KERN_INFO "trying to reboot (ret = %d)", ret);
}

static int my_thread(void *arg) {
    wait_event(&wq, showtime);
    my_reboot();
    return 0;
}

irqreturn_t rebootmodule_irq_handler(int irq, void *dev_id) {
    showtime = 1;
    wake_up(&wq);
    return IRQ_HANDLED;
}

void __init rebootmodule_init(void) {
    kthread_run(my_thread, NULL, "my_module");
    request_any_context_irq(MY_IRQ_ID, rebootmodule_irq_handler, IRQF_TRIGGER_FALLING, "irq-name", NULL);
}

Не забудьте обработать модуль __exit и случай, когда прерывание наступило до потока ядра, отправленного в спящий режим.

...