Commit 4a801b22 authored by David Johnson's avatar David Johnson

Move emergency_restart call out of bh in Linux ipod module on aarch64/powerpc64.

Calling emergency_restart directly from the softirq/bh ipod icmp handler
has a history of causing panics prior to the intended shutdown on both
aarch64 and powerpc64.  The panics didn't inhibit the intended reboot,
but on OPAL-booted ppc64le, were very noisy, because each "hyperthread"
cpu attempted a dealloc of the irq handler from within the handler, so
the console got a noisy stack trace for each thread.

So now if IPOD_QUEUE_RESTART is defined (and it is by default on aarch64
and powerpc64), we move the call to emergency_restart into a dedicated,
preallocated workqueue thread, whose sole purpose is to (eventually)
reboot the machine.  Wasteful, but we don't want to need to initialize
anything, or use a shared workqueue, if an IPOD is really necessary, at
IPOD time.
parent f8533dad
/*
* Copyright (c) 2000-2018 University of Utah and the Flux Group.
* Copyright (c) 2000-2019 University of Utah and the Flux Group.
*
* {{{EMULAB-LICENSE
*
......@@ -41,7 +41,25 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Flux Research Group");
MODULE_VERSION("3.0.0");
MODULE_VERSION("3.1.0");
#if defined(__aarch64__) || defined(__powerpc64__)
#define IPOD_QUEUE_RESTART
#endif
#ifdef IPOD_QUEUE_RESTART
#include <linux/workqueue.h>
static struct workqueue_struct *restart_queue;
static void restart_work_func(struct work_struct *work)
{
printk(KERN_CRIT "IPOD: restarting (delayed)...\n");
emergency_restart();
}
DECLARE_WORK(restart_work,restart_work_func);
#endif
#define IPOD_ICMP_TYPE 6
#define IPOD_ICMP_CODE 6
......@@ -245,7 +263,11 @@ static unsigned int ipod_hook_fn(
if (doit) {
sysctl_ipod_enabled = 0;
printk(KERN_CRIT "IPOD: reboot forced by %pI4...\n",&iph->saddr);
#ifdef IPOD_QUEUE_RESTART
queue_work(restart_queue,&restart_work);
#else
emergency_restart();
#endif
return NF_DROP;
}
else {
......@@ -288,11 +310,21 @@ static int __init ipod_init_module(void) {
return -1;
}
#ifdef IPOD_QUEUE_RESTART
restart_queue = create_singlethread_workqueue("ipod_restart_queue");
#endif
return 0;
}
static void __exit ipod_cleanup_module(void) {
printk(KERN_INFO "removing IPOD\n");
#ifdef IPOD_QUEUE_RESTART
cancel_work_sync(&restart_work);
destroy_workqueue(restart_queue);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
nf_unregister_net_hook(&init_net,&ipod_hook_ops);
#else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment