2019-01-18 02:18:16 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2017-03-26 00:59:38 +08:00
|
|
|
/*
|
|
|
|
* Sleepable Read-Copy Update mechanism for mutual exclusion,
|
|
|
|
* tiny version for non-preemptible single-CPU use.
|
|
|
|
*
|
|
|
|
* Copyright (C) IBM Corporation, 2017
|
|
|
|
*
|
2019-01-18 02:18:16 +08:00
|
|
|
* Author: Paul McKenney <paulmck@linux.ibm.com>
|
2017-03-26 00:59:38 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/export.h>
|
|
|
|
#include <linux/mutex.h>
|
|
|
|
#include <linux/preempt.h>
|
|
|
|
#include <linux/rcupdate_wait.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/srcu.h>
|
|
|
|
|
|
|
|
#include <linux/rcu_node_tree.h>
|
2017-05-02 16:31:18 +08:00
|
|
|
#include "rcu_segcblist.h"
|
2017-03-26 00:59:38 +08:00
|
|
|
#include "rcu.h"
|
|
|
|
|
2017-05-27 07:16:40 +08:00
|
|
|
int rcu_scheduler_active __read_mostly;
|
srcu: Make call_srcu() available during very early boot
Event tracing is moving to SRCU in order to take advantage of the fact
that SRCU may be safely used from idle and even offline CPUs. However,
event tracing can invoke call_srcu() very early in the boot process,
even before workqueue_init_early() is invoked (let alone rcu_init()).
Therefore, call_srcu()'s attempts to queue work fail miserably.
This commit therefore detects this situation, and refrains from attempting
to queue work before rcu_init() time, but does everything else that it
would have done, and in addition, adds the srcu_struct to a global list.
The rcu_init() function now invokes a new srcu_init() function, which
is empty if CONFIG_SRCU=n. Otherwise, srcu_init() queues work for
each srcu_struct on the list. This all happens early enough in boot
that there is but a single CPU with interrupts disabled, which allows
synchronization to be dispensed with.
Of course, the queued work won't actually be invoked until after
workqueue_init() is invoked, which happens shortly after the scheduler
is up and running. This means that although call_srcu() may be invoked
any time after per-CPU variables have been set up, there is still a very
narrow window when synchronize_srcu() won't work, and this window
extends from the time that the scheduler starts until the time that
workqueue_init() returns. This can be fixed in a manner similar to
the fix for synchronize_rcu_expedited() and friends, but until someone
actually needs to use synchronize_srcu() during this window, this fix
is added churn for no benefit.
Finally, note that Tree SRCU's new srcu_init() function invokes
queue_work() rather than the queue_delayed_work() function that is
invoked post-boot. The reason is that queue_delayed_work() will (as you
would expect) post a timer, and timers have not yet been initialized.
So use of queue_work() avoids the complaints about use of uninitialized
spinlocks that would otherwise result. Besides, some delay is already
provide by the aforementioned fact that the queued work won't actually
be invoked until after the scheduler is up and running.
Requested-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Tested-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
2018-08-14 23:45:54 +08:00
|
|
|
static LIST_HEAD(srcu_boot_list);
|
|
|
|
static bool srcu_init_done;
|
2017-05-27 07:16:40 +08:00
|
|
|
|
2018-10-29 01:32:51 +08:00
|
|
|
static int init_srcu_struct_fields(struct srcu_struct *ssp)
|
2017-03-26 00:59:38 +08:00
|
|
|
{
|
2018-10-29 01:32:51 +08:00
|
|
|
ssp->srcu_lock_nesting[0] = 0;
|
|
|
|
ssp->srcu_lock_nesting[1] = 0;
|
|
|
|
init_swait_queue_head(&ssp->srcu_wq);
|
|
|
|
ssp->srcu_cb_head = NULL;
|
|
|
|
ssp->srcu_cb_tail = &ssp->srcu_cb_head;
|
|
|
|
ssp->srcu_gp_running = false;
|
|
|
|
ssp->srcu_gp_waiting = false;
|
|
|
|
ssp->srcu_idx = 0;
|
2020-11-14 04:54:48 +08:00
|
|
|
ssp->srcu_idx_max = 0;
|
2018-10-29 01:32:51 +08:00
|
|
|
INIT_WORK(&ssp->srcu_work, srcu_drive_gp);
|
|
|
|
INIT_LIST_HEAD(&ssp->srcu_work.entry);
|
2017-03-26 00:59:38 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
|
|
|
2018-10-29 01:32:51 +08:00
|
|
|
int __init_srcu_struct(struct srcu_struct *ssp, const char *name,
|
2017-03-26 00:59:38 +08:00
|
|
|
struct lock_class_key *key)
|
|
|
|
{
|
|
|
|
/* Don't re-initialize a lock while it is held. */
|
2018-10-29 01:32:51 +08:00
|
|
|
debug_check_no_locks_freed((void *)ssp, sizeof(*ssp));
|
|
|
|
lockdep_init_map(&ssp->dep_map, name, key, 0);
|
|
|
|
return init_srcu_struct_fields(ssp);
|
2017-03-26 00:59:38 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(__init_srcu_struct);
|
|
|
|
|
|
|
|
#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* init_srcu_struct - initialize a sleep-RCU structure
|
2018-10-29 01:32:51 +08:00
|
|
|
* @ssp: structure to initialize.
|
2017-03-26 00:59:38 +08:00
|
|
|
*
|
|
|
|
* Must invoke this on a given srcu_struct before passing that srcu_struct
|
|
|
|
* to any other function. Each srcu_struct represents a separate domain
|
|
|
|
* of SRCU protection.
|
|
|
|
*/
|
2018-10-29 01:32:51 +08:00
|
|
|
int init_srcu_struct(struct srcu_struct *ssp)
|
2017-03-26 00:59:38 +08:00
|
|
|
{
|
2018-10-29 01:32:51 +08:00
|
|
|
return init_srcu_struct_fields(ssp);
|
2017-03-26 00:59:38 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(init_srcu_struct);
|
|
|
|
|
|
|
|
#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* cleanup_srcu_struct - deconstruct a sleep-RCU structure
|
2018-10-29 01:32:51 +08:00
|
|
|
* @ssp: structure to clean up.
|
2017-03-26 00:59:38 +08:00
|
|
|
*
|
|
|
|
* Must invoke this after you are finished using a given srcu_struct that
|
|
|
|
* was initialized via init_srcu_struct(), else you leak memory.
|
|
|
|
*/
|
2019-02-14 05:54:37 +08:00
|
|
|
void cleanup_srcu_struct(struct srcu_struct *ssp)
|
2017-03-26 00:59:38 +08:00
|
|
|
{
|
2018-10-29 01:32:51 +08:00
|
|
|
WARN_ON(ssp->srcu_lock_nesting[0] || ssp->srcu_lock_nesting[1]);
|
2019-02-14 05:54:37 +08:00
|
|
|
flush_work(&ssp->srcu_work);
|
2018-10-29 01:32:51 +08:00
|
|
|
WARN_ON(ssp->srcu_gp_running);
|
|
|
|
WARN_ON(ssp->srcu_gp_waiting);
|
|
|
|
WARN_ON(ssp->srcu_cb_head);
|
|
|
|
WARN_ON(&ssp->srcu_cb_head != ssp->srcu_cb_tail);
|
2020-11-14 04:54:48 +08:00
|
|
|
WARN_ON(ssp->srcu_idx != ssp->srcu_idx_max);
|
|
|
|
WARN_ON(ssp->srcu_idx & 0x1);
|
2017-03-26 00:59:38 +08:00
|
|
|
}
|
2019-02-14 05:54:37 +08:00
|
|
|
EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
|
2017-03-26 00:59:38 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Removes the count for the old reader from the appropriate element of
|
srcu: Allow use of Tiny/Tree SRCU from both process and interrupt context
Linu Cherian reported a WARN in cleanup_srcu_struct() when shutting
down a guest running iperf on a VFIO assigned device. This happens
because irqfd_wakeup() calls srcu_read_lock(&kvm->irq_srcu) in interrupt
context, while a worker thread does the same inside kvm_set_irq(). If the
interrupt happens while the worker thread is executing __srcu_read_lock(),
updates to the Classic SRCU ->lock_count[] field or the Tree SRCU
->srcu_lock_count[] field can be lost.
The docs say you are not supposed to call srcu_read_lock() and
srcu_read_unlock() from irq context, but KVM interrupt injection happens
from (host) interrupt context and it would be nice if SRCU supported the
use case. KVM is using SRCU here not really for the "sleepable" part,
but rather due to its IPI-free fast detection of grace periods. It is
therefore not desirable to switch back to RCU, which would effectively
revert commit 719d93cd5f5c ("kvm/irqchip: Speed up KVM_SET_GSI_ROUTING",
2014-01-16).
However, the docs are overly conservative. You can have an SRCU instance
only has users in irq context, and you can mix process and irq context
as long as process context users disable interrupts. In addition,
__srcu_read_unlock() actually uses this_cpu_dec() on both Tree SRCU and
Classic SRCU. For those two implementations, only srcu_read_lock()
is unsafe.
When Classic SRCU's __srcu_read_unlock() was changed to use this_cpu_dec(),
in commit 5a41344a3d83 ("srcu: Simplify __srcu_read_unlock() via
this_cpu_dec()", 2012-11-29), __srcu_read_lock() did two increments.
Therefore it kept __this_cpu_inc(), with preempt_disable/enable in
the caller. Tree SRCU however only does one increment, so on most
architectures it is more efficient for __srcu_read_lock() to use
this_cpu_inc(), and any performance differences appear to be down in
the noise.
Unlike Classic and Tree SRCU, Tiny SRCU does increments and decrements on
a single variable. Therefore, as Peter Zijlstra pointed out, Tiny SRCU's
implementation already supports mixed-context use of srcu_read_lock()
and srcu_read_unlock(), at least as long as uses of srcu_read_lock()
and srcu_read_unlock() in each handler are nested and paired properly.
In other words, it is still illegal to (say) invoke srcu_read_lock()
in an interrupt handler and to invoke the matching srcu_read_unlock()
in a softirq handler. Therefore, the only change required for Tiny SRCU
is to its comments.
Fixes: 719d93cd5f5c ("kvm/irqchip: Speed up KVM_SET_GSI_ROUTING")
Reported-by: Linu Cherian <linuc.decode@gmail.com>
Suggested-by: Linu Cherian <linuc.decode@gmail.com>
Cc: kvm@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Tested-by: Paolo Bonzini <pbonzini@redhat.com>
2017-05-31 20:03:10 +08:00
|
|
|
* the srcu_struct.
|
2017-03-26 00:59:38 +08:00
|
|
|
*/
|
2018-10-29 01:32:51 +08:00
|
|
|
void __srcu_read_unlock(struct srcu_struct *ssp, int idx)
|
2017-03-26 00:59:38 +08:00
|
|
|
{
|
2021-06-03 07:31:38 +08:00
|
|
|
int newval = READ_ONCE(ssp->srcu_lock_nesting[idx]) - 1;
|
2017-03-26 00:59:38 +08:00
|
|
|
|
2018-10-29 01:32:51 +08:00
|
|
|
WRITE_ONCE(ssp->srcu_lock_nesting[idx], newval);
|
|
|
|
if (!newval && READ_ONCE(ssp->srcu_gp_waiting))
|
|
|
|
swake_up_one(&ssp->srcu_wq);
|
2017-03-26 00:59:38 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(__srcu_read_unlock);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Workqueue handler to drive one grace period and invoke any callbacks
|
2019-10-16 03:18:14 +08:00
|
|
|
* that become ready as a result. Single-CPU and !PREEMPTION operation
|
2017-03-26 00:59:38 +08:00
|
|
|
* means that we get away with murder on synchronization. ;-)
|
|
|
|
*/
|
|
|
|
void srcu_drive_gp(struct work_struct *wp)
|
|
|
|
{
|
|
|
|
int idx;
|
2017-05-05 05:29:16 +08:00
|
|
|
struct rcu_head *lh;
|
2017-03-26 00:59:38 +08:00
|
|
|
struct rcu_head *rhp;
|
2018-10-29 01:32:51 +08:00
|
|
|
struct srcu_struct *ssp;
|
2017-03-26 00:59:38 +08:00
|
|
|
|
2018-10-29 01:32:51 +08:00
|
|
|
ssp = container_of(wp, struct srcu_struct, srcu_work);
|
2020-11-14 04:54:48 +08:00
|
|
|
if (ssp->srcu_gp_running || USHORT_CMP_GE(ssp->srcu_idx, READ_ONCE(ssp->srcu_idx_max)))
|
2017-03-26 00:59:38 +08:00
|
|
|
return; /* Already running or nothing to do. */
|
|
|
|
|
2017-05-05 05:29:16 +08:00
|
|
|
/* Remove recently arrived callbacks and wait for readers. */
|
2018-10-29 01:32:51 +08:00
|
|
|
WRITE_ONCE(ssp->srcu_gp_running, true);
|
2017-05-05 05:29:16 +08:00
|
|
|
local_irq_disable();
|
2018-10-29 01:32:51 +08:00
|
|
|
lh = ssp->srcu_cb_head;
|
|
|
|
ssp->srcu_cb_head = NULL;
|
|
|
|
ssp->srcu_cb_tail = &ssp->srcu_cb_head;
|
2017-05-05 05:29:16 +08:00
|
|
|
local_irq_enable();
|
2020-11-13 08:34:09 +08:00
|
|
|
idx = (ssp->srcu_idx & 0x2) / 2;
|
|
|
|
WRITE_ONCE(ssp->srcu_idx, ssp->srcu_idx + 1);
|
2018-10-29 01:32:51 +08:00
|
|
|
WRITE_ONCE(ssp->srcu_gp_waiting, true); /* srcu_read_unlock() wakes! */
|
|
|
|
swait_event_exclusive(ssp->srcu_wq, !READ_ONCE(ssp->srcu_lock_nesting[idx]));
|
|
|
|
WRITE_ONCE(ssp->srcu_gp_waiting, false); /* srcu_read_unlock() cheap. */
|
2020-11-13 08:34:09 +08:00
|
|
|
WRITE_ONCE(ssp->srcu_idx, ssp->srcu_idx + 1);
|
2017-05-05 05:29:16 +08:00
|
|
|
|
|
|
|
/* Invoke the callbacks we removed above. */
|
|
|
|
while (lh) {
|
|
|
|
rhp = lh;
|
|
|
|
lh = lh->next;
|
|
|
|
local_bh_disable();
|
|
|
|
rhp->func(rhp);
|
|
|
|
local_bh_enable();
|
2017-03-26 00:59:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-05-05 05:29:16 +08:00
|
|
|
* Enable rescheduling, and if there are more callbacks,
|
|
|
|
* reschedule ourselves. This can race with a call_srcu()
|
|
|
|
* at interrupt level, but the ->srcu_gp_running checks will
|
|
|
|
* straighten that out.
|
2017-03-26 00:59:38 +08:00
|
|
|
*/
|
2018-10-29 01:32:51 +08:00
|
|
|
WRITE_ONCE(ssp->srcu_gp_running, false);
|
2020-11-14 04:54:48 +08:00
|
|
|
if (USHORT_CMP_LT(ssp->srcu_idx, READ_ONCE(ssp->srcu_idx_max)))
|
2018-10-29 01:32:51 +08:00
|
|
|
schedule_work(&ssp->srcu_work);
|
2017-03-26 00:59:38 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(srcu_drive_gp);
|
|
|
|
|
2020-11-14 01:37:39 +08:00
|
|
|
static void srcu_gp_start_if_needed(struct srcu_struct *ssp)
|
|
|
|
{
|
2020-11-14 04:54:48 +08:00
|
|
|
unsigned short cookie;
|
|
|
|
|
|
|
|
cookie = get_state_synchronize_srcu(ssp);
|
|
|
|
if (USHORT_CMP_GE(READ_ONCE(ssp->srcu_idx_max), cookie))
|
|
|
|
return;
|
|
|
|
WRITE_ONCE(ssp->srcu_idx_max, cookie);
|
2020-11-14 01:37:39 +08:00
|
|
|
if (!READ_ONCE(ssp->srcu_gp_running)) {
|
|
|
|
if (likely(srcu_init_done))
|
|
|
|
schedule_work(&ssp->srcu_work);
|
|
|
|
else if (list_empty(&ssp->srcu_work.entry))
|
|
|
|
list_add(&ssp->srcu_work.entry, &srcu_boot_list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-26 00:59:38 +08:00
|
|
|
/*
|
|
|
|
* Enqueue an SRCU callback on the specified srcu_struct structure,
|
|
|
|
* initiating grace-period processing if it is not already running.
|
|
|
|
*/
|
2018-10-29 01:32:51 +08:00
|
|
|
void call_srcu(struct srcu_struct *ssp, struct rcu_head *rhp,
|
2017-03-26 00:59:38 +08:00
|
|
|
rcu_callback_t func)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
2017-05-05 05:29:16 +08:00
|
|
|
rhp->func = func;
|
|
|
|
rhp->next = NULL;
|
2017-03-26 00:59:38 +08:00
|
|
|
local_irq_save(flags);
|
2018-10-29 01:32:51 +08:00
|
|
|
*ssp->srcu_cb_tail = rhp;
|
|
|
|
ssp->srcu_cb_tail = &rhp->next;
|
2017-03-26 00:59:38 +08:00
|
|
|
local_irq_restore(flags);
|
2020-11-14 01:37:39 +08:00
|
|
|
srcu_gp_start_if_needed(ssp);
|
2017-03-26 00:59:38 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(call_srcu);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* synchronize_srcu - wait for prior SRCU read-side critical-section completion
|
|
|
|
*/
|
2018-10-29 01:32:51 +08:00
|
|
|
void synchronize_srcu(struct srcu_struct *ssp)
|
2017-03-26 00:59:38 +08:00
|
|
|
{
|
|
|
|
struct rcu_synchronize rs;
|
|
|
|
|
|
|
|
init_rcu_head_on_stack(&rs.head);
|
|
|
|
init_completion(&rs.completion);
|
2018-10-29 01:32:51 +08:00
|
|
|
call_srcu(ssp, &rs.head, wakeme_after_rcu);
|
2017-03-26 00:59:38 +08:00
|
|
|
wait_for_completion(&rs.completion);
|
|
|
|
destroy_rcu_head_on_stack(&rs.head);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(synchronize_srcu);
|
2017-05-27 07:16:40 +08:00
|
|
|
|
2020-11-14 04:54:48 +08:00
|
|
|
/*
|
|
|
|
* get_state_synchronize_srcu - Provide an end-of-grace-period cookie
|
|
|
|
*/
|
|
|
|
unsigned long get_state_synchronize_srcu(struct srcu_struct *ssp)
|
|
|
|
{
|
|
|
|
unsigned long ret;
|
|
|
|
|
|
|
|
barrier();
|
|
|
|
ret = (READ_ONCE(ssp->srcu_idx) + 3) & ~0x1;
|
|
|
|
barrier();
|
|
|
|
return ret & USHRT_MAX;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(get_state_synchronize_srcu);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* start_poll_synchronize_srcu - Provide cookie and start grace period
|
|
|
|
*
|
|
|
|
* The difference between this and get_state_synchronize_srcu() is that
|
|
|
|
* this function ensures that the poll_state_synchronize_srcu() will
|
|
|
|
* eventually return the value true.
|
|
|
|
*/
|
|
|
|
unsigned long start_poll_synchronize_srcu(struct srcu_struct *ssp)
|
|
|
|
{
|
|
|
|
unsigned long ret = get_state_synchronize_srcu(ssp);
|
|
|
|
|
|
|
|
srcu_gp_start_if_needed(ssp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(start_poll_synchronize_srcu);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* poll_state_synchronize_srcu - Has cookie's grace period ended?
|
|
|
|
*/
|
|
|
|
bool poll_state_synchronize_srcu(struct srcu_struct *ssp, unsigned long cookie)
|
|
|
|
{
|
|
|
|
bool ret = USHORT_CMP_GE(READ_ONCE(ssp->srcu_idx), cookie);
|
|
|
|
|
|
|
|
barrier();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(poll_state_synchronize_srcu);
|
|
|
|
|
2017-05-27 07:16:40 +08:00
|
|
|
/* Lockdep diagnostics. */
|
|
|
|
void __init rcu_scheduler_starting(void)
|
|
|
|
{
|
|
|
|
rcu_scheduler_active = RCU_SCHEDULER_RUNNING;
|
|
|
|
}
|
srcu: Make call_srcu() available during very early boot
Event tracing is moving to SRCU in order to take advantage of the fact
that SRCU may be safely used from idle and even offline CPUs. However,
event tracing can invoke call_srcu() very early in the boot process,
even before workqueue_init_early() is invoked (let alone rcu_init()).
Therefore, call_srcu()'s attempts to queue work fail miserably.
This commit therefore detects this situation, and refrains from attempting
to queue work before rcu_init() time, but does everything else that it
would have done, and in addition, adds the srcu_struct to a global list.
The rcu_init() function now invokes a new srcu_init() function, which
is empty if CONFIG_SRCU=n. Otherwise, srcu_init() queues work for
each srcu_struct on the list. This all happens early enough in boot
that there is but a single CPU with interrupts disabled, which allows
synchronization to be dispensed with.
Of course, the queued work won't actually be invoked until after
workqueue_init() is invoked, which happens shortly after the scheduler
is up and running. This means that although call_srcu() may be invoked
any time after per-CPU variables have been set up, there is still a very
narrow window when synchronize_srcu() won't work, and this window
extends from the time that the scheduler starts until the time that
workqueue_init() returns. This can be fixed in a manner similar to
the fix for synchronize_rcu_expedited() and friends, but until someone
actually needs to use synchronize_srcu() during this window, this fix
is added churn for no benefit.
Finally, note that Tree SRCU's new srcu_init() function invokes
queue_work() rather than the queue_delayed_work() function that is
invoked post-boot. The reason is that queue_delayed_work() will (as you
would expect) post a timer, and timers have not yet been initialized.
So use of queue_work() avoids the complaints about use of uninitialized
spinlocks that would otherwise result. Besides, some delay is already
provide by the aforementioned fact that the queued work won't actually
be invoked until after the scheduler is up and running.
Requested-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Tested-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
2018-08-14 23:45:54 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Queue work for srcu_struct structures with early boot callbacks.
|
|
|
|
* The work won't actually execute until the workqueue initialization
|
|
|
|
* phase that takes place after the scheduler starts.
|
|
|
|
*/
|
|
|
|
void __init srcu_init(void)
|
|
|
|
{
|
2018-10-29 01:32:51 +08:00
|
|
|
struct srcu_struct *ssp;
|
srcu: Make call_srcu() available during very early boot
Event tracing is moving to SRCU in order to take advantage of the fact
that SRCU may be safely used from idle and even offline CPUs. However,
event tracing can invoke call_srcu() very early in the boot process,
even before workqueue_init_early() is invoked (let alone rcu_init()).
Therefore, call_srcu()'s attempts to queue work fail miserably.
This commit therefore detects this situation, and refrains from attempting
to queue work before rcu_init() time, but does everything else that it
would have done, and in addition, adds the srcu_struct to a global list.
The rcu_init() function now invokes a new srcu_init() function, which
is empty if CONFIG_SRCU=n. Otherwise, srcu_init() queues work for
each srcu_struct on the list. This all happens early enough in boot
that there is but a single CPU with interrupts disabled, which allows
synchronization to be dispensed with.
Of course, the queued work won't actually be invoked until after
workqueue_init() is invoked, which happens shortly after the scheduler
is up and running. This means that although call_srcu() may be invoked
any time after per-CPU variables have been set up, there is still a very
narrow window when synchronize_srcu() won't work, and this window
extends from the time that the scheduler starts until the time that
workqueue_init() returns. This can be fixed in a manner similar to
the fix for synchronize_rcu_expedited() and friends, but until someone
actually needs to use synchronize_srcu() during this window, this fix
is added churn for no benefit.
Finally, note that Tree SRCU's new srcu_init() function invokes
queue_work() rather than the queue_delayed_work() function that is
invoked post-boot. The reason is that queue_delayed_work() will (as you
would expect) post a timer, and timers have not yet been initialized.
So use of queue_work() avoids the complaints about use of uninitialized
spinlocks that would otherwise result. Besides, some delay is already
provide by the aforementioned fact that the queued work won't actually
be invoked until after the scheduler is up and running.
Requested-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Tested-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
2018-08-14 23:45:54 +08:00
|
|
|
|
|
|
|
srcu_init_done = true;
|
|
|
|
while (!list_empty(&srcu_boot_list)) {
|
2018-10-29 01:32:51 +08:00
|
|
|
ssp = list_first_entry(&srcu_boot_list,
|
2018-08-15 05:41:49 +08:00
|
|
|
struct srcu_struct, srcu_work.entry);
|
2018-10-29 01:32:51 +08:00
|
|
|
list_del_init(&ssp->srcu_work.entry);
|
|
|
|
schedule_work(&ssp->srcu_work);
|
srcu: Make call_srcu() available during very early boot
Event tracing is moving to SRCU in order to take advantage of the fact
that SRCU may be safely used from idle and even offline CPUs. However,
event tracing can invoke call_srcu() very early in the boot process,
even before workqueue_init_early() is invoked (let alone rcu_init()).
Therefore, call_srcu()'s attempts to queue work fail miserably.
This commit therefore detects this situation, and refrains from attempting
to queue work before rcu_init() time, but does everything else that it
would have done, and in addition, adds the srcu_struct to a global list.
The rcu_init() function now invokes a new srcu_init() function, which
is empty if CONFIG_SRCU=n. Otherwise, srcu_init() queues work for
each srcu_struct on the list. This all happens early enough in boot
that there is but a single CPU with interrupts disabled, which allows
synchronization to be dispensed with.
Of course, the queued work won't actually be invoked until after
workqueue_init() is invoked, which happens shortly after the scheduler
is up and running. This means that although call_srcu() may be invoked
any time after per-CPU variables have been set up, there is still a very
narrow window when synchronize_srcu() won't work, and this window
extends from the time that the scheduler starts until the time that
workqueue_init() returns. This can be fixed in a manner similar to
the fix for synchronize_rcu_expedited() and friends, but until someone
actually needs to use synchronize_srcu() during this window, this fix
is added churn for no benefit.
Finally, note that Tree SRCU's new srcu_init() function invokes
queue_work() rather than the queue_delayed_work() function that is
invoked post-boot. The reason is that queue_delayed_work() will (as you
would expect) post a timer, and timers have not yet been initialized.
So use of queue_work() avoids the complaints about use of uninitialized
spinlocks that would otherwise result. Besides, some delay is already
provide by the aforementioned fact that the queued work won't actually
be invoked until after the scheduler is up and running.
Requested-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Tested-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
2018-08-14 23:45:54 +08:00
|
|
|
}
|
|
|
|
}
|