Skip to content

Commit

Permalink
Merge commit '29ce831000081dd757d3116bf774aafffc4b6b20' into next
Browse files Browse the repository at this point in the history
* commit '29ce831000081dd757d3116bf774aafffc4b6b20': (34 commits)
  rcu: provide rcu_virt_note_context_switch() function.
  rcu: get rid of signed overflow in check_cpu_stall()
  rcu: optimize rcutiny
  rcu: prevent call_rcu() from diving into rcu core if irqs disabled
  rcu: further lower priority in rcu_yield()
  rcu: introduce kfree_rcu()
  rcu: fix spelling
  rcu: call __rcu_read_unlock() in exit_rcu for tree RCU
  rcu: Converge TINY_RCU expedited and normal boosting
  rcu: remove useless ->boosted_this_gp field
  rcu: code cleanups in TINY_RCU priority boosting.
  rcu: Switch to this_cpu() primitives
  rcu: Use WARN_ON_ONCE for DEBUG_OBJECTS_RCU_HEAD warnings
  rcu: mark rcutorture boosting callback as being on-stack
  rcu: add DEBUG_OBJECTS_RCU_HEAD check for alignment
  rcu: Enable DEBUG_OBJECTS_RCU_HEAD from !PREEMPT
  rcu: Add forward-progress diagnostic for per-CPU kthreads
  rcu: add grace-period age and more kthread state to tracing
  rcu: fix tracing bug thinko on boost-balk attribution
  rcu: update tracing documentation for new rcutorture and rcuboost
  ...

Pulling in rcu_virt_note_context_switch().

Signed-off-by: Avi Kivity <avi@redhat.com>

* commit '29ce831000081dd757d3116bf774aafffc4b6b20': (34 commits)
  rcu: provide rcu_virt_note_context_switch() function.
  rcu: get rid of signed overflow in check_cpu_stall()
  rcu: optimize rcutiny
  rcu: prevent call_rcu() from diving into rcu core if irqs disabled
  rcu: further lower priority in rcu_yield()
  rcu: introduce kfree_rcu()
  rcu: fix spelling
  rcu: call __rcu_read_unlock() in exit_rcu for tree RCU
  rcu: Converge TINY_RCU expedited and normal boosting
  rcu: remove useless ->boosted_this_gp field
  rcu: code cleanups in TINY_RCU priority boosting.
  rcu: Switch to this_cpu() primitives
  rcu: Use WARN_ON_ONCE for DEBUG_OBJECTS_RCU_HEAD warnings
  rcu: mark rcutorture boosting callback as being on-stack
  rcu: add DEBUG_OBJECTS_RCU_HEAD check for alignment
  rcu: Enable DEBUG_OBJECTS_RCU_HEAD from !PREEMPT
  rcu: Add forward-progress diagnostic for per-CPU kthreads
  rcu: add grace-period age and more kthread state to tracing
  rcu: fix tracing bug thinko on boost-balk attribution
  rcu: update tracing documentation for new rcutorture and rcuboost
  ...
  • Loading branch information
Avi Kivity committed May 22, 2011
2 parents d2f6276 + 29ce831 commit e3aa52d
Show file tree
Hide file tree
Showing 21 changed files with 1,783 additions and 551 deletions.
2 changes: 1 addition & 1 deletion Documentation/RCU/00-INDEX
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ rcu.txt
RTFP.txt
- List of RCU papers (bibliography) going back to 1980.
stallwarn.txt
- RCU CPU stall warnings (CONFIG_RCU_CPU_STALL_DETECTOR)
- RCU CPU stall warnings (module parameter rcu_cpu_stall_suppress)
torture.txt
- RCU Torture Test Operation (CONFIG_RCU_TORTURE_TEST)
trace.txt
Expand Down
23 changes: 13 additions & 10 deletions Documentation/RCU/stallwarn.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
Using RCU's CPU Stall Detector

The CONFIG_RCU_CPU_STALL_DETECTOR kernel config parameter enables
RCU's CPU stall detector, which detects conditions that unduly delay
RCU grace periods. The stall detector's idea of what constitutes
"unduly delayed" is controlled by a set of C preprocessor macros:
The rcu_cpu_stall_suppress module parameter enables RCU's CPU stall
detector, which detects conditions that unduly delay RCU grace periods.
This module parameter enables CPU stall detection by default, but
may be overridden via boot-time parameter or at runtime via sysfs.
The stall detector's idea of what constitutes "unduly delayed" is
controlled by a set of kernel configuration variables and cpp macros:

