rcu: Panic if a call_rcu() CB blocks
[akaros.git] / kern / include / rcupdate.h
index f816fc7..62d1ffe 100644 (file)
 #ifndef __LINUX_RCUPDATE_H
 #define __LINUX_RCUPDATE_H
 
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <linux/atomic.h>
-#include <linux/irqflags.h>
-#include <linux/preempt.h>
-#include <linux/bottom_half.h>
-#include <linux/lockdep.h>
-#include <asm/processor.h>
-#include <linux/cpumask.h>
-
 #define ULONG_CMP_GE(a, b)     (ULONG_MAX / 2 >= (a) - (b))
 #define ULONG_CMP_LT(a, b)     (ULONG_MAX / 2 < (a) - (b))
 #define ulong2long(a)          (*(long *)(&(a)))
 
-/* Exported common interfaces */
-
-#ifdef CONFIG_PREEMPT_RCU
 void call_rcu(struct rcu_head *head, rcu_callback_t func);
-#else /* #ifdef CONFIG_PREEMPT_RCU */
-#define        call_rcu        call_rcu_sched
-#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
-
-void call_rcu_bh(struct rcu_head *head, rcu_callback_t func);
-void call_rcu_sched(struct rcu_head *head, rcu_callback_t func);
-void synchronize_sched(void);
-void call_rcu_tasks(struct rcu_head *head, rcu_callback_t func);
-void synchronize_rcu_tasks(void);
-void rcu_barrier_tasks(void);
-
-#ifdef CONFIG_PREEMPT_RCU
-
-void __rcu_read_lock(void);
-void __rcu_read_unlock(void);
-void rcu_read_unlock_special(struct task_struct *t);
-void synchronize_rcu(void);
-
-/*
- * Defined as a macro as it is a very low level header included from
- * areas that don't even know about current.  This gives the rcu_read_lock()
- * nesting depth, but makes sense only if CONFIG_PREEMPT_RCU -- in other
- * types of kernel builds, the rcu_read_lock() nesting depth is unknowable.
- */
-#define rcu_preempt_depth() (current->rcu_read_lock_nesting)
-
-#else /* #ifdef CONFIG_PREEMPT_RCU */
-
-static inline void __rcu_read_lock(void)
-{
-       if (IS_ENABLED(CONFIG_PREEMPT_COUNT))
-               preempt_disable();
-}
-
-static inline void __rcu_read_unlock(void)
-{
-       if (IS_ENABLED(CONFIG_PREEMPT_COUNT))
-               preempt_enable();
-}
 
