rcu: Provide OOM handler to motivate lazy RCU callbacks
In kernels built with CONFIG_RCU_FAST_NO_HZ=y, CPUs can accumulate a
large number of lazy callbacks, which as the name implies will be slow
to be invoked. This can be a problem on small-memory systems, where
the default 6-second sleep for CPUs having only lazy RCU callbacks
could well be fatal. This commit therefore installs an OOM hander
that invokes all flavors of rcu_barrier(), thus ensuring that every
CPU with callbacks has at least one non-lazy callback, in turn ensuring
timely advancement for these callbacks.
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 931f36b..f767543 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -25,6 +25,7 @@
*/
#include <linux/delay.h>
+#include <linux/oom.h>
#define RCU_KTHREAD_PRIO 1
@@ -2244,6 +2245,35 @@
__this_cpu_add(rcu_dynticks.nonlazy_posted, 1);
}
+/*
+ * If low on memory, do a full round of rcu_barrier() calls to ensure
+ * that each CPU has a non-lazy callback. This will wake up CPUs that
+ * have only lazy callbacks, ensuring that they free up the corresponding
+ * memory in a timely manner.
+ */
+static int rcu_oom_notify(struct notifier_block *self,
+ unsigned long notused, void *nfreed)
+{
+#ifdef CONFIG_PREEMPT_RCU
+ rcu_barrier();
+#endif /* #ifdef CONFIG_PREEMPT_RCU */
+ rcu_barrier_bh();
+ rcu_barrier_sched();
+ *(unsigned long *)nfreed = 1;
+ return NOTIFY_OK;
+}
+
+static struct notifier_block rcu_oom_nb = {
+ .notifier_call = rcu_oom_notify
+};
+
+static int __init rcu_register_oom_notifier(void)
+{
+ register_oom_notifier(&rcu_oom_nb);
+ return 0;
+}
+early_initcall(rcu_register_oom_notifier);
+
#endif /* #else #if !defined(CONFIG_RCU_FAST_NO_HZ) */
#ifdef CONFIG_RCU_CPU_STALL_INFO