RCU_SECONDS_TILL_STALL_CHECK
CONFIG_RCU_CPU_STALL_TIMEOUT

This macro defines the period of time that RCU will wait from
the beginning of a grace period until it issues an RCU CPU
stall warning. This time period is normally ten seconds.
This kernel configuration parameter defines the period of time
that RCU will wait from the beginning of a grace period until it
issues an RCU CPU stall warning. This time period is normally
ten seconds.

RCU_SECONDS_TILL_STALL_RECHECK

This macro defines the period of time that RCU will wait after
issuing a stall warning until it issues another stall warning
for the same stall. This time period is normally set to thirty
seconds.
for the same stall. This time period is normally set to three
times the check interval plus thirty seconds.

RCU_STALL_RAT_DELAY

Expand Down
295 changes: 236 additions & 59 deletions Documentation/RCU/trace.txt

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion Documentation/filesystems/proc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,6 @@ Provides counts of softirq handlers serviced since boot time, for each cpu.
TASKLET: 0 0 0 290
SCHED: 27035 26983 26971 26746
HRTIMER: 0 0 0 0
RCU: 1678 1769 2178 2250


1.3 IDE devices in /proc/ide
Expand Down
1 change: 0 additions & 1 deletion include/linux/interrupt.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,6 @@ enum
TASKLET_SOFTIRQ,
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ,
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */

NR_SOFTIRQS
};
Expand Down
70 changes: 69 additions & 1 deletion include/linux/rcupdate.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@
extern int rcutorture_runnable; /* for sysctl */
#endif /* #ifdef CONFIG_RCU_TORTURE_TEST */

#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
extern void rcutorture_record_test_transition(void);
extern void rcutorture_record_progress(unsigned long vernum);
#else
static inline void rcutorture_record_test_transition(void)
{
}
static inline void rcutorture_record_progress(unsigned long vernum)
{
}
#endif

#define UINT_CMP_GE(a, b) (UINT_MAX / 2 >= (a) - (b))
#define UINT_CMP_LT(a, b) (UINT_MAX / 2 < (a) - (b))
#define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >= (a) - (b))
Expand All @@ -68,7 +80,6 @@ extern void call_rcu_sched(struct rcu_head *head,
extern void synchronize_sched(void);
extern void rcu_barrier_bh(void);
extern void rcu_barrier_sched(void);
extern int sched_expedited_torture_stats(char *page);

static inline void __rcu_read_lock_bh(void)
{
Expand Down Expand Up @@ -774,6 +785,7 @@ extern struct debug_obj_descr rcuhead_debug_descr;

static inline void debug_rcu_head_queue(struct rcu_head *head)
{
WARN_ON_ONCE((unsigned long)head & 0x3);
debug_object_activate(head, &rcuhead_debug_descr);
debug_object_active_state(head, &rcuhead_debug_descr,
STATE_RCU_HEAD_READY,
Expand All @@ -797,4 +809,60 @@ static inline void debug_rcu_head_unqueue(struct rcu_head *head)
}
#endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */

static __always_inline bool __is_kfree_rcu_offset(unsigned long offset)
{
return offset < 4096;
}

static __always_inline
void __kfree_rcu(struct rcu_head *head, unsigned long offset)
{
typedef void (*rcu_callback)(struct rcu_head *);

BUILD_BUG_ON(!__builtin_constant_p(offset));

/* See the kfree_rcu() header comment. */
BUILD_BUG_ON(!__is_kfree_rcu_offset(offset));

call_rcu(head, (rcu_callback)offset);
}

extern void kfree(const void *);

static inline void __rcu_reclaim(struct rcu_head *head)
{
unsigned long offset = (unsigned long)head->func;

if (__is_kfree_rcu_offset(offset))
kfree((void *)head - offset);
else
head->func(head);
}

/**
* kfree_rcu() - kfree an object after a grace period.
* @ptr: pointer to kfree
* @rcu_head: the name of the struct rcu_head within the type of @ptr.
*
* Many rcu callbacks functions just call kfree() on the base structure.
* These functions are trivial, but their size adds up, and furthermore
* when they are used in a kernel module, that module must invoke the
* high-latency rcu_barrier() function at module-unload time.
*
* The kfree_rcu() function handles this issue. Rather than encoding a
* function address in the embedded rcu_head structure, kfree_rcu() instead
* encodes the offset of the rcu_head structure within the base structure.
* Because the functions are not allowed in the low-order 4096 bytes of
* kernel virtual memory, offsets up to 4095 bytes can be accommodated.
* If the offset is larger than 4095 bytes, a compile-time error will
* be generated in __kfree_rcu(). If this error is triggered, you can
* either fall back to use of call_rcu() or rearrange the structure to
* position the rcu_head structure into the first 4096 bytes.
*
* Note that the allowable offset might decrease in the future, for example,
* to allow something like kmem_cache_free_rcu().
*/
#define kfree_rcu(ptr, rcu_head) \
__kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head))

#endif /* __LINUX_RCUPDATE_H */
8 changes: 8 additions & 0 deletions include/linux/rcutiny.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ static inline void rcu_note_context_switch(int cpu)
rcu_preempt_note_context_switch();
}

