Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a518b76 authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Paul E. McKenney
Browse files

rcu_sync: Add CONFIG_PROVE_RCU checks



This commit validates that the caller of rcu_sync_is_idle() holds the
corresponding type of RCU read-side lock, but only in kernels built
with CONFIG_PROVE_RCU=y.  This validation is carried out via a new
rcu_sync_ops->held() method that is checked within rcu_sync_is_idle().

Note that although this does add code to the fast path, it only does so
in kernels built with CONFIG_PROVE_RCU=y.

Suggested-by: default avatar"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: default avatarJosh Triplett <josh@joshtriplett.org>
parent 82e8c565
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ struct rcu_sync {
	enum rcu_sync_type	gp_type;
};

extern bool __rcu_sync_is_idle(struct rcu_sync *);

/**
 * rcu_sync_is_idle() - Are readers permitted to use their fastpaths?
 * @rsp: Pointer to rcu_sync structure to use for synchronization
@@ -50,7 +52,11 @@ struct rcu_sync {
 */
static inline bool rcu_sync_is_idle(struct rcu_sync *rsp)
{
#ifdef CONFIG_PROVE_RCU
	return __rcu_sync_is_idle(rsp);
#else
	return !rsp->gp_state; /* GP_IDLE */
#endif
}

extern void rcu_sync_init(struct rcu_sync *, enum rcu_sync_type);
+20 −0
Original line number Diff line number Diff line
@@ -23,21 +23,33 @@
#include <linux/rcu_sync.h>
#include <linux/sched.h>

#ifdef CONFIG_PROVE_RCU
#define __INIT_HELD(func)	.held = func,
#else
#define __INIT_HELD(func)
#endif

static const struct {
	void (*sync)(void);
	void (*call)(struct rcu_head *, void (*)(struct rcu_head *));
#ifdef CONFIG_PROVE_RCU
	int  (*held)(void);
#endif
} gp_ops[] = {
	[RCU_SYNC] = {
		.sync = synchronize_rcu,
		.call = call_rcu,
		__INIT_HELD(rcu_read_lock_held)
	},
	[RCU_SCHED_SYNC] = {
		.sync = synchronize_sched,
		.call = call_rcu_sched,
		__INIT_HELD(rcu_read_lock_sched_held)
	},
	[RCU_BH_SYNC] = {
		.sync = synchronize_rcu_bh,
		.call = call_rcu_bh,
		__INIT_HELD(rcu_read_lock_bh_held)
	},
};

@@ -46,6 +58,14 @@ enum { CB_IDLE = 0, CB_PENDING, CB_REPLAY };

#define	rss_lock	gp_wait.lock

#ifdef CONFIG_PROVE_RCU
bool __rcu_sync_is_idle(struct rcu_sync *rsp)
{
	WARN_ON(!gp_ops[rsp->gp_type].held());
	return rsp->gp_state == GP_IDLE;
}
#endif

/**
 * rcu_sync_init() - Initialize an rcu_sync structure
 * @rsp: Pointer to rcu_sync structure to be initialized