Additional RCU commits queued for 2.6.37
Subsystems (5)
PATCH 1/1 Additional RCU commits queued for 2.6.37
Hello!
This patchset shows additional patches queued for 2.6.37, over and above those posted at http://lkml.org/lkml/2010/7/14/334. These are all minor fixes, with the exception of patch #8, which adds TINY_PREEMPT_RCU. The patches are as follows:
1. Remove the rcu_head initialization macros (from Mathieu Desnoyers).
This patch can move forward now that all uses of these macros have been removed from mainline.
2. Update documentation to note the demise of the rcu_head
initialization macros.
3. Fix kernel-locking.tmpl docbook documentation, which was still
using the now-ancient three-argument version of call_rcu().
4. Allow RCU's CPU stall-warning messages to be controlled via sysfs.
5. Now that TINY_RCU has been in-tree for a few releases, adjust
the configuration so that TINY_RCU is mandatory for kernels built with !SMP and !PREEMPT. Once TINY_PREEMPT_RCU has gained a similar level of experience, !SMP code will be eliminated from TREE_RCU.
6. Allow kernels to be built such that RCU CPU stall warnings are
suppressed at boot time. Patch #4 above allows them to be manually re-enabled once the system has booted.
7. Updates the RCU_FANOUT message to take commit cf244dc01bf68 into
account. This commit added a fourth level to TREE_RCU.
8. Add TINY_PREEMPT_RCU, allowing reduced memory footprint for
UP builds of preemptible RCU. This is a cleaned-up version of the patch posted at http://lkml.org/lkml/2010/7/21/364.
9. The "It is illegal to block while in an RCU read-side critical
section" docbook comment was obsoleted long ago by preemptible RCU, so this patch brings it up to the present day.
10. Add comments above the RCU CPU stall-warning printk()s pointing
people at the Documentation/RCU/stallwarn.txt documentation.
For a testing-only version of this patchset from git, please see:
git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-2.6-rcu.git rcu/testing
Thanx, Paul
Documentation/DocBook/kernel-locking.tmpl | 6 b/Documentation/DocBook/kernel-locking.tmpl | 8 b/include/linux/hardirq.h | 2 b/include/linux/init_task.h | 10 b/include/linux/rcupdate.h | 6 b/include/linux/rcutiny.h | 126 ++++-- b/include/linux/rcutree.h | 2 b/include/linux/sched.h | 10 b/init/Kconfig | 1 b/kernel/Makefile | 1 b/kernel/rcutiny.c | 33 - b/kernel/rcutiny_plugin.h | 580 +++++++++++++++++++++++++++- b/kernel/rcutree.c | 2 b/kernel/rcutree.h | 6 b/lib/Kconfig.debug | 13 include/linux/rcupdate.h | 18 init/Kconfig | 25 + kernel/rcutree.c | 14 18 files changed, 771 insertions(+), 92 deletions(-)
PATCH 1/10 rcu head remove init
From: Mathieu Desnoyers <[email protected]>
RCU heads really don't need to be initialized. Their state before call_rcu() really does not matter.
We need to keep init/destroy_rcu_head_on_stack() though, since we want debugobjects to be able to keep track of these objects.
--- include/linux/rcupdate.h | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-)
include/linux/rcupdate.h +0 -6
@@ -75,12 +75,6 @@ extern void rcu_init(void);#error "Unknown RCU implementation specified to kernel configuration"#endif -#define RCU_HEAD_INIT { .next = NULL, .func = NULL } -#define RCU_HEAD (head) struct rcu_head head = RCU_HEAD_INIT -#define INIT_RCU_HEAD (ptr) do { \ - (ptr)->next = NULL; (ptr)->func = NULL; \ -} while (0) -/* * init_rcu_head_on_stack()/destroy_rcu_head_on_stack() are needed for dynamic * initialization and destruction of rcu_head on the stack. rcu_head structures
Signature · 1 line
1.7.0.6
PATCH 2/10 Update documentation to note the passage of INIT_RCU_HEAD()
In reply to Paul E. McKenney--- Documentation/DocBook/kernel-locking.tmpl | 8 -------- 1 files changed, 0 insertions(+), 8 deletions(-)
Documentation/DocBook/kernel-locking.tmpl +0 -8
@@ -1725,14 +1725,6 @@ the amount of locking which needs to be done. if (++cache_num > MAX_CACHE_SIZE) { struct object *i, *outcast = NULL; list_for_each_entry(i, &cache, list) { -@@ -85,6 +94,7 @@ - obj->popularity = 0; - atomic_set(&obj->refcnt, 1); /* The cache holds a reference */ - spin_lock_init(&obj->lock); -+ INIT_RCU_HEAD(&obj->rcu); - - spin_lock_irqsave(&cache_lock, flags); - __cache_add(obj); @@ -104,12 +114,11 @@ struct object *cache_find(int id) {
Signature · 1 line
1.7.0.6
PATCH 3/10 Update call_rcu() usage, add synchronize_rcu()
In reply to Paul E. McKenney--- Documentation/DocBook/kernel-locking.tmpl | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-)
Documentation/DocBook/kernel-locking.tmpl +4 -2
@@ -1645,7 +1645,9 @@ the amount of locking which needs to be done. all the readers who were traversing the list when we deleted the element are finished. We use <function>call_rcu()</function> to register a callback which will actually destroy the object once - the readers are finished. + all pre-existing readers are finished. Alternatively, + <function>synchronize_rcu()</function> may be used to block until + all pre-existing are finished. </para> <para> But how does Read Copy Update know when the readers are
@@ -1714,7 +1716,7 @@ the amount of locking which needs to be done. - object_put(obj); + list_del_rcu(&obj->list); cache_num--; -+ call_rcu(&obj->rcu, cache_delete_rcu, obj); ++ call_rcu(&obj->rcu, cache_delete_rcu); } /* Must be holding cache_lock */
Signature · 1 line
1.7.0.6
PATCH 4/10 rcu: allow RCU CPU stall warning messages to be controlled in /sys
In reply to Paul E. McKenneySet the permissions of the rcu_cpu_stall_suppress to 644 to enable RCU CPU stall warnings to be enabled and disabled at runtime via sysfs.
--- kernel/rcutree.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
kernel/rcutree.c +1 -1
@@ -145,7 +145,7 @@ module_param(qlowmark, int, 0);#ifdef CONFIG_RCU_CPU_STALL_DETECTOR int rcu_cpu_stall_suppress__read_mostly ; -module_param (rcu_cpu_stall_suppress, int,0 ); +module_param (rcu_cpu_stall_suppress, int,0644 );#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ static void force_quiescent_state (struct rcu_state *rsp,int relaxed);
Signature · 1 line
1.7.0.6
PATCH 5/10 rcu: restrict TREE_RCU to SMP builds with !PREEMPT
In reply to Paul E. McKenneyBecause both TINY_RCU and TREE_PREEMPT_RCU have been in mainline for several releases, it is time to restrict the use of TREE_RCU to SMP non-preemptible systems. This reduces testing/validation effort. This commit is a first step towards driving the selection of RCU implementation directly off of the SMP and PREEMPT configuration parameters.
--- init/Kconfig | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
init/Kconfig +1 -0
@@ -336,6 +336,7 @@ choice config TREE_RCU bool "Tree-based hierarchical RCU" + depends on !PREEMPT && SMP help This option selects the RCU implementation that is designed for very large SMP system with hundreds or
Signature · 1 line
1.7.0.6
PATCH 6/10 rcu: Allow RCU CPU stall warnings to be off at boot, but manually enablable
In reply to Paul E. McKenneyCurrently, if RCU CPU stall warnings are enabled, they are enabled immediately upon boot. They can be manually disabled via /sys (and also re-enabled via /sys), and are automatically disabled upon panic. However, some users need RCU CPU stalls to be disabled at boot time, but to be enabled without rebuilding/rebooting. For example, someone running a real-time application in production might not want the additional latency of RCU CPU stall detection in normal operation, but might need to enable it at any point for fault isolation purposes.
This commit therefore provides a new CONFIG_RCU_CPU_STALL_DETECTOR_RUNNABLE kernel configuration parameter that maintains the current behavior (enable at boot) by default, but allows a kernel to be configured with RCU CPU stall detection built into the kernel, but disabled at boot time.
--- kernel/rcutree.c | 2 +- kernel/rcutree.h | 6 ++++++ lib/Kconfig.debug | 13 +++++++++++++ 3 files changed, 20 insertions(+), 1 deletions(-)
kernel/rcutree.c +1 -1
@@ -144,7 +144,7 @@ module_param(qhimark, int, 0);module_param (qlowmark, int,0 );#ifdef CONFIG_RCU_CPU_STALL_DETECTOR -int rcu_cpu_stall_suppress__read_mostly ; +int rcu_cpu_stall_suppress__read_mostly =RCU_CPU_STALL_SUPPRESS_INIT ;module_param (rcu_cpu_stall_suppress, int,0644 );#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
kernel/rcutree.h +6 -0
@@ -264,6 +264,12 @@ struct rcu_data {/* scheduling clock irq */ /* before ratting on them. */ +#ifdef CONFIG_RCU_CPU_STALL_DETECTOR_RUNNABLE +#define RCU_CPU_STALL_SUPPRESS_INIT 0 +#else +#define RCU_CPU_STALL_SUPPRESS_INIT 1 +#endif +#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ #define ULONG_CMP_GE (a, b) (ULONG_MAX / 2 >= (a) - (b))
lib/Kconfig.debug +13 -0
@@ -832,6 +832,19 @@ config RCU_CPU_STALL_TIMEOUT RCU grace period persists, additional CPU stall warnings are printed at more widely spaced intervals. +config RCU_CPU_STALL_DETECTOR_RUNNABLE + bool "RCU CPU stall checking starts automatically at boot" + depends on RCU_CPU_STALL_DETECTOR + default y + help + If set, start checking for RCU CPU stalls immediately on + boot. Otherwise, RCU CPU stall checking must be manually + enabled. + + Say Y if you are unsure. + + Say N if you wish to suppress RCU CPU stall checking during boot. + config RCU_CPU_STALL_VERBOSE bool "Print additional per-task information for RCU_CPU_STALL_DETECTOR" depends on RCU_CPU_STALL_DETECTOR && TREE_PREEMPT_RCU
Signature · 1 line
1.7.0.6
PATCH 7/10 rcu: Fix RCU_FANOUT help message
In reply to Paul E. McKenneyCommit cf244dc01bf68 added a fourth level to the TREE_RCU hierarchy, but the RCU_FANOUT help message still said "cube root". This commit fixes this to "fourth root" and also emphasizes that production systems are well-served by the default. (Stress-testing RCU itself uses small RCU_FANOUT values in order to test large-system code paths on small(er) systems.)
--- init/Kconfig | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-)
init/Kconfig +6 -3
@@ -384,9 +384,12 @@ config RCU_FANOUT help This option controls the fanout of hierarchical implementations of RCU, allowing RCU to work efficiently on machines with - large numbers of CPUs. This value must be at least the cube - root of NR_CPUS, which allows NR_CPUS up to 32,768 for 32-bit - systems and up to 262,144 for 64-bit systems. + large numbers of CPUs. This value must be at least the fourth + root of NR_CPUS, which allows NR_CPUS to be insanely large. + The default value of RCU_FANOUT should be used for production + systems, but if you are stress-testing the RCU implementation + itself, small RCU_FANOUT values allow you to test large-system + code paths on small(er) systems. Select a specific number if testing RCU itself. Take the default if unsure.
Signature · 1 line
1.7.0.6
PATCH 8/10 rcu: Add a TINY_PREEMPT_RCU
In reply to Paul E. McKenneyImplement a small-memory-footprint uniprocessor-only implementation of preemptible RCU. This implementation uses but a single blocked-tasks list rather than the combinatorial number used per leaf rcu_node by TREE_PREEMPT_RCU, which reduces memory consumption and greatly simplifies processing. This version also takes advantage of uniprocessor execution to accelerate grace periods in the case where there are no readers.
The general design is otherwise broadly similar to that of TREE_PREEMPT_RCU.
This implementation is a step towards having RCU implementation driven off of the SMP and PREEMPT kernel configuration variables, which can happen once this implementation has accumulated sufficient experience.
--- include/linux/hardirq.h | 2 +- include/linux/init_task.h | 10 +- include/linux/rcupdate.h | 3 +- include/linux/rcutiny.h | 126 +++++++--- include/linux/rcutree.h | 2 + include/linux/sched.h | 10 +- init/Kconfig | 16 ++- kernel/Makefile | 1 + kernel/rcutiny.c | 33 +-- kernel/rcutiny_plugin.h | 580 ++++++++++++++++++++++++++++++++++++++++++++- 10 files changed, 715 insertions(+), 68 deletions(-)
include/linux/hardirq.h +1 -1
@@ -139,7 +139,7 @@ static inline void account_system_vtime(struct task_struct *tsk)#endif #if defined(CONFIG_NO_HZ ) -#if defined(CONFIG_TINY_RCU ) +#if defined(CONFIG_TINY_RCU ) || defined(CONFIG_TINY_PREEMPT_RCU )extern void rcu_enter_nohz (void );extern void rcu_exit_nohz (void );
include/linux/init_task.h +8 -2
@@ -82,11 +82,17 @@ extern struct group_info init_groups;# define CAP_INIT_BSET CAP_FULL_SET#ifdef CONFIG_TREE_PREEMPT_RCU +#define INIT_TASK_RCU_TREE_PREEMPT () \ + .rcu_blocked_node = NULL, +#else +#define INIT_TASK_RCU_TREE_PREEMPT (tsk) +#endif +#ifdef CONFIG_PREEMPT_RCU #define INIT_TASK_RCU_PREEMPT (tsk) \ .rcu_read_lock_nesting = 0, \ .rcu_read_unlock_special = 0, \ - .rcu_blocked_node = NULL, \ - .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), + .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), \ + INIT_TASK_RCU_TREE_PREEMPT()#else #define INIT_TASK_RCU_PREEMPT (tsk)#endif
include/linux/rcupdate.h +1 -2
@@ -58,7 +58,6 @@ struct rcu_head { };/* Exported common interfaces */ -extern void rcu_barrier (void );extern void rcu_barrier_bh (void );extern void rcu_barrier_sched (void );extern void synchronize_sched_expedited (void );
@@ -69,7 +68,7 @@ extern void rcu_init(void);#if defined(CONFIG_TREE_RCU ) || defined(CONFIG_TREE_PREEMPT_RCU )#include <linux/rcutree.h> -#elif defined(CONFIG_TINY_RCU ) +#elif defined(CONFIG_TINY_RCU ) || defined(CONFIG_TINY_PREEMPT_RCU )#include <linux/rcutiny.h> #else #error "Unknown RCU implementation specified to kernel configuration"
include/linux/rcutiny.h +89 -37
170 lines not on this page · raw message
include/linux/rcutree.h +2 -0
@@ -95,6 +95,8 @@ static inline void synchronize_rcu_bh_expedited(void)synchronize_sched_expedited (); } +extern void rcu_barrier (void ); +extern void rcu_check_callbacks (int cpu,int user);extern long rcu_batches_completed (void );
include/linux/sched.h +7 -3
@@ -1211,11 +1211,13 @@ struct task_struct {unsigned int policy;cpumask_t cpus_allowed; -#ifdef CONFIG_TREE_PREEMPT_RCU +#ifdef CONFIG_PREEMPT_RCU int rcu_read_lock_nesting;char rcu_read_unlock_special; -struct rcu_node *rcu_blocked_node;struct list_head rcu_node_entry; +#endif /* #ifdef CONFIG_PREEMPT_RCU */ +#ifdef CONFIG_TREE_PREEMPT_RCU +struct rcu_node *rcu_blocked_node;#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ #if defined(CONFIG_SCHEDSTATS ) || defined(CONFIG_TASK_DELAY_ACCT )
@@ -1748,7 +1750,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *#define tsk_used_math (p) ((p)->flags & PF_USED_MATH)#define used_math () tsk_used_math(current) -#ifdef CONFIG_TREE_PREEMPT_RCU +#ifdef CONFIG_PREEMPT_RCU #define RCU_READ_UNLOCK_BLOCKED (1 << 0)/* blocked while in RCU read-side. */ #define RCU_READ_UNLOCK_NEED_QS (1 << 1)/* RCU core needs CPU response. */
@@ -1757,7 +1759,9 @@ static inline void rcu_copy_process(struct task_struct *p) { p->rcu_read_lock_nesting =0 ; p->rcu_read_unlock_special =0 ; +#ifdef CONFIG_TREE_PREEMPT_RCU p->rcu_blocked_node =NULL ; +#endif INIT_LIST_HEAD (&p->rcu_node_entry); }
init/Kconfig +15 -1
@@ -344,7 +344,7 @@ config TREE_RCU smaller systems. config TREE_PREEMPT_RCU - bool "Preemptable tree-based hierarchical RCU" + bool "Preemptible tree-based hierarchical RCU" depends on PREEMPT help This option selects the RCU implementation that is
@@ -362,8 +362,22 @@ config TINY_RCU is not required. This option greatly reduces the memory footprint of RCU. +config TINY_PREEMPT_RCU + bool "Preemptible UP-only small-memory-footprint RCU" + depends on !SMP && PREEMPT + help + This option selects the RCU implementation that is designed + for real-time UP systems. This option greatly reduces the + memory footprint of RCU. + endchoice +config PREEMPT_RCU + def_bool ( TREE_PREEMPT_RCU || TINY_PREEMPT_RCU ) + help + This option enables preemptible-RCU code that is common between + the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations. + config RCU_TRACE bool "Enable tracing for RCU" depends on TREE_RCU || TREE_PREEMPT_RCU
kernel/Makefile +1 -0
@@ -85,6 +85,7 @@ obj-$(CONFIG_TREE_RCU) += rcutree.o obj-$(CONFIG_TREE_PREEMPT_RCU) += rcutree.o obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o obj-$(CONFIG_TINY_RCU) += rcutiny.o +obj-$(CONFIG_TINY_PREEMPT_RCU) += rcutiny.o obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_SYSCTL) += utsname_sysctl.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
kernel/rcutiny.c +14 -19
@@ -59,6 +59,14 @@ int rcu_scheduler_active __read_mostly;EXPORT_SYMBOL_GPL (rcu_scheduler_active);#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +/* Forward declarations for rcutiny_plugin.h. */ +static void __rcu_process_callbacks (struct rcu_ctrlblk *rcp); +static void __call_rcu (struct rcu_head *head, +void (*func)(struct rcu_head *rcu), +struct rcu_ctrlblk *rcp); + +#include "rcutiny_plugin.h" +#ifdef CONFIG_NO_HZ static long rcu_dynticks_nesting =1 ;
@@ -140,6 +148,7 @@ void rcu_check_callbacks(int cpu, int user)rcu_sched_qs (cpu); else if (!in_softirq()) rcu_bh_qs(cpu); +rcu_preempt_check_callbacks (); }/*
@@ -162,6 +171,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) *rcp->donetail =NULL ;if (rcp->curtail == rcp->donetail) rcp->curtail = &rcp->rcucblist; +rcu_preempt_remove_callbacks (rcp); rcp->donetail = &rcp->rcucblist;local_irq_restore (flags);
@@ -182,6 +192,7 @@ static void rcu_process_callbacks(struct softirq_action *unused) {__rcu_process_callbacks (&rcu_sched_ctrlblk);__rcu_process_callbacks (&rcu_bh_ctrlblk); +rcu_preempt_process_callbacks (); }/*
@@ -223,15 +234,15 @@ static void __call_rcu(struct rcu_head *head, }/* -* Post an RCU callback to be invoked after the end of an RCU grace +* Post an RCU callback to be invoked after the end of an RCU-sched grace * period. But since we have but one CPU, that would be after any * quiescent state. */ -void call_rcu (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) +void call_rcu_sched (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) {__call_rcu (head, func, &rcu_sched_ctrlblk); } -EXPORT_SYMBOL_GPL (call_rcu); +EXPORT_SYMBOL_GPL (call_rcu_sched);/* * Post an RCU bottom-half callback to be invoked after any subsequent
@@ -243,20 +254,6 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) }EXPORT_SYMBOL_GPL (call_rcu_bh); -void rcu_barrier (void ) -{ -struct rcu_synchronize rcu; - -init_rcu_head_on_stack (&rcu.head); -init_completion (&rcu.completion); -/* Will wake me after RCU finished. */ -call_rcu (&rcu.head, wakeme_after_rcu); -/* Wait for it. */ -wait_for_completion (&rcu.completion); -destroy_rcu_head_on_stack (&rcu.head); -} -EXPORT_SYMBOL_GPL (rcu_barrier); -void rcu_barrier_bh (void ) {struct rcu_synchronize rcu;
@@ -289,5 +286,3 @@ void __init rcu_init(void) {open_softirq (RCU_SOFTIRQ , rcu_process_callbacks); } - -#include "rcutiny_plugin.h"
kernel/rcutiny_plugin.h +577 -3
595 lines not on this page · raw message
Signature · 1 line
1.7.0.6
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
* Paul E. McKenney ([email protected]) wrote:
[...]
Quoted 5 lines
kernel/rcutiny_plugin.h +5
-0+ +/* +* Tiny-preemptible RCU implementation for rcu_read_unlock(). +* Decrement ->rcu_read_lock_nesting. If the result is zero (outermost +* rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then
kernel/rcutiny_plugin.h line 354
Quoted 10 lines
kernel/rcutiny_plugin.h +10
-0+* invoke rcu_read_unlock_special() to clean up after a context switch +* in an RCU read-side critical section and other special cases. +*/ +void __rcu_read_unlock (void ) +{ +struct task_struct *t = current; + +barrier ();/* needed if we ever invoke rcu_read_unlock in rcutiny.c */ +if (--t->rcu_read_lock_nesting ==0 && +unlikely (t->rcu_read_unlock_special))
Hrm I think we discussed this in a past life, but would the following sequence be possible and correct ?
CPU 0
read t->rcu_read_unlock_special
interrupt comes in, preempts. sets t->rcu_read_unlock_special <preempted>
<scheduled back>
iret
decrement and read t->rcu_read_lock_nesting
test both old "special" value (which we have locally on the stack) and detect that rcu_read_lock_nesting is 0.
We actually missed a reschedule.
I think we might need a barrier() between the t->rcu_read_lock_nesting and t->rcu_read_unlock_special reads. We might need to audit TREE PREEMPT RCU for the same kind of behavior.
But I might be (again ?) missing something. I've got the feeling you already convinced me that this was OK for some reason, but I trip on this every time I read the code.
[...]
Quoted 6 lines
kernel/rcutiny_plugin.h +6
-0+/* +* Check for a task exiting while in a preemptible -RCU read-side +* critical section, clean up if so. No need to issue warnings, +* as debug_check_no_locks_held() already does this if lockdep +* is enabled. +*/
kernel/rcutiny_plugin.h line 570
Quoted 10 lines
kernel/rcutiny_plugin.h +10
-0+void exit_rcu (void ) +{ +struct task_struct *t = current; + +if (t->rcu_read_lock_nesting ==0 ) +return ; + t->rcu_read_lock_nesting =1 ; +rcu_read_unlock (); +} +
The interaction with preemption is unclear here. exit.c disables preemption around the call to exit_rcu(), but if, for some reason, rcu_read_unlock_special was set earlier by preemption, then the rcu_read_unlock() code might block and cause problems.
Maybe we should consider clearing rcu_read_unlock_special here ?
Thanks,
Mathieu
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 17 lines · Mathieu Desnoyers
* Paul E. McKenney ([email protected]) wrote:
[...]Quoted 5 lines
kernel/rcutiny_plugin.h +5
-0+ +/* +* Tiny-preemptible RCU implementation for rcu_read_unlock(). +* Decrement ->rcu_read_lock_nesting. If the result is zero (outermost +* rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then kernel/rcutiny_plugin.h line 354
Quoted 10 lines
kernel/rcutiny_plugin.h +10
-0+* invoke rcu_read_unlock_special() to clean up after a context switch +* in an RCU read-side critical section and other special cases. +*/ +void __rcu_read_unlock (void ) +{ +struct task_struct *t = current; + +barrier ();/* needed if we ever invoke rcu_read_unlock in rcutiny.c */ +if (--t->rcu_read_lock_nesting ==0 && +unlikely (t->rcu_read_unlock_special))
First, thank you for looking this over!!!
Quoted 14 lines
Hrm I think we discussed this in a past life, but would the following sequence be possible and correct ?
CPU 0
read
t->rcu_read_unlock_special
interrupt comes in, preempts. setst->rcu_read_unlock_special<preempted>
<scheduled back>
iret
decrement and readt->rcu_read_lock_nesting
test both old "special" value (which we have locally on the stack) and detect thatrcu_read_lock_nestingis 0.
Quoted 4 lines
We actually missed a reschedule.
I think we might need a
barrier()between thet->rcu_read_lock_nestingandt->rcu_read_unlock_specialreads.
You are correct -- I got too aggressive in eliminating synchronization.
Good catch!!!
I added an ACCESS_ONCE() to the second term of the "if" condition so that it now reads:
if (--t->rcu_read_lock_nesting == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))
This prevents the compiler from reordering because the ACCESS_ONCE() prohibits accessing t->rcu_read_unlock_special unless the value of t->rcu_read_lock_nesting is known to be zero.
Quoted 2 lines
We might need to audit
TREE PREEMPT RCU for the same kind of behavior.
The version of __rcu_read_unlock() in kernel/rcutree_plugin.h is as follows:
void __rcu_read_unlock(void)
{
struct task_struct *t = current;
barrier(); /* needed if we ever invoke rcu_read_unlock in rcutree.c */
if (--ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 &&
unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
rcu_read_unlock_special(t);
#ifdef CONFIG_PROVE_LOCKING
WARN_ON_ONCE(ACCESS_ONCE(t->rcu_read_lock_nesting) < 0);#endif /* #ifdef CONFIG_PROVE_LOCKING */
}
The ACCESS_ONCE() calls should cover this. I believe that the first ACCESS_ONCE() is redundant, and have checking this more closely on my todo list.
Quoted 19 lines
But I might be (again ?) missing something. I've got the feeling you already convinced me that this was OK for some reason, but I trip on this every time I read the code.
[...]
Quoted 13 lines
kernel/rcutiny_plugin.h +13
-0+/* +* Check for a task exiting while in a preemptible -RCU read-side +* critical section, clean up if so. No need to issue warnings, +* as debug_check_no_locks_held() already does this if lockdep +* is enabled. +*/ +void exit_rcu (void ) +{ +struct task_struct *t = current; + +if (t->rcu_read_lock_nesting ==0 ) +return ; + t->rcu_read_lock_nesting =1 ;
Quoted 8 lines
kernel/rcutiny_plugin.h line 570
Quoted 3 lines
kernel/rcutiny_plugin.h +3
-0+rcu_read_unlock (); +} +The interaction with preemption is unclear here.
exit.cdisables preemption around the call toexit_rcu(), but if, for some reason,rcu_read_unlock_specialwas set earlier by preemption, then thercu_read_unlock()code might block and cause problems.
But rcu_read_unlock_special() does not block. In fact, it disables interrupts over almost all of its execution. Or am I missing some subtlety here?
Quoted 1 line
Maybe we should consider clearing
rcu_read_unlock_specialhere ?
If the task blocked in an RCU read-side critical section just before exit_rcu() was called, we need to remove the task from the ->blkd_tasks list. If we fail to do so, we might get a segfault later on. Also, we do need to handle any RCU_READ_UNLOCK_NEED_QS requests from the RCU core.
So I really do like the current approach of calling rcu_read_unlock() to do this sort of cleanup.
Thanx, Paul
Quoted 14 lines
Thanks,
Mathieu
Signature · 9 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 47 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 17 lines · Mathieu Desnoyers
* Paul E. McKenney ([email protected]) wrote:
[...]Quoted 5 lines
kernel/rcutiny_plugin.h +5
-0+ +/* +* Tiny-preemptible RCU implementation for rcu_read_unlock(). +* Decrement ->rcu_read_lock_nesting. If the result is zero (outermost +* rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then kernel/rcutiny_plugin.h line 354
Quoted 10 lines
kernel/rcutiny_plugin.h +10
-0+* invoke rcu_read_unlock_special() to clean up after a context switch +* in an RCU read-side critical section and other special cases. +*/ +void __rcu_read_unlock (void ) +{ +struct task_struct *t = current; + +barrier ();/* needed if we ever invoke rcu_read_unlock in rcutiny.c */ +if (--t->rcu_read_lock_nesting ==0 && +unlikely (t->rcu_read_unlock_special))First, thank you for looking this over!!!
Quoted 14 lines
Hrm I think we discussed this in a past life, but would the following sequence be possible and correct ?
CPU 0
read
t->rcu_read_unlock_special
interrupt comes in, preempts. setst->rcu_read_unlock_special<preempted>
<scheduled back>
iret
decrement and readt->rcu_read_lock_nesting
test both old "special" value (which we have locally on the stack) and detect thatrcu_read_lock_nestingis 0.Quoted 4 lines
We actually missed a reschedule.
I think we might need a
barrier()between thet->rcu_read_lock_nestingandt->rcu_read_unlock_specialreads.You are correct -- I got too aggressive in eliminating synchronization.
Good catch!!!
I added an
ACCESS_ONCE()to the second term of the "if" condition so that it now reads:
Quoted 6 lines
if (--t->rcu_read_lock_nesting == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))This prevents the compiler from reordering because the
ACCESS_ONCE()prohibits accessingt->rcu_read_unlock_specialunless the value oft->rcu_read_lock_nestingis known to be zero.
Hrm, --t->rcu_read_lock_nesting does not have any globally visible side-effect, so the compiler is free to reorder the memory access across the rcu_read_unlock_special access. I think we need the ACCESS_ONCE() around the t->rcu_read_lock_nesting access too.
Quoted 7 lines
Quoted 3 lines
We might need to audit
TREE PREEMPT RCU for the same kind of behavior.The version of
__rcu_read_unlock()inkernel/rcutree_plugin.his as follows:
Quoted 7 lines
void
__rcu_read_unlock(void){ struct task_struct *t = current; barrier(); /* needed if we ever invoke rcu_read_unlock in rcutree.c */ if (--ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 && unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
This seem to work because we have:
volatile access (read/update t->rcu_read_lock_nesting) && (sequence point)
volatile access (t->rcu_read_unlock_special)
The C standard seems to forbid reordering of volatile accesses across sequence points, so this should be fine. But it would probably be good to document this implied ordering explicitly.
Quoted 9 lines
rcu_read_unlock_special(t); #ifdef CONFIG_PROVE_LOCKING WARN_ON_ONCE(ACCESS_ONCE(t->rcu_read_lock_nesting) < 0);#endif /* #ifdef
CONFIG_PROVE_LOCKING*/
}The
ACCESS_ONCE()calls should cover this. I believe that the firstACCESS_ONCE()is redundant, and have checking this more closely on my todo list.
I doubt so, see explanation above.
Quoted 29 lines
Quoted 20 lines
But I might be (again ?) missing something. I've got the feeling you already convinced me that this was OK for some reason, but I trip on this every time I read the code.
[...]
Quoted 13 lines
kernel/rcutiny_plugin.h +13
-0+/* +* Check for a task exiting while in a preemptible -RCU read-side +* critical section, clean up if so. No need to issue warnings, +* as debug_check_no_locks_held() already does this if lockdep +* is enabled. +*/ +void exit_rcu (void ) +{ +struct task_struct *t = current; + +if (t->rcu_read_lock_nesting ==0 ) +return ; + t->rcu_read_lock_nesting =1 ;Quoted 8 lines
kernel/rcutiny_plugin.h line 570
Quoted 3 lines
kernel/rcutiny_plugin.h +3
-0+rcu_read_unlock (); +} +The interaction with preemption is unclear here.
exit.cdisables preemption around the call toexit_rcu(), but if, for some reason,rcu_read_unlock_specialwas set earlier by preemption, then thercu_read_unlock()code might block and cause problems.
Quoted 3 lines
But
rcu_read_unlock_special()does not block. In fact, it disables interrupts over almost all of its execution. Or am I missing some subtlety here?
I am probably the one who was missing a subtlety about how rcu_read_unlock_special() works.
Quoted 11 lines
Quoted 2 lines
Maybe we should consider clearing
rcu_read_unlock_specialhere ?If the task blocked in an RCU read-side critical section just before
exit_rcu()was called, we need to remove the task from the ->blkd_tasks list. If we fail to do so, we might get a segfault later on. Also, we do need to handle anyRCU_READ_UNLOCK_NEED_QSrequests from the RCU core.So I really do like the current approach of calling
rcu_read_unlock()to do this sort of cleanup.
It looks good then, I just wanted to ensure that the side-effects of calling rcu_read_unlock() in this code path were well-thought.
Thanks,
Mathieu
Quoted 17 lines
Thanx, Paul
Quoted 14 lines
Thanks,
Mathieu
Signature · 9 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 51 lines · Mathieu Desnoyers
Quoted 50 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 17 lines · Mathieu Desnoyers
* Paul E. McKenney ([email protected]) wrote:
[...]Quoted 5 lines
kernel/rcutiny_plugin.h +5
-0+ +/* +* Tiny-preemptible RCU implementation for rcu_read_unlock(). +* Decrement ->rcu_read_lock_nesting. If the result is zero (outermost +* rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then kernel/rcutiny_plugin.h line 354
Quoted 10 lines
kernel/rcutiny_plugin.h +10
-0+* invoke rcu_read_unlock_special() to clean up after a context switch +* in an RCU read-side critical section and other special cases. +*/ +void __rcu_read_unlock (void ) +{ +struct task_struct *t = current; + +barrier ();/* needed if we ever invoke rcu_read_unlock in rcutiny.c */ +if (--t->rcu_read_lock_nesting ==0 && +unlikely (t->rcu_read_unlock_special))First, thank you for looking this over!!!
Quoted 14 lines
Hrm I think we discussed this in a past life, but would the following sequence be possible and correct ?
CPU 0
read
t->rcu_read_unlock_special
interrupt comes in, preempts. setst->rcu_read_unlock_special<preempted>
<scheduled back>
iret
decrement and readt->rcu_read_lock_nesting
test both old "special" value (which we have locally on the stack) and detect thatrcu_read_lock_nestingis 0.Quoted 4 lines
We actually missed a reschedule.
I think we might need a
barrier()between thet->rcu_read_lock_nestingandt->rcu_read_unlock_specialreads.You are correct -- I got too aggressive in eliminating synchronization.
Good catch!!!
I added an
ACCESS_ONCE()to the second term of the "if" condition so that it now reads:if (--t->rcu_read_lock_nesting == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))
Quoted 8 lines
Quoted 3 lines
This prevents the compiler from reordering because the
ACCESS_ONCE()prohibits accessingt->rcu_read_unlock_specialunless the value oft->rcu_read_lock_nestingis known to be zero.Hrm, --t->rcu_read_lock_nesting does not have any globally visible side-effect, so the compiler is free to reorder the memory access across the
rcu_read_unlock_specialaccess. I think we need theACCESS_ONCE()around thet->rcu_read_lock_nestingaccess too.
Indeed, it is free to reorder that access. This has the effect of extending the scope of the RCU read-side critical section, which is harmless as long as it doesn't pull a lock or some such into it.
Quoted 14 lines
Quoted 6 lines
Quoted 2 lines
We might need to audit
TREE PREEMPT RCU for the same kind of behavior.The version of
__rcu_read_unlock()inkernel/rcutree_plugin.his as follows:Quoted 7 lines
void
__rcu_read_unlock(void){ struct task_struct *t = current; barrier(); /* needed if we ever invoke rcu_read_unlock in rcutree.c */ if (--ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 && unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
Quoted 5 lines
This seem to work because we have:
volatile access (read/update
t->rcu_read_lock_nesting) && (sequence point)
volatile access (t->rcu_read_unlock_special)
Yep!!! ;-)
Quoted 3 lines
The C standard seems to forbid reordering of volatile accesses across sequence points, so this should be fine. But it would probably be good to document this implied ordering explicitly.
I should probably review commenting globally, and this might be one place needing help.
Quoted 11 lines
Quoted 9 lines
rcu_read_unlock_special(t); #ifdef CONFIG_PROVE_LOCKING WARN_ON_ONCE(ACCESS_ONCE(t->rcu_read_lock_nesting) < 0);#endif /* #ifdef
CONFIG_PROVE_LOCKING*/
}The
ACCESS_ONCE()calls should cover this. I believe that the firstACCESS_ONCE()is redundant, and have checking this more closely on my todo list.I doubt so, see explanation above.
Ditto! ;-)
Quoted 44 lines
Quoted 28 lines
Quoted 19 lines
But I might be (again ?) missing something. I've got the feeling you already convinced me that this was OK for some reason, but I trip on this every time I read the code.
[...]
Quoted 13 lines
kernel/rcutiny_plugin.h +13
-0+/* +* Check for a task exiting while in a preemptible -RCU read-side +* critical section, clean up if so. No need to issue warnings, +* as debug_check_no_locks_held() already does this if lockdep +* is enabled. +*/ +void exit_rcu (void ) +{ +struct task_struct *t = current; + +if (t->rcu_read_lock_nesting ==0 ) +return ; + t->rcu_read_lock_nesting =1 ;Quoted 8 lines
kernel/rcutiny_plugin.h line 570
Quoted 3 lines
kernel/rcutiny_plugin.h +3
-0+rcu_read_unlock (); +} +The interaction with preemption is unclear here.
exit.cdisables preemption around the call toexit_rcu(), but if, for some reason,rcu_read_unlock_specialwas set earlier by preemption, then thercu_read_unlock()code might block and cause problems.Quoted 3 lines
But
rcu_read_unlock_special()does not block. In fact, it disables interrupts over almost all of its execution. Or am I missing some subtlety here?I am probably the one who was missing a subtlety about how
rcu_read_unlock_special()works.Quoted 9 lines
Quoted 2 lines
Maybe we should consider clearing
rcu_read_unlock_specialhere ?If the task blocked in an RCU read-side critical section just before
exit_rcu()was called, we need to remove the task from the ->blkd_tasks list. If we fail to do so, we might get a segfault later on. Also, we do need to handle anyRCU_READ_UNLOCK_NEED_QSrequests from the RCU core.
Quoted 5 lines
Quoted 2 lines
So I really do like the current approach of calling
rcu_read_unlock()to do this sort of cleanup.It looks good then, I just wanted to ensure that the side-effects of calling
rcu_read_unlock()in this code path were well-thought.
Long ago on the first RCU priority-boosting implementation I tried doing the rcu_read_unlock() by hand. The unhappy lessons learned caused me to just use rcu_read_unlock() when I encountered similar situations later on. ;-)
Thanx, Paul
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 56 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 55 lines · Mathieu Desnoyers
Quoted 53 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 17 lines · Mathieu Desnoyers
* Paul E. McKenney ([email protected]) wrote:
[...]Quoted 5 lines
kernel/rcutiny_plugin.h +5
-0+ +/* +* Tiny-preemptible RCU implementation for rcu_read_unlock(). +* Decrement ->rcu_read_lock_nesting. If the result is zero (outermost +* rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then kernel/rcutiny_plugin.h line 354
Quoted 10 lines
kernel/rcutiny_plugin.h +10
-0+* invoke rcu_read_unlock_special() to clean up after a context switch +* in an RCU read-side critical section and other special cases. +*/ +void __rcu_read_unlock (void ) +{ +struct task_struct *t = current; + +barrier ();/* needed if we ever invoke rcu_read_unlock in rcutiny.c */ +if (--t->rcu_read_lock_nesting ==0 && +unlikely (t->rcu_read_unlock_special))First, thank you for looking this over!!!
Quoted 14 lines
Hrm I think we discussed this in a past life, but would the following sequence be possible and correct ?
CPU 0
read
t->rcu_read_unlock_special
interrupt comes in, preempts. setst->rcu_read_unlock_special<preempted>
<scheduled back>
iret
decrement and readt->rcu_read_lock_nesting
test both old "special" value (which we have locally on the stack) and detect thatrcu_read_lock_nestingis 0.Quoted 4 lines
We actually missed a reschedule.
I think we might need a
barrier()between thet->rcu_read_lock_nestingandt->rcu_read_unlock_specialreads.You are correct -- I got too aggressive in eliminating synchronization.
Good catch!!!
I added an
ACCESS_ONCE()to the second term of the "if" condition so that it now reads:if (--t->rcu_read_lock_nesting == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))This prevents the compiler from reordering because the
ACCESS_ONCE()prohibits accessingt->rcu_read_unlock_specialunless the value oft->rcu_read_lock_nestingis known to be zero.
Quoted 9 lines
Quoted 4 lines
Hrm, --t->rcu_read_lock_nesting does not have any globally visible side-effect, so the compiler is free to reorder the memory access across the
rcu_read_unlock_specialaccess. I think we need theACCESS_ONCE()around thet->rcu_read_lock_nestingaccess too.Indeed, it is free to reorder that access. This has the effect of extending the scope of the RCU read-side critical section, which is harmless as long as it doesn't pull a lock or some such into it.
So what happens if we get:
CPU 0
read t->rcu_read_lock_nesting
check if equals to 1
read t->rcu_read_unlock_special
interrupt comes in, preempts. sets t->rcu_read_unlock_special <preempted>
<scheduled back>
iret
decrement t->rcu_read_lock_nesting
test rcu_read_unlock_special value (read prior to interrupt)
-> fails to notice the preemption that came in after the
rcu_read_unlock_special read.
Thanks,
Mathieu
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 71 lines · Mathieu Desnoyers
Quoted 56 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 55 lines · Mathieu Desnoyers
Quoted 53 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 17 lines · Mathieu Desnoyers
* Paul E. McKenney ([email protected]) wrote:
[...]Quoted 5 lines
kernel/rcutiny_plugin.h +5
-0+ +/* +* Tiny-preemptible RCU implementation for rcu_read_unlock(). +* Decrement ->rcu_read_lock_nesting. If the result is zero (outermost +* rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then kernel/rcutiny_plugin.h line 354
Quoted 10 lines
kernel/rcutiny_plugin.h +10
-0+* invoke rcu_read_unlock_special() to clean up after a context switch +* in an RCU read-side critical section and other special cases. +*/ +void __rcu_read_unlock (void ) +{ +struct task_struct *t = current; + +barrier ();/* needed if we ever invoke rcu_read_unlock in rcutiny.c */ +if (--t->rcu_read_lock_nesting ==0 && +unlikely (t->rcu_read_unlock_special))First, thank you for looking this over!!!
Quoted 14 lines
Hrm I think we discussed this in a past life, but would the following sequence be possible and correct ?
CPU 0
read
t->rcu_read_unlock_special
interrupt comes in, preempts. setst->rcu_read_unlock_special<preempted>
<scheduled back>
iret
decrement and readt->rcu_read_lock_nesting
test both old "special" value (which we have locally on the stack) and detect thatrcu_read_lock_nestingis 0.Quoted 4 lines
We actually missed a reschedule.
I think we might need a
barrier()between thet->rcu_read_lock_nestingandt->rcu_read_unlock_specialreads.You are correct -- I got too aggressive in eliminating synchronization.
Good catch!!!
I added an
ACCESS_ONCE()to the second term of the "if" condition so that it now reads:if (--t->rcu_read_lock_nesting == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))This prevents the compiler from reordering because the
ACCESS_ONCE()prohibits accessingt->rcu_read_unlock_specialunless the value oft->rcu_read_lock_nestingis known to be zero.Quoted 9 lines
Quoted 4 lines
Hrm, --t->rcu_read_lock_nesting does not have any globally visible side-effect, so the compiler is free to reorder the memory access across the
rcu_read_unlock_specialaccess. I think we need theACCESS_ONCE()around thet->rcu_read_lock_nestingaccess too.Indeed, it is free to reorder that access. This has the effect of extending the scope of the RCU read-side critical section, which is harmless as long as it doesn't pull a lock or some such into it.
So what happens if we get:
CPU 0
Quoted 8 lines
read
t->rcu_read_lock_nesting
check if equals to 1
readt->rcu_read_unlock_special
interrupt comes in, preempts. setst->rcu_read_unlock_special<preempted>
<scheduled back>
iret
decrementt->rcu_read_lock_nesting
Moving this down past the check of t->rcu_read_lock_special (which is now covered by ACCESS_ONCE()) would violate the C standard, as it would be equivalent to moving a volatile up past a sequence point.
Thanx, Paul
Quoted 13 lines
test
rcu_read_unlock_specialvalue (read prior to interrupt)
-> fails to notice the preemption that came in after the
rcu_read_unlock_specialread.Thanks,
Mathieu
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 81 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 71 lines · Mathieu Desnoyers
Quoted 56 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 55 lines · Mathieu Desnoyers
Quoted 53 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 17 lines · Mathieu Desnoyers
* Paul E. McKenney ([email protected]) wrote:
[...]Quoted 5 lines
(quoted diff) +5
-0+ +/* + * Tiny-preemptible RCU implementation for rcu_read_unlock(). + * Decrement ->rcu_read_lock_nesting. If the result is zero (outermost + * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, thenReview
Quoted 10 lines
(quoted diff) +10
-0+ * invoke rcu_read_unlock_special() to clean up after a context switch + * in an RCU read-side critical section and other special cases. + */ +void __rcu_read_unlock(void) +{ + struct task_struct *t = current; + + barrier(); /* needed if we ever invoke rcu_read_unlock in rcutiny.c */ + if (--t->rcu_read_lock_nesting == 0 && + unlikely(t->rcu_read_unlock_special))First, thank you for looking this over!!!
Quoted 14 lines
Hrm I think we discussed this in a past life, but would the following sequence be possible and correct ?
CPU 0
read
t->rcu_read_unlock_special
interrupt comes in, preempts. setst->rcu_read_unlock_special<preempted>
<scheduled back>
iret
decrement and readt->rcu_read_lock_nesting
test both old "special" value (which we have locally on the stack) and detect thatrcu_read_lock_nestingis 0.Quoted 4 lines
We actually missed a reschedule.
I think we might need a
barrier()between thet->rcu_read_lock_nestingandt->rcu_read_unlock_specialreads.You are correct -- I got too aggressive in eliminating synchronization.
Good catch!!!
I added an
ACCESS_ONCE()to the second term of the "if" condition so that it now reads:if (--t->rcu_read_lock_nesting == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))This prevents the compiler from reordering because the
ACCESS_ONCE()prohibits accessingt->rcu_read_unlock_specialunless the value oft->rcu_read_lock_nestingis known to be zero.Quoted 9 lines
Quoted 4 lines
Hrm, --t->rcu_read_lock_nesting does not have any globally visible side-effect, so the compiler is free to reorder the memory access across the
rcu_read_unlock_specialaccess. I think we need theACCESS_ONCE()around thet->rcu_read_lock_nestingaccess too.Indeed, it is free to reorder that access. This has the effect of extending the scope of the RCU read-side critical section, which is harmless as long as it doesn't pull a lock or some such into it.
So what happens if we get:
CPU 0
Quoted 8 lines
read
t->rcu_read_lock_nesting
check if equals to 1
readt->rcu_read_unlock_special
interrupt comes in, preempts. setst->rcu_read_unlock_special<preempted>
<scheduled back>
iret
decrementt->rcu_read_lock_nesting
Quoted 3 lines
Moving this down past the check of
t->rcu_read_lock_special(which is now covered byACCESS_ONCE()) would violate the C standard, as it would be equivalent to moving a volatile up past a sequence point.
Hrm, I'm not quite convinced yet. I am not concerned about gcc moving the volatile access prior to the sequence point (as you say, this is forbidden by the C standard), but rather that:
--(t->rcu_read_lock_nesting)
could be split in two distinct operations:
read t->rcu_read_lock_nesting
decrement t->rcu_read_lock_nesting
Note that in order to know the result required to pass the sequence point "&&" (the test), we only need to perform the read, not the decrement. AFAIU, gcc would be in its rights to move the t->rcu_read_lock_nesting update after the volatile access.
Thanks,
Mathieu
Quoted 16 lines
Thanx, Paul
Quoted 13 lines
test
rcu_read_unlock_specialvalue (read prior to interrupt)
-> fails to notice the preemption that came in after the
rcu_read_unlock_specialread.Thanks,
Mathieu
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 94 lines · Mathieu Desnoyers
Quoted 81 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 71 lines · Mathieu Desnoyers
Quoted 56 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 55 lines · Mathieu Desnoyers
Quoted 53 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 17 lines · Mathieu Desnoyers
* Paul E. McKenney ([email protected]) wrote:
[...]Quoted 5 lines
(quoted diff) +5
-0+ +/* + * Tiny-preemptible RCU implementation for rcu_read_unlock(). + * Decrement ->rcu_read_lock_nesting. If the result is zero (outermost + * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, thenReview
Quoted 10 lines
(quoted diff) +10
-0+ * invoke rcu_read_unlock_special() to clean up after a context switch + * in an RCU read-side critical section and other special cases. + */ +void __rcu_read_unlock(void) +{ + struct task_struct *t = current; + + barrier(); /* needed if we ever invoke rcu_read_unlock in rcutiny.c */ + if (--t->rcu_read_lock_nesting == 0 && + unlikely(t->rcu_read_unlock_special))First, thank you for looking this over!!!
Quoted 14 lines
Hrm I think we discussed this in a past life, but would the following sequence be possible and correct ?
CPU 0
read
t->rcu_read_unlock_special
interrupt comes in, preempts. setst->rcu_read_unlock_special<preempted>
<scheduled back>
iret
decrement and readt->rcu_read_lock_nesting
test both old "special" value (which we have locally on the stack) and detect thatrcu_read_lock_nestingis 0.Quoted 4 lines
We actually missed a reschedule.
I think we might need a
barrier()between thet->rcu_read_lock_nestingandt->rcu_read_unlock_specialreads.You are correct -- I got too aggressive in eliminating synchronization.
Good catch!!!
I added an
ACCESS_ONCE()to the second term of the "if" condition so that it now reads:if (--t->rcu_read_lock_nesting == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))This prevents the compiler from reordering because the
ACCESS_ONCE()prohibits accessingt->rcu_read_unlock_specialunless the value oft->rcu_read_lock_nestingis known to be zero.Quoted 9 lines
Quoted 4 lines
Hrm, --t->rcu_read_lock_nesting does not have any globally visible side-effect, so the compiler is free to reorder the memory access across the
rcu_read_unlock_specialaccess. I think we need theACCESS_ONCE()around thet->rcu_read_lock_nestingaccess too.Indeed, it is free to reorder that access. This has the effect of extending the scope of the RCU read-side critical section, which is harmless as long as it doesn't pull a lock or some such into it.
So what happens if we get:
CPU 0
Quoted 8 lines
read
t->rcu_read_lock_nesting
check if equals to 1
readt->rcu_read_unlock_special
interrupt comes in, preempts. setst->rcu_read_unlock_special<preempted>
<scheduled back>
iret
decrementt->rcu_read_lock_nestingQuoted 3 lines
Moving this down past the check of
t->rcu_read_lock_special(which is now covered byACCESS_ONCE()) would violate the C standard, as it would be equivalent to moving a volatile up past a sequence point.Hrm, I'm not quite convinced yet. I am not concerned about gcc moving the volatile access prior to the sequence point (as you say, this is forbidden by the C standard), but rather that:
--(t->rcu_read_lock_nesting)
could be split in two distinct operations:
Quoted 7 lines
read
t->rcu_read_lock_nesting
decrementt->rcu_read_lock_nestingNote that in order to know the result required to pass the sequence point "&&" (the test), we only need to perform the read, not the decrement. AFAIU, gcc would be in its rights to move the
t->rcu_read_lock_nestingupdate after the volatile access.
I will run this by some compiler experts.
Thanx, Paul
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 7 lines · Paul E. McKenney
Quoted 7 lines
--(t->rcu_read_lock_nesting)
could be split in two distinct operations:
read
t->rcu_read_lock_nesting
decrementt->rcu_read_lock_nesting
Quoted 7 lines
Quoted 4 lines
Note that in order to know the result required to pass the sequence point "&&" (the test), we only need to perform the read, not the decrement. AFAIU, gcc would be in its rights to move the
t->rcu_read_lock_nestingupdate after the volatile access.I will run this by some compiler experts.
We can just use "read and decrement statements" instead of "--" to avoid dependency from compilers.
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 14 lines · Lai Jiangshan
Quoted 12 lines · Paul E. McKenney
Quoted 11 lines
--(t->rcu_read_lock_nesting)
could be split in two distinct operations:
read
t->rcu_read_lock_nesting
decrementt->rcu_read_lock_nestingNote that in order to know the result required to pass the sequence point "&&" (the test), we only need to perform the read, not the decrement. AFAIU, gcc would be in its rights to move the
t->rcu_read_lock_nestingupdate after the volatile access.
Quoted 4 lines
Quoted 1 line
I will run this by some compiler experts.
We can just use "read and decrement statements" instead of "--" to avoid dependency from compilers.
You mean something like local_add_return()? This turns into atomic_add_return() on many platforms, including x86 as it turns out, so I am reluctant to use it.
If you had something else in mind, please don't keep it a secret!
Thanx, Paul
Steven Rostedt
reviewerRe: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
In reply to Mathieu DesnoyersQuoted 12 lines · Mathieu Desnoyers
Quoted 3 lines
Moving this down past the check of
t->rcu_read_lock_special(which is now covered byACCESS_ONCE()) would violate the C standard, as it would be equivalent to moving a volatile up past a sequence point.Hrm, I'm not quite convinced yet. I am not concerned about gcc moving the volatile access prior to the sequence point (as you say, this is forbidden by the C standard), but rather that:
--(t->rcu_read_lock_nesting)
could be split in two distinct operations:
Quoted 8 lines
read
t->rcu_read_lock_nesting
decrementt->rcu_read_lock_nestingNote that in order to know the result required to pass the sequence point "&&" (the test), we only need to perform the read, not the decrement. AFAIU, gcc would be in its rights to move the
t->rcu_read_lock_nestingupdate after the volatile access.
If we are this concerned, what about just doing:
--t->rcu_read_lock_nesting;
if (ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 &&
unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))-- Steve
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 23 lines · * Steven Rostedt ([email protected]) wrote:
Quoted 12 lines · Mathieu Desnoyers
Quoted 3 lines
Moving this down past the check of
t->rcu_read_lock_special(which is now covered byACCESS_ONCE()) would violate the C standard, as it would be equivalent to moving a volatile up past a sequence point.Hrm, I'm not quite convinced yet. I am not concerned about gcc moving the volatile access prior to the sequence point (as you say, this is forbidden by the C standard), but rather that:
--(t->rcu_read_lock_nesting)
could be split in two distinct operations:
Quoted 8 lines
read
t->rcu_read_lock_nesting
decrementt->rcu_read_lock_nestingNote that in order to know the result required to pass the sequence point "&&" (the test), we only need to perform the read, not the decrement. AFAIU, gcc would be in its rights to move the
t->rcu_read_lock_nestingupdate after the volatile access.
Quoted 5 lines
If we are this concerned, what about just doing:
--t->rcu_read_lock_nesting; if (ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))
I'd be concerned by the fact that there is no strong ordering guarantee that the non-volatile --t->rcu_read_lock_nesting is done before ACCESS_ONCE(t->rcu_read_unlock_special).
My concern is that the compiler might be allowed to turn your code into:
if (ACCESS_ONCE(t->rcu_read_lock_nesting) == 1 &&
unlikely((ACCESS_ONCE(t->rcu_read_unlock_special))) {
--t->rcu_read_lock_nesting;
do_something();
} else
--t->rcu_read_lock_nesting;So whether or not this could be done by the compiler depending on the various definitions of volatile, I strongly recommend against using volatile accesses to provide compiler ordering guarantees. It is bad in terms of code documentation (we don't document _what_ is ordered) and it is also bad because the volatile ordering guarantees seems to be very easy to misinterpret.
ACCESS_ONCE() should be only that: a macro that tells the access should be performed only once. Why are we suddenly presuming it should have any ordering semantic ?
It should be totally valid to create arch-specific ACCESS_ONCE() macros that only perform the "read once", without the ordering guarantees provided by the current ACCESS_ONCE() "volatile" implementation. The following code is only for unsigned long, but you get the idea: there is no volatile at all, and I ensure that "val" is only read once by using the "+m" (val) constraint, telling the compiler (falsely) that the assembler is modifying the value (it therefore has a side-effect), so gcc won't be tempted to re-issue the assembly statement.
static inline unsigned long arch_access_once(unsigned long val)
{
unsigned long ret;#if (__BITS_PER_LONG == 32)
asm ("movl %1,%0": "=r" (ret), "+m" (val));
#else
asm ("movq %1,%0": "=r" (ret), "+m" (val));#endif
}
Thanks,
Mathieu
Quoted 4 lines
-- Steve
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Steven Rostedt
reviewerRe: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 12 lines · Mathieu Desnoyers
Quoted 5 lines · * Steven Rostedt ([email protected]) wrote:
If we are this concerned, what about just doing:
--t->rcu_read_lock_nesting; if (ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))I'd be concerned by the fact that there is no strong ordering guarantee that the non-volatile --t->rcu_read_lock_nesting is done before
ACCESS_ONCE(t->rcu_read_unlock_special).
Quoted 8 lines
My concern is that the compiler might be allowed to turn your code into:
if (ACCESS_ONCE(t->rcu_read_lock_nesting) == 1 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special))) { --t->rcu_read_lock_nesting; do_something(); } else --t->rcu_read_lock_nesting;
That just seems to break all sorts of rules.
Quoted 7 lines
So whether or not this could be done by the compiler depending on the various definitions of volatile, I strongly recommend against using volatile accesses to provide compiler ordering guarantees. It is bad in terms of code documentation (we don't document _what_ is ordered) and it is also bad because the volatile ordering guarantees seems to be very easy to misinterpret.
Yes, volatile does not guarantee ordering of other accesses, but it should at least guarantee ordering of access to the thing that is volatile.
b++; a++; c = ACCESS_ONCE(a);
'b++' can be moved to anywhere. But I'm pretty sure the compiler is not allowed to move the 'a++' after the ACCESS_ONCE(a) because it is the thing that is volatile. We are telling the compiler that 'a' can change outside our scope, which to me is the same as doing:
a++; c = some_global_function(&a);
Where, the compiler does not know the result of 'a' and can not move the 'a++'.
Maybe I'm wrong, and need to verify this with a compiler expert. But what's the use of volatile if it can't protect the ordering of what is volatile from itself.
Quoted 4 lines
ACCESS_ONCE()should be only that: a macro that tells the access should be performed only once. Why are we suddenly presuming it should have any ordering semantic ?
Only ordering with the variable that is volatile. It has no ordering to any other variable.
Quoted 14 lines
It should be totally valid to create arch-specific
ACCESS_ONCE()macros that only perform the "read once", without the ordering guarantees provided by the currentACCESS_ONCE()"volatile" implementation. The following code is only for unsigned long, but you get the idea: there is no volatile at all, and I ensure that "val" is only read once by using the "+m" (val) constraint, telling the compiler (falsely) that the assembler is modifying the value (it therefore has a side-effect), so gcc won't be tempted to re-issue the assembly statement.static inline unsigned long
arch_access_once(unsigned long val){ unsigned long ret;
Quoted 6 lines
#if (__BITS_PER_LONG == 32) asm ("movl %1,%0": "=r" (ret), "+m" (val)); #else asm ("movq %1,%0": "=r" (ret), "+m" (val));#endif
}
Heck, this is too much micro optimization. We could just be safe and do the:
--t->rcu_read_lock_nesting;
barrier();
if (ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 &&
unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))And be done with it.
-- Steve
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 23 lines · * Steven Rostedt ([email protected]) wrote:
Quoted 12 lines · Mathieu Desnoyers
Quoted 5 lines · * Steven Rostedt ([email protected]) wrote:
If we are this concerned, what about just doing:
--t->rcu_read_lock_nesting; if (ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))I'd be concerned by the fact that there is no strong ordering guarantee that the non-volatile --t->rcu_read_lock_nesting is done before
ACCESS_ONCE(t->rcu_read_unlock_special).Quoted 8 lines
My concern is that the compiler might be allowed to turn your code into:
if (ACCESS_ONCE(t->rcu_read_lock_nesting) == 1 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special))) { --t->rcu_read_lock_nesting; do_something(); } else --t->rcu_read_lock_nesting;
Quoted 1 line
That just seems to break all sorts of rules.
Is there a rule stating that a non-volatile access is ensured to be in issued in program order wrt other accesses to that same variable ?
The stardard discourages compilers to do any kind of optimization when volatile is detected on a variable
(http://gcc.gnu.org/onlinedocs/gcc/Volatiles.html), but that's a very weak guarantee I would not like to rely on.
The only strong guarantee it provides is:
"The minimum either standard specifies is that at a sequence point all previous accesses to volatile objects have stabilized and no subsequent accesses have occurred."
So the question here is: given that the "--t->rcu_read_lock_nesting" access is not marked volatile, but the following "ACCESS_ONCE(t->rcu_read_lock_nesting)" read is volatile, should we consider than "--t->rcu_read_lock_nesting" apply to a volatile object or not ?
This is the kind of grey zone I dislike.
Quoted 13 lines
Quoted 8 lines
So whether or not this could be done by the compiler depending on the various definitions of volatile, I strongly recommend against using volatile accesses to provide compiler ordering guarantees. It is bad in terms of code documentation (we don't document _what_ is ordered) and it is also bad because the volatile ordering guarantees seems to be very easy to misinterpret.
Yes, volatile does not guarantee ordering of other accesses, but it should at least guarantee ordering of access to the thing that is volatile.
Quoted 7 lines
b++; a++; c = ACCESS_ONCE(a);'b++' can be moved to anywhere. But I'm pretty sure the compiler is not allowed to move the 'a++' after the
ACCESS_ONCE(a)because it is the thing that is volatile.
AFAIU, the standard only requires ordering between volatile "objects". So when we cast non-volatile objects to volatile, I assume the non-volatile accesses apply only to the non-volatile version of the object. So volatile ordering guarantees would not apply to "a".
Quoted 8 lines
We are telling the compiler that 'a' can change outside our scope, which to me is the same as doing:
a++; c = some_global_function(&a);Where, the compiler does not know the result of 'a' and can not move the 'a++'.
The code here is different: calling an external function is equivalent to put a full compiler memory barrier ("memory" clobber). Volatile is quite different from that; the compiler is only told to keep ordering between volatile accesses, and to try not to optimize the volatile access per se.
Quoted 5 lines
Maybe I'm wrong, and need to verify this with a compiler expert. But what's the use of volatile if it can't protect the ordering of what is volatile from itself.
I'm concerned about the fact that volatile seems to have been initially designed to apply to a variable declaration (object) rather than a specific access through a cast. So I really wonder if the non-volatile object accesses has the same guarantees as the accesses performed on its volatile cast version.
Quoted 8 lines
Quoted 5 lines
ACCESS_ONCE()should be only that: a macro that tells the access should be performed only once. Why are we suddenly presuming it should have any ordering semantic ?Only ordering with the variable that is volatile. It has no ordering to any other variable.
This is not quite correct. Volatile orders with respect to _all_ other volatile accesses.
What I am pointing out here is that the macro name "ACCESS_ONCE()" does not convey any ordering semantic, and should not.
Quoted 22 lines
Quoted 15 lines
It should be totally valid to create arch-specific
ACCESS_ONCE()macros that only perform the "read once", without the ordering guarantees provided by the currentACCESS_ONCE()"volatile" implementation. The following code is only for unsigned long, but you get the idea: there is no volatile at all, and I ensure that "val" is only read once by using the "+m" (val) constraint, telling the compiler (falsely) that the assembler is modifying the value (it therefore has a side-effect), so gcc won't be tempted to re-issue the assembly statement.static inline unsigned long
arch_access_once(unsigned long val){ unsigned long ret;Quoted 6 lines
#if (__BITS_PER_LONG == 32) asm ("movl %1,%0": "=r" (ret), "+m" (val)); #else asm ("movq %1,%0": "=r" (ret), "+m" (val));#endif
}
Quoted 8 lines
Heck, this is too much micro optimization. We could just be safe and do the:
--t->rcu_read_lock_nesting; barrier(); if (ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))And be done with it.
Then we could go for the simpler:
--t->rcu_read_lock_nesting;
barrier();
if (t->rcu_read_lock_nesting == 0 &&
unlikely((t->rcu_read_unlock_special))Which puts a constraint across all memory accesses. I'd be fine with that if you are afraid of too much micro-optimization (e.g. my barrier2(a, b) proposal).
Thanks,
Mathieu
Quoted 4 lines
-- Steve
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Steven Rostedt
reviewerRe: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 7 lines · Mathieu Desnoyers
Quoted 7 lines
Heck, this is too much micro optimization. We could just be safe and do the:
--t->rcu_read_lock_nesting; barrier(); if (ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 && unlikely((ACCESS_ONCE(t->rcu_read_unlock_special)))
Quoted 8 lines
Quoted 1 line
And be done with it.
Then we could go for the simpler:
--t->rcu_read_lock_nesting;
barrier(); if (t->rcu_read_lock_nesting == 0 && unlikely((t->rcu_read_unlock_special))
Yeah, that's what I meant, I was too lazy to remove the ACCESS_ONCE() from the cut and paste I did.
Quoted 4 lines
Which puts a constraint across all memory accesses. I'd be fine with that if you are afraid of too much micro-optimization (e.g. my
barrier2(a, b)proposal).
Not afraid, but just too much code for a simple solution.
-- Steve
Steven Rostedt
reviewerRe: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 11 lines · Steven Rostedt
Quoted 6 lines
Then we could go for the simpler:
--t->rcu_read_lock_nesting;
barrier(); if (t->rcu_read_lock_nesting == 0 && unlikely((t->rcu_read_unlock_special))Yeah, that's what I meant, I was too lazy to remove the
ACCESS_ONCE()from the cut and paste I did.Quoted 1 line
Quoted 5 lines
Quoted 3 lines
Which puts a constraint across all memory accesses. I'd be fine with that if you are afraid of too much micro-optimization (e.g. my
barrier2(a, b)proposal).Not afraid, but just too much code for a simple solution.
IOW,
I think just pulling out the '--' and adding the barrier() is the proper solution here. Compiler barriers are rather cheap.
Can we all agree on this solution?
-- Steve
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 17 lines · * Steven Rostedt ([email protected]) wrote:
Quoted 15 lines · Steven Rostedt
Quoted 6 lines
Then we could go for the simpler:
--t->rcu_read_lock_nesting;
barrier(); if (t->rcu_read_lock_nesting == 0 && unlikely((t->rcu_read_unlock_special))Yeah, that's what I meant, I was too lazy to remove the
ACCESS_ONCE()from the cut and paste I did.Quoted 4 lines
Which puts a constraint across all memory accesses. I'd be fine with that if you are afraid of too much micro-optimization (e.g. my
barrier2(a, b)proposal).
Quoted 8 lines
Quoted 1 line
Not afraid, but just too much code for a simple solution.
IOW,
I think just pulling out the '--' and adding the
barrier()is the proper solution here. Compiler barriers are rather cheap.Can we all agree on this solution?
Given that we already have a barrier() at the beginning of rcu_read_unlock(), adding a second one will not have much more global optimisation impact than what is already there. I'm personally fine with this solution. Let's see what others have to say about this.
Thanks,
Mathieu
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 25 lines · Mathieu Desnoyers
Quoted 24 lines · * Steven Rostedt ([email protected]) wrote:
Quoted 11 lines · Steven Rostedt
Quoted 6 lines
Then we could go for the simpler:
--t->rcu_read_lock_nesting;
barrier(); if (t->rcu_read_lock_nesting == 0 && unlikely((t->rcu_read_unlock_special))Yeah, that's what I meant, I was too lazy to remove the
ACCESS_ONCE()from the cut and paste I did.Quoted 1 line
Quoted 5 lines
Quoted 3 lines
Which puts a constraint across all memory accesses. I'd be fine with that if you are afraid of too much micro-optimization (e.g. my
barrier2(a, b)proposal).Not afraid, but just too much code for a simple solution.
IOW,
I think just pulling out the '--' and adding the
barrier()is the proper solution here. Compiler barriers are rather cheap.
Quoted 6 lines
Quoted 1 line
Can we all agree on this solution?
Given that we already have a
barrier()at the beginning ofrcu_read_unlock(), adding a second one will not have much more global optimisation impact than what is already there. I'm personally fine with this solution. Let's see what others have to say about this.
Thank you both for the optimization work -- the read-side primitives do need to be fast. And the barrier() approach generates decent code, on some systems better than the original. So the second barrier wins. ;-)
Thanx, Paul
Re: [PATCH tip/core/rcu 08/10] rcu: Add a TINY_PREEMPT_RCU
Quoted 28 lines · Paul E. McKenney
Quoted 27 lines · Mathieu Desnoyers
Quoted 25 lines · * Steven Rostedt ([email protected]) wrote:
Quoted 11 lines · Steven Rostedt
Quoted 6 lines
Then we could go for the simpler:
--t->rcu_read_lock_nesting;
barrier(); if (t->rcu_read_lock_nesting == 0 && unlikely((t->rcu_read_unlock_special))Yeah, that's what I meant, I was too lazy to remove the
ACCESS_ONCE()from the cut and paste I did.Quoted 1 line
Quoted 5 lines
Quoted 3 lines
Which puts a constraint across all memory accesses. I'd be fine with that if you are afraid of too much micro-optimization (e.g. my
barrier2(a, b)proposal).Not afraid, but just too much code for a simple solution.
IOW,
I think just pulling out the '--' and adding the
barrier()is the proper solution here. Compiler barriers are rather cheap.Can we all agree on this solution?
Quoted 8 lines
Quoted 4 lines
Given that we already have a
barrier()at the beginning ofrcu_read_unlock(), adding a second one will not have much more global optimisation impact than what is already there. I'm personally fine with this solution. Let's see what others have to say about this.Thank you both for the optimization work -- the read-side primitives do need to be fast. And the
barrier()approach generates decent code, on some systems better than the original. So the second barrier wins. ;-)
And here is the updated version of this patch.
Thanx, Paul
------------------------------------------------------------------------
commit e4fb476c3a41e0c1dde1f8e303a328623c9eaa92
Author: Paul E. McKenney <[email protected]> Date: Tue Jun 29 16:49:16 2010 -0700
rcu: Add a TINY_PREEMPT_RCU
Implement a small-memory-footprint uniprocessor-only implementation of preemptible RCU. This implementation uses but a single blocked-tasks list rather than the combinatorial number used per leaf rcu_node by TREE_PREEMPT_RCU, which reduces memory consumption and greatly simplifies processing. This version also takes advantage of uniprocessor execution to accelerate grace periods in the case where there are no readers.
The general design is otherwise broadly similar to that of TREE_PREEMPT_RCU.
This implementation is a step towards having RCU implementation driven off of the SMP and PREEMPT kernel configuration variables, which can happen once this implementation has accumulated sufficient experience.
Removed ACCESS_ONCE() from __rcu_read_unlock() and added barrier() as suggested by Steve Rostedt in order to avoid the compiler-reordering issue noted by Mathieu Desnoyers (http://lkml.org/lkml/2010/8/16/183).
include/linux/hardirq.h +1 -1
@@ -139,7 +139,7 @@ static inline void account_system_vtime(struct task_struct *tsk)#endif #if defined(CONFIG_NO_HZ ) -#if defined(CONFIG_TINY_RCU ) +#if defined(CONFIG_TINY_RCU ) || defined(CONFIG_TINY_PREEMPT_RCU )extern void rcu_enter_nohz (void );extern void rcu_exit_nohz (void );
include/linux/init_task.h +8 -2
@@ -82,11 +82,17 @@ extern struct group_info init_groups;# define CAP_INIT_BSET CAP_FULL_SET#ifdef CONFIG_TREE_PREEMPT_RCU +#define INIT_TASK_RCU_TREE_PREEMPT () \ + .rcu_blocked_node = NULL, +#else +#define INIT_TASK_RCU_TREE_PREEMPT (tsk) +#endif +#ifdef CONFIG_PREEMPT_RCU #define INIT_TASK_RCU_PREEMPT (tsk) \ .rcu_read_lock_nesting = 0, \ .rcu_read_unlock_special = 0, \ - .rcu_blocked_node = NULL, \ - .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), + .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), \ + INIT_TASK_RCU_TREE_PREEMPT()#else #define INIT_TASK_RCU_PREEMPT (tsk)#endif
include/linux/rcupdate.h +1 -2
@@ -58,7 +58,6 @@ struct rcu_head { };/* Exported common interfaces */ -extern void rcu_barrier (void );extern void rcu_barrier_bh (void );extern void rcu_barrier_sched (void );extern void synchronize_sched_expedited (void );
@@ -69,7 +68,7 @@ extern void rcu_init(void);#if defined(CONFIG_TREE_RCU ) || defined(CONFIG_TREE_PREEMPT_RCU )#include <linux/rcutree.h> -#elif defined(CONFIG_TINY_RCU ) +#elif defined(CONFIG_TINY_RCU ) || defined(CONFIG_TINY_PREEMPT_RCU )#include <linux/rcutiny.h> #else #error "Unknown RCU implementation specified to kernel configuration"
include/linux/rcutiny.h +89 -37
170 lines not on this page · raw message
include/linux/rcutree.h +2 -0
@@ -95,6 +95,8 @@ static inline void synchronize_rcu_bh_expedited(void)synchronize_sched_expedited (); } +extern void rcu_barrier (void ); +extern void rcu_check_callbacks (int cpu,int user);extern long rcu_batches_completed (void );
include/linux/sched.h +7 -3
@@ -1211,11 +1211,13 @@ struct task_struct {unsigned int policy;cpumask_t cpus_allowed; -#ifdef CONFIG_TREE_PREEMPT_RCU +#ifdef CONFIG_PREEMPT_RCU int rcu_read_lock_nesting;char rcu_read_unlock_special; -struct rcu_node *rcu_blocked_node;struct list_head rcu_node_entry; +#endif /* #ifdef CONFIG_PREEMPT_RCU */ +#ifdef CONFIG_TREE_PREEMPT_RCU +struct rcu_node *rcu_blocked_node;#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ #if defined(CONFIG_SCHEDSTATS ) || defined(CONFIG_TASK_DELAY_ACCT )
@@ -1748,7 +1750,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *#define tsk_used_math (p) ((p)->flags & PF_USED_MATH)#define used_math () tsk_used_math(current) -#ifdef CONFIG_TREE_PREEMPT_RCU +#ifdef CONFIG_PREEMPT_RCU #define RCU_READ_UNLOCK_BLOCKED (1 << 0)/* blocked while in RCU read-side. */ #define RCU_READ_UNLOCK_NEED_QS (1 << 1)/* RCU core needs CPU response. */
@@ -1757,7 +1759,9 @@ static inline void rcu_copy_process(struct task_struct *p) { p->rcu_read_lock_nesting =0 ; p->rcu_read_unlock_special =0 ; +#ifdef CONFIG_TREE_PREEMPT_RCU p->rcu_blocked_node =NULL ; +#endif INIT_LIST_HEAD (&p->rcu_node_entry); }
init/Kconfig +15 -1
@@ -344,7 +344,7 @@ config TREE_RCU smaller systems. config TREE_PREEMPT_RCU - bool "Preemptable tree-based hierarchical RCU" + bool "Preemptible tree-based hierarchical RCU" depends on PREEMPT help This option selects the RCU implementation that is
@@ -362,8 +362,22 @@ config TINY_RCU is not required. This option greatly reduces the memory footprint of RCU. +config TINY_PREEMPT_RCU + bool "Preemptible UP-only small-memory-footprint RCU" + depends on !SMP && PREEMPT + help + This option selects the RCU implementation that is designed + for real-time UP systems. This option greatly reduces the + memory footprint of RCU. + endchoice +config PREEMPT_RCU + def_bool ( TREE_PREEMPT_RCU || TINY_PREEMPT_RCU ) + help + This option enables preemptible-RCU code that is common between + the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations. + config RCU_TRACE bool "Enable tracing for RCU" depends on TREE_RCU || TREE_PREEMPT_RCU
kernel/Makefile +1 -0
@@ -85,6 +85,7 @@ obj-$(CONFIG_TREE_RCU) += rcutree.o obj-$(CONFIG_TREE_PREEMPT_RCU) += rcutree.o obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o obj-$(CONFIG_TINY_RCU) += rcutiny.o +obj-$(CONFIG_TINY_PREEMPT_RCU) += rcutiny.o obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_SYSCTL) += utsname_sysctl.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
kernel/rcutiny.c +14 -19
@@ -59,6 +59,14 @@ int rcu_scheduler_active __read_mostly;EXPORT_SYMBOL_GPL (rcu_scheduler_active);#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +/* Forward declarations for rcutiny_plugin.h. */ +static void __rcu_process_callbacks (struct rcu_ctrlblk *rcp); +static void __call_rcu (struct rcu_head *head, +void (*func)(struct rcu_head *rcu), +struct rcu_ctrlblk *rcp); + +#include "rcutiny_plugin.h" +#ifdef CONFIG_NO_HZ static long rcu_dynticks_nesting =1 ;
@@ -140,6 +148,7 @@ void rcu_check_callbacks(int cpu, int user)rcu_sched_qs (cpu); else if (!in_softirq()) rcu_bh_qs(cpu); +rcu_preempt_check_callbacks (); }/*
@@ -162,6 +171,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) *rcp->donetail =NULL ;if (rcp->curtail == rcp->donetail) rcp->curtail = &rcp->rcucblist; +rcu_preempt_remove_callbacks (rcp); rcp->donetail = &rcp->rcucblist;local_irq_restore (flags);
@@ -182,6 +192,7 @@ static void rcu_process_callbacks(struct softirq_action *unused) {__rcu_process_callbacks (&rcu_sched_ctrlblk);__rcu_process_callbacks (&rcu_bh_ctrlblk); +rcu_preempt_process_callbacks (); }/*
@@ -223,15 +234,15 @@ static void __call_rcu(struct rcu_head *head, }/* -* Post an RCU callback to be invoked after the end of an RCU grace +* Post an RCU callback to be invoked after the end of an RCU-sched grace * period. But since we have but one CPU, that would be after any * quiescent state. */ -void call_rcu (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) +void call_rcu_sched (struct rcu_head *head,void (*func)(struct rcu_head *rcu)) {__call_rcu (head, func, &rcu_sched_ctrlblk); } -EXPORT_SYMBOL_GPL (call_rcu); +EXPORT_SYMBOL_GPL (call_rcu_sched);/* * Post an RCU bottom-half callback to be invoked after any subsequent
@@ -243,20 +254,6 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) }EXPORT_SYMBOL_GPL (call_rcu_bh); -void rcu_barrier (void ) -{ -struct rcu_synchronize rcu; - -init_rcu_head_on_stack (&rcu.head); -init_completion (&rcu.completion); -/* Will wake me after RCU finished. */ -call_rcu (&rcu.head, wakeme_after_rcu); -/* Wait for it. */ -wait_for_completion (&rcu.completion); -destroy_rcu_head_on_stack (&rcu.head); -} -EXPORT_SYMBOL_GPL (rcu_barrier); -void rcu_barrier_bh (void ) {struct rcu_synchronize rcu;
@@ -289,5 +286,3 @@ void __init rcu_init(void) {open_softirq (RCU_SOFTIRQ , rcu_process_callbacks); } - -#include "rcutiny_plugin.h"
kernel/rcutiny_plugin.h +579 -3
597 lines not on this page · raw message
PATCH 9/10 rcu: update obsolete rcu_read_lock() comment.
In reply to Paul E. McKenneyThe comment says that blocking is illegal in rcu_read_lock()-style RCU read-side critical sections, which is no longer entirely true given preemptible RCU. This commit provides a fix.
--- include/linux/rcupdate.h | 15 ++++++++++++++- 1 files changed, 14 insertions(+), 1 deletions(-)
include/linux/rcupdate.h +14 -1
@@ -458,7 +458,20 @@ extern int rcu_my_thread_group_empty(void);* 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. +* You can avoid reading and understanding the next paragraph by +* following this rule: don't put anything in an rcu_read_lock() RCU +* read-side critical section that would block in a !PREEMPT kernel. +* But if you want the full story, read on! +* +* In non-preemptible RCU implementations (TREE_RCU and TINY_RCU), it +* is illegal to block while in an RCU read-side critical section. In +* preemptible RCU implementations (TREE_PREEMPT_RCU and TINY_PREEMPT_RCU) +* in CONFIG_PREEMPT kernel builds, RCU read-side critical sections may +* be preempted, but explicit blocking is illegal. Finally, in preemptible +* RCU implementations in real-time (CONFIG_PREEMPT_RT) kernel builds, +* RCU read-side critical sections may be preempted and they may also +* block, but only when acquiring spinlocks that are subject to priority +* inheritance. */ static inline void rcu_read_lock (void ) {
Signature · 1 line
1.7.0.6
Re: [PATCH tip/core/rcu 09/10] rcu: update obsolete rcu_read_lock() comment.
Quoted 23 lines · * Paul E. McKenney ([email protected]) wrote:
The comment says that blocking is illegal in rcu_read_lock()-style RCU read-side critical sections, which is no longer entirely true given preemptible RCU. This commit provides a fix.
Suggested-by David Miller <[email protected]>Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/rcupdate.h | 15 ++++++++++++++- 1 files changed, 14 insertions(+), 1 deletions(-)include/linux/rcupdate.h +4
-1@@ -458,7 +458,20 @@ extern int rcu_my_thread_group_empty(void);* 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. +* You can avoid reading and understanding the next paragraph by +* following this rule: don't put anything in an rcu_read_lock() RCU +* read-side critical section that would block in a !PREEMPT kernel. +* But if you want the full story, read on!
include/linux/rcupdate.h extern int rcu_my_thread_group_empty(void); · line 474
Quoted 10 lines
include/linux/rcupdate.h +10
-0+* +* In non-preemptible RCU implementations (TREE_RCU and TINY_RCU), it +* is illegal to block while in an RCU read-side critical section. In +* preemptible RCU implementations (TREE_PREEMPT_RCU and TINY_PREEMPT_RCU) +* in CONFIG_PREEMPT kernel builds, RCU read-side critical sections may +* be preempted, but explicit blocking is illegal. Finally, in preemptible +* RCU implementations in real-time (CONFIG_PREEMPT_RT) kernel builds, +* RCU read-side critical sections may be preempted and they may also +* block, but only when acquiring spinlocks that are subject to priority +* inheritance.
It might be good to add a note about locking chain dependency that is created in the RT case, e.g., the lock we are sharing with another context in preempt RT is subject to the same rules as the RCU C.S.. It should never call synchronize_rcu(); this would cause a RCU+lock-induced deadlock.
I must admit, however, that because calling synchronize_rcu() from spinlocks is already forbidden, this is already implied.
Thanks,
Mathieu
Quoted 6 lines
include/linux/rcupdate.h +0
-0*/ static inline void rcu_read_lock (void ) {Signature · 1 line
1.7.0.6
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Re: [PATCH tip/core/rcu 09/10] rcu: update obsolete rcu_read_lock() comment.
Quoted 41 lines · Mathieu Desnoyers
Quoted 23 lines · * Paul E. McKenney ([email protected]) wrote:
The comment says that blocking is illegal in rcu_read_lock()-style RCU read-side critical sections, which is no longer entirely true given preemptible RCU. This commit provides a fix.
Suggested-by David Miller <[email protected]>Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/rcupdate.h | 15 ++++++++++++++- 1 files changed, 14 insertions(+), 1 deletions(-)include/linux/rcupdate.h +4
-1@@ -458,7 +458,20 @@ extern int rcu_my_thread_group_empty(void);* 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. +* You can avoid reading and understanding the next paragraph by +* following this rule: don't put anything in an rcu_read_lock() RCU +* read-side critical section that would block in a !PREEMPT kernel. +* But if you want the full story, read on! include/linux/rcupdate.h extern int rcu_my_thread_group_empty(void); · line 474
Quoted 10 lines
include/linux/rcupdate.h +10
-0+* +* In non-preemptible RCU implementations (TREE_RCU and TINY_RCU), it +* is illegal to block while in an RCU read-side critical section. In +* preemptible RCU implementations (TREE_PREEMPT_RCU and TINY_PREEMPT_RCU) +* in CONFIG_PREEMPT kernel builds, RCU read-side critical sections may +* be preempted, but explicit blocking is illegal. Finally, in preemptible +* RCU implementations in real-time (CONFIG_PREEMPT_RT) kernel builds, +* RCU read-side critical sections may be preempted and they may also +* block, but only when acquiring spinlocks that are subject to priority +* inheritance. It might be good to add a note about locking chain dependency that is created in the RT case, e.g., the lock we are sharing with another context in preempt RT is subject to the same rules as the RCU
C.S.. It should never callsynchronize_rcu(); this would cause a RCU+lock-induced deadlock.
Quoted 2 lines
I must admit, however, that because calling
synchronize_rcu()from spinlocks is already forbidden, this is already implied.
Thank you for looking this over!
I am updating the srcu_read_lock() docbook comments to call out the potential for this problem, given that SRCU read-side critical sections can acquire mutexes, which can be held across both synchronize_srcu() and synchronize_srcu_expedited().
Seem reasonable?
Thanx, Paul
include/linux/srcu.h +6 -1
@@ -139,7 +139,12 @@ static inline int srcu_read_lock_held(struct srcu_struct *sp)* @sp: srcu_struct in which to register the new reader. * * Enter an SRCU read-side critical section. Note that SRCU read-side -* critical sections may be nested. +* critical sections may be nested. However, it is illegal to +* call anything that waits on an SRCU grace period for the same +* srcu_struct, whether directly or indirectly. Please note that +* one way to indirectly wait on an SRCU grace period is to acquire +* a mutex that is held elsewhere while calling synchronize_srcu() or +* synchronize_srcu_expedited(). */ static inline int srcu_read_lock (struct srcu_struct *sp)__acquires (sp) {
Quoted 16 lines
Thanks,
Mathieu
Quoted 6 lines
include/linux/rcupdate.h +0
-0*/ static inline void rcu_read_lock (void ) {Signature · 1 line
1.7.0.6Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Re: [PATCH tip/core/rcu 09/10] rcu: update obsolete rcu_read_lock() comment.
Quoted 45 lines · * Paul E. McKenney ([email protected]) wrote:
Quoted 41 lines · Mathieu Desnoyers
Quoted 23 lines · * Paul E. McKenney ([email protected]) wrote:
The comment says that blocking is illegal in rcu_read_lock()-style RCU read-side critical sections, which is no longer entirely true given preemptible RCU. This commit provides a fix.
Suggested-by David Miller <[email protected]>Signed-off-by Paul E. McKenney <[email protected]>--- include/linux/rcupdate.h | 15 ++++++++++++++- 1 files changed, 14 insertions(+), 1 deletions(-)include/linux/rcupdate.h +4
-1@@ -458,7 +458,20 @@ extern int rcu_my_thread_group_empty(void);* 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. +* You can avoid reading and understanding the next paragraph by +* following this rule: don't put anything in an rcu_read_lock() RCU +* read-side critical section that would block in a !PREEMPT kernel. +* But if you want the full story, read on! include/linux/rcupdate.h extern int rcu_my_thread_group_empty(void); · line 474
Quoted 10 lines
include/linux/rcupdate.h +10
-0+* +* In non-preemptible RCU implementations (TREE_RCU and TINY_RCU), it +* is illegal to block while in an RCU read-side critical section. In +* preemptible RCU implementations (TREE_PREEMPT_RCU and TINY_PREEMPT_RCU) +* in CONFIG_PREEMPT kernel builds, RCU read-side critical sections may +* be preempted, but explicit blocking is illegal. Finally, in preemptible +* RCU implementations in real-time (CONFIG_PREEMPT_RT) kernel builds, +* RCU read-side critical sections may be preempted and they may also +* block, but only when acquiring spinlocks that are subject to priority +* inheritance. It might be good to add a note about locking chain dependency that is created in the RT case, e.g., the lock we are sharing with another context in preempt RT is subject to the same rules as the RCU
C.S.. It should never callsynchronize_rcu(); this would cause a RCU+lock-induced deadlock.Quoted 2 lines
I must admit, however, that because calling
synchronize_rcu()from spinlocks is already forbidden, this is already implied.
Quoted 8 lines
Thank you for looking this over!
I am updating the
srcu_read_lock()docbook comments to call out the potential for this problem, given that SRCU read-side critical sections can acquire mutexes, which can be held across bothsynchronize_srcu()andsynchronize_srcu_expedited().Seem reasonable?
Yep, thanks!
Mathieu
Quoted 38 lines
Thanx, Paul
include/linux/srcu.h +6
-1@@ -139,7 +139,12 @@ static inline int srcu_read_lock_held(struct srcu_struct *sp)* @sp: srcu_struct in which to register the new reader. * * Enter an SRCU read-side critical section. Note that SRCU read-side -* critical sections may be nested. +* critical sections may be nested. However, it is illegal to +* call anything that waits on an SRCU grace period for the same +* srcu_struct, whether directly or indirectly. Please note that +* one way to indirectly wait on an SRCU grace period is to acquire +* a mutex that is held elsewhere while calling synchronize_srcu() or +* synchronize_srcu_expedited(). */ static inline int srcu_read_lock (struct srcu_struct *sp)__acquires (sp) {Quoted 17 lines
Thanks,
Mathieu
Quoted 6 lines
include/linux/rcupdate.h +0
-0*/ static inline void rcu_read_lock (void ) {Signature · 1 line
1.7.0.6Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
Signature · 4 lines
Mathieu Desnoyers Operating System Efficiency R&D Consultant EfficiOS Inc. http://www.efficios.com
PATCH 10/10 rcu: refer RCU CPU stall-warning victims to stallwarn.txt
In reply to Paul E. McKenneyThere is some documentation on RCU CPU stall warnings contained in Documentation/RCU/stallwarn.txt, but it will not be apparent to someone who runs into such a warning while under time pressure. This commit therefore adds comments preceding the printk()s pointing out the location of this documentation.
--- kernel/rcutree.c | 12 ++++++++++-- 1 files changed, 10 insertions(+), 2 deletions(-)
kernel/rcutree.c +10 -2
@@ -487,8 +487,11 @@ static void print_other_cpu_stall(struct rcu_state *rsp)rcu_print_task_stall (rnp);raw_spin_unlock_irqrestore (&rnp->lock, flags); -/* OK, time to rat on our buddy... */ - +/* +* OK, time to rat on our buddy... +* See Documentation/RCU/stallwarn.txt for info on how to debug +* RCU CPU stall warnings. +*/ printk (KERN_ERR "INFO: %s detected stalls on CPUs/tasks: {" , rsp->name);rcu_for_each_leaf_node (rsp, rnp) {
@@ -517,6 +520,11 @@ static void print_cpu_stall(struct rcu_state *rsp)unsigned long flags;struct rcu_node *rnp =rcu_get_root (rsp); +/* +* OK, time to rat on ourselves... +* See Documentation/RCU/stallwarn.txt for info on how to debug +* RCU CPU stall warnings. +*/ printk (KERN_ERR "INFO: %s detected stall on CPU %d (t=%lu jiffies)\n" , rsp->name,smp_processor_id (), jiffies - rsp->gp_start);trigger_all_cpu_backtrace ();
Signature · 1 line
1.7.0.6