rcu: add assertions to debug build

Xen's RCU implementation relies on no softirq handling taking place
while being in a RCU critical section. Add ASSERT()s in debug builds
in order to catch any violations.

For that purpose modify rcu_read_[un]lock() to use a dedicated percpu
counter additional to preempt_[en|dis]able() as this enables to test
that condition in __do_softirq() (ASSERT_NOT_IN_ATOMIC() is not
usable there due to __cpu_up() calling process_pending_softirqs()
while holding the cpu hotplug lock).

While at it switch the rcu_read_[un]lock() implementation to static
inline functions instead of macros.

Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Juergen Gross authored and Jan Beulich committed 2020-03-26 12:46:48 +01:00
1 parent cef21210fb
commit a6fe79a597
3 files changed
+39 -4

No files matched your search

+2
View File
@@ -46,6 +46,8 @@
#include <xen/cpu.h>
#include <xen/stop_machine.h>
DEFINE_PER_CPU(unsigned int, rcu_lock_cnt);
/* Global control variables for rcupdate callback mechanism. */
static struct rcu_ctrlblk {
long cur; /* Current batch number. */
+3 -1
View File
@@ -31,6 +31,8 @@ static void __do_softirq(unsigned long ignore_mask)
unsigned long pending;
bool rcu_allowed = !(ignore_mask & (1ul << RCU_SOFTIRQ));
ASSERT(!rcu_allowed || rcu_quiesce_allowed());
for ( ; ; )
{
/*
@@ -58,7 +60,7 @@ void process_pending_softirqs(void)
(1ul << SCHED_SLAVE_SOFTIRQ);
/* Block RCU processing in case of rcu_read_lock() held. */
if ( preempt_count() )
if ( !rcu_quiesce_allowed() )
ignore_mask |= 1ul << RCU_SOFTIRQ;
ASSERT(!in_irq() && local_irq_is_enabled());
+34 -3
View File
@@ -32,12 +32,35 @@
#define __XEN_RCUPDATE_H
#include <xen/cache.h>
#include <xen/compiler.h>
#include <xen/spinlock.h>
#include <xen/cpumask.h>
#include <xen/percpu.h>
#include <xen/preempt.h>
#define __rcu
DECLARE_PER_CPU(unsigned int, rcu_lock_cnt);
static inline void rcu_quiesce_disable(void)
{
preempt_disable();
this_cpu(rcu_lock_cnt)++;
barrier();
}
static inline void rcu_quiesce_enable(void)
{
barrier();
this_cpu(rcu_lock_cnt)--;
preempt_enable();
}
static inline bool rcu_quiesce_allowed(void)
{
return !this_cpu(rcu_lock_cnt);
}
/**
* struct rcu_head - callback structure for use with RCU
* @next: next update requests in a list
@@ -91,16 +114,24 @@ typedef struct _rcu_read_lock rcu_read_lock_t;
* will be deferred until the outermost RCU read-side critical section
* completes.
*
* It is illegal to block while in an RCU read-side critical section.
* It is illegal to process softirqs or block while in an RCU read-side
* critical section.
*/
#define rcu_read_lock(x) ({ ((void)(x)); preempt_disable(); })
static inline void rcu_read_lock(rcu_read_lock_t *lock)
{
rcu_quiesce_disable();
}
/**
* rcu_read_unlock - marks the end of an RCU read-side critical section.
*
* See rcu_read_lock() for more information.
*/
#define rcu_read_unlock(x) ({ ((void)(x)); preempt_enable(); })
static inline void rcu_read_unlock(rcu_read_lock_t *lock)
{
ASSERT(!rcu_quiesce_allowed());
rcu_quiesce_enable();
}
/*
* So where is rcu_write_lock()? It does not exist, as there is no
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.