/*
* Take advantage of the fact that there is only one CPU, which
* allows us to ignore virtualization-based context switches.
*/
static inline void rcu_virt_note_context_switch(int cpu)
{
}

/*
* Return the number of grace periods.
*/
Expand Down
13 changes: 13 additions & 0 deletions include/linux/rcutree.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ extern void rcu_note_context_switch(int cpu);
extern int rcu_needs_cpu(int cpu);
extern void rcu_cpu_stall_reset(void);

/*
* Note a virtualization-based context switch. This is simply a
* wrapper around rcu_note_context_switch(), which allows TINY_RCU
* to save a few bytes.
*/
static inline void rcu_virt_note_context_switch(int cpu)
{
rcu_note_context_switch(cpu);
}

#ifdef CONFIG_TREE_PREEMPT_RCU

extern void exit_rcu(void);
Expand All @@ -58,9 +68,12 @@ static inline void synchronize_rcu_bh_expedited(void)

extern void rcu_barrier(void);

extern unsigned long rcutorture_testseq;
extern unsigned long rcutorture_vernum;
extern long rcu_batches_completed(void);
extern long rcu_batches_completed_bh(void);
extern long rcu_batches_completed_sched(void);

extern void rcu_force_quiescent_state(void);
extern void rcu_bh_force_quiescent_state(void);
extern void rcu_sched_force_quiescent_state(void);
Expand Down
3 changes: 1 addition & 2 deletions include/trace/events/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ struct softirq_action;
softirq_name(BLOCK_IOPOLL), \
softirq_name(TASKLET), \
softirq_name(SCHED), \
softirq_name(HRTIMER), \
softirq_name(RCU))
softirq_name(HRTIMER))

/**
* irq_handler_entry - called immediately before the irq action handler
Expand Down
2 changes: 1 addition & 1 deletion init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ config TREE_RCU_TRACE

config RCU_BOOST
bool "Enable RCU priority boosting"
depends on RT_MUTEXES && TINY_PREEMPT_RCU
depends on RT_MUTEXES && PREEMPT_RCU
default n
help
This option boosts the priority of preempted RCU readers that
Expand Down
32 changes: 24 additions & 8 deletions kernel/rcupdate.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,17 @@ static int rcuhead_fixup_init(void *addr, enum debug_obj_state state)
* Ensure that queued callbacks are all executed.
* If we detect that we are nested in a RCU read-side critical
* section, we should simply fail, otherwise we would deadlock.
* In !PREEMPT configurations, there is no way to tell if we are
* in a RCU read-side critical section or not, so we never
* attempt any fixup and just print a warning.
*/
#ifndef CONFIG_PREEMPT
WARN_ON_ONCE(1);
return 0;
#endif
if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
irqs_disabled()) {
WARN_ON(1);
WARN_ON_ONCE(1);
return 0;
}
rcu_barrier();
Expand Down Expand Up @@ -184,10 +191,17 @@ static int rcuhead_fixup_activate(void *addr, enum debug_obj_state state)
* Ensure that queued callbacks are all executed.
* If we detect that we are nested in a RCU read-side critical
* section, we should simply fail, otherwise we would deadlock.
* In !PREEMPT configurations, there is no way to tell if we are
* in a RCU read-side critical section or not, so we never
* attempt any fixup and just print a warning.
*/
#ifndef CONFIG_PREEMPT
WARN_ON_ONCE(1);
return 0;
#endif
if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
irqs_disabled()) {
WARN_ON(1);
WARN_ON_ONCE(1);
return 0;
}
rcu_barrier();
Expand All @@ -214,15 +228,17 @@ static int rcuhead_fixup_free(void *addr, enum debug_obj_state state)
* Ensure that queued callbacks are all executed.
* If we detect that we are nested in a RCU read-side critical
* section, we should simply fail, otherwise we would deadlock.
* Note that the machinery to reliably determine whether
* or not we are in an RCU read-side critical section
* exists only in the preemptible RCU implementations
* (TINY_PREEMPT_RCU and TREE_PREEMPT_RCU), which is why
* DEBUG_OBJECTS_RCU_HEAD is disallowed if !PREEMPT.
* In !PREEMPT configurations, there is no way to tell if we are
* in a RCU read-side critical section or not, so we never
* attempt any fixup and just print a warning.
*/
#ifndef CONFIG_PREEMPT
WARN_ON_ONCE(1);
return 0;
#endif
if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
irqs_disabled()) {
WARN_ON(1);
WARN_ON_ONCE(1);
return 0;
}
rcu_barrier();
Expand Down
45 changes: 22 additions & 23 deletions kernel/rcutiny.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@
static struct task_struct *rcu_kthread_task;
static DECLARE_WAIT_QUEUE_HEAD(rcu_kthread_wq);
static unsigned long have_rcu_kthread_work;
static void invoke_rcu_kthread(void);