-static inline void synchronize_rcu(void)
-{
-       synchronize_sched();
-}
-
-static inline int rcu_preempt_depth(void)
-{
-       return 0;
-}
-
-#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
-
-/* Internal to kernel */
-void rcu_init(void);
-void rcu_sched_qs(void);
-void rcu_bh_qs(void);
-void rcu_check_callbacks(int user);
-void rcu_report_dead(unsigned int cpu);
-void rcu_cpu_starting(unsigned int cpu);
-
-#ifdef CONFIG_RCU_STALL_COMMON
-void rcu_sysrq_start(void);
-void rcu_sysrq_end(void);
-#else /* #ifdef CONFIG_RCU_STALL_COMMON */
-static inline void rcu_sysrq_start(void) { }
-static inline void rcu_sysrq_end(void) { }
-#endif /* #else #ifdef CONFIG_RCU_STALL_COMMON */
-
-#ifdef CONFIG_NO_HZ_FULL
-void rcu_user_enter(void);
-void rcu_user_exit(void);
-#else
-static inline void rcu_user_enter(void) { }
-static inline void rcu_user_exit(void) { }
-#endif /* CONFIG_NO_HZ_FULL */
-
-#ifdef CONFIG_RCU_NOCB_CPU
-void rcu_init_nohz(void);
-#else /* #ifdef CONFIG_RCU_NOCB_CPU */
-static inline void rcu_init_nohz(void) { }
-#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
-
-/**
- * RCU_NONIDLE - Indicate idle-loop code that needs RCU readers
- * @a: Code that RCU needs to pay attention to.
- *
- * RCU, RCU-bh, and RCU-sched read-side critical sections are forbidden
- * in the inner idle loop, that is, between the rcu_idle_enter() and
- * the rcu_idle_exit() -- RCU will happily ignore any such read-side
- * critical sections.  However, things like powertop need tracepoints
- * in the inner idle loop.
- *
- * This macro provides the way out:  RCU_NONIDLE(do_something_with_RCU())
- * will tell RCU that it needs to pay attention, invoke its argument
- * (in this example, calling the do_something_with_RCU() function),
- * and then tell RCU to go back to ignoring this CPU.  It is permissible
- * to nest RCU_NONIDLE() wrappers, but not indefinitely (but the limit is
- * on the order of a million or so, even on 32-bit systems).  It is
- * not legal to block within RCU_NONIDLE(), nor is it permissible to
- * transfer control either into or out of RCU_NONIDLE()'s statement.
- */
-#define RCU_NONIDLE(a) \
-       do { \
-               rcu_irq_enter_irqson(); \
-               do { a; } while (0); \
-               rcu_irq_exit_irqson(); \
-       } while (0)
-
-/*
- * Note a voluntary context switch for RCU-tasks benefit.  This is a
- * macro rather than an inline function to avoid #include hell.
- */
-#ifdef CONFIG_TASKS_RCU
-#define TASKS_RCU(x) x
-extern struct srcu_struct tasks_rcu_exit_srcu;
-#define rcu_note_voluntary_context_switch_lite(t) \
-       do { \
-               if (READ_ONCE((t)->rcu_tasks_holdout)) \
-                       WRITE_ONCE((t)->rcu_tasks_holdout, false); \
-       } while (0)
-#define rcu_note_voluntary_context_switch(t) \
-       do { \
-               rcu_all_qs(); \
-               rcu_note_voluntary_context_switch_lite(t); \
-       } while (0)
-#else /* #ifdef CONFIG_TASKS_RCU */
-#define TASKS_RCU(x) do { } while (0)
-#define rcu_note_voluntary_context_switch_lite(t)      do { } while (0)
-#define rcu_note_voluntary_context_switch(t)           rcu_all_qs()
-#endif /* #else #ifdef CONFIG_TASKS_RCU */
-
-/**
- * cond_resched_rcu_qs - Report potential quiescent states to RCU
- *
- * This macro resembles cond_resched(), except that it is defined to
- * report potential quiescent states to RCU-tasks even if the cond_resched()
- * machinery were to be shut off, as some advocate for PREEMPT kernels.
- */
-#define cond_resched_rcu_qs() \
-do { \
-       if (!cond_resched()) \
-               rcu_note_voluntary_context_switch(current); \
-} while (0)
-
-/*
- * Infrastructure to implement the synchronize_() primitives in
- * TREE_RCU and rcu_barrier_() primitives in TINY_RCU.
- */
-
-#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU)
-#include <linux/rcutree.h>
-#elif defined(CONFIG_TINY_RCU)
-#include <linux/rcutiny.h>
-#else
-#error "Unknown RCU implementation specified to kernel configuration"
-#endif
+void synchronize_rcu(void);
 
 /*
  * init_rcu_head_on_stack()/destroy_rcu_head_on_stack() are needed for dynamic
@@ -226,111 +59,21 @@ static inline void init_rcu_head_on_stack(struct rcu_head *head) { }
 static inline void destroy_rcu_head_on_stack(struct rcu_head *head) { }
 #endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
-#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU)
-bool rcu_lockdep_current_cpu_online(void);
-#else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
-static inline bool rcu_lockdep_current_cpu_online(void) { return true; }
-#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
-
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-
-static inline void rcu_lock_acquire(struct lockdep_map *map)
-{
-       lock_acquire(map, 0, 0, 2, 0, NULL, _THIS_IP_);
-}
-
-static inline void rcu_lock_release(struct lockdep_map *map)
-{
-       lock_release(map, 1, _THIS_IP_);
-}
-
-extern struct lockdep_map rcu_lock_map;
-extern struct lockdep_map rcu_bh_lock_map;
-extern struct lockdep_map rcu_sched_lock_map;
-extern struct lockdep_map rcu_callback_map;
-int debug_lockdep_rcu_enabled(void);
-int rcu_read_lock_held(void);
-int rcu_read_lock_bh_held(void);
-int rcu_read_lock_sched_held(void);
-
-#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
-
-# define rcu_lock_acquire(a)           do { } while (0)
-# define rcu_lock_release(a)           do { } while (0)
-
-static inline int rcu_read_lock_held(void)
-{
-       return 1;
-}
-
-static inline int rcu_read_lock_bh_held(void)
-{
-       return 1;
-}
+#define RCU_LOCKDEP_WARN(c, s) do { } while (0)
+#define rcu_sleep_check() do { } while (0)
+#define rcu_lock_acquire(a)            do { } while (0)
+#define rcu_lock_release(a)            do { } while (0)
+#define rcu_dereference_sparse(p, space)
 
-static inline int rcu_read_lock_sched_held(void)
+static inline void __rcu_read_lock(void)
 {
-       return !preemptible();
+       cmb();
 }
-#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
-
-#ifdef CONFIG_PROVE_RCU
-
-/**
- * RCU_LOCKDEP_WARN - emit lockdep splat if specified condition is met
- * @c: condition to check
- * @s: informative message
- */
-#define RCU_LOCKDEP_WARN(c, s)                                         \
-       do {                                                            \
-               static bool __section(.data.unlikely) __warned;         \
-               if (debug_lockdep_rcu_enabled() && !__warned && (c)) {  \
-                       __warned = true;                                \
-                       lockdep_rcu_suspicious(__FILE__, __LINE__, s);  \
-               }                                                       \
-       } while (0)
 
