* Patch to introduce RCU-bh QS where safe from softirq
@ 2011-10-05 18:45 Paul E. McKenney
2011-10-05 18:59 ` Paul E. McKenney
0 siblings, 1 reply; 2+ messages in thread
From: Paul E. McKenney @ 2011-10-05 18:45 UTC (permalink / raw)
To: tglx; +Cc: linux-rt-users
Hello!
The below patch is a first cut for inserting RCU-bh quiescent states
between successive calls to softirq handlers. This applies on top of
rcu-disable-the-rcu-bh-stuff-for-rt.patch, which implements RCU-bh
in terms of RCU-preempt when CONFIG_PREEMPT_RT_FULL=y.
This patch is probably totally broken, so RFC only.
So, on to scripting running -rt under KVM...
Thanx, Paul
------------------------------------------------------------------------
rcu: Make ksoftirqd do RCU quiescent states
Implementing RCU-bh in terms of RCU-preempt makes the system vulnerable
to network-based denial-of-service attacks. This patch therefore
makes __do_softirq() invoke rcu_bh_qs(), but only when __do_softirq()
is running in ksoftirqd context. A wrapper layer in interposed so that
other calls to __do_softirq() avoid invoking rcu_bh_qs(). The underlying
function __do_softirq_common() does the actual work.
The reason that rcu_bh_qs() is bad in these non-ksoftirqd contexts is
that there might be a local_bh_enable() inside an RCU-preempt read-side
critical section. This local_bh_enable() can invoke __do_softirq()
directly, so if __do_softirq() were to invoke rcu_bh_qs() (which just
calls rcu_preempt_qs() in the PREEMPT_RT_FULL case), there would be
an illegal RCU-preempt quiescent state in the middle of an RCU-preempt
read-side critical section. Therefore, quiescent states can only happen
in cases where __do_softirq() is invoked directly from ksoftirqd.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 8ca18f2..e8dc1d8 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -144,13 +144,7 @@ static inline int rcu_preempt_depth(void)
/* Internal to kernel */
extern void rcu_sched_qs(int cpu);
-
-#ifndef CONFIG_PREEMPT_RT_FULL
extern void rcu_bh_qs(int cpu);
-#else
-static inline void rcu_bh_qs(int cpu) { }
-#endif
-
extern void rcu_check_callbacks(int cpu, int user);
struct notifier_block;
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 3ffcc9d..71341ab 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -166,7 +166,12 @@ void rcu_sched_qs(int cpu)
rdp->passed_quiesc = 1;
}
-#ifndef CONFIG_PREEMPT_RT_FULL
+#ifdef CONFIG_PREEMPT_RT_FULL
+void rcu_bh_qs(int cpu)
+{
+ rcu_preempt_qs(cpu);
+}
+#else
void rcu_bh_qs(int cpu)
{
struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu);
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index 7d91e1b..a8faf16 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -422,6 +422,7 @@ DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data);
/* Forward declarations for rcutree_plugin.h */
static void rcu_bootup_announce(void);
long rcu_batches_completed(void);
+static void rcu_preempt_qs(int cpu);
static void rcu_preempt_note_context_switch(int cpu);
static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp);
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 38549eb..2bc9a23 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -1892,7 +1892,7 @@ EXPORT_SYMBOL_GPL(synchronize_sched_expedited);
#endif /* #else #ifndef CONFIG_SMP */
-#if !defined(CONFIG_RCU_FAST_NO_HZ)
+#if 1 /* !defined(CONFIG_RCU_FAST_NO_HZ) */
/*
* Check to see if any future RCU-related work will need to be done
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 1afd30b..fd27e9b 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -138,7 +138,7 @@ static void wakeup_softirqd(void)
wake_up_process(tsk);
}
-static void handle_pending_softirqs(u32 pending, int cpu)
+static void handle_pending_softirqs(u32 pending, int cpu, int need_rcu_bh_qs)
{
struct softirq_action *h = softirq_vec;
unsigned int prev_count = preempt_count();
@@ -161,7 +161,8 @@ static void handle_pending_softirqs(u32 pending, int cpu)
prev_count, (unsigned int) preempt_count());
preempt_count() = prev_count;
}
- rcu_bh_qs(cpu);
+ if (need_rcu_bh_qs)
+ rcu_bh_qs(cpu);
}
local_irq_disable();
}
@@ -313,7 +314,7 @@ restart:
/* Reset the pending bitmask before enabling irqs */
set_softirq_pending(0);
- handle_pending_softirqs(pending, cpu);
+ handle_pending_softirqs(pending, cpu, 1);
pending = local_softirq_pending();
if (pending && --max_restart)
@@ -383,7 +384,12 @@ static inline void ksoftirqd_clr_sched_params(void) { }
static DEFINE_LOCAL_IRQ_LOCK(local_softirq_lock);
static DEFINE_PER_CPU(struct task_struct *, local_softirq_runner);
-static void __do_softirq(void);
+static void __do_softirq_common(int need_rcu_bh_qs);
+
+void __do_softirq(void)
+{
+ __do_softirq_common(0);
+}
void __init softirq_early_init(void)
{
@@ -446,7 +452,7 @@ int in_serving_softirq(void)
* Called with bh and local interrupts disabled. For full RT cpu must
* be pinned.
*/
-static void __do_softirq(void)
+static void __do_softirq_common(int need_rcu_bh_qs)
{
u32 pending = local_softirq_pending();
int cpu = smp_processor_id();
@@ -460,7 +466,7 @@ static void __do_softirq(void)
lockdep_softirq_enter();
- handle_pending_softirqs(pending, cpu);
+ handle_pending_softirqs(pending, cpu, need_rcu_bh_qs);
pending = local_softirq_pending();
if (pending)
@@ -499,7 +505,7 @@ static int __thread_do_softirq(int cpu)
* schedule!
*/
if (local_softirq_pending())
- __do_softirq();
+ __do_softirq_common(cpu >= 0);
local_unlock(local_softirq_lock);
unpin_current_cpu();
preempt_disable();
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: Patch to introduce RCU-bh QS where safe from softirq
2011-10-05 18:45 Patch to introduce RCU-bh QS where safe from softirq Paul E. McKenney
@ 2011-10-05 18:59 ` Paul E. McKenney
0 siblings, 0 replies; 2+ messages in thread
From: Paul E. McKenney @ 2011-10-05 18:59 UTC (permalink / raw)
To: tglx; +Cc: linux-rt-users
On Wed, Oct 05, 2011 at 11:45:18AM -0700, Paul E. McKenney wrote:
> Hello!
>
> The below patch is a first cut for inserting RCU-bh quiescent states
> between successive calls to softirq handlers. This applies on top of
> rcu-disable-the-rcu-bh-stuff-for-rt.patch, which implements RCU-bh
> in terms of RCU-preempt when CONFIG_PREEMPT_RT_FULL=y.
>
> This patch is probably totally broken, so RFC only.
>
> So, on to scripting running -rt under KVM...
And here is a version of rcu-disable-the-rcu-bh-stuff-for-rt.patch
with an updated changelog.
Thanx, Paul
------------------------------------------------------------------------
rcu: Merge RCU-bh into RCU-preempt
The Linux kernel has long RCU-bh read-side critical sections that
intolerably increase scheduling latency under mainline's RCU-bh rules,
which include RCU-bh read-side critical sections being non-preemptible.
This patch therefore arranges for RCU-bh to be implemented in terms of
RCU-preempt for CONFIG_PREEMPT_RT_FULL=y.
This has the downside of defeating the purpose of RCU-bh, namely,
handling the case where the system is subjected to a network-based
denial-of-service attack that keeps at least one CPU doing full-time
softirq processing. This issue will be fixed by a later commit.
The current commit will need some work to make it appropriate for
mainline use, for example, it needs to be extended to cover Tiny RCU.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index e8f9d18..8ca18f2 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -78,7 +78,13 @@ struct rcu_head {
extern void call_rcu_sched(struct rcu_head *head,
void (*func)(struct rcu_head *rcu));
extern void synchronize_sched(void);
+
+#ifdef CONFIG_PREEMPT_RT_FULL
+# define rcu_barrier_bh rcu_barrier
+#else
extern void rcu_barrier_bh(void);
+#endif
+
extern void rcu_barrier_sched(void);
static inline void __rcu_read_lock_bh(void)
@@ -138,7 +144,13 @@ static inline int rcu_preempt_depth(void)
/* Internal to kernel */
extern void rcu_sched_qs(int cpu);
+
+#ifndef CONFIG_PREEMPT_RT_FULL
extern void rcu_bh_qs(int cpu);
+#else
+static inline void rcu_bh_qs(int cpu) { }
+#endif
+
extern void rcu_check_callbacks(int cpu, int user);
struct notifier_block;
@@ -229,7 +241,14 @@ static inline int rcu_read_lock_held(void)
* rcu_read_lock_bh_held() is defined out of line to avoid #include-file
* hell.
*/
+#ifdef CONFIG_PREEMPT_RT_FULL
+static inline int rcu_read_lock_bh_held(void)
+{
+ return rcu_read_lock_held();
+}
+#else
extern int rcu_read_lock_bh_held(void);
+#endif
/**
* rcu_read_lock_sched_held() - might we be in RCU-sched read-side critical section?
@@ -638,8 +657,13 @@ static inline void rcu_read_unlock(void)
static inline void rcu_read_lock_bh(void)
{
__rcu_read_lock_bh();
+
+#ifdef CONFIG_PREEMPT_RT_FULL
+ rcu_read_lock();
+#else
__acquire(RCU_BH);
rcu_read_acquire_bh();
+#endif
}
/*
@@ -649,8 +673,12 @@ static inline void rcu_read_lock_bh(void)
*/
static inline void rcu_read_unlock_bh(void)
{
+#ifdef CONFIG_PREEMPT_RT_FULL
+ rcu_read_unlock();
+#else
rcu_read_release_bh();
__release(RCU_BH);
+#endif
__rcu_read_unlock_bh();
}
@@ -757,6 +785,9 @@ extern void call_rcu(struct rcu_head *head,
#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
+#ifdef CONFIG_PREEMPT_RT_FULL
+#define call_rcu_bh call_rcu
+#else
/**
* call_rcu_bh() - Queue an RCU for invocation after a quicker grace period.
* @head: structure to be used for queueing the RCU updates.
@@ -777,6 +808,7 @@ extern void call_rcu(struct rcu_head *head,
*/
extern void call_rcu_bh(struct rcu_head *head,
void (*func)(struct rcu_head *head));
+#endif
/*
* debug_rcu_head_queue()/debug_rcu_head_unqueue() are used internally
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index e65d066..7a25aea 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -57,7 +57,11 @@ static inline void exit_rcu(void)
#endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */
+#ifndef CONFIG_PREEMPT_RT_FULL
extern void synchronize_rcu_bh(void);
+#else
+# define synchronize_rcu_bh() synchronize_rcu()
+#endif
extern void synchronize_sched_expedited(void);
extern void synchronize_rcu_expedited(void);
@@ -71,13 +75,19 @@ extern void rcu_barrier(void);
extern unsigned long rcutorture_testseq;
extern unsigned long rcutorture_vernum;
extern long rcu_batches_completed(void);
-extern long rcu_batches_completed_bh(void);
extern long rcu_batches_completed_sched(void);
extern void rcu_force_quiescent_state(void);
-extern void rcu_bh_force_quiescent_state(void);
extern void rcu_sched_force_quiescent_state(void);
+#ifndef CONFIG_PREEMPT_RT_FULL
+extern void rcu_bh_force_quiescent_state(void);
+extern long rcu_batches_completed_bh(void);
+#else
+# define rcu_bh_force_quiescent_state rcu_force_quiescent_state
+# define rcu_batches_completed_bh rcu_batches_completed
+#endif
+
/* A context switch is a grace period for RCU-sched and RCU-bh. */
static inline int rcu_blocking_is_gp(void)
{
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 7784bd2..5e0577b 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -72,6 +72,7 @@ int debug_lockdep_rcu_enabled(void)
}
EXPORT_SYMBOL_GPL(debug_lockdep_rcu_enabled);
+#ifndef CONFIG_PREEMPT_RT_FULL
/**
* rcu_read_lock_bh_held() - might we be in RCU-bh read-side critical section?
*
@@ -91,6 +92,7 @@ int rcu_read_lock_bh_held(void)
return in_softirq() || irqs_disabled();
}
EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held);
+#endif
#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 4151bfc..3ffcc9d 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -166,6 +166,7 @@ void rcu_sched_qs(int cpu)
rdp->passed_quiesc = 1;
}
+#ifndef CONFIG_PREEMPT_RT_FULL
void rcu_bh_qs(int cpu)
{
struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu);
@@ -174,6 +175,7 @@ void rcu_bh_qs(int cpu)
barrier();
rdp->passed_quiesc = 1;
}
+#endif
/*
* Note a context switch. This is a quiescent state for RCU-sched,
@@ -216,6 +218,7 @@ long rcu_batches_completed_sched(void)
}
EXPORT_SYMBOL_GPL(rcu_batches_completed_sched);
+#ifndef CONFIG_PREEMPT_RT_FULL
/*
* Return the number of RCU BH batches processed thus far for debug & stats.
*/
@@ -233,6 +236,7 @@ void rcu_bh_force_quiescent_state(void)
force_quiescent_state(&rcu_bh_state, 0);
}
EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state);
+#endif
/*
* Record the number of times rcutorture tests have been initiated and
@@ -1579,6 +1583,7 @@ void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
}
EXPORT_SYMBOL_GPL(call_rcu_sched);
+#ifndef CONFIG_PREEMPT_RT_FULL
/*
* Queue an RCU for invocation after a quicker grace period.
*/
@@ -1587,6 +1592,7 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
__call_rcu(head, func, &rcu_bh_state);
}
EXPORT_SYMBOL_GPL(call_rcu_bh);
+#endif
/**
* synchronize_sched - wait until an rcu-sched grace period has elapsed.
@@ -1628,6 +1634,7 @@ void synchronize_sched(void)
}
EXPORT_SYMBOL_GPL(synchronize_sched);
+#ifndef CONFIG_PREEMPT_RT_FULL
/**
* synchronize_rcu_bh - wait until an rcu_bh grace period has elapsed.
*
@@ -1653,6 +1660,7 @@ void synchronize_rcu_bh(void)
destroy_rcu_head_on_stack(&rcu.head);
}
EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
+#endif
/*
* Check to see if there is any immediate RCU-related work to be done
@@ -1806,6 +1814,7 @@ static void _rcu_barrier(struct rcu_state *rsp,
mutex_unlock(&rcu_barrier_mutex);
}
+#ifndef CONFIG_PREEMPT_RT_FULL
/**
* rcu_barrier_bh - Wait until all in-flight call_rcu_bh() callbacks complete.
*/
@@ -1814,6 +1823,7 @@ void rcu_barrier_bh(void)
_rcu_barrier(&rcu_bh_state, call_rcu_bh);
}
EXPORT_SYMBOL_GPL(rcu_barrier_bh);
+#endif
/**
* rcu_barrier_sched - Wait for in-flight call_rcu_sched() callbacks.
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2011-10-05 18:59 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-05 18:45 Patch to introduce RCU-bh QS where safe from softirq Paul E. McKenney
2011-10-05 18:59 ` Paul E. McKenney
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.