RCU and CONFIG_PREEMPT_RT semi-sane patch
Subsystems (3)
RFC PATCH 1/1 RCU and CONFIG_PREEMPT_RT semi-sane patch
Hello!
The attached patch passed about 36 hours of torture test on each of two 4-CPU x86 machines (about 100 passes through the torture-test script), so am officially declaring it to be semi-sane. That said, on eight runs of kernbench+LTP (also on 4-CPU x86 machines), only six passed, and the other two hung in LTP (but both did make it through five rounds of kernbench). So there are still some problems in there somewhere. The hangs were such that I got no debug info of any sort :-/ , so will be continuing testing.
But this patch might be acceptable to courageous users of the CONFIG_PREEMPT_RT patch who aren't too concerned about SMP performance and scalability. ;-)
The following caveats still apply:
o Still have heavyweight operations in rcu_read_lock() and
rcu_read_unlock(). Will work on removing the atomic_inc() and atomic_dec() first, with the memory barriers later.
o Global callback queues result in poor SMP performance. On
the list to fix. Will likely require handling CPU hotplug (current code is too stupid to need to care about CPU hotplug).
o Grace-period-detection code is probably too aggressive, but will
worry about that later. This will interact with OOM on systems with small memories.
o There are likely still bugs. Which might cause occasional
hangs. ;-)
o Applies against V0.7.51-27 of Ingo's patch.
However, the code (but not the patch) should work in a stock kernel as well as in the CONFIG_PREEMPT_RT environment. Thanks to Steve Rostedt and Bill Huey for their help with this!
Thoughts?
Thanx, Paul
PS. Will be on travel next week, so response time may be a bit slow.
fs/proc/proc_misc.c +37 -0
@@ -599,6 +599,38 @@ void create_seq_entry(char *name, mode_t entry->proc_fops = f; } +#ifdef CONFIG_RCU_STATS +int rcu_read_proc (char *page,char **start,off_t off, +int count,int *eof,void *data) +{ +int len; +extern int rcu_read_proc_data (char *page); + + len =rcu_read_proc_data (page); +return proc_calc_metrics (page, start, off, count, eof, len); +} + +int rcu_read_proc_gp (char *page,char **start,off_t off, +int count,int *eof,void *data) +{ +int len; +extern int rcu_read_proc_gp_data (char *page); + + len =rcu_read_proc_gp_data (page); +return proc_calc_metrics (page, start, off, count, eof, len); +} + +int rcu_read_proc_ptrs (char *page,char **start,off_t off, +int count,int *eof,void *data) +{ +int len; +extern int rcu_read_proc_ptrs_data (char *page); + + len =rcu_read_proc_ptrs_data (page); +return proc_calc_metrics (page, start, off, count, eof, len); +} +#endif /* #ifdef CONFIG_RCU_STATS */ +void __init proc_misc_init (void ) {struct proc_dir_entry *entry;
@@ -621,6 +653,11 @@ void __init proc_misc_init(void) {"cmdline", cmdline_read_proc}, {"locks", locks_read_proc}, {"execdomains", execdomains_read_proc}, +#ifdef CONFIG_RCU_STATS + {"rcustats", rcu_read_proc}, + {"rcugp", rcu_read_proc_gp}, + {"rcuptrs", rcu_read_proc_ptrs}, +#endif /* #ifdef CONFIG_RCU_STATS */ {NULL,} };for (p = simple_ones; p->name; p++)
include/linux/rcupdate.h +25 -2
@@ -59,6 +59,7 @@ struct rcu_head { } while (0) +#ifndef CONFIG_PREEMPT_RCU /* Global control variables for rcupdate callback mechanism. */ struct rcu_ctrlblk {
@@ -209,6 +210,18 @@ static inline int rcu_pending(int cpu)# define rcu_read_unlock preempt_enable#endif +#else /* #ifndef CONFIG_PREEMPT_RCU */ + +#define rcu_qsctr_inc (cpu) +#define rcu_bh_qsctr_inc (cpu) +#define call_rcu_bh (head, rcu) call_rcu(head, rcu) + +extern void rcu_read_lock (void ); +extern void rcu_read_unlock (void ); +extern int rcu_pending (int cpu); + +#endif /* #else #ifndef CONFIG_PREEMPT_RCU */ +/* * So where is rcu_write_lock()? It does not exist, as there is no * way for writers to lock out RCU readers. This is a feature, not
@@ -230,16 +243,22 @@ static inline int rcu_pending(int cpu)* can use just rcu_read_lock(). * */ -//#define rcu_read_lock_bh() local_bh_disable() +#ifndef CONFIG_PREEMPT_RCU +#define rcu_read_lock_bh () local_bh_disable() +#else /* #ifndef CONFIG_PREEMPT_RCU */ #define rcu_read_lock_bh () { rcu_read_lock(); local_bh_disable(); } +#endif /* #else #ifndef CONFIG_PREEMPT_RCU */ /* * rcu_read_unlock_bh - marks the end of a softirq-only RCU critical section * * See rcu_read_lock_bh() for more information. */ -//#define rcu_read_unlock_bh() local_bh_enable() +#ifndef CONFIG_PREEMPT_RCU +#define rcu_read_unlock_bh () local_bh_enable() +#else /* #ifndef CONFIG_PREEMPT_RCU */ #define rcu_read_unlock_bh () { local_bh_enable(); rcu_read_unlock(); } +#endif /* #else #ifndef CONFIG_PREEMPT_RCU */ /** * rcu_dereference - fetch an RCU-protected pointer in an
@@ -288,7 +307,11 @@ static inline int rcu_pending(int cpu)* synchronize_kernel() API. In contrast, synchronize_rcu() only * guarantees that rcu_read_lock() sections will have completed. */ +#ifndef CONFIG_PREEMPT_RCU #define synchronize_sched () synchronize_rcu() +#else /* #ifndef CONFIG_PREEMPT_RCU */ +extern void synchronize_sched (void ); +#endif /* #else #ifndef CONFIG_PREEMPT_RCU */ extern void rcu_init (void );extern void rcu_check_callbacks (int cpu,int user);
include/linux/sched.h +2 -1
@@ -917,7 +917,8 @@ struct task_struct {#endif #ifdef CONFIG_PREEMPT_RCU int rcu_read_lock_nesting; -struct rcu_data *rcu_data; +atomic_t *rcu_flipctr1; +atomic_t *rcu_flipctr2;#endif };
kernel/Kconfig.preempt +14 -1
@@ -127,10 +127,23 @@ config PREEMPT_RCU This option reduces the latency of the kernel by making certain RCU sections preemptible. Normally RCU code is non-preemptible, if this option is selected then read-only RCU sections become - preemptible. This helps latency, but may increase memory utilization. + preemptible. This helps latency, but may expose bugs due to + now-naive assumptions about each RCU read-side critical section + remaining on a given CPU through its execution. Say N if you are unsure. +config RCU_STATS + bool "/proc stats for preemptible RCU read-side critical sections" + depends on PREEMPT_RCU + default y + help + This option provides /proc stats to provide debugging info for + the preemptible realtime RCU implementation. + + Say Y here if you want to see RCU stats in /proc + Say N if you are unsure. + config SPINLOCK_BKL bool "Old-Style Big Kernel Lock" depends on (PREEMPT || SMP) && !PREEMPT_RT
kernel/rcupdate.c +387 -58
475 lines not on this page · raw message