Skip to content

Commit

Permalink
Merge branch 'rcu/next' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/paulmck/linux-rcu into core/rcu

Pull the RCU tree from Paul E. McKenney:

"The major features of this series are:

1.	Preventing latency spikes of more than 200 microseconds for
	kernels built with NR_CPUS=4096, which is reportedly becoming
	the default for some distros.  This is a first step, as it does
	not help with systems that actually -have- 4096 CPUs (work on
	this case is in progress, but is not yet ready for mainline).
	This category also includes improving concurrency of rcu_barrier(),
	placed here due to conflicts.  Posted to LKML at:
	https://lkml.org/lkml/2012/6/22/381.  Note that patches 18-22
	of that series have been defered to 3.7, as they have not yet
	proven themselves to be mainline-ready (and yes, these are the
	ones intended to get rid of RCU's latency spikes for systems
	that actually have 4096 CPUs).
2.	Updates to documentation and rcutorture fixes, the latter category
	including improvements to rcu_barrier() testing.  Posted to LKML at:
	http://lkml.indiana.edu/hypermail/linux/kernel/1206.1/04094.html.
3.	Miscellaneous fixes posted to LKML at:
	https://lkml.org/lkml/2012/6/22/500, with the exception of the
	last commit, which was posted here:
	http://www.gossamer-threads.com/lists/linux/kernel/1561830
4.	RCU_FAST_NO_HZ fixes and improvements.  Posted to LKML at:
	http://lkml.indiana.edu/hypermail/linux/kernel/1206.1/00006.html
	and http://www.gossamer-threads.com/lists/linux/kernel/1561833.
	The first four patches of the first series went into 3.5 to fix
	a regression.
5.	Code-style fixes.  These were posted to LKML at
	http://lkml.indiana.edu/hypermail/linux/kernel/1205.2/01180.html and
	http://lkml.indiana.edu/hypermail/linux/kernel/1205.2/01181.html.
"

Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Ingo Molnar committed Jul 6, 2012
2 parents c4aed35 + 5cf05ad commit 5c09d12
Show file tree
Hide file tree
Showing 23 changed files with 688 additions and 606 deletions.
39 changes: 20 additions & 19 deletions Documentation/RCU/checklist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ over a rather long period of time, but improvements are always welcome!
when publicizing a pointer to a structure that can
be traversed by an RCU read-side critical section.

5. If call_rcu(), or a related primitive such as call_rcu_bh() or
call_rcu_sched(), is used, the callback function must be
written to be called from softirq context. In particular,
5. If call_rcu(), or a related primitive such as call_rcu_bh(),
call_rcu_sched(), or call_srcu() is used, the callback function
must be written to be called from softirq context. In particular,
it cannot block.

6. Since synchronize_rcu() can block, it cannot be called from
Expand Down Expand Up @@ -202,11 +202,12 @@ over a rather long period of time, but improvements are always welcome!
updater uses call_rcu_sched() or synchronize_sched(), then
the corresponding readers must disable preemption, possibly
by calling rcu_read_lock_sched() and rcu_read_unlock_sched().
If the updater uses synchronize_srcu(), the the corresponding
readers must use srcu_read_lock() and srcu_read_unlock(),
and with the same srcu_struct. The rules for the expedited
primitives are the same as for their non-expedited counterparts.
Mixing things up will result in confusion and broken kernels.
If the updater uses synchronize_srcu() or call_srcu(),
the the corresponding readers must use srcu_read_lock() and
srcu_read_unlock(), and with the same srcu_struct. The rules for
the expedited primitives are the same as for their non-expedited
counterparts. Mixing things up will result in confusion and
broken kernels.

One exception to this rule: rcu_read_lock() and rcu_read_unlock()
may be substituted for rcu_read_lock_bh() and rcu_read_unlock_bh()
Expand Down Expand Up @@ -333,14 +334,14 @@ over a rather long period of time, but improvements are always welcome!
victim CPU from ever going offline.)

