include/linux/types.h | 1 + include/net/dst.h | 2 +- kernel/rcu.h | 1 + kernel/rcutree.c | 6 ++++++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/linux/types.h b/include/linux/types.h index 4d118ba11349..3f0d9daff906 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -209,6 +209,7 @@ struct ustat { struct callback_head { struct callback_head *next; void (*func)(struct callback_head *head); + unsigned long magic; }; #define rcu_head callback_head diff --git a/include/net/dst.h b/include/net/dst.h index 1f8fd109e225..6f8acd031948 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -89,7 +89,7 @@ struct dst_entry { * (L1_CACHE_SIZE would be too much) */ #ifdef CONFIG_64BIT - long __pad_to_align_refcnt[2]; + long __pad_to_align_refcnt[1]; #endif /* * __refcnt wants to be on a different cache line from diff --git a/kernel/rcu.h b/kernel/rcu.h index 7f8e7590e3e5..0381ed3721bb 100644 --- a/kernel/rcu.h +++ b/kernel/rcu.h @@ -98,6 +98,7 @@ static inline bool __rcu_reclaim(char *rn, struct rcu_head *head) { unsigned long offset = (unsigned long)head->func; + head->magic = 0; if (__is_kfree_rcu_offset(offset)) { RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset)); kfree((void *)head - offset); diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 5b8ad827fd86..80f9cfb63748 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -2221,6 +2221,9 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp, } } +/* Unlikely bit-pattern to check double RCU calls! */ +#define RCU_HEAD_MAGIC ((unsigned long)(0xfeeddead1acef8edll)) + /* * Helper function for call_rcu() and friends. The cpu argument will * normally be -1, indicating "currently running CPU". It may specify @@ -2235,9 +2238,12 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), struct rcu_data *rdp; WARN_ON_ONCE((unsigned long)head & 0x3); /* Misaligned rcu_head! */ + if (WARN_ON_ONCE(head->magic == RCU_HEAD_MAGIC)) + return; debug_rcu_head_queue(head); head->func = func; head->next = NULL; + head->magic = RCU_HEAD_MAGIC; /* * Opportunistically note grace-period endings and beginnings.