/* Forward declarations for rcutiny_plugin.h. */
struct rcu_ctrlblk;
static void invoke_rcu_kthread(void);
static void rcu_process_callbacks(struct rcu_ctrlblk *rcp);
static int rcu_kthread(void *arg);
static void __call_rcu(struct rcu_head *head,
Expand Down Expand Up @@ -79,45 +79,58 @@ void rcu_exit_nohz(void)
#endif /* #ifdef CONFIG_NO_HZ */

/*
* Helper function for rcu_qsctr_inc() and rcu_bh_qsctr_inc().
* Also disable irqs to avoid confusion due to interrupt handlers
* Helper function for rcu_sched_qs() and rcu_bh_qs().
* Also irqs are disabled to avoid confusion due to interrupt handlers
* invoking call_rcu().
*/
static int rcu_qsctr_help(struct rcu_ctrlblk *rcp)
{
unsigned long flags;

local_irq_save(flags);
if (rcp->rcucblist != NULL &&
rcp->donetail != rcp->curtail) {
rcp->donetail = rcp->curtail;
local_irq_restore(flags);
return 1;
}
local_irq_restore(flags);

return 0;
}

/*
* Wake up rcu_kthread() to process callbacks now eligible for invocation
* or to boost readers.
*/
static void invoke_rcu_kthread(void)
{
have_rcu_kthread_work = 1;
wake_up(&rcu_kthread_wq);
}

/*
* Record an rcu quiescent state. And an rcu_bh quiescent state while we
* are at it, given that any rcu quiescent state is also an rcu_bh
* quiescent state. Use "+" instead of "||" to defeat short circuiting.
*/
void rcu_sched_qs(int cpu)
{
unsigned long flags;

local_irq_save(flags);
if (rcu_qsctr_help(&rcu_sched_ctrlblk) +
rcu_qsctr_help(&rcu_bh_ctrlblk))
invoke_rcu_kthread();
local_irq_restore(flags);
}

/*
* Record an rcu_bh quiescent state.
*/
void rcu_bh_qs(int cpu)
{
unsigned long flags;

local_irq_save(flags);
if (rcu_qsctr_help(&rcu_bh_ctrlblk))
invoke_rcu_kthread();
local_irq_restore(flags);
}

/*
Expand Down Expand Up @@ -167,7 +180,7 @@ static void rcu_process_callbacks(struct rcu_ctrlblk *rcp)
prefetch(next);
debug_rcu_head_unqueue(list);
local_bh_disable();
list->func(list);
__rcu_reclaim(list);
local_bh_enable();
list = next;
RCU_TRACE(cb_count++);
Expand Down Expand Up @@ -207,20 +220,6 @@ static int rcu_kthread(void *arg)
return 0; /* Not reached, but needed to shut gcc up. */
}

/*
* Wake up rcu_kthread() to process callbacks now eligible for invocation
* or to boost readers.
*/
static void invoke_rcu_kthread(void)
{
unsigned long flags;

local_irq_save(flags);
have_rcu_kthread_work = 1;
wake_up(&rcu_kthread_wq);
local_irq_restore(flags);
}

/*
* Wait for a grace period to elapse. But it is illegal to invoke
* synchronize_sched() from within an RCU read-side critical section.
Expand Down
Loading

0 comments on commit e3aa52d

Please sign in to comment.