14. SRCU (srcu_read_lock(), srcu_read_unlock(), srcu_dereference(),
synchronize_srcu(), and synchronize_srcu_expedited()) may only
be invoked from process context. Unlike other forms of RCU, it
-is- permissible to block in an SRCU read-side critical section
(demarked by srcu_read_lock() and srcu_read_unlock()), hence the
"SRCU": "sleepable RCU". Please note that if you don't need
to sleep in read-side critical sections, you should be using
RCU rather than SRCU, because RCU is almost always faster and
easier to use than is SRCU.
synchronize_srcu(), synchronize_srcu_expedited(), and call_srcu())
may only be invoked from process context. Unlike other forms of
RCU, it -is- permissible to block in an SRCU read-side critical
section (demarked by srcu_read_lock() and srcu_read_unlock()),
hence the "SRCU": "sleepable RCU". Please note that if you
don't need to sleep in read-side critical sections, you should be
using RCU rather than SRCU, because RCU is almost always faster
and easier to use than is SRCU.

If you need to enter your read-side critical section in a
hardirq or exception handler, and then exit that same read-side
Expand All @@ -353,8 +354,8 @@ over a rather long period of time, but improvements are always welcome!
cleanup_srcu_struct(). These are passed a "struct srcu_struct"
that defines the scope of a given SRCU domain. Once initialized,
the srcu_struct is passed to srcu_read_lock(), srcu_read_unlock()
synchronize_srcu(), and synchronize_srcu_expedited(). A given
synchronize_srcu() waits only for SRCU read-side critical
synchronize_srcu(), synchronize_srcu_expedited(), and call_srcu().
A given synchronize_srcu() waits only for SRCU read-side critical
sections governed by srcu_read_lock() and srcu_read_unlock()
calls that have been passed the same srcu_struct. This property
is what makes sleeping read-side critical sections tolerable --
Expand All @@ -374,7 +375,7 @@ over a rather long period of time, but improvements are always welcome!
requiring SRCU's read-side deadlock immunity or low read-side
realtime latency.

Note that, rcu_assign_pointer() relates to SRCU just as they do
Note that, rcu_assign_pointer() relates to SRCU just as it does
to other forms of RCU.

15. The whole point of call_rcu(), synchronize_rcu(), and friends
Expand Down
15 changes: 4 additions & 11 deletions Documentation/RCU/rcubarrier.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ complete. Pseudo-code using rcu_barrier() is as follows:
2. Execute rcu_barrier().
3. Allow the module to be unloaded.

Quick Quiz #1: Why is there no srcu_barrier()?

The rcutorture module makes use of rcu_barrier in its exit function
as follows:

Expand Down Expand Up @@ -162,7 +160,7 @@ for any pre-existing callbacks to complete.
Then lines 55-62 print status and do operation-specific cleanup, and
then return, permitting the module-unload operation to be completed.

Quick Quiz #2: Is there any other situation where rcu_barrier() might
Quick Quiz #1: Is there any other situation where rcu_barrier() might
be required?

Your module might have additional complications. For example, if your
Expand Down Expand Up @@ -242,7 +240,7 @@ reaches zero, as follows:
4 complete(&rcu_barrier_completion);
5 }

Quick Quiz #3: What happens if CPU 0's rcu_barrier_func() executes
Quick Quiz #2: What happens if CPU 0's rcu_barrier_func() executes
immediately (thus incrementing rcu_barrier_cpu_count to the
value one), but the other CPU's rcu_barrier_func() invocations
are delayed for a full grace period? Couldn't this result in
Expand All @@ -259,12 +257,7 @@ so that your module may be safely unloaded.

Answers to Quick Quizzes

Quick Quiz #1: Why is there no srcu_barrier()?

Answer: Since there is no call_srcu(), there can be no outstanding SRCU
callbacks. Therefore, there is no need to wait for them.

Quick Quiz #2: Is there any other situation where rcu_barrier() might
Quick Quiz #1: Is there any other situation where rcu_barrier() might
be required?

Answer: Interestingly enough, rcu_barrier() was not originally
Expand All @@ -278,7 +271,7 @@ Answer: Interestingly enough, rcu_barrier() was not originally
implementing rcutorture, and found that rcu_barrier() solves
this problem as well.

Quick Quiz #3: What happens if CPU 0's rcu_barrier_func() executes
Quick Quiz #2: What happens if CPU 0's rcu_barrier_func() executes
immediately (thus incrementing rcu_barrier_cpu_count to the
value one), but the other CPU's rcu_barrier_func() invocations
are delayed for a full grace period? Couldn't this result in
Expand Down
9 changes: 9 additions & 0 deletions Documentation/RCU/torture.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,20 @@ torture_type The type of RCU to test, with string values as follows:
and synchronize_rcu_bh_expedited().

