Merge branches 'doc.2020.08.24a', 'fixes.2020.09.03b' and 'torture.2020.08.24a' into HEAD
doc.2020.08.24a: Documentation updates. fixes.2020.09.03b: Miscellaneous fixes. torture.2020.08.24a: Torture-test updates.
This commit is contained in:
commit
cfb2c1070a
|
@ -4269,6 +4269,18 @@
|
|||
are zero, rcutorture acts as if is interpreted
|
||||
they are all non-zero.
|
||||
|
||||
rcutorture.irqreader= [KNL]
|
||||
Run RCU readers from irq handlers, or, more
|
||||
accurately, from a timer handler. Not all RCU
|
||||
flavors take kindly to this sort of thing.
|
||||
|
||||
rcutorture.leakpointer= [KNL]
|
||||
Leak an RCU-protected pointer out of the reader.
|
||||
This can of course result in splats, and is
|
||||
intended to test the ability of things like
|
||||
CONFIG_RCU_STRICT_GRACE_PERIOD=y to detect
|
||||
such leaks.
|
||||
|
||||
rcutorture.n_barrier_cbs= [KNL]
|
||||
Set callbacks/threads for rcu_barrier() testing.
|
||||
|
||||
|
|
|
@ -229,7 +229,8 @@ void kvm_page_track_write(struct kvm_vcpu *vcpu, gpa_t gpa, const u8 *new,
|
|||
return;
|
||||
|
||||
idx = srcu_read_lock(&head->track_srcu);
|
||||
hlist_for_each_entry_rcu(n, &head->track_notifier_list, node)
|
||||
hlist_for_each_entry_srcu(n, &head->track_notifier_list, node,
|
||||
srcu_read_lock_held(&head->track_srcu))
|
||||
if (n->track_write)
|
||||
n->track_write(vcpu, gpa, new, bytes, n);
|
||||
srcu_read_unlock(&head->track_srcu, idx);
|
||||
|
@ -254,7 +255,8 @@ void kvm_page_track_flush_slot(struct kvm *kvm, struct kvm_memory_slot *slot)
|
|||
return;
|
||||
|
||||
idx = srcu_read_lock(&head->track_srcu);
|
||||
hlist_for_each_entry_rcu(n, &head->track_notifier_list, node)
|
||||
hlist_for_each_entry_srcu(n, &head->track_notifier_list, node,
|
||||
srcu_read_lock_held(&head->track_srcu))
|
||||
if (n->track_flush_slot)
|
||||
n->track_flush_slot(kvm, slot, n);
|
||||
srcu_read_unlock(&head->track_srcu, idx);
|
||||
|
|
|
@ -63,9 +63,17 @@ static inline void INIT_LIST_HEAD_RCU(struct list_head *list)
|
|||
RCU_LOCKDEP_WARN(!(cond) && !rcu_read_lock_any_held(), \
|
||||
"RCU-list traversed in non-reader section!"); \
|
||||
})
|
||||
|
||||
#define __list_check_srcu(cond) \
|
||||
({ \
|
||||
RCU_LOCKDEP_WARN(!(cond), \
|
||||
"RCU-list traversed without holding the required lock!");\
|
||||
})
|
||||
#else
|
||||
#define __list_check_rcu(dummy, cond, extra...) \
|
||||
({ check_arg_count_one(extra); })
|
||||
|
||||
#define __list_check_srcu(cond) ({ })
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -385,6 +393,25 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
|
|||
&pos->member != (head); \
|
||||
pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_srcu - iterate over rcu list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
* @cond: lockdep expression for the lock required to traverse the list.
|
||||
*
|
||||
* This list-traversal primitive may safely run concurrently with
|
||||
* the _rcu list-mutation primitives such as list_add_rcu()
|
||||
* as long as the traversal is guarded by srcu_read_lock().
|
||||
* The lockdep expression srcu_read_lock_held() can be passed as the
|
||||
* cond argument from read side.
|
||||
*/
|
||||
#define list_for_each_entry_srcu(pos, head, member, cond) \
|
||||
for (__list_check_srcu(cond), \
|
||||
pos = list_entry_rcu((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_entry_lockless - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
|
@ -683,6 +710,27 @@ static inline void hlist_add_behind_rcu(struct hlist_node *n,
|
|||
pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(\
|
||||
&(pos)->member)), typeof(*(pos)), member))
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_srcu - iterate over rcu list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
* @cond: lockdep expression for the lock required to traverse the list.
|
||||
*
|
||||
* This list-traversal primitive may safely run concurrently with
|
||||
* the _rcu list-mutation primitives such as hlist_add_head_rcu()
|
||||
* as long as the traversal is guarded by srcu_read_lock().
|
||||
* The lockdep expression srcu_read_lock_held() can be passed as the
|
||||
* cond argument from read side.
|
||||
*/
|
||||
#define hlist_for_each_entry_srcu(pos, head, member, cond) \
|
||||
for (__list_check_srcu(cond), \
|
||||
pos = hlist_entry_safe(rcu_dereference_raw(hlist_first_rcu(head)),\
|
||||
typeof(*(pos)), member); \
|
||||
pos; \
|
||||
pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(\
|
||||
&(pos)->member)), typeof(*(pos)), member))
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_rcu_notrace - iterate over rcu list of given type (for tracing)
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
|
|
|
@ -709,8 +709,8 @@ static inline void rcu_read_lock_bh(void)
|
|||
"rcu_read_lock_bh() used illegally while idle");
|
||||
}
|
||||
|
||||
/*
|
||||
* rcu_read_unlock_bh - marks the end of a softirq-only RCU critical section
|
||||
/**
|
||||
* rcu_read_unlock_bh() - marks the end of a softirq-only RCU critical section
|
||||
*
|
||||
* See rcu_read_lock_bh() for more information.
|
||||
*/
|
||||
|
@ -751,10 +751,10 @@ static inline notrace void rcu_read_lock_sched_notrace(void)
|
|||
__acquire(RCU_SCHED);
|
||||
}
|
||||
|
||||
/*
|
||||
* rcu_read_unlock_sched - marks the end of a RCU-classic critical section
|
||||
/**
|
||||
* rcu_read_unlock_sched() - marks the end of a RCU-classic critical section
|
||||
*
|
||||
* See rcu_read_lock_sched for more information.
|
||||
* See rcu_read_lock_sched() for more information.
|
||||
*/
|
||||
static inline void rcu_read_unlock_sched(void)
|
||||
{
|
||||
|
@ -945,7 +945,7 @@ static inline void rcu_head_init(struct rcu_head *rhp)
|
|||
}
|
||||
|
||||
/**
|
||||
* rcu_head_after_call_rcu - Has this rcu_head been passed to call_rcu()?
|
||||
* rcu_head_after_call_rcu() - Has this rcu_head been passed to call_rcu()?
|
||||
* @rhp: The rcu_head structure to test.
|
||||
* @f: The function passed to call_rcu() along with @rhp.
|
||||
*
|
||||
|
|
|
@ -103,7 +103,6 @@ static inline void rcu_scheduler_starting(void) { }
|
|||
static inline void rcu_end_inkernel_boot(void) { }
|
||||
static inline bool rcu_inkernel_boot_has_ended(void) { return true; }
|
||||
static inline bool rcu_is_watching(void) { return true; }
|
||||
static inline bool __rcu_is_watching(void) { return true; }
|
||||
static inline void rcu_momentary_dyntick_idle(void) { }
|
||||
static inline void kfree_rcu_scheduler_running(void) { }
|
||||
static inline bool rcu_gp_might_be_stalled(void) { return false; }
|
||||
|
|
|
@ -64,7 +64,6 @@ extern int rcu_scheduler_active __read_mostly;
|
|||
void rcu_end_inkernel_boot(void);
|
||||
bool rcu_inkernel_boot_has_ended(void);
|
||||
bool rcu_is_watching(void);
|
||||
bool __rcu_is_watching(void);
|
||||
#ifndef CONFIG_PREEMPTION
|
||||
void rcu_all_qs(void);
|
||||
#endif
|
||||
|
|
|
@ -74,17 +74,17 @@ TRACE_EVENT_RCU(rcu_grace_period,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(const char *, rcuname)
|
||||
__field(unsigned long, gp_seq)
|
||||
__field(long, gp_seq)
|
||||
__field(const char *, gpevent)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->rcuname = rcuname;
|
||||
__entry->gp_seq = gp_seq;
|
||||
__entry->gp_seq = (long)gp_seq;
|
||||
__entry->gpevent = gpevent;
|
||||
),
|
||||
|
||||
TP_printk("%s %lu %s",
|
||||
TP_printk("%s %ld %s",
|
||||
__entry->rcuname, __entry->gp_seq, __entry->gpevent)
|
||||
);
|
||||
|
||||
|
@ -114,8 +114,8 @@ TRACE_EVENT_RCU(rcu_future_grace_period,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(const char *, rcuname)
|
||||
__field(unsigned long, gp_seq)
|
||||
__field(unsigned long, gp_seq_req)
|
||||
__field(long, gp_seq)
|
||||
__field(long, gp_seq_req)
|
||||
__field(u8, level)
|
||||
__field(int, grplo)
|
||||
__field(int, grphi)
|
||||
|
@ -124,16 +124,16 @@ TRACE_EVENT_RCU(rcu_future_grace_period,
|
|||
|
||||
TP_fast_assign(
|
||||
__entry->rcuname = rcuname;
|
||||
__entry->gp_seq = gp_seq;
|
||||
__entry->gp_seq_req = gp_seq_req;
|
||||
__entry->gp_seq = (long)gp_seq;
|
||||
__entry->gp_seq_req = (long)gp_seq_req;
|
||||
__entry->level = level;
|
||||
__entry->grplo = grplo;
|
||||
__entry->grphi = grphi;
|
||||
__entry->gpevent = gpevent;
|
||||
),
|
||||
|
||||
TP_printk("%s %lu %lu %u %d %d %s",
|
||||
__entry->rcuname, __entry->gp_seq, __entry->gp_seq_req, __entry->level,
|
||||
TP_printk("%s %ld %ld %u %d %d %s",
|
||||
__entry->rcuname, (long)__entry->gp_seq, (long)__entry->gp_seq_req, __entry->level,
|
||||
__entry->grplo, __entry->grphi, __entry->gpevent)
|
||||
);
|
||||
|
||||
|
@ -153,7 +153,7 @@ TRACE_EVENT_RCU(rcu_grace_period_init,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(const char *, rcuname)
|
||||
__field(unsigned long, gp_seq)
|
||||
__field(long, gp_seq)
|
||||
__field(u8, level)
|
||||
__field(int, grplo)
|
||||
__field(int, grphi)
|
||||
|
@ -162,14 +162,14 @@ TRACE_EVENT_RCU(rcu_grace_period_init,
|
|||
|
||||
TP_fast_assign(
|
||||
__entry->rcuname = rcuname;
|
||||
__entry->gp_seq = gp_seq;
|
||||
__entry->gp_seq = (long)gp_seq;
|
||||
__entry->level = level;
|
||||
__entry->grplo = grplo;
|
||||
__entry->grphi = grphi;
|
||||
__entry->qsmask = qsmask;
|
||||
),
|
||||
|
||||
TP_printk("%s %lu %u %d %d %lx",
|
||||
TP_printk("%s %ld %u %d %d %lx",
|
||||
__entry->rcuname, __entry->gp_seq, __entry->level,
|
||||
__entry->grplo, __entry->grphi, __entry->qsmask)
|
||||
);
|
||||
|
@ -197,17 +197,17 @@ TRACE_EVENT_RCU(rcu_exp_grace_period,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(const char *, rcuname)
|
||||
__field(unsigned long, gpseq)
|
||||
__field(long, gpseq)
|
||||
__field(const char *, gpevent)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->rcuname = rcuname;
|
||||
__entry->gpseq = gpseq;
|
||||
__entry->gpseq = (long)gpseq;
|
||||
__entry->gpevent = gpevent;
|
||||
),
|
||||
|
||||
TP_printk("%s %lu %s",
|
||||
TP_printk("%s %ld %s",
|
||||
__entry->rcuname, __entry->gpseq, __entry->gpevent)
|
||||
);
|
||||
|
||||
|
@ -316,17 +316,17 @@ TRACE_EVENT_RCU(rcu_preempt_task,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(const char *, rcuname)
|
||||
__field(unsigned long, gp_seq)
|
||||
__field(long, gp_seq)
|
||||
__field(int, pid)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->rcuname = rcuname;
|
||||
__entry->gp_seq = gp_seq;
|
||||
__entry->gp_seq = (long)gp_seq;
|
||||
__entry->pid = pid;
|
||||
),
|
||||
|
||||
TP_printk("%s %lu %d",
|
||||
TP_printk("%s %ld %d",
|
||||
__entry->rcuname, __entry->gp_seq, __entry->pid)
|
||||
);
|
||||
|
||||
|
@ -343,17 +343,17 @@ TRACE_EVENT_RCU(rcu_unlock_preempted_task,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(const char *, rcuname)
|
||||
__field(unsigned long, gp_seq)
|
||||
__field(long, gp_seq)
|
||||
__field(int, pid)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->rcuname = rcuname;
|
||||
__entry->gp_seq = gp_seq;
|
||||
__entry->gp_seq = (long)gp_seq;
|
||||
__entry->pid = pid;
|
||||
),
|
||||
|
||||
TP_printk("%s %lu %d", __entry->rcuname, __entry->gp_seq, __entry->pid)
|
||||
TP_printk("%s %ld %d", __entry->rcuname, __entry->gp_seq, __entry->pid)
|
||||
);
|
||||
|
||||
/*
|
||||
|
@ -374,7 +374,7 @@ TRACE_EVENT_RCU(rcu_quiescent_state_report,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(const char *, rcuname)
|
||||
__field(unsigned long, gp_seq)
|
||||
__field(long, gp_seq)
|
||||
__field(unsigned long, mask)
|
||||
__field(unsigned long, qsmask)
|
||||
__field(u8, level)
|
||||
|
@ -385,7 +385,7 @@ TRACE_EVENT_RCU(rcu_quiescent_state_report,
|
|||
|
||||
TP_fast_assign(
|
||||
__entry->rcuname = rcuname;
|
||||
__entry->gp_seq = gp_seq;
|
||||
__entry->gp_seq = (long)gp_seq;
|
||||
__entry->mask = mask;
|
||||
__entry->qsmask = qsmask;
|
||||
__entry->level = level;
|
||||
|
@ -394,7 +394,7 @@ TRACE_EVENT_RCU(rcu_quiescent_state_report,
|
|||
__entry->gp_tasks = gp_tasks;
|
||||
),
|
||||
|
||||
TP_printk("%s %lu %lx>%lx %u %d %d %u",
|
||||
TP_printk("%s %ld %lx>%lx %u %d %d %u",
|
||||
__entry->rcuname, __entry->gp_seq,
|
||||
__entry->mask, __entry->qsmask, __entry->level,
|
||||
__entry->grplo, __entry->grphi, __entry->gp_tasks)
|
||||
|
@ -415,19 +415,19 @@ TRACE_EVENT_RCU(rcu_fqs,
|
|||
|
||||
TP_STRUCT__entry(
|
||||
__field(const char *, rcuname)
|
||||
__field(unsigned long, gp_seq)
|
||||
__field(long, gp_seq)
|
||||
__field(int, cpu)
|
||||
__field(const char *, qsevent)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->rcuname = rcuname;
|
||||
__entry->gp_seq = gp_seq;
|
||||
__entry->gp_seq = (long)gp_seq;
|
||||
__entry->cpu = cpu;
|
||||
__entry->qsevent = qsevent;
|
||||
),
|
||||
|
||||
TP_printk("%s %lu %d %s",
|
||||
TP_printk("%s %ld %d %s",
|
||||
__entry->rcuname, __entry->gp_seq,
|
||||
__entry->cpu, __entry->qsevent)
|
||||
);
|
||||
|
|
|
@ -278,7 +278,7 @@ noinstr irqentry_state_t irqentry_enter(struct pt_regs *regs)
|
|||
* terminate a grace period, if and only if the timer interrupt is
|
||||
* not nested into another interrupt.
|
||||
*
|
||||
* Checking for __rcu_is_watching() here would prevent the nesting
|
||||
* Checking for rcu_is_watching() here would prevent the nesting
|
||||
* interrupt to invoke rcu_irq_enter(). If that nested interrupt is
|
||||
* the tick then rcu_flavor_sched_clock_irq() would wrongfully
|
||||
* assume that it is the first interupt and eventually claim
|
||||
|
|
|
@ -566,7 +566,7 @@ static struct lock_torture_ops rwsem_lock_ops = {
|
|||
#include <linux/percpu-rwsem.h>
|
||||
static struct percpu_rw_semaphore pcpu_rwsem;
|
||||
|
||||
void torture_percpu_rwsem_init(void)
|
||||
static void torture_percpu_rwsem_init(void)
|
||||
{
|
||||
BUG_ON(percpu_init_rwsem(&pcpu_rwsem));
|
||||
}
|
||||
|
|
|
@ -475,8 +475,16 @@ bool rcu_segcblist_accelerate(struct rcu_segcblist *rsclp, unsigned long seq)
|
|||
* Also advance to the oldest segment of callbacks whose
|
||||
* ->gp_seq[] completion is at or after that passed in via "seq",
|
||||
* skipping any empty segments.
|
||||
*
|
||||
* Note that segment "i" (and any lower-numbered segments
|
||||
* containing older callbacks) will be unaffected, and their
|
||||
* grace-period numbers remain unchanged. For example, if i ==
|
||||
* WAIT_TAIL, then neither WAIT_TAIL nor DONE_TAIL will be touched.
|
||||
* Instead, the CBs in NEXT_TAIL will be merged with those in
|
||||
* NEXT_READY_TAIL and the grace-period number of NEXT_READY_TAIL
|
||||
* would be updated. NEXT_TAIL would then be empty.
|
||||
*/
|
||||
if (++i >= RCU_NEXT_TAIL)
|
||||
if (rcu_segcblist_restempty(rsclp, i) || ++i >= RCU_NEXT_TAIL)
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
|
|
@ -52,19 +52,6 @@
|
|||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com> and Josh Triplett <josh@joshtriplett.org>");
|
||||
|
||||
#ifndef data_race
|
||||
#define data_race(expr) \
|
||||
({ \
|
||||
expr; \
|
||||
})
|
||||
#endif
|
||||
#ifndef ASSERT_EXCLUSIVE_WRITER
|
||||
#define ASSERT_EXCLUSIVE_WRITER(var) do { } while (0)
|
||||
#endif
|
||||
#ifndef ASSERT_EXCLUSIVE_ACCESS
|
||||
#define ASSERT_EXCLUSIVE_ACCESS(var) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* Bits for ->extendables field, extendables param, and related definitions. */
|
||||
#define RCUTORTURE_RDR_SHIFT 8 /* Put SRCU index in upper bits. */
|
||||
#define RCUTORTURE_RDR_MASK ((1 << RCUTORTURE_RDR_SHIFT) - 1)
|
||||
|
@ -100,6 +87,7 @@ torture_param(bool, gp_normal, false,
|
|||
"Use normal (non-expedited) GP wait primitives");
|
||||
torture_param(bool, gp_sync, false, "Use synchronous GP wait primitives");
|
||||
torture_param(int, irqreader, 1, "Allow RCU readers from irq handlers");
|
||||
torture_param(int, leakpointer, 0, "Leak pointer dereferences from readers");
|
||||
torture_param(int, n_barrier_cbs, 0,
|
||||
"# of callbacks/kthreads for barrier testing");
|
||||
torture_param(int, nfakewriters, 4, "Number of RCU fake writer threads");
|
||||
|
@ -185,6 +173,7 @@ static long n_barrier_successes; /* did rcu_barrier test succeed? */
|
|||
static unsigned long n_read_exits;
|
||||
static struct list_head rcu_torture_removed;
|
||||
static unsigned long shutdown_jiffies;
|
||||
static unsigned long start_gp_seq;
|
||||
|
||||
static int rcu_torture_writer_state;
|
||||
#define RTWS_FIXED_DELAY 0
|
||||
|
@ -1413,6 +1402,9 @@ static bool rcu_torture_one_read(struct torture_random_state *trsp)
|
|||
preempt_enable();
|
||||
rcutorture_one_extend(&readstate, 0, trsp, rtrsp);
|
||||
WARN_ON_ONCE(readstate & RCUTORTURE_RDR_MASK);
|
||||
// This next splat is expected behavior if leakpointer, especially
|
||||
// for CONFIG_RCU_STRICT_GRACE_PERIOD=y kernels.
|
||||
WARN_ON_ONCE(leakpointer && READ_ONCE(p->rtort_pipe_count) > 1);
|
||||
|
||||
/* If error or close call, record the sequence of reader protections. */
|
||||
if ((pipe_count > 1 || completed > 1) && !xchg(&err_segs_recorded, 1)) {
|
||||
|
@ -1808,6 +1800,7 @@ struct rcu_fwd {
|
|||
unsigned long rcu_launder_gp_seq_start;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(rcu_fwd_mutex);
|
||||
static struct rcu_fwd *rcu_fwds;
|
||||
static bool rcu_fwd_emergency_stop;
|
||||
|
||||
|
@ -2074,8 +2067,14 @@ static void rcu_torture_fwd_prog_cr(struct rcu_fwd *rfp)
|
|||
static int rcutorture_oom_notify(struct notifier_block *self,
|
||||
unsigned long notused, void *nfreed)
|
||||
{
|
||||
struct rcu_fwd *rfp = rcu_fwds;
|
||||
struct rcu_fwd *rfp;
|
||||
|
||||
mutex_lock(&rcu_fwd_mutex);
|
||||
rfp = rcu_fwds;
|
||||
if (!rfp) {
|
||||
mutex_unlock(&rcu_fwd_mutex);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
WARN(1, "%s invoked upon OOM during forward-progress testing.\n",
|
||||
__func__);
|
||||
rcu_torture_fwd_cb_hist(rfp);
|
||||
|
@ -2093,6 +2092,7 @@ static int rcutorture_oom_notify(struct notifier_block *self,
|
|||
smp_mb(); /* Frees before return to avoid redoing OOM. */
|
||||
(*(unsigned long *)nfreed)++; /* Forward progress CBs freed! */
|
||||
pr_info("%s returning after OOM processing.\n", __func__);
|
||||
mutex_unlock(&rcu_fwd_mutex);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
@ -2114,13 +2114,11 @@ static int rcu_torture_fwd_prog(void *args)
|
|||
do {
|
||||
schedule_timeout_interruptible(fwd_progress_holdoff * HZ);
|
||||
WRITE_ONCE(rcu_fwd_emergency_stop, false);
|
||||
register_oom_notifier(&rcutorture_oom_nb);
|
||||
if (!IS_ENABLED(CONFIG_TINY_RCU) ||
|
||||
rcu_inkernel_boot_has_ended())
|
||||
rcu_torture_fwd_prog_nr(rfp, &tested, &tested_tries);
|
||||
if (rcu_inkernel_boot_has_ended())
|
||||
rcu_torture_fwd_prog_cr(rfp);
|
||||
unregister_oom_notifier(&rcutorture_oom_nb);
|
||||
|
||||
/* Avoid slow periods, better to test when busy. */
|
||||
stutter_wait("rcu_torture_fwd_prog");
|
||||
|
@ -2160,9 +2158,26 @@ static int __init rcu_torture_fwd_prog_init(void)
|
|||
return -ENOMEM;
|
||||
spin_lock_init(&rfp->rcu_fwd_lock);
|
||||
rfp->rcu_fwd_cb_tail = &rfp->rcu_fwd_cb_head;
|
||||
mutex_lock(&rcu_fwd_mutex);
|
||||
rcu_fwds = rfp;
|
||||
mutex_unlock(&rcu_fwd_mutex);
|
||||
register_oom_notifier(&rcutorture_oom_nb);
|
||||
return torture_create_kthread(rcu_torture_fwd_prog, rfp, fwd_prog_task);
|
||||
}
|
||||
|
||||
static void rcu_torture_fwd_prog_cleanup(void)
|
||||
{
|
||||
struct rcu_fwd *rfp;
|
||||
|
||||
torture_stop_kthread(rcu_torture_fwd_prog, fwd_prog_task);
|
||||
rfp = rcu_fwds;
|
||||
mutex_lock(&rcu_fwd_mutex);
|
||||
rcu_fwds = NULL;
|
||||
mutex_unlock(&rcu_fwd_mutex);
|
||||
unregister_oom_notifier(&rcutorture_oom_nb);
|
||||
kfree(rfp);
|
||||
}
|
||||
|
||||
/* Callback function for RCU barrier testing. */
|
||||
static void rcu_torture_barrier_cbf(struct rcu_head *rcu)
|
||||
{
|
||||
|
@ -2460,7 +2475,7 @@ rcu_torture_cleanup(void)
|
|||
show_rcu_gp_kthreads();
|
||||
rcu_torture_read_exit_cleanup();
|
||||
rcu_torture_barrier_cleanup();
|
||||
torture_stop_kthread(rcu_torture_fwd_prog, fwd_prog_task);
|
||||
rcu_torture_fwd_prog_cleanup();
|
||||
torture_stop_kthread(rcu_torture_stall, stall_task);
|
||||
torture_stop_kthread(rcu_torture_writer, writer_task);
|
||||
|
||||
|
@ -2482,8 +2497,9 @@ rcu_torture_cleanup(void)
|
|||
|
||||
rcutorture_get_gp_data(cur_ops->ttype, &flags, &gp_seq);
|
||||
srcutorture_get_gp_data(cur_ops->ttype, srcu_ctlp, &flags, &gp_seq);
|
||||
pr_alert("%s: End-test grace-period state: g%lu f%#x\n",
|
||||
cur_ops->name, gp_seq, flags);
|
||||
pr_alert("%s: End-test grace-period state: g%ld f%#x total-gps=%ld\n",
|
||||
cur_ops->name, (long)gp_seq, flags,
|
||||
rcutorture_seq_diff(gp_seq, start_gp_seq));
|
||||
torture_stop_kthread(rcu_torture_stats, stats_task);
|
||||
torture_stop_kthread(rcu_torture_fqs, fqs_task);
|
||||
if (rcu_torture_can_boost())
|
||||
|
@ -2607,6 +2623,8 @@ rcu_torture_init(void)
|
|||
long i;
|
||||
int cpu;
|
||||
int firsterr = 0;
|
||||
int flags = 0;
|
||||
unsigned long gp_seq = 0;
|
||||
static struct rcu_torture_ops *torture_ops[] = {
|
||||
&rcu_ops, &rcu_busted_ops, &srcu_ops, &srcud_ops,
|
||||
&busted_srcud_ops, &tasks_ops, &tasks_rude_ops,
|
||||
|
@ -2649,6 +2667,11 @@ rcu_torture_init(void)
|
|||
nrealreaders = 1;
|
||||
}
|
||||
rcu_torture_print_module_parms(cur_ops, "Start of test");
|
||||
rcutorture_get_gp_data(cur_ops->ttype, &flags, &gp_seq);
|
||||
srcutorture_get_gp_data(cur_ops->ttype, srcu_ctlp, &flags, &gp_seq);
|
||||
start_gp_seq = gp_seq;
|
||||
pr_alert("%s: Start-test grace-period state: g%ld f%#x\n",
|
||||
cur_ops->name, (long)gp_seq, flags);
|
||||
|
||||
/* Set up the freelist. */
|
||||
|
||||
|
|
|
@ -546,9 +546,11 @@ static int main_func(void *arg)
|
|||
// Print the average of all experiments
|
||||
SCALEOUT("END OF TEST. Calculating average duration per loop (nanoseconds)...\n");
|
||||
|
||||
buf[0] = 0;
|
||||
strcat(buf, "\n");
|
||||
strcat(buf, "Runs\tTime(ns)\n");
|
||||
if (!errexit) {
|
||||
buf[0] = 0;
|
||||
strcat(buf, "\n");
|
||||
strcat(buf, "Runs\tTime(ns)\n");
|
||||
}
|
||||
|
||||
for (exp = 0; exp < nruns; exp++) {
|
||||
u64 avg;
|
||||
|
|
|
@ -29,19 +29,6 @@
|
|||
#include "rcu.h"
|
||||
#include "rcu_segcblist.h"
|
||||
|
||||
#ifndef data_race
|
||||
#define data_race(expr) \
|
||||
({ \
|
||||
expr; \
|
||||
})
|
||||
#endif
|
||||
#ifndef ASSERT_EXCLUSIVE_WRITER
|
||||
#define ASSERT_EXCLUSIVE_WRITER(var) do { } while (0)
|
||||
#endif
|
||||
#ifndef ASSERT_EXCLUSIVE_ACCESS
|
||||
#define ASSERT_EXCLUSIVE_ACCESS(var) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* Holdoff in nanoseconds for auto-expediting. */
|
||||
#define DEFAULT_SRCU_EXP_HOLDOFF (25 * 1000)
|
||||
static ulong exp_holdoff = DEFAULT_SRCU_EXP_HOLDOFF;
|
||||
|
|
|
@ -70,19 +70,6 @@
|
|||
#endif
|
||||
#define MODULE_PARAM_PREFIX "rcutree."
|
||||
|
||||
#ifndef data_race
|
||||
#define data_race(expr) \
|
||||
({ \
|
||||
expr; \
|
||||
})
|
||||
#endif
|
||||
#ifndef ASSERT_EXCLUSIVE_WRITER
|
||||
#define ASSERT_EXCLUSIVE_WRITER(var) do { } while (0)
|
||||
#endif
|
||||
#ifndef ASSERT_EXCLUSIVE_ACCESS
|
||||
#define ASSERT_EXCLUSIVE_ACCESS(var) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* Data structures. */
|
||||
|
||||
/*
|
||||
|
@ -1090,11 +1077,6 @@ static void rcu_disable_urgency_upon_qs(struct rcu_data *rdp)
|
|||
}
|
||||
}
|
||||
|
||||
noinstr bool __rcu_is_watching(void)
|
||||
{
|
||||
return !rcu_dynticks_curr_cpu_in_eqs();
|
||||
}
|
||||
|
||||
/**
|
||||
* rcu_is_watching - see if RCU thinks that the current CPU is not idle
|
||||
*
|
||||
|
@ -1227,13 +1209,28 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* If waiting too long on an offline CPU, complain. */
|
||||
if (!(rdp->grpmask & rcu_rnp_online_cpus(rnp)) &&
|
||||
time_after(jiffies, rcu_state.gp_start + HZ)) {
|
||||
/*
|
||||
* Complain if a CPU that is considered to be offline from RCU's
|
||||
* perspective has not yet reported a quiescent state. After all,
|
||||
* the offline CPU should have reported a quiescent state during
|
||||
* the CPU-offline process, or, failing that, by rcu_gp_init()
|
||||
* if it ran concurrently with either the CPU going offline or the
|
||||
* last task on a leaf rcu_node structure exiting its RCU read-side
|
||||
* critical section while all CPUs corresponding to that structure
|
||||
* are offline. This added warning detects bugs in any of these
|
||||
* code paths.
|
||||
*
|
||||
* The rcu_node structure's ->lock is held here, which excludes
|
||||
* the relevant portions the CPU-hotplug code, the grace-period
|
||||
* initialization code, and the rcu_read_unlock() code paths.
|
||||
*
|
||||
* For more detail, please refer to the "Hotplug CPU" section
|
||||
* of RCU's Requirements documentation.
|
||||
*/
|
||||
if (WARN_ON_ONCE(!(rdp->grpmask & rcu_rnp_online_cpus(rnp)))) {
|
||||
bool onl;
|
||||
struct rcu_node *rnp1;
|
||||
|
||||
WARN_ON(1); /* Offline CPUs are supposed to report QS! */
|
||||
pr_info("%s: grp: %d-%d level: %d ->gp_seq %ld ->completedqs %ld\n",
|
||||
__func__, rnp->grplo, rnp->grphi, rnp->level,
|
||||
(long)rnp->gp_seq, (long)rnp->completedqs);
|
||||
|
@ -1496,9 +1493,10 @@ static bool rcu_accelerate_cbs(struct rcu_node *rnp, struct rcu_data *rdp)
|
|||
|
||||
/* Trace depending on how much we were able to accelerate. */
|
||||
if (rcu_segcblist_restempty(&rdp->cblist, RCU_WAIT_TAIL))
|
||||
trace_rcu_grace_period(rcu_state.name, rdp->gp_seq, TPS("AccWaitCB"));
|
||||
trace_rcu_grace_period(rcu_state.name, gp_seq_req, TPS("AccWaitCB"));
|
||||
else
|
||||
trace_rcu_grace_period(rcu_state.name, rdp->gp_seq, TPS("AccReadyCB"));
|
||||
trace_rcu_grace_period(rcu_state.name, gp_seq_req, TPS("AccReadyCB"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1718,10 +1716,13 @@ static bool rcu_gp_init(void)
|
|||
raw_spin_unlock_irq_rcu_node(rnp);
|
||||
|
||||
/*
|
||||
* Apply per-leaf buffered online and offline operations to the
|
||||
* rcu_node tree. Note that this new grace period need not wait
|
||||
* for subsequent online CPUs, and that quiescent-state forcing
|
||||
* will handle subsequent offline CPUs.
|
||||
* Apply per-leaf buffered online and offline operations to
|
||||
* the rcu_node tree. Note that this new grace period need not
|
||||
* wait for subsequent online CPUs, and that RCU hooks in the CPU
|
||||
* offlining path, when combined with checks in this function,
|
||||
* will handle CPUs that are currently going offline or that will
|
||||
* go offline later. Please also refer to "Hotplug CPU" section
|
||||
* of RCU's Requirements documentation.
|
||||
*/
|
||||
rcu_state.gp_state = RCU_GP_ONOFF;
|
||||
rcu_for_each_leaf_node(rnp) {
|
||||
|
@ -1896,7 +1897,7 @@ static void rcu_gp_fqs_loop(void)
|
|||
break;
|
||||
/* If time for quiescent-state forcing, do it. */
|
||||
if (!time_after(rcu_state.jiffies_force_qs, jiffies) ||
|
||||
(gf & RCU_GP_FLAG_FQS)) {
|
||||
(gf & (RCU_GP_FLAG_FQS | RCU_GP_FLAG_OVLD))) {
|
||||
trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
|
||||
TPS("fqsstart"));
|
||||
rcu_gp_fqs(first_gp_fqs);
|
||||
|
@ -2374,6 +2375,7 @@ int rcutree_dead_cpu(unsigned int cpu)
|
|||
*/
|
||||
static void rcu_do_batch(struct rcu_data *rdp)
|
||||
{
|
||||
int div;
|
||||
unsigned long flags;
|
||||
const bool offloaded = IS_ENABLED(CONFIG_RCU_NOCB_CPU) &&
|
||||
rcu_segcblist_is_offloaded(&rdp->cblist);
|
||||
|
@ -2402,9 +2404,15 @@ static void rcu_do_batch(struct rcu_data *rdp)
|
|||
rcu_nocb_lock(rdp);
|
||||
WARN_ON_ONCE(cpu_is_offline(smp_processor_id()));
|
||||
pending = rcu_segcblist_n_cbs(&rdp->cblist);
|
||||
bl = max(rdp->blimit, pending >> rcu_divisor);
|
||||
if (unlikely(bl > 100))
|
||||
tlimit = local_clock() + rcu_resched_ns;
|
||||
div = READ_ONCE(rcu_divisor);
|
||||
div = div < 0 ? 7 : div > sizeof(long) * 8 - 2 ? sizeof(long) * 8 - 2 : div;
|
||||
bl = max(rdp->blimit, pending >> div);
|
||||
if (unlikely(bl > 100)) {
|
||||
long rrn = READ_ONCE(rcu_resched_ns);
|
||||
|
||||
rrn = rrn < NSEC_PER_MSEC ? NSEC_PER_MSEC : rrn > NSEC_PER_SEC ? NSEC_PER_SEC : rrn;
|
||||
tlimit = local_clock() + rrn;
|
||||
}
|
||||
trace_rcu_batch_start(rcu_state.name,
|
||||
rcu_segcblist_n_cbs(&rdp->cblist), bl);
|
||||
rcu_segcblist_extract_done_cbs(&rdp->cblist, &rcl);
|
||||
|
@ -2545,8 +2553,7 @@ static void force_qs_rnp(int (*f)(struct rcu_data *rdp))
|
|||
raw_spin_lock_irqsave_rcu_node(rnp, flags);
|
||||
rcu_state.cbovldnext |= !!rnp->cbovldmask;
|
||||
if (rnp->qsmask == 0) {
|
||||
if (!IS_ENABLED(CONFIG_PREEMPT_RCU) ||
|
||||
rcu_preempt_blocked_readers_cgp(rnp)) {
|
||||
if (rcu_preempt_blocked_readers_cgp(rnp)) {
|
||||
/*
|
||||
* No point in scanning bits because they
|
||||
* are all zero. But we might need to
|
||||
|
@ -3443,7 +3450,7 @@ kfree_rcu_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
|
|||
unsigned long count = 0;
|
||||
|
||||
/* Snapshot count of all CPUs */
|
||||
for_each_online_cpu(cpu) {
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct kfree_rcu_cpu *krcp = per_cpu_ptr(&krc, cpu);
|
||||
|
||||
count += READ_ONCE(krcp->count);
|
||||
|
@ -3458,7 +3465,7 @@ kfree_rcu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
|||
int cpu, freed = 0;
|
||||
unsigned long flags;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
for_each_possible_cpu(cpu) {
|
||||
int count;
|
||||
struct kfree_rcu_cpu *krcp = per_cpu_ptr(&krc, cpu);
|
||||
|
||||
|
@ -3491,7 +3498,7 @@ void __init kfree_rcu_scheduler_running(void)
|
|||
int cpu;
|
||||
unsigned long flags;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct kfree_rcu_cpu *krcp = per_cpu_ptr(&krc, cpu);
|
||||
|
||||
raw_spin_lock_irqsave(&krcp->lock, flags);
|
||||
|
@ -3973,8 +3980,6 @@ int rcutree_offline_cpu(unsigned int cpu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(int, rcu_cpu_started);
|
||||
|
||||
/*
|
||||
* Mark the specified CPU as being online so that subsequent grace periods
|
||||
* (both expedited and normal) will wait on it. Note that this means that
|
||||
|
@ -3994,12 +3999,11 @@ void rcu_cpu_starting(unsigned int cpu)
|
|||
struct rcu_node *rnp;
|
||||
bool newcpu;
|
||||
|
||||
if (per_cpu(rcu_cpu_started, cpu))
|
||||
return;
|
||||
|
||||
per_cpu(rcu_cpu_started, cpu) = 1;
|
||||
|
||||
rdp = per_cpu_ptr(&rcu_data, cpu);
|
||||
if (rdp->cpu_started)
|
||||
return;
|
||||
rdp->cpu_started = true;
|
||||
|
||||
rnp = rdp->mynode;
|
||||
mask = rdp->grpmask;
|
||||
raw_spin_lock_irqsave_rcu_node(rnp, flags);
|
||||
|
@ -4059,7 +4063,7 @@ void rcu_report_dead(unsigned int cpu)
|
|||
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
|
||||
raw_spin_unlock(&rcu_state.ofl_lock);
|
||||
|
||||
per_cpu(rcu_cpu_started, cpu) = 0;
|
||||
rdp->cpu_started = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -156,6 +156,7 @@ struct rcu_data {
|
|||
bool beenonline; /* CPU online at least once. */
|
||||
bool gpwrap; /* Possible ->gp_seq wrap. */
|
||||
bool exp_deferred_qs; /* This CPU awaiting a deferred QS? */
|
||||
bool cpu_started; /* RCU watching this onlining CPU. */
|
||||
struct rcu_node *mynode; /* This CPU's leaf of hierarchy */
|
||||
unsigned long grpmask; /* Mask to apply to leaf qsmask. */
|
||||
unsigned long ticks_this_gp; /* The number of scheduling-clock */
|
||||
|
|
|
@ -732,11 +732,9 @@ static void rcu_exp_need_qs(void)
|
|||
/* Invoked on each online non-idle CPU for expedited quiescent state. */
|
||||
static void rcu_exp_handler(void *unused)
|
||||
{
|
||||
struct rcu_data *rdp;
|
||||
struct rcu_node *rnp;
|
||||
struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
|
||||
struct rcu_node *rnp = rdp->mynode;
|
||||
|
||||
rdp = this_cpu_ptr(&rcu_data);
|
||||
rnp = rdp->mynode;
|
||||
if (!(READ_ONCE(rnp->expmask) & rdp->grpmask) ||
|
||||
__this_cpu_read(rcu_data.cpu_no_qs.b.exp))
|
||||
return;
|
||||
|
|
|
@ -1926,6 +1926,7 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
|
|||
* nearest grace period (if any) to wait for next. The CB kthreads
|
||||
* and the global grace-period kthread are awakened if needed.
|
||||
*/
|
||||
WARN_ON_ONCE(my_rdp->nocb_gp_rdp != my_rdp);
|
||||
for (rdp = my_rdp; rdp; rdp = rdp->nocb_next_cb_rdp) {
|
||||
trace_rcu_nocb_wake(rcu_state.name, rdp->cpu, TPS("Check"));
|
||||
rcu_nocb_lock_irqsave(rdp, flags);
|
||||
|
@ -2411,13 +2412,12 @@ static void show_rcu_nocb_state(struct rcu_data *rdp)
|
|||
return;
|
||||
|
||||
waslocked = raw_spin_is_locked(&rdp->nocb_gp_lock);
|
||||
wastimer = timer_pending(&rdp->nocb_timer);
|
||||
wastimer = timer_pending(&rdp->nocb_bypass_timer);
|
||||
wassleep = swait_active(&rdp->nocb_gp_wq);
|
||||
if (!rdp->nocb_defer_wakeup && !rdp->nocb_gp_sleep &&
|
||||
!waslocked && !wastimer && !wassleep)
|
||||
if (!rdp->nocb_gp_sleep && !waslocked && !wastimer && !wassleep)
|
||||
return; /* Nothing untowards. */
|
||||
|
||||
pr_info(" !!! %c%c%c%c %c\n",
|
||||
pr_info(" nocb GP activity on CB-only CPU!!! %c%c%c%c %c\n",
|
||||
"lL"[waslocked],
|
||||
"dD"[!!rdp->nocb_defer_wakeup],
|
||||
"tT"[wastimer],
|
||||
|
|
|
@ -158,7 +158,7 @@ static void rcu_stall_kick_kthreads(void)
|
|||
{
|
||||
unsigned long j;
|
||||
|
||||
if (!rcu_kick_kthreads)
|
||||
if (!READ_ONCE(rcu_kick_kthreads))
|
||||
return;
|
||||
j = READ_ONCE(rcu_state.jiffies_kick_kthreads);
|
||||
if (time_after(jiffies, j) && rcu_state.gp_kthread &&
|
||||
|
@ -580,7 +580,7 @@ static void check_cpu_stall(struct rcu_data *rdp)
|
|||
unsigned long js;
|
||||
struct rcu_node *rnp;
|
||||
|
||||
if ((rcu_stall_is_suppressed() && !rcu_kick_kthreads) ||
|
||||
if ((rcu_stall_is_suppressed() && !READ_ONCE(rcu_kick_kthreads)) ||
|
||||
!rcu_gp_in_progress())
|
||||
return;
|
||||
rcu_stall_kick_kthreads();
|
||||
|
@ -623,7 +623,7 @@ static void check_cpu_stall(struct rcu_data *rdp)
|
|||
|
||||
/* We haven't checked in, so go dump stack. */
|
||||
print_cpu_stall(gps);
|
||||
if (rcu_cpu_stall_ftrace_dump)
|
||||
if (READ_ONCE(rcu_cpu_stall_ftrace_dump))
|
||||
rcu_ftrace_dump(DUMP_ALL);
|
||||
|
||||
} else if (rcu_gp_in_progress() &&
|
||||
|
@ -632,7 +632,7 @@ static void check_cpu_stall(struct rcu_data *rdp)
|
|||
|
||||
/* They had a few time units to dump stack, so complain. */
|
||||
print_other_cpu_stall(gs2, gps);
|
||||
if (rcu_cpu_stall_ftrace_dump)
|
||||
if (READ_ONCE(rcu_cpu_stall_ftrace_dump))
|
||||
rcu_ftrace_dump(DUMP_ALL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,19 +53,6 @@
|
|||
#endif
|
||||
#define MODULE_PARAM_PREFIX "rcupdate."
|
||||
|
||||
#ifndef data_race
|
||||
#define data_race(expr) \
|
||||
({ \
|
||||
expr; \
|
||||
})
|
||||
#endif
|
||||
#ifndef ASSERT_EXCLUSIVE_WRITER
|
||||
#define ASSERT_EXCLUSIVE_WRITER(var) do { } while (0)
|
||||
#endif
|
||||
#ifndef ASSERT_EXCLUSIVE_ACCESS
|
||||
#define ASSERT_EXCLUSIVE_ACCESS(var) do { } while (0)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_TINY_RCU
|
||||
module_param(rcu_expedited, int, 0);
|
||||
module_param(rcu_normal, int, 0);
|
||||
|
|
|
@ -66,6 +66,7 @@ config_override_param () {
|
|||
echo > $T/KcList
|
||||
config_override_param "$config_dir/CFcommon" KcList "`cat $config_dir/CFcommon 2> /dev/null`"
|
||||
config_override_param "$config_template" KcList "`cat $config_template 2> /dev/null`"
|
||||
config_override_param "--gdb options" KcList "$TORTURE_KCONFIG_GDB_ARG"
|
||||
config_override_param "--kasan options" KcList "$TORTURE_KCONFIG_KASAN_ARG"
|
||||
config_override_param "--kcsan options" KcList "$TORTURE_KCONFIG_KCSAN_ARG"
|
||||
config_override_param "--kconfig argument" KcList "$TORTURE_KCONFIG_ARG"
|
||||
|
@ -152,7 +153,11 @@ qemu_append="`identify_qemu_append "$QEMU"`"
|
|||
boot_args="`configfrag_boot_params "$boot_args" "$config_template"`"
|
||||
# Generate kernel-version-specific boot parameters
|
||||
boot_args="`per_version_boot_params "$boot_args" $resdir/.config $seconds`"
|
||||
echo $QEMU $qemu_args -m $TORTURE_QEMU_MEM -kernel $KERNEL -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
|
||||
if test -n "$TORTURE_BOOT_GDB_ARG"
|
||||
then
|
||||
boot_args="$boot_args $TORTURE_BOOT_GDB_ARG"
|
||||
fi
|
||||
echo $QEMU $qemu_args -m $TORTURE_QEMU_MEM -kernel $KERNEL -append \"$qemu_append $boot_args\" $TORTURE_QEMU_GDB_ARG > $resdir/qemu-cmd
|
||||
|
||||
if test -n "$TORTURE_BUILDONLY"
|
||||
then
|
||||
|
@ -171,14 +176,26 @@ echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log
|
|||
# Attempt to run qemu
|
||||
( . $T/qemu-cmd; wait `cat $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) &
|
||||
commandcompleted=0
|
||||
sleep 10 # Give qemu's pid a chance to reach the file
|
||||
if test -s "$resdir/qemu_pid"
|
||||
if test -z "$TORTURE_KCONFIG_GDB_ARG"
|
||||
then
|
||||
qemu_pid=`cat "$resdir/qemu_pid"`
|
||||
echo Monitoring qemu job at pid $qemu_pid
|
||||
else
|
||||
qemu_pid=""
|
||||
echo Monitoring qemu job at yet-as-unknown pid
|
||||
sleep 10 # Give qemu's pid a chance to reach the file
|
||||
if test -s "$resdir/qemu_pid"
|
||||
then
|
||||
qemu_pid=`cat "$resdir/qemu_pid"`
|
||||
echo Monitoring qemu job at pid $qemu_pid
|
||||
else
|
||||
qemu_pid=""
|
||||
echo Monitoring qemu job at yet-as-unknown pid
|
||||
fi
|
||||
fi
|
||||
if test -n "$TORTURE_KCONFIG_GDB_ARG"
|
||||
then
|
||||
echo Waiting for you to attach a debug session, for example: > /dev/tty
|
||||
echo " gdb $base_resdir/vmlinux" > /dev/tty
|
||||
echo 'After symbols load and the "(gdb)" prompt appears:' > /dev/tty
|
||||
echo " target remote :1234" > /dev/tty
|
||||
echo " continue" > /dev/tty
|
||||
kstarttime=`gawk 'BEGIN { print systime() }' < /dev/null`
|
||||
fi
|
||||
while :
|
||||
do
|
||||
|
|
|
@ -31,6 +31,9 @@ TORTURE_DEFCONFIG=defconfig
|
|||
TORTURE_BOOT_IMAGE=""
|
||||
TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD
|
||||
TORTURE_KCONFIG_ARG=""
|
||||
TORTURE_KCONFIG_GDB_ARG=""
|
||||
TORTURE_BOOT_GDB_ARG=""
|
||||
TORTURE_QEMU_GDB_ARG=""
|
||||
TORTURE_KCONFIG_KASAN_ARG=""
|
||||
TORTURE_KCONFIG_KCSAN_ARG=""
|
||||
TORTURE_KMAKE_ARG=""
|
||||
|
@ -46,6 +49,7 @@ jitter="-1"
|
|||
|
||||
usage () {
|
||||
echo "Usage: $scriptname optional arguments:"
|
||||
echo " --allcpus"
|
||||
echo " --bootargs kernel-boot-arguments"
|
||||
echo " --bootimage relative-path-to-kernel-boot-image"
|
||||
echo " --buildonly"
|
||||
|
@ -55,17 +59,19 @@ usage () {
|
|||
echo " --defconfig string"
|
||||
echo " --dryrun sched|script"
|
||||
echo " --duration minutes"
|
||||
echo " --gdb"
|
||||
echo " --help"
|
||||
echo " --interactive"
|
||||
echo " --jitter N [ maxsleep (us) [ maxspin (us) ] ]"
|
||||
echo " --kconfig Kconfig-options"
|
||||
echo " --kmake-arg kernel-make-arguments"
|
||||
echo " --mac nn:nn:nn:nn:nn:nn"
|
||||
echo " --memory megabytes | nnnG"
|
||||
echo " --memory megabytes|nnnG"
|
||||
echo " --no-initrd"
|
||||
echo " --qemu-args qemu-arguments"
|
||||
echo " --qemu-cmd qemu-system-..."
|
||||
echo " --results absolute-pathname"
|
||||
echo " --torture rcu"
|
||||
echo " --torture lock|rcu|rcuperf|refscale|scf"
|
||||
echo " --trust-make"
|
||||
exit 1
|
||||
}
|
||||
|
@ -126,6 +132,14 @@ do
|
|||
dur=$(($2*60))
|
||||
shift
|
||||
;;
|
||||
--gdb)
|
||||
TORTURE_KCONFIG_GDB_ARG="CONFIG_DEBUG_INFO=y"; export TORTURE_KCONFIG_GDB_ARG
|
||||
TORTURE_BOOT_GDB_ARG="nokaslr"; export TORTURE_BOOT_GDB_ARG
|
||||
TORTURE_QEMU_GDB_ARG="-s -S"; export TORTURE_QEMU_GDB_ARG
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
;;
|
||||
--interactive)
|
||||
TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE
|
||||
;;
|
||||
|
@ -248,6 +262,15 @@ do
|
|||
done
|
||||
touch $T/cfgcpu
|
||||
configs_derep="`echo $configs_derep | sed -e "s/\<CFLIST\>/$defaultconfigs/g"`"
|
||||
if test -n "$TORTURE_KCONFIG_GDB_ARG"
|
||||
then
|
||||
if test "`echo $configs_derep | wc -w`" -gt 1
|
||||
then
|
||||
echo "The --config list is: $configs_derep."
|
||||
echo "Only one --config permitted with --gdb, terminating."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
for CF1 in $configs_derep
|
||||
do
|
||||
if test -f "$CONFIGFRAG/$CF1"
|
||||
|
@ -323,6 +346,9 @@ TORTURE_BUILDONLY="$TORTURE_BUILDONLY"; export TORTURE_BUILDONLY
|
|||
TORTURE_DEFCONFIG="$TORTURE_DEFCONFIG"; export TORTURE_DEFCONFIG
|
||||
TORTURE_INITRD="$TORTURE_INITRD"; export TORTURE_INITRD
|
||||
TORTURE_KCONFIG_ARG="$TORTURE_KCONFIG_ARG"; export TORTURE_KCONFIG_ARG
|
||||
TORTURE_KCONFIG_GDB_ARG="$TORTURE_KCONFIG_GDB_ARG"; export TORTURE_KCONFIG_GDB_ARG
|
||||
TORTURE_BOOT_GDB_ARG="$TORTURE_BOOT_GDB_ARG"; export TORTURE_BOOT_GDB_ARG
|
||||
TORTURE_QEMU_GDB_ARG="$TORTURE_QEMU_GDB_ARG"; export TORTURE_QEMU_GDB_ARG
|
||||
TORTURE_KCONFIG_KASAN_ARG="$TORTURE_KCONFIG_KASAN_ARG"; export TORTURE_KCONFIG_KASAN_ARG
|
||||
TORTURE_KCONFIG_KCSAN_ARG="$TORTURE_KCONFIG_KCSAN_ARG"; export TORTURE_KCONFIG_KCSAN_ARG
|
||||
TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG
|
||||
|
|
|
@ -16,5 +16,6 @@ CONFIG_RCU_NOCB_CPU=y
|
|||
CONFIG_DEBUG_LOCK_ALLOC=y
|
||||
CONFIG_PROVE_LOCKING=y
|
||||
#CHECK#CONFIG_PROVE_RCU=y
|
||||
CONFIG_PROVE_RCU_LIST=y
|
||||
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
|
||||
CONFIG_RCU_EXPERT=y
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
The rcutorture scripting tools automatically create the needed initrd
|
||||
directory using dracut. Failing that, this tool will create an initrd
|
||||
containing a single statically linked binary named "init" that loops
|
||||
over a very long sleep() call. In both cases, this creation is done
|
||||
by tools/testing/selftests/rcutorture/bin/mkinitrd.sh.
|
||||
The rcutorture scripting tools automatically create an initrd containing
|
||||
a single statically linked binary named "init" that loops over a
|
||||
very long sleep() call. In both cases, this creation is done by
|
||||
tools/testing/selftests/rcutorture/bin/mkinitrd.sh.
|
||||
|
||||
However, if you are attempting to run rcutorture on a system that does
|
||||
not have dracut installed, and if you don't like the notion of static
|
||||
linking, you might wish to press an existing initrd into service:
|
||||
However, if you don't like the notion of statically linked bare-bones
|
||||
userspace environments, you might wish to press an existing initrd
|
||||
into service:
|
||||
|
||||
------------------------------------------------------------------------
|
||||
cd tools/testing/selftests/rcutorture
|
||||
|
@ -15,24 +14,3 @@ mkdir initrd
|
|||
cd initrd
|
||||
cpio -id < /tmp/initrd.img.zcat
|
||||
# Manually verify that initrd contains needed binaries and libraries.
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Interestingly enough, if you are running rcutorture, you don't really
|
||||
need userspace in many cases. Running without userspace has the
|
||||
advantage of allowing you to test your kernel independently of the
|
||||
distro in place, the root-filesystem layout, and so on. To make this
|
||||
happen, put the following script in the initrd's tree's "/init" file,
|
||||
with 0755 mode.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
#!/bin/sh
|
||||
|
||||
while :
|
||||
do
|
||||
sleep 10
|
||||
done
|
||||
------------------------------------------------------------------------
|
||||
|
||||
This approach also allows most of the binaries and libraries in the
|
||||
initrd filesystem to be dispensed with, which can save significant
|
||||
space in rcutorture's "res" directory.
|
||||
|
|
|
@ -1,8 +1,33 @@
|
|||
This document describes one way to create the rcu-test-image file
|
||||
that contains the filesystem used by the guest-OS kernel. There are
|
||||
probably much better ways of doing this, and this filesystem could no
|
||||
doubt be smaller. It is probably also possible to simply download
|
||||
an appropriate image from any number of places.
|
||||
Normally, a minimal initrd is created automatically by the rcutorture
|
||||
scripting. But minimal really does mean "minimal", namely just a single
|
||||
root directory with a single statically linked executable named "init":
|
||||
|
||||
$ size tools/testing/selftests/rcutorture/initrd/init
|
||||
text data bss dec hex filename
|
||||
328 0 8 336 150 tools/testing/selftests/rcutorture/initrd/init
|
||||
|
||||
Suppose you need to run some scripts, perhaps to monitor or control
|
||||
some aspect of the rcutorture testing. This will require a more fully
|
||||
filled-out userspace, perhaps containing libraries, executables for
|
||||
the shell and other utilities, and soforth. In that case, place your
|
||||
desired filesystem here:
|
||||
|
||||
tools/testing/selftests/rcutorture/initrd
|
||||
|
||||
For example, your tools/testing/selftests/rcutorture/initrd/init might
|
||||
be a script that does any needed mount operations and starts whatever
|
||||
scripts need starting to properly monitor or control your testing.
|
||||
The next rcutorture build will then incorporate this filesystem into
|
||||
the kernel image that is passed to qemu.
|
||||
|
||||
Or maybe you need a real root filesystem for some reason, in which case
|
||||
please read on!
|
||||
|
||||
The remainder of this document describes one way to create the
|
||||
rcu-test-image file that contains the filesystem used by the guest-OS
|
||||
kernel. There are probably much better ways of doing this, and this
|
||||
filesystem could no doubt be smaller. It is probably also possible to
|
||||
simply download an appropriate image from any number of places.
|
||||
|
||||
That said, here are the commands:
|
||||
|
||||
|
@ -36,7 +61,7 @@ References:
|
|||
https://help.ubuntu.com/community/JeOSVMBuilder
|
||||
http://wiki.libvirt.org/page/UbuntuKVMWalkthrough
|
||||
http://www.moe.co.uk/2011/01/07/pci_add_option_rom-failed-to-find-romfile-pxe-rtl8139-bin/ -- "apt-get install kvm-pxe"
|
||||
http://www.landley.net/writing/rootfs-howto.html
|
||||
http://en.wikipedia.org/wiki/Initrd
|
||||
http://en.wikipedia.org/wiki/Cpio
|
||||
https://www.landley.net/writing/rootfs-howto.html
|
||||
https://en.wikipedia.org/wiki/Initrd
|
||||
https://en.wikipedia.org/wiki/Cpio
|
||||
http://wiki.libvirt.org/page/UbuntuKVMWalkthrough
|
||||
|
|
Loading…
Reference in New Issue