-#if defined(CONFIG_PROVE_RCU) && !defined(CONFIG_PREEMPT_RCU)
-static inline void rcu_preempt_sleep_check(void)
+static inline void __rcu_read_unlock(void)
 {
-       RCU_LOCKDEP_WARN(lock_is_held(&rcu_lock_map),
-                        "Illegal context switch in RCU read-side critical section");
+       cmb();
 }
-#else /* #ifdef CONFIG_PROVE_RCU */
-static inline void rcu_preempt_sleep_check(void) { }
-#endif /* #else #ifdef CONFIG_PROVE_RCU */
-
-#define rcu_sleep_check()                                              \
-       do {                                                            \
-               rcu_preempt_sleep_check();                              \
-               RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map),        \
-                                "Illegal context switch in RCU-bh read-side critical section"); \
-               RCU_LOCKDEP_WARN(lock_is_held(&rcu_sched_lock_map),     \
-                                "Illegal context switch in RCU-sched read-side critical section"); \
-       } while (0)
-
-#else /* #ifdef CONFIG_PROVE_RCU */
-
-#define RCU_LOCKDEP_WARN(c, s) do { } while (0)
-#define rcu_sleep_check() do { } while (0)
-
-#endif /* #else #ifdef CONFIG_PROVE_RCU */
-
-/*
- * Helper functions for rcu_dereference_check(), rcu_dereference_protected()
- * and rcu_assign_pointer().  Some of these could be folded into their
- * callers, but they are left separate in order to ease introduction of
- * multiple flavors of pointers to match the multiple flavors of RCU
- * (e.g., __rcu_bh, * __rcu_sched, and __srcu), should this make sense in
- * the future.
- */
-
-#ifdef __CHECKER__
-#define rcu_dereference_sparse(p, space) \
-       ((void)(((typeof(*p) space *)p) == p))
-#else /* #ifdef __CHECKER__ */
-#define rcu_dereference_sparse(p, space)
-#endif /* #else #ifdef __CHECKER__ */
 
 #define __rcu_access_pointer(p, space) \
 ({ \
@@ -666,96 +409,6 @@ static inline void rcu_read_unlock(void)
 }
 
 /**
- * rcu_read_lock_bh() - mark the beginning of an RCU-bh critical section
- *
- * This is equivalent of rcu_read_lock(), but to be used when updates
- * are being done using call_rcu_bh() or synchronize_rcu_bh(). Since
- * both call_rcu_bh() and synchronize_rcu_bh() consider completion of a
- * softirq handler to be a quiescent state, a process in RCU read-side
- * critical section must be protected by disabling softirqs. Read-side
- * critical sections in interrupt context can use just rcu_read_lock(),
- * though this should at least be commented to avoid confusing people
- * reading the code.
- *
- * Note that rcu_read_lock_bh() and the matching rcu_read_unlock_bh()
- * must occur in the same context, for example, it is illegal to invoke
- * rcu_read_unlock_bh() from one task if the matching rcu_read_lock_bh()
- * was invoked from some other task.
- */
-static inline void rcu_read_lock_bh(void)
-{
-       local_bh_disable();
-       __acquire(RCU_BH);
-       rcu_lock_acquire(&rcu_bh_lock_map);
-       RCU_LOCKDEP_WARN(!rcu_is_watching(),
-                        "rcu_read_lock_bh() used illegally while idle");
-}
-
-/*
- * rcu_read_unlock_bh - marks the end of a softirq-only RCU critical section
- *
- * See rcu_read_lock_bh() for more information.
- */
-static inline void rcu_read_unlock_bh(void)
-{
-       RCU_LOCKDEP_WARN(!rcu_is_watching(),
-                        "rcu_read_unlock_bh() used illegally while idle");
-       rcu_lock_release(&rcu_bh_lock_map);
-       __release(RCU_BH);
-       local_bh_enable();
-}
-
-/**
- * rcu_read_lock_sched() - mark the beginning of a RCU-sched critical section
- *
- * This is equivalent of rcu_read_lock(), but to be used when updates
- * are being done using call_rcu_sched() or synchronize_rcu_sched().
- * Read-side critical sections can also be introduced by anything that
- * disables preemption, including local_irq_disable() and friends.
- *
- * Note that rcu_read_lock_sched() and the matching rcu_read_unlock_sched()
- * must occur in the same context, for example, it is illegal to invoke
- * rcu_read_unlock_sched() from process context if the matching
- * rcu_read_lock_sched() was invoked from an NMI handler.
- */
-static inline void rcu_read_lock_sched(void)
-{
-       preempt_disable();
-       __acquire(RCU_SCHED);
-       rcu_lock_acquire(&rcu_sched_lock_map);
-       RCU_LOCKDEP_WARN(!rcu_is_watching(),
-                        "rcu_read_lock_sched() used illegally while idle");
-}
-
-/* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */
-static inline notrace void rcu_read_lock_sched_notrace(void)
-{
-       preempt_disable_notrace();
-       __acquire(RCU_SCHED);
-}
-
-/*
- * rcu_read_unlock_sched - marks the end of a RCU-classic critical section
- *
- * See rcu_read_lock_sched for more information.
- */
-static inline void rcu_read_unlock_sched(void)
-{
-       RCU_LOCKDEP_WARN(!rcu_is_watching(),
-                        "rcu_read_unlock_sched() used illegally while idle");
-       rcu_lock_release(&rcu_sched_lock_map);
-       __release(RCU_SCHED);
-       preempt_enable();
-}
-
-/* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */
-static inline notrace void rcu_read_unlock_sched_notrace(void)
-{
-       __release(RCU_SCHED);
-       preempt_enable_notrace();
-}
-
-/**
  * RCU_INIT_POINTER() - initialize an RCU protected pointer
  *
  * Initialize an RCU-protected pointer in special cases where readers
@@ -815,7 +468,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
  */
 #define __kfree_rcu(head, offset) \
        do { \
-               BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); \
+               static_assert(__is_kfree_rcu_offset(offset)); \
                kfree_call_rcu(head, (rcu_callback_t)(unsigned long)(offset)); \
        } while (0)