"srcu": srcu_read_lock(), srcu_read_unlock() and
call_srcu().

"srcu_sync": srcu_read_lock(), srcu_read_unlock() and
synchronize_srcu().

"srcu_expedited": srcu_read_lock(), srcu_read_unlock() and
synchronize_srcu_expedited().

"srcu_raw": srcu_read_lock_raw(), srcu_read_unlock_raw(),
and call_srcu().

"srcu_raw_sync": srcu_read_lock_raw(), srcu_read_unlock_raw(),
and synchronize_srcu().

"sched": preempt_disable(), preempt_enable(), and
call_rcu_sched().

Expand Down
6 changes: 3 additions & 3 deletions Documentation/RCU/whatisRCU.txt
Original file line number Diff line number Diff line change
Expand Up @@ -833,9 +833,9 @@ sched: Critical sections Grace period Barrier

SRCU: Critical sections Grace period Barrier

srcu_read_lock synchronize_srcu N/A
srcu_read_unlock synchronize_srcu_expedited
srcu_read_lock_raw
srcu_read_lock synchronize_srcu srcu_barrier
srcu_read_unlock call_srcu
srcu_read_lock_raw synchronize_srcu_expedited
srcu_read_unlock_raw
srcu_dereference

Expand Down
5 changes: 5 additions & 0 deletions Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2367,6 +2367,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Set maximum number of finished RCU callbacks to process
in one batch.

rcutree.fanout_leaf= [KNL,BOOT]
Increase the number of CPUs assigned to each
leaf rcu_node structure. Useful for very large
systems.

rcutree.qhimark= [KNL,BOOT]
Set threshold of queued
RCU callbacks over which batch limiting is disabled.
Expand Down
1 change: 0 additions & 1 deletion arch/um/drivers/mconsole_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,6 @@ static void stack_proc(void *arg)
struct task_struct *from = current, *to = arg;

to->thread.saved_task = from;
rcu_switch_from(from);
switch_to(from, to, from);
}

Expand Down
4 changes: 2 additions & 2 deletions include/linux/init_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ extern struct cred init_cred;
.children = LIST_HEAD_INIT(tsk.children), \
.sibling = LIST_HEAD_INIT(tsk.sibling), \
.group_leader = &tsk, \
RCU_INIT_POINTER(.real_cred, &init_cred), \
RCU_INIT_POINTER(.cred, &init_cred), \
RCU_POINTER_INITIALIZER(real_cred, &init_cred), \
RCU_POINTER_INITIALIZER(cred, &init_cred), \
.comm = INIT_TASK_COMM, \
.thread = INIT_THREAD, \
.fs = &init_fs, \
Expand Down
4 changes: 3 additions & 1 deletion include/linux/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,9 @@ static inline bool key_is_instantiated(const struct key *key)
rwsem_is_locked(&((struct key *)(KEY))->sem)))

#define rcu_assign_keypointer(KEY, PAYLOAD) \
(rcu_assign_pointer((KEY)->payload.rcudata, PAYLOAD))
do { \
rcu_assign_pointer((KEY)->payload.rcudata, (PAYLOAD)); \
} while (0)

#ifdef CONFIG_SYSCTL
extern ctl_table key_sysctls[];
Expand Down
54 changes: 20 additions & 34 deletions include/linux/rcupdate.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ extern void synchronize_sched(void);

extern void __rcu_read_lock(void);
extern void __rcu_read_unlock(void);
extern void rcu_read_unlock_special(struct task_struct *t);
void synchronize_rcu(void);

/*
Expand Down Expand Up @@ -184,7 +185,6 @@ static inline int rcu_preempt_depth(void)
/* Internal to kernel */
extern void rcu_sched_qs(int cpu);
extern void rcu_bh_qs(int cpu);
extern void rcu_preempt_note_context_switch(void);
extern void rcu_check_callbacks(int cpu, int user);
struct notifier_block;
extern void rcu_idle_enter(void);
Expand Down Expand Up @@ -256,6 +256,10 @@ static inline void destroy_rcu_head_on_stack(struct rcu_head *head)
}
#endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */

#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SMP)
extern int rcu_is_cpu_idle(void);
#endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SMP) */

