How to soft reboot from a non-monolithic kernel module in an IRQ scope?
-
24-05-2021 - |
Question
I need to reboot upon handling an IRQ in kernel land.
I want to call the /sbin/reboot
binary, but I have got limitations due to the IRQ scope.
Code follows :
#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);
}
I can see the printk(...)
when the IRQ is triggered but I have some errors, even if I replace /sbin/reboot
by /bin/rm /tmp/its-not-working
.
I tested other way to do reboot like mvBoardReset()
, machine_halt()
, arm_pm_restart()
, pm_power_off()
, kill(1, SIGTSTP)
, reboot()
, handle_sysrq('b')
, I always have errors that I don't have outside the IRQ scope.
I really want to call /sbin/reboot
, since it does clean soft reset.
Thank you for your time.
Solution
Just an idea: you can start kernel thread by kthread_run()
, put it to sleep by wait_event()
, wake it up in the IRQ handler by wake_up()
, do your stuff (run /sbin/reboot
or whatever you want) in the kernel thread. Something like this (completely untested):
#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);
}
Don't forget to handle module __exit
and the case when interrupt has come before the kernel thread was sent to sleep.