#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU)
bool rcu_lockdep_current_cpu_online(void);
#else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
Expand All @@ -267,15 +271,6 @@ static inline bool rcu_lockdep_current_cpu_online(void)

#ifdef CONFIG_DEBUG_LOCK_ALLOC

#ifdef CONFIG_PROVE_RCU
extern int rcu_is_cpu_idle(void);
#else /* !CONFIG_PROVE_RCU */
static inline int rcu_is_cpu_idle(void)
{
return 0;
}
#endif /* else !CONFIG_PROVE_RCU */

static inline void rcu_lock_acquire(struct lockdep_map *map)
{
lock_acquire(map, 0, 0, 2, 1, NULL, _THIS_IP_);
Expand Down Expand Up @@ -432,8 +427,7 @@ extern int rcu_my_thread_group_empty(void);
static inline void rcu_preempt_sleep_check(void)
{
rcu_lockdep_assert(!lock_is_held(&rcu_lock_map),
"Illegal context switch in RCU read-side "
"critical section");
"Illegal context switch in RCU read-side critical section");
}
#else /* #ifdef CONFIG_PROVE_RCU */
static inline void rcu_preempt_sleep_check(void)
Expand Down Expand Up @@ -514,10 +508,10 @@ static inline void rcu_preempt_sleep_check(void)
(_________p1); \
})
#define __rcu_assign_pointer(p, v, space) \
({ \
do { \
smp_wmb(); \
(p) = (typeof(*v) __force space *)(v); \
})
} while (0)


/**
Expand Down Expand Up @@ -852,7 +846,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
*
* Assigns the specified value to the specified RCU-protected
* pointer, ensuring that any concurrent RCU readers will see
* any prior initialization. Returns the value assigned.
* any prior initialization.
*
* Inserts memory barriers on architectures that require them
* (which is most of them), and also prevents the compiler from
Expand Down Expand Up @@ -904,25 +898,17 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
* the reader-accessible portions of the linked structure.
*/
#define RCU_INIT_POINTER(p, v) \
p = (typeof(*v) __force __rcu *)(v)

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));
do { \
p = (typeof(*v) __force __rcu *)(v); \
} while (0)

kfree_call_rcu(head, (rcu_callback)offset);
}
/**
* RCU_POINTER_INITIALIZER() - statically initialize an RCU protected pointer
*
* GCC-style initialization for an RCU-protected pointer in a structure field.
*/
#define RCU_POINTER_INITIALIZER(p, v) \
.p = (typeof(*v) __force __rcu *)(v)

/*
* Does the specified offset indicate that the corresponding rcu_head
Expand All @@ -936,7 +922,7 @@ void __kfree_rcu(struct rcu_head *head, unsigned long offset)
#define __kfree_rcu(head, offset) \
do { \
BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); \
call_rcu(head, (void (*)(struct rcu_head *))(unsigned long)(offset)); \
kfree_call_rcu(head, (void (*)(struct rcu_head *))(unsigned long)(offset)); \
} while (0)

/**
Expand Down
6 changes: 6 additions & 0 deletions include/linux/rcutiny.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ static inline void kfree_call_rcu(struct rcu_head *head,

#ifdef CONFIG_TINY_RCU

static inline void rcu_preempt_note_context_switch(void)
{
}

static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
{
*delta_jiffies = ULONG_MAX;
Expand All @@ -95,6 +99,7 @@ static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)

#else /* #ifdef CONFIG_TINY_RCU */

void rcu_preempt_note_context_switch(void);
int rcu_preempt_needs_cpu(void);

static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
Expand All @@ -108,6 +113,7 @@ static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
static inline void rcu_note_context_switch(int cpu)
{
rcu_sched_qs(cpu);
rcu_preempt_note_context_switch();
}

/*
Expand Down
10 changes: 0 additions & 10 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1871,22 +1871,12 @@ static inline void rcu_copy_process(struct task_struct *p)
INIT_LIST_HEAD(&p->rcu_node_entry);
}

static inline void rcu_switch_from(struct task_struct *prev)
{
if (prev->rcu_read_lock_nesting != 0)
rcu_preempt_note_context_switch();
}

#else

static inline void rcu_copy_process(struct task_struct *p)
{
}

static inline void rcu_switch_from(struct task_struct *prev)
{
}

#endif

#ifdef CONFIG_SMP
Expand Down
Loading

0 comments on commit 5c09d12

Please sign in to comment.