Commit 9a45da92 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'core-rcu-2021-04-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull RCU updates from Ingo Molnar:

 - Support for "N" as alias for last bit in bitmap parsing library (eg
   using syntax like "nohz_full=2-N")

 - kvfree_rcu updates

 - mm_dump_obj() updates. (One of these is to mm, but was suggested by
   Andrew Morton.)

 - RCU callback offloading update

 - Polling RCU grace-period interfaces

 - Realtime-related RCU updates

 - Tasks-RCU updates

 - Torture-test updates

 - Torture-test scripting updates

 - Miscellaneous fixes

* tag 'core-rcu-2021-04-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (77 commits)
  rcutorture: Test start_poll_synchronize_rcu() and poll_state_synchronize_rcu()
  rcu: Provide polling interfaces for Tiny RCU grace periods
  torture: Fix kvm.sh --datestamp regex check
  torture: Consolidate qemu-cmd duration editing into kvm-transform.sh
  torture: Print proper vmlinux path for kvm-again.sh runs
  torture: Make TORTURE_TRUST_MAKE available in kvm-again.sh environment
  torture: Make kvm-transform.sh update jitter commands
  torture: Add --duration argument to kvm-again.sh
  torture: Add kvm-again.sh to rerun a previous torture-test
  torture: Create a "batches" file for build reuse
  torture: De-capitalize TORTURE_SUITE
  torture: Make upper-case-only no-dot no-slash scenario names official
  torture: Rename SRCU-t and SRCU-u to avoid lowercase characters
  torture: Remove no-mpstat error message
  torture: Record kvm-test-1-run.sh and kvm-test-1-run-qemu.sh PIDs
  torture: Record jitter start/stop commands
  torture: Extract kvm-test-1-run-qemu.sh from kvm-test-1-run.sh
  torture: Record TORTURE_KCONFIG_GDB_ARG in qemu-cmd
  torture: Abstract jitter.sh start/stop into scripts
  rcu: Provide polling interfaces for Tree RCU grace periods
  ...
parents 68a32ba1 120b566d
...@@ -847,7 +847,7 @@ Symposium on Distributed Computing} ...@@ -847,7 +847,7 @@ Symposium on Distributed Computing}
'It's entirely possible that the current user could be replaced 'It's entirely possible that the current user could be replaced
by RCU and/or seqlocks, and we could get rid of brlocks entirely.' by RCU and/or seqlocks, and we could get rid of brlocks entirely.'
. .
Steve Hemminger responds by replacing them with RCU. Stephen Hemminger responds by replacing them with RCU.
} }
} }
......
...@@ -68,6 +68,13 @@ For example one can add to the command line following parameter: ...@@ -68,6 +68,13 @@ For example one can add to the command line following parameter:
where the final item represents CPUs 100,101,125,126,150,151,... where the final item represents CPUs 100,101,125,126,150,151,...
The value "N" can be used to represent the numerically last CPU on the system,
i.e "foo_cpus=16-N" would be equivalent to "16-31" on a 32 core system.
Keep in mind that "N" is dynamic, so if system changes cause the bitmap width
to change, such as less cores in the CPU list, then N and any ranges using N
will also change. Use the same on a small 4 core system, and "16-N" becomes
"16-3" and now the same boot input will be flagged as invalid (start > end).
This document may not be entirely up to date and comprehensive. The command This document may not be entirely up to date and comprehensive. The command
......
...@@ -4077,9 +4077,7 @@ ...@@ -4077,9 +4077,7 @@
see CONFIG_RAS_CEC help text. see CONFIG_RAS_CEC help text.
rcu_nocbs= [KNL] rcu_nocbs= [KNL]
The argument is a cpu list, as described above, The argument is a cpu list, as described above.
except that the string "all" can be used to
specify every CPU on the system.
In kernels built with CONFIG_RCU_NOCB_CPU=y, set In kernels built with CONFIG_RCU_NOCB_CPU=y, set
the specified list of CPUs to be no-callback CPUs. the specified list of CPUs to be no-callback CPUs.
...@@ -4268,6 +4266,18 @@ ...@@ -4268,6 +4266,18 @@
rcuscale.kfree_rcu_test= [KNL] rcuscale.kfree_rcu_test= [KNL]
Set to measure performance of kfree_rcu() flooding. Set to measure performance of kfree_rcu() flooding.
rcuscale.kfree_rcu_test_double= [KNL]
Test the double-argument variant of kfree_rcu().
If this parameter has the same value as
rcuscale.kfree_rcu_test_single, both the single-
and double-argument variants are tested.
rcuscale.kfree_rcu_test_single= [KNL]
Test the single-argument variant of kfree_rcu().
If this parameter has the same value as
rcuscale.kfree_rcu_test_double, both the single-
and double-argument variants are tested.
rcuscale.kfree_nthreads= [KNL] rcuscale.kfree_nthreads= [KNL]
The number of threads running loops of kfree_rcu(). The number of threads running loops of kfree_rcu().
......
...@@ -3180,7 +3180,11 @@ unsigned long wp_shared_mapping_range(struct address_space *mapping, ...@@ -3180,7 +3180,11 @@ unsigned long wp_shared_mapping_range(struct address_space *mapping,
extern int sysctl_nr_trim_pages; extern int sysctl_nr_trim_pages;
#ifdef CONFIG_PRINTK
void mem_dump_obj(void *object); void mem_dump_obj(void *object);
#else
static inline void mem_dump_obj(void *object) {}
#endif
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _LINUX_MM_H */ #endif /* _LINUX_MM_H */
...@@ -109,7 +109,7 @@ struct rcu_cblist { ...@@ -109,7 +109,7 @@ struct rcu_cblist {
* | SEGCBLIST_KTHREAD_GP | * | SEGCBLIST_KTHREAD_GP |
* | | * | |
* | Kthreads handle callbacks holding nocb_lock, local rcu_core() stops | * | Kthreads handle callbacks holding nocb_lock, local rcu_core() stops |
* | handling callbacks. | * | handling callbacks. Enable bypass queueing. |
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
...@@ -125,7 +125,7 @@ struct rcu_cblist { ...@@ -125,7 +125,7 @@ struct rcu_cblist {
* | SEGCBLIST_KTHREAD_GP | * | SEGCBLIST_KTHREAD_GP |
* | | * | |
* | CB/GP kthreads handle callbacks holding nocb_lock, local rcu_core() | * | CB/GP kthreads handle callbacks holding nocb_lock, local rcu_core() |
* | ignores callbacks. | * | ignores callbacks. Bypass enqueue is enabled. |
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* | * |
* v * v
...@@ -134,7 +134,8 @@ struct rcu_cblist { ...@@ -134,7 +134,8 @@ struct rcu_cblist {
* | SEGCBLIST_KTHREAD_GP | * | SEGCBLIST_KTHREAD_GP |
* | | * | |
* | CB/GP kthreads and local rcu_core() handle callbacks concurrently | * | CB/GP kthreads and local rcu_core() handle callbacks concurrently |
* | holding nocb_lock. Wake up CB and GP kthreads if necessary. | * | holding nocb_lock. Wake up CB and GP kthreads if necessary. Disable |
* | bypass enqueue. |
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* | * |
* v * v
......
...@@ -161,7 +161,7 @@ static inline void hlist_nulls_add_fake(struct hlist_nulls_node *n) ...@@ -161,7 +161,7 @@ static inline void hlist_nulls_add_fake(struct hlist_nulls_node *n)
* *
* The barrier() is needed to make sure compiler doesn't cache first element [1], * The barrier() is needed to make sure compiler doesn't cache first element [1],
* as this loop can be restarted [2] * as this loop can be restarted [2]
* [1] Documentation/core-api/atomic_ops.rst around line 114 * [1] Documentation/memory-barriers.txt around line 1533
* [2] Documentation/RCU/rculist_nulls.rst around line 146 * [2] Documentation/RCU/rculist_nulls.rst around line 146
*/ */
#define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \ #define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \
......
...@@ -882,7 +882,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) ...@@ -882,7 +882,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
* The BUILD_BUG_ON check must not involve any function calls, hence the * The BUILD_BUG_ON check must not involve any function calls, hence the
* checks are done in macros here. * checks are done in macros here.
*/ */
#define kfree_rcu kvfree_rcu #define kfree_rcu(ptr, rhf...) kvfree_rcu(ptr, ## rhf)
/** /**
* kvfree_rcu() - kvfree an object after a grace period. * kvfree_rcu() - kvfree an object after a grace period.
......
...@@ -17,10 +17,9 @@ ...@@ -17,10 +17,9 @@
/* Never flag non-existent other CPUs! */ /* Never flag non-existent other CPUs! */
static inline bool rcu_eqs_special_set(int cpu) { return false; } static inline bool rcu_eqs_special_set(int cpu) { return false; }
static inline unsigned long get_state_synchronize_rcu(void) unsigned long get_state_synchronize_rcu(void);
{ unsigned long start_poll_synchronize_rcu(void);
return 0; bool poll_state_synchronize_rcu(unsigned long oldstate);
}
static inline void cond_synchronize_rcu(unsigned long oldstate) static inline void cond_synchronize_rcu(unsigned long oldstate)
{ {
......
...@@ -41,6 +41,8 @@ void rcu_momentary_dyntick_idle(void); ...@@ -41,6 +41,8 @@ void rcu_momentary_dyntick_idle(void);
void kfree_rcu_scheduler_running(void); void kfree_rcu_scheduler_running(void);
bool rcu_gp_might_be_stalled(void); bool rcu_gp_might_be_stalled(void);
unsigned long get_state_synchronize_rcu(void); unsigned long get_state_synchronize_rcu(void);
unsigned long start_poll_synchronize_rcu(void);
bool poll_state_synchronize_rcu(unsigned long oldstate);
void cond_synchronize_rcu(unsigned long oldstate); void cond_synchronize_rcu(unsigned long oldstate);
void rcu_idle_enter(void); void rcu_idle_enter(void);
......
...@@ -186,8 +186,10 @@ void kfree(const void *); ...@@ -186,8 +186,10 @@ void kfree(const void *);
void kfree_sensitive(const void *); void kfree_sensitive(const void *);
size_t __ksize(const void *); size_t __ksize(const void *);
size_t ksize(const void *); size_t ksize(const void *);
#ifdef CONFIG_PRINTK
bool kmem_valid_obj(void *object); bool kmem_valid_obj(void *object);
void kmem_dump_obj(void *object); void kmem_dump_obj(void *object);
#endif
#ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR #ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR
void __check_heap_object(const void *ptr, unsigned long n, struct page *page, void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
......
...@@ -241,7 +241,7 @@ pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms) ...@@ -241,7 +241,7 @@ pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
int register_vmap_purge_notifier(struct notifier_block *nb); int register_vmap_purge_notifier(struct notifier_block *nb);
int unregister_vmap_purge_notifier(struct notifier_block *nb); int unregister_vmap_purge_notifier(struct notifier_block *nb);
#ifdef CONFIG_MMU #if defined(CONFIG_MMU) && defined(CONFIG_PRINTK)
bool vmalloc_dump_obj(void *object); bool vmalloc_dump_obj(void *object);
#else #else
static inline bool vmalloc_dump_obj(void *object) { return false; } static inline bool vmalloc_dump_obj(void *object) { return false; }
......
...@@ -432,6 +432,34 @@ TRACE_EVENT_RCU(rcu_fqs, ...@@ -432,6 +432,34 @@ TRACE_EVENT_RCU(rcu_fqs,
__entry->cpu, __entry->qsevent) __entry->cpu, __entry->qsevent)
); );
/*
* Tracepoint for RCU stall events. Takes a string identifying the RCU flavor
* and a string identifying which function detected the RCU stall as follows:
*
* "StallDetected": Scheduler-tick detects other CPU's stalls.
* "SelfDetected": Scheduler-tick detects a current CPU's stall.
* "ExpeditedStall": Expedited grace period detects stalls.
*/
TRACE_EVENT(rcu_stall_warning,
TP_PROTO(const char *rcuname, const char *msg),
TP_ARGS(rcuname, msg),
TP_STRUCT__entry(
__field(const char *, rcuname)
__field(const char *, msg)
),
TP_fast_assign(
__entry->rcuname = rcuname;
__entry->msg = msg;
),
TP_printk("%s %s",
__entry->rcuname, __entry->msg)
);
#endif /* #if defined(CONFIG_TREE_RCU) */ #endif /* #if defined(CONFIG_TREE_RCU) */
/* /*
......
...@@ -261,8 +261,7 @@ void rcu_segcblist_disable(struct rcu_segcblist *rsclp) ...@@ -261,8 +261,7 @@ void rcu_segcblist_disable(struct rcu_segcblist *rsclp)
} }
/* /*
* Mark the specified rcu_segcblist structure as offloaded. This * Mark the specified rcu_segcblist structure as offloaded.
* structure must be empty.
*/ */
void rcu_segcblist_offload(struct rcu_segcblist *rsclp, bool offload) void rcu_segcblist_offload(struct rcu_segcblist *rsclp, bool offload)
{ {
......
...@@ -625,6 +625,8 @@ rcu_scale_shutdown(void *arg) ...@@ -625,6 +625,8 @@ rcu_scale_shutdown(void *arg)
torture_param(int, kfree_nthreads, -1, "Number of threads running loops of kfree_rcu()."); torture_param(int, kfree_nthreads, -1, "Number of threads running loops of kfree_rcu().");
torture_param(int, kfree_alloc_num, 8000, "Number of allocations and frees done in an iteration."); torture_param(int, kfree_alloc_num, 8000, "Number of allocations and frees done in an iteration.");
torture_param(int, kfree_loops, 10, "Number of loops doing kfree_alloc_num allocations and frees."); torture_param(int, kfree_loops, 10, "Number of loops doing kfree_alloc_num allocations and frees.");
torture_param(bool, kfree_rcu_test_double, false, "Do we run a kfree_rcu() double-argument scale test?");
torture_param(bool, kfree_rcu_test_single, false, "Do we run a kfree_rcu() single-argument scale test?");
static struct task_struct **kfree_reader_tasks; static struct task_struct **kfree_reader_tasks;
static int kfree_nrealthreads; static int kfree_nrealthreads;
...@@ -644,10 +646,13 @@ kfree_scale_thread(void *arg) ...@@ -644,10 +646,13 @@ kfree_scale_thread(void *arg)
struct kfree_obj *alloc_ptr; struct kfree_obj *alloc_ptr;
u64 start_time, end_time; u64 start_time, end_time;
long long mem_begin, mem_during = 0; long long mem_begin, mem_during = 0;
bool kfree_rcu_test_both;
DEFINE_TORTURE_RANDOM(tr);
VERBOSE_SCALEOUT_STRING("kfree_scale_thread task started"); VERBOSE_SCALEOUT_STRING("kfree_scale_thread task started");
set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids)); set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
set_user_nice(current, MAX_NICE); set_user_nice(current, MAX_NICE);
kfree_rcu_test_both = (kfree_rcu_test_single == kfree_rcu_test_double);
start_time = ktime_get_mono_fast_ns(); start_time = ktime_get_mono_fast_ns();
...@@ -670,7 +675,15 @@ kfree_scale_thread(void *arg) ...@@ -670,7 +675,15 @@ kfree_scale_thread(void *arg)
if (!alloc_ptr) if (!alloc_ptr)
return -ENOMEM; return -ENOMEM;
kfree_rcu(alloc_ptr, rh); // By default kfree_rcu_test_single and kfree_rcu_test_double are
// initialized to false. If both have the same value (false or true)
// both are randomly tested, otherwise only the one with value true
// is tested.
if ((kfree_rcu_test_single && !kfree_rcu_test_double) ||
(kfree_rcu_test_both && torture_random(&tr) & 0x800))
kfree_rcu(alloc_ptr);
else
kfree_rcu(alloc_ptr, rh);
} }
cond_resched(); cond_resched();
......
...@@ -245,11 +245,11 @@ static const char *rcu_torture_writer_state_getname(void) ...@@ -245,11 +245,11 @@ static const char *rcu_torture_writer_state_getname(void)
return rcu_torture_writer_state_names[i]; return rcu_torture_writer_state_names[i];
} }
#if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) #if defined(CONFIG_RCU_BOOST) && defined(CONFIG_PREEMPT_RT)
#define rcu_can_boost() 1 # define rcu_can_boost() 1
#else /* #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */ #else
#define rcu_can_boost() 0 # define rcu_can_boost() 0
#endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */ #endif
#ifdef CONFIG_RCU_TRACE #ifdef CONFIG_RCU_TRACE
static u64 notrace rcu_trace_clock_local(void) static u64 notrace rcu_trace_clock_local(void)
...@@ -494,6 +494,8 @@ static struct rcu_torture_ops rcu_ops = { ...@@ -494,6 +494,8 @@ static struct rcu_torture_ops rcu_ops = {
.sync = synchronize_rcu, .sync = synchronize_rcu,
.exp_sync = synchronize_rcu_expedited, .exp_sync = synchronize_rcu_expedited,
.get_gp_state = get_state_synchronize_rcu, .get_gp_state = get_state_synchronize_rcu,
.start_gp_poll = start_poll_synchronize_rcu,
.poll_gp_state = poll_state_synchronize_rcu,
.cond_sync = cond_synchronize_rcu, .cond_sync = cond_synchronize_rcu,
.call = call_rcu, .call = call_rcu,
.cb_barrier = rcu_barrier, .cb_barrier = rcu_barrier,
...@@ -923,9 +925,13 @@ static void rcu_torture_enable_rt_throttle(void) ...@@ -923,9 +925,13 @@ static void rcu_torture_enable_rt_throttle(void)
static bool rcu_torture_boost_failed(unsigned long start, unsigned long end) static bool rcu_torture_boost_failed(unsigned long start, unsigned long end)
{ {
static int dbg_done;
if (end - start > test_boost_duration * HZ - HZ / 2) { if (end - start > test_boost_duration * HZ - HZ / 2) {
VERBOSE_TOROUT_STRING("rcu_torture_boost boosting failed"); VERBOSE_TOROUT_STRING("rcu_torture_boost boosting failed");
n_rcu_torture_boost_failure++; n_rcu_torture_boost_failure++;
if (!xchg(&dbg_done, 1) && cur_ops->gp_kthread_dbg)
cur_ops->gp_kthread_dbg();
return true; /* failed */ return true; /* failed */
} }
...@@ -948,8 +954,8 @@ static int rcu_torture_boost(void *arg) ...@@ -948,8 +954,8 @@ static int rcu_torture_boost(void *arg)
init_rcu_head_on_stack(&rbi.rcu); init_rcu_head_on_stack(&rbi.rcu);
/* Each pass through the following loop does one boost-test cycle. */ /* Each pass through the following loop does one boost-test cycle. */
do { do {
/* Track if the test failed already in this test interval? */ bool failed = false; // Test failed already in this test interval
bool failed = false; bool firsttime = true;
/* Increment n_rcu_torture_boosts once per boost-test */ /* Increment n_rcu_torture_boosts once per boost-test */
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
...@@ -975,18 +981,17 @@ static int rcu_torture_boost(void *arg) ...@@ -975,18 +981,17 @@ static int rcu_torture_boost(void *arg)
/* Do one boost-test interval. */ /* Do one boost-test interval. */
endtime = oldstarttime + test_boost_duration * HZ; endtime = oldstarttime + test_boost_duration * HZ;
call_rcu_time = jiffies;
while (time_before(jiffies, endtime)) { while (time_before(jiffies, endtime)) {
/* If we don't have a callback in flight, post one. */ /* If we don't have a callback in flight, post one. */
if (!smp_load_acquire(&rbi.inflight)) { if (!smp_load_acquire(&rbi.inflight)) {
/* RCU core before ->inflight = 1. */ /* RCU core before ->inflight = 1. */
smp_store_release(&rbi.inflight, 1); smp_store_release(&rbi.inflight, 1);
call_rcu(&rbi.rcu, rcu_torture_boost_cb); cur_ops->call(&rbi.rcu, rcu_torture_boost_cb);
/* Check if the boost test failed */ /* Check if the boost test failed */
failed = failed || if (!firsttime && !failed)
rcu_torture_boost_failed(call_rcu_time, failed = rcu_torture_boost_failed(call_rcu_time, jiffies);
jiffies);
call_rcu_time = jiffies; call_rcu_time = jiffies;
firsttime = false;
} }
if (stutter_wait("rcu_torture_boost")) if (stutter_wait("rcu_torture_boost"))
sched_set_fifo_low(current); sched_set_fifo_low(current);
...@@ -999,7 +1004,7 @@ static int rcu_torture_boost(void *arg) ...@@ -999,7 +1004,7 @@ static int rcu_torture_boost(void *arg)
* this case the boost check would never happen in the above * this case the boost check would never happen in the above
* loop so do another one here. * loop so do another one here.
*/ */
if (!failed && smp_load_acquire(&rbi.inflight)) if (!firsttime && !failed && smp_load_acquire(&rbi.inflight))
rcu_torture_boost_failed(call_rcu_time, jiffies); rcu_torture_boost_failed(call_rcu_time, jiffies);
/* /*
...@@ -1025,6 +1030,9 @@ checkwait: if (stutter_wait("rcu_torture_boost")) ...@@ -1025,6 +1030,9 @@ checkwait: if (stutter_wait("rcu_torture_boost"))
sched_set_fifo_low(current); sched_set_fifo_low(current);
} while (!torture_must_stop()); } while (!torture_must_stop());
while (smp_load_acquire(&rbi.inflight))
schedule_timeout_uninterruptible(1); // rcu_barrier() deadlocks.
/* Clean up and exit. */ /* Clean up and exit. */
while (!kthread_should_stop() || smp_load_acquire(&rbi.inflight)) { while (!kthread_should_stop() || smp_load_acquire(&rbi.inflight)) {
torture_shutdown_absorb("rcu_torture_boost"); torture_shutdown_absorb("rcu_torture_boost");
...@@ -1223,14 +1231,6 @@ rcu_torture_writer(void *arg) ...@@ -1223,14 +1231,6 @@ rcu_torture_writer(void *arg)
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
break; break;
} }
if (cur_ops->get_gp_state && cur_ops->poll_gp_state)
WARN_ONCE(rcu_torture_writer_state != RTWS_DEF_FREE &&
!cur_ops->poll_gp_state(cookie),
"%s: Cookie check 2 failed %s(%d) %lu->%lu\n",
__func__,
rcu_torture_writer_state_getname(),
rcu_torture_writer_state,
cookie, cur_ops->get_gp_state());
} }
WRITE_ONCE(rcu_torture_current_version, WRITE_ONCE(rcu_torture_current_version,
rcu_torture_current_version + 1); rcu_torture_current_version + 1);
...@@ -1589,7 +1589,7 @@ static bool rcu_torture_one_read(struct torture_random_state *trsp, long myid) ...@@ -1589,7 +1589,7 @@ static bool rcu_torture_one_read(struct torture_random_state *trsp, long myid)
preempt_enable(); preempt_enable();
if (cur_ops->get_gp_state && cur_ops->poll_gp_state) if (cur_ops->get_gp_state && cur_ops->poll_gp_state)
WARN_ONCE(cur_ops->poll_gp_state(cookie), WARN_ONCE(cur_ops->poll_gp_state(cookie),
"%s: Cookie check 3 failed %s(%d) %lu->%lu\n", "%s: Cookie check 2 failed %s(%d) %lu->%lu\n",
__func__, __func__,
rcu_torture_writer_state_getname(), rcu_torture_writer_state_getname(),
rcu_torture_writer_state, rcu_torture_writer_state,
...@@ -1797,7 +1797,7 @@ rcu_torture_stats_print(void) ...@@ -1797,7 +1797,7 @@ rcu_torture_stats_print(void)
WARN_ON_ONCE(n_rcu_torture_barrier_error); // rcu_barrier() WARN_ON_ONCE(n_rcu_torture_barrier_error); // rcu_barrier()
WARN_ON_ONCE(n_rcu_torture_boost_ktrerror); // no boost kthread WARN_ON_ONCE(n_rcu_torture_boost_ktrerror); // no boost kthread
WARN_ON_ONCE(n_rcu_torture_boost_rterror); // can't set RT prio WARN_ON_ONCE(n_rcu_torture_boost_rterror); // can't set RT prio
WARN_ON_ONCE(n_rcu_torture_boost_failure); // RCU boost failed WARN_ON_ONCE(n_rcu_torture_boost_failure); // boost failed (TIMER_SOFTIRQ RT prio?)
WARN_ON_ONCE(i > 1); // Too-short grace period WARN_ON_ONCE(i > 1); // Too-short grace period
} }
pr_cont("Reader Pipe: "); pr_cont("Reader Pipe: ");
...@@ -1861,6 +1861,45 @@ rcu_torture_stats(void *arg) ...@@ -1861,6 +1861,45 @@ rcu_torture_stats(void *arg)
torture_shutdown_absorb("rcu_torture_stats"); torture_shutdown_absorb("rcu_torture_stats");
} while (!torture_must_stop()); } while (!torture_must_stop());
torture_kthread_stopping("rcu_torture_stats"); torture_kthread_stopping("rcu_torture_stats");
{
struct rcu_head *rhp;
struct kmem_cache *kcp;
static int z;
kcp = kmem_cache_create("rcuscale", 136, 8, SLAB_STORE_USER, NULL);
rhp = kmem_cache_alloc(kcp, GFP_KERNEL);
pr_alert("mem_dump_obj() slab test: rcu_torture_stats = %px, &rhp = %px, rhp = %px, &z = %px\n", stats_task, &rhp, rhp, &z);
pr_alert("mem_dump_obj(ZERO_SIZE_PTR):");
mem_dump_obj(ZERO_SIZE_PTR);
pr_alert("mem_dump_obj(NULL):");
mem_dump_obj(NULL);
pr_alert("mem_dump_obj(%px):", &rhp);
mem_dump_obj(&rhp);
pr_alert("mem_dump_obj(%px):", rhp);
mem_dump_obj(rhp);
pr_alert("mem_dump_obj(%px):", &rhp->func);
mem_dump_obj(&rhp->func);
pr_alert("mem_dump_obj(%px):", &z);
mem_dump_obj(&z);
kmem_cache_free(kcp, rhp);
kmem_cache_destroy(kcp);
rhp = kmalloc(sizeof(*rhp), GFP_KERNEL);
pr_alert("mem_dump_obj() kmalloc test: rcu_torture_stats = %px, &rhp = %px, rhp = %px\n", stats_task, &rhp, rhp);
pr_alert("mem_dump_obj(kmalloc %px):", rhp);
mem_dump_obj(rhp);
pr_alert("mem_dump_obj(kmalloc %px):", &rhp->func);
mem_dump_obj(&rhp->func);
kfree(rhp);
rhp = vmalloc(4096);
pr_alert("mem_dump_obj() vmalloc test: rcu_torture_stats = %px, &rhp = %px, rhp = %px\n", stats_task, &rhp, rhp);
pr_alert("mem_dump_obj(vmalloc %px):", rhp);
mem_dump_obj(rhp);
pr_alert("mem_dump_obj(vmalloc %px):", &rhp->func);
mem_dump_obj(&rhp->func);
vfree(rhp);
}
return 0; return 0;
} }
...@@ -1971,8 +2010,8 @@ static int rcu_torture_stall(void *args) ...@@ -1971,8 +2010,8 @@ static int rcu_torture_stall(void *args)
local_irq_disable(); local_irq_disable();
else if (!stall_cpu_block) else if (!stall_cpu_block)
preempt_disable(); preempt_disable();
pr_alert("rcu_torture_stall start on CPU %d.\n", pr_alert("%s start on CPU %d.\n",
raw_smp_processor_id()); __func__, raw_smp_processor_id());
while (ULONG_CMP_LT((unsigned long)ktime_get_seconds(), while (ULONG_CMP_LT((unsigned long)ktime_get_seconds(),
stop_at)) stop_at))
if (stall_cpu_block) if (stall_cpu_block)
...@@ -1983,7 +2022,7 @@ static int rcu_torture_stall(void *args) ...@@ -1983,7 +2022,7 @@ static int rcu_torture_stall(void *args)
preempt_enable(); preempt_enable();
cur_ops->readunlock(idx); cur_ops->readunlock(idx);
} }
pr_alert("rcu_torture_stall end.\n"); pr_alert("%s end.\n", __func__);
torture_shutdown_absorb("rcu_torture_stall"); torture_shutdown_absorb("rcu_torture_stall");
while (!kthread_should_stop()) while (!kthread_should_stop())
schedule_timeout_interruptible(10 * HZ); schedule_timeout_interruptible(10 * HZ);
...@@ -2595,6 +2634,8 @@ static bool rcu_torture_can_boost(void) ...@@ -2595,6 +2634,8 @@ static bool rcu_torture_can_boost(void)
if (!(test_boost == 1 && cur_ops->can_boost) && test_boost != 2) if (!(test_boost == 1 && cur_ops->can_boost) && test_boost != 2)
return false; return false;
if (!cur_ops->call)
return false;
prio = rcu_get_gp_kthreads_prio(); prio = rcu_get_gp_kthreads_prio();
if (!prio) if (!prio)
......
...@@ -20,7 +20,7 @@ typedef void (*holdouts_func_t)(struct list_head *hop, bool ndrpt, bool *frptp); ...@@ -20,7 +20,7 @@ typedef void (*holdouts_func_t)(struct list_head *hop, bool ndrpt, bool *frptp);
typedef void (*postgp_func_t)(struct rcu_tasks *rtp); typedef void (*postgp_func_t)(struct rcu_tasks *rtp);
/** /**
* Definition for a Tasks-RCU-like mechanism. * struct rcu_tasks - Definition for a Tasks-RCU-like mechanism.
* @cbs_head: Head of callback list. * @cbs_head: Head of callback list.
* @cbs_tail: Tail pointer for callback list. * @cbs_tail: Tail pointer for callback list.
* @cbs_wq: Wait queue allowning new callback to get kthread's attention. * @cbs_wq: Wait queue allowning new callback to get kthread's attention.
...@@ -38,7 +38,7 @@ typedef void (*postgp_func_t)(struct rcu_tasks *rtp); ...@@ -38,7 +38,7 @@ typedef void (*postgp_func_t)(struct rcu_tasks *rtp);
* @pregp_func: This flavor's pre-grace-period function (optional). * @pregp_func: This flavor's pre-grace-period function (optional).
* @pertask_func: This flavor's per-task scan function (optional). * @pertask_func: This flavor's per-task scan function (optional).
* @postscan_func: This flavor's post-task scan function (optional). * @postscan_func: This flavor's post-task scan function (optional).
* @holdout_func: This flavor's holdout-list scan function (optional). * @holdouts_func: This flavor's holdout-list scan function (optional).
* @postgp_func: This flavor's post-grace-period function (optional). * @postgp_func: This flavor's post-grace-period function (optional).
* @call_func: This flavor's call_rcu()-equivalent function. * @call_func: This flavor's call_rcu()-equivalent function.
* @name: This flavor's textual name. * @name: This flavor's textual name.
...@@ -726,6 +726,42 @@ EXPORT_SYMBOL_GPL(show_rcu_tasks_rude_gp_kthread); ...@@ -726,6 +726,42 @@ EXPORT_SYMBOL_GPL(show_rcu_tasks_rude_gp_kthread);
// flavors, rcu_preempt and rcu_sched. The fact that RCU Tasks Trace // flavors, rcu_preempt and rcu_sched. The fact that RCU Tasks Trace
// readers can operate from idle, offline, and exception entry/exit in no // readers can operate from idle, offline, and exception entry/exit in no
// way allows rcu_preempt and rcu_sched readers to also do so. // way allows rcu_preempt and rcu_sched readers to also do so.
//
// The implementation uses rcu_tasks_wait_gp(), which relies on function
// pointers in the rcu_tasks structure. The rcu_spawn_tasks_trace_kthread()
// function sets these function pointers up so that rcu_tasks_wait_gp()
// invokes these functions in this order:
//
// rcu_tasks_trace_pregp_step():
// Initialize the count of readers and block CPU-hotplug operations.
// rcu_tasks_trace_pertask(), invoked on every non-idle task:
// Initialize per-task state and attempt to identify an immediate
// quiescent state for that task, or, failing that, attempt to
// set that task's .need_qs flag so that task's next outermost
// rcu_read_unlock_trace() will report the quiescent state (in which
// case the count of readers is incremented). If both attempts fail,
// the task is added to a "holdout" list.
// rcu_tasks_trace_postscan():
// Initialize state and attempt to identify an immediate quiescent
// state as above (but only for idle tasks), unblock CPU-hotplug
// operations, and wait for an RCU grace period to avoid races with
// tasks that are in the process of exiting.
// check_all_holdout_tasks_trace(), repeatedly until holdout list is empty:
// Scans the holdout list, attempting to identify a quiescent state
// for each task on the list. If there is a quiescent state, the
// corresponding task is removed from the holdout list.
// rcu_tasks_trace_postgp():
// Wait for the count of readers do drop to zero, reporting any stalls.
// Also execute full memory barriers to maintain ordering with code
// executing after the grace period.
//
// The exit_tasks_rcu_finish_trace() synchronizes with exiting tasks.
//
// Pre-grace-period update-side code is ordered before the grace
// period via the ->cbs_lock and barriers in rcu_tasks_kthread().
// Pre-grace-period read-side code is ordered before the grace period by
// atomic_dec_and_test() of the count of readers (for IPIed readers) and by
// scheduler context-switch ordering (for locked-down non-running readers).
// The lockdep state must be outside of #ifdef to be useful. // The lockdep state must be outside of #ifdef to be useful.
#ifdef CONFIG_DEBUG_LOCK_ALLOC #ifdef CONFIG_DEBUG_LOCK_ALLOC
......
...@@ -32,12 +32,14 @@ struct rcu_ctrlblk { ...@@ -32,12 +32,14 @@ struct rcu_ctrlblk {
struct rcu_head *rcucblist; /* List of pending callbacks (CBs). */ struct rcu_head *rcucblist; /* List of pending callbacks (CBs). */
struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ struct rcu_head **donetail; /* ->next pointer of last "done" CB. */
struct rcu_head **curtail; /* ->next pointer of last CB. */ struct rcu_head **curtail; /* ->next pointer of last CB. */
unsigned long gp_seq; /* Grace-period counter. */
}; };
/* Definition for rcupdate control block. */ /* Definition for rcupdate control block. */
static struct rcu_ctrlblk rcu_ctrlblk = { static struct rcu_ctrlblk rcu_ctrlblk = {
.donetail = &rcu_ctrlblk.rcucblist, .donetail = &rcu_ctrlblk.rcucblist,
.curtail = &rcu_ctrlblk.rcucblist, .curtail = &rcu_ctrlblk.rcucblist,
.gp_seq = 0 - 300UL,
}; };
void rcu_barrier(void) void rcu_barrier(void)
...@@ -56,6 +58,7 @@ void rcu_qs(void) ...@@ -56,6 +58,7 @@ void rcu_qs(void)
rcu_ctrlblk.donetail = rcu_ctrlblk.curtail; rcu_ctrlblk.donetail = rcu_ctrlblk.curtail;
raise_softirq_irqoff(RCU_SOFTIRQ); raise_softirq_irqoff(RCU_SOFTIRQ);
} }
WRITE_ONCE(rcu_ctrlblk.gp_seq, rcu_ctrlblk.gp_seq + 1);
local_irq_restore(flags); local_irq_restore(flags);
} }
...@@ -177,6 +180,43 @@ void call_rcu(struct rcu_head *head, rcu_callback_t func) ...@@ -177,6 +180,43 @@ void call_rcu(struct rcu_head *head, rcu_callback_t func)
} }
EXPORT_SYMBOL_GPL(call_rcu); EXPORT_SYMBOL_GPL(call_rcu);
/*
* Return a grace-period-counter "cookie". For more information,
* see the Tree RCU header comment.
*/
unsigned long get_state_synchronize_rcu(void)
{
return READ_ONCE(rcu_ctrlblk.gp_seq);
}
EXPORT_SYMBOL_GPL(get_state_synchronize_rcu);
/*
* Return a grace-period-counter "cookie" and ensure that a future grace
* period completes. For more information, see the Tree RCU header comment.
*/
unsigned long start_poll_synchronize_rcu(void)
{
unsigned long gp_seq = get_state_synchronize_rcu();
if (unlikely(is_idle_task(current))) {
/* force scheduling for rcu_qs() */
resched_cpu(0);
}
return gp_seq;
}
EXPORT_SYMBOL_GPL(start_poll_synchronize_rcu);
/*
* Return true if the grace period corresponding to oldstate has completed
* and false otherwise. For more information, see the Tree RCU header
* comment.
*/
bool poll_state_synchronize_rcu(unsigned long oldstate)
{
return READ_ONCE(rcu_ctrlblk.gp_seq) != oldstate;
}
EXPORT_SYMBOL_GPL(poll_state_synchronize_rcu);
void __init rcu_init(void) void __init rcu_init(void)
{ {
open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
......
This diff is collapsed.
...@@ -521,6 +521,7 @@ static void synchronize_rcu_expedited_wait(void) ...@@ -521,6 +521,7 @@ static void synchronize_rcu_expedited_wait(void)
if (rcu_stall_is_suppressed()) if (rcu_stall_is_suppressed())
continue; continue;
panic_on_rcu_stall(); panic_on_rcu_stall();
trace_rcu_stall_warning(rcu_state.name, TPS("ExpeditedStall"));
pr_err("INFO: %s detected expedited stalls on CPUs/tasks: {", pr_err("INFO: %s detected expedited stalls on CPUs/tasks: {",
rcu_state.name); rcu_state.name);
ndetected = 0; ndetected = 0;
......
This diff is collapsed.
...@@ -536,6 +536,7 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps) ...@@ -536,6 +536,7 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps)
* See Documentation/RCU/stallwarn.rst for info on how to debug * See Documentation/RCU/stallwarn.rst for info on how to debug
* RCU CPU stall warnings. * RCU CPU stall warnings.
*/ */
trace_rcu_stall_warning(rcu_state.name, TPS("StallDetected"));
pr_err("INFO: %s detected stalls on CPUs/tasks:\n", rcu_state.name); pr_err("INFO: %s detected stalls on CPUs/tasks:\n", rcu_state.name);
rcu_for_each_leaf_node(rnp) { rcu_for_each_leaf_node(rnp) {
raw_spin_lock_irqsave_rcu_node(rnp, flags); raw_spin_lock_irqsave_rcu_node(rnp, flags);
...@@ -606,6 +607,7 @@ static void print_cpu_stall(unsigned long gps) ...@@ -606,6 +607,7 @@ static void print_cpu_stall(unsigned long gps)
* See Documentation/RCU/stallwarn.rst for info on how to debug * See Documentation/RCU/stallwarn.rst for info on how to debug
* RCU CPU stall warnings. * RCU CPU stall warnings.
*/ */
trace_rcu_stall_warning(rcu_state.name, TPS("SelfDetected"));
pr_err("INFO: %s self-detected stall on CPU\n", rcu_state.name); pr_err("INFO: %s self-detected stall on CPU\n", rcu_state.name);
raw_spin_lock_irqsave_rcu_node(rdp->mynode, flags); raw_spin_lock_irqsave_rcu_node(rdp->mynode, flags);
print_cpu_stall_info(smp_processor_id()); print_cpu_stall_info(smp_processor_id());
......
...@@ -423,7 +423,7 @@ static inline void invoke_softirq(void) ...@@ -423,7 +423,7 @@ static inline void invoke_softirq(void)
if (ksoftirqd_running(local_softirq_pending())) if (ksoftirqd_running(local_softirq_pending()))
return; return;
if (!force_irqthreads) { if (!force_irqthreads || !__this_cpu_read(ksoftirqd)) {
#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
/* /*
* We can safely execute softirq on the current stack if * We can safely execute softirq on the current stack if
......
...@@ -816,9 +816,9 @@ bool torture_init_begin(char *ttype, int v) ...@@ -816,9 +816,9 @@ bool torture_init_begin(char *ttype, int v)
{ {
mutex_lock(&fullstop_mutex); mutex_lock(&fullstop_mutex);
if (torture_type != NULL) { if (torture_type != NULL) {
pr_alert("torture_init_begin: Refusing %s init: %s running.\n", pr_alert("%s: Refusing %s init: %s running.\n",
ttype, torture_type); __func__, ttype, torture_type);
pr_alert("torture_init_begin: One torture test at a time!\n"); pr_alert("%s: One torture test at a time!\n", __func__);
mutex_unlock(&fullstop_mutex); mutex_unlock(&fullstop_mutex);
return false; return false;
} }
......
...@@ -487,30 +487,25 @@ EXPORT_SYMBOL(bitmap_print_to_pagebuf); ...@@ -487,30 +487,25 @@ EXPORT_SYMBOL(bitmap_print_to_pagebuf);
/* /*
* Region 9-38:4/10 describes the following bitmap structure: * Region 9-38:4/10 describes the following bitmap structure:
* 0 9 12 18 38 * 0 9 12 18 38 N
* .........****......****......****...... * .........****......****......****..................
* ^ ^ ^ ^ * ^ ^ ^ ^ ^
* start off group_len end * start off group_len end nbits
*/ */
struct region { struct region {
unsigned int start; unsigned int start;
unsigned int off; unsigned int off;
unsigned int group_len; unsigned int group_len;
unsigned int end; unsigned int end;
unsigned int nbits;
}; };
static int bitmap_set_region(const struct region *r, static void bitmap_set_region(const struct region *r, unsigned long *bitmap)
unsigned long *bitmap, int nbits)
{ {
unsigned int start; unsigned int start;
if (r->end >= nbits)
return -ERANGE;
for (start = r->start; start <= r->end; start += r->group_len) for (start = r->start; start <= r->end; start += r->group_len)
bitmap_set(bitmap, start, min(r->end - start + 1, r->off)); bitmap_set(bitmap, start, min(r->end - start + 1, r->off));
return 0;
} }
static int bitmap_check_region(const struct region *r) static int bitmap_check_region(const struct region *r)
...@@ -518,14 +513,23 @@ static int bitmap_check_region(const struct region *r) ...@@ -518,14 +513,23 @@ static int bitmap_check_region(const struct region *r)
if (r->start > r->end || r->group_len == 0 || r->off > r->group_len) if (r->start > r->end || r->group_len == 0 || r->off > r->group_len)
return -EINVAL; return -EINVAL;
if (r->end >= r->nbits)
return -ERANGE;
return 0; return 0;
} }
static const char *bitmap_getnum(const char *str, unsigned int *num) static const char *bitmap_getnum(const char *str, unsigned int *num,
unsigned int lastbit)
{ {
unsigned long long n; unsigned long long n;
unsigned int len; unsigned int len;
if (str[0] == 'N') {
*num = lastbit;
return str + 1;
}
len = _parse_integer(str, 10, &n); len = _parse_integer(str, 10, &n);
if (!len) if (!len)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -573,7 +577,9 @@ static const char *bitmap_find_region_reverse(const char *start, const char *end ...@@ -573,7 +577,9 @@ static const char *bitmap_find_region_reverse(const char *start, const char *end
static const char *bitmap_parse_region(const char *str, struct region *r) static const char *bitmap_parse_region(const char *str, struct region *r)
{ {
str = bitmap_getnum(str, &r->start); unsigned int lastbit = r->nbits - 1;
str = bitmap_getnum(str, &r->start, lastbit);
if (IS_ERR(str)) if (IS_ERR(str))
return str; return str;
...@@ -583,7 +589,7 @@ static const char *bitmap_parse_region(const char *str, struct region *r) ...@@ -583,7 +589,7 @@ static const char *bitmap_parse_region(const char *str, struct region *r)
if (*str != '-') if (*str != '-')
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
str = bitmap_getnum(str + 1, &r->end); str = bitmap_getnum(str + 1, &r->end, lastbit);
if (IS_ERR(str)) if (IS_ERR(str))
return str; return str;
...@@ -593,14 +599,14 @@ static const char *bitmap_parse_region(const char *str, struct region *r) ...@@ -593,14 +599,14 @@ static const char *bitmap_parse_region(const char *str, struct region *r)
if (*str != ':') if (*str != ':')
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
str = bitmap_getnum(str + 1, &r->off); str = bitmap_getnum(str + 1, &r->off, lastbit);
if (IS_ERR(str)) if (IS_ERR(str))
return str; return str;
if (*str != '/') if (*str != '/')
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
return bitmap_getnum(str + 1, &r->group_len); return bitmap_getnum(str + 1, &r->group_len, lastbit);
no_end: no_end:
r->end = r->start; r->end = r->start;
...@@ -627,6 +633,10 @@ static const char *bitmap_parse_region(const char *str, struct region *r) ...@@ -627,6 +633,10 @@ static const char *bitmap_parse_region(const char *str, struct region *r)
* From each group will be used only defined amount of bits. * From each group will be used only defined amount of bits.
* Syntax: range:used_size/group_size * Syntax: range:used_size/group_size
* Example: 0-1023:2/256 ==> 0,1,256,257,512,513,768,769 * Example: 0-1023:2/256 ==> 0,1,256,257,512,513,768,769
* The value 'N' can be used as a dynamically substituted token for the
* maximum allowed value; i.e (nmaskbits - 1). Keep in mind that it is
* dynamic, so if system changes cause the bitmap width to change, such
* as more cores in a CPU list, then any ranges using N will also change.
* *
* Returns: 0 on success, -errno on invalid input strings. Error values: * Returns: 0 on success, -errno on invalid input strings. Error values:
* *
...@@ -640,7 +650,8 @@ int bitmap_parselist(const char *buf, unsigned long *maskp, int nmaskbits) ...@@ -640,7 +650,8 @@ int bitmap_parselist(const char *buf, unsigned long *maskp, int nmaskbits)
struct region r; struct region r;
long ret; long ret;
bitmap_zero(maskp, nmaskbits); r.nbits = nmaskbits;
bitmap_zero(maskp, r.nbits);
while (buf) { while (buf) {
buf = bitmap_find_region(buf); buf = bitmap_find_region(buf);
...@@ -655,9 +666,7 @@ int bitmap_parselist(const char *buf, unsigned long *maskp, int nmaskbits) ...@@ -655,9 +666,7 @@ int bitmap_parselist(const char *buf, unsigned long *maskp, int nmaskbits)
if (ret) if (ret)
return ret; return ret;
ret = bitmap_set_region(&r, maskp, nmaskbits); bitmap_set_region(&r, maskp);
if (ret)
return ret;
} }
return 0; return 0;
......
...@@ -34,6 +34,8 @@ static const unsigned long exp1[] __initconst = { ...@@ -34,6 +34,8 @@ static const unsigned long exp1[] __initconst = {
BITMAP_FROM_U64(0x3333333311111111ULL), BITMAP_FROM_U64(0x3333333311111111ULL),
BITMAP_FROM_U64(0xffffffff77777777ULL), BITMAP_FROM_U64(0xffffffff77777777ULL),
BITMAP_FROM_U64(0), BITMAP_FROM_U64(0),
BITMAP_FROM_U64(0x00008000),
BITMAP_FROM_U64(0x80000000),
}; };
static const unsigned long exp2[] __initconst = { static const unsigned long exp2[] __initconst = {
...@@ -334,15 +336,47 @@ static const struct test_bitmap_parselist parselist_tests[] __initconst = { ...@@ -334,15 +336,47 @@ static const struct test_bitmap_parselist parselist_tests[] __initconst = {
{0, " , ,, , , ", &exp1[12 * step], 8, 0}, {0, " , ,, , , ", &exp1[12 * step], 8, 0},
{0, " , ,, , , \n", &exp1[12 * step], 8, 0}, {0, " , ,, , , \n", &exp1[12 * step], 8, 0},
{0, "0-0", &exp1[0], 32, 0},
{0, "1-1", &exp1[1 * step], 32, 0},
{0, "15-15", &exp1[13 * step], 32, 0},
{0, "31-31", &exp1[14 * step], 32, 0},
{0, "0-0:0/1", &exp1[12 * step], 32, 0},
{0, "0-0:1/1", &exp1[0], 32, 0},
{0, "0-0:1/31", &exp1[0], 32, 0},
{0, "0-0:31/31", &exp1[0], 32, 0},
{0, "1-1:1/1", &exp1[1 * step], 32, 0},
{0, "0-15:16/31", &exp1[2 * step], 32, 0},
{0, "15-15:1/2", &exp1[13 * step], 32, 0},
{0, "15-15:31/31", &exp1[13 * step], 32, 0},
{0, "15-31:1/31", &exp1[13 * step], 32, 0},
{0, "16-31:16/31", &exp1[3 * step], 32, 0},
{0, "31-31:31/31", &exp1[14 * step], 32, 0},
{0, "N-N", &exp1[14 * step], 32, 0},
{0, "0-0:1/N", &exp1[0], 32, 0},
{0, "0-0:N/N", &exp1[0], 32, 0},
{0, "0-15:16/N", &exp1[2 * step], 32, 0},
{0, "15-15:N/N", &exp1[13 * step], 32, 0},
{0, "15-N:1/N", &exp1[13 * step], 32, 0},
{0, "16-N:16/N", &exp1[3 * step], 32, 0},
{0, "N-N:N/N", &exp1[14 * step], 32, 0},
{0, "0-N:1/3,1-N:1/3,2-N:1/3", &exp1[8 * step], 32, 0},
{0, "0-31:1/3,1-31:1/3,2-31:1/3", &exp1[8 * step], 32, 0},
{0, "1-10:8/12,8-31:24/29,0-31:0/3", &exp1[9 * step], 32, 0},
{-EINVAL, "-1", NULL, 8, 0}, {-EINVAL, "-1", NULL, 8, 0},
{-EINVAL, "-0", NULL, 8, 0}, {-EINVAL, "-0", NULL, 8, 0},
{-EINVAL, "10-1", NULL, 8, 0}, {-EINVAL, "10-1", NULL, 8, 0},
{-EINVAL, "0-31:", NULL, 8, 0}, {-ERANGE, "8-8", NULL, 8, 0},
{-EINVAL, "0-31:0", NULL, 8, 0}, {-ERANGE, "0-31", NULL, 8, 0},
{-EINVAL, "0-31:0/", NULL, 8, 0}, {-EINVAL, "0-31:", NULL, 32, 0},
{-EINVAL, "0-31:0/0", NULL, 8, 0}, {-EINVAL, "0-31:0", NULL, 32, 0},
{-EINVAL, "0-31:1/0", NULL, 8, 0}, {-EINVAL, "0-31:0/", NULL, 32, 0},
{-EINVAL, "0-31:10/1", NULL, 8, 0}, {-EINVAL, "0-31:0/0", NULL, 32, 0},
{-EINVAL, "0-31:1/0", NULL, 32, 0},
{-EINVAL, "0-31:10/1", NULL, 32, 0},
{-EOVERFLOW, "0-98765432123456789:10/1", NULL, 8, 0}, {-EOVERFLOW, "0-98765432123456789:10/1", NULL, 8, 0},
{-EINVAL, "a-31", NULL, 8, 0}, {-EINVAL, "a-31", NULL, 8, 0},
......
...@@ -3651,6 +3651,7 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t flags, ...@@ -3651,6 +3651,7 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t flags,
EXPORT_SYMBOL(__kmalloc_node_track_caller); EXPORT_SYMBOL(__kmalloc_node_track_caller);
#endif /* CONFIG_NUMA */ #endif /* CONFIG_NUMA */
#ifdef CONFIG_PRINTK
void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page) void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page)
{ {
struct kmem_cache *cachep; struct kmem_cache *cachep;
...@@ -3670,6 +3671,7 @@ void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page) ...@@ -3670,6 +3671,7 @@ void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page)
if (DEBUG && cachep->flags & SLAB_STORE_USER) if (DEBUG && cachep->flags & SLAB_STORE_USER)
kpp->kp_ret = *dbg_userword(cachep, objp); kpp->kp_ret = *dbg_userword(cachep, objp);
} }
#endif
/** /**
* __do_kmalloc - allocate memory * __do_kmalloc - allocate memory
......
...@@ -621,6 +621,7 @@ static inline bool slab_want_init_on_free(struct kmem_cache *c) ...@@ -621,6 +621,7 @@ static inline bool slab_want_init_on_free(struct kmem_cache *c)
return false; return false;
} }
#ifdef CONFIG_PRINTK
#define KS_ADDRS_COUNT 16 #define KS_ADDRS_COUNT 16
struct kmem_obj_info { struct kmem_obj_info {
void *kp_ptr; void *kp_ptr;
...@@ -632,5 +633,6 @@ struct kmem_obj_info { ...@@ -632,5 +633,6 @@ struct kmem_obj_info {
void *kp_stack[KS_ADDRS_COUNT]; void *kp_stack[KS_ADDRS_COUNT];
}; };
void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page); void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page);
#endif
#endif /* MM_SLAB_H */ #endif /* MM_SLAB_H */
...@@ -526,6 +526,7 @@ bool slab_is_available(void) ...@@ -526,6 +526,7 @@ bool slab_is_available(void)
return slab_state >= UP; return slab_state >= UP;
} }
#ifdef CONFIG_PRINTK
/** /**
* kmem_valid_obj - does the pointer reference a valid slab object? * kmem_valid_obj - does the pointer reference a valid slab object?
* @object: pointer to query. * @object: pointer to query.
...@@ -544,6 +545,7 @@ bool kmem_valid_obj(void *object) ...@@ -544,6 +545,7 @@ bool kmem_valid_obj(void *object)
page = virt_to_head_page(object); page = virt_to_head_page(object);
return PageSlab(page); return PageSlab(page);
} }
EXPORT_SYMBOL_GPL(kmem_valid_obj);
/** /**
* kmem_dump_obj - Print available slab provenance information * kmem_dump_obj - Print available slab provenance information
...@@ -600,6 +602,8 @@ void kmem_dump_obj(void *object) ...@@ -600,6 +602,8 @@ void kmem_dump_obj(void *object)
pr_info(" %pS\n", kp.kp_stack[i]); pr_info(" %pS\n", kp.kp_stack[i]);
} }
} }
EXPORT_SYMBOL_GPL(kmem_dump_obj);
#endif
#ifndef CONFIG_SLOB #ifndef CONFIG_SLOB
/* Create a cache during boot when no slab services are available yet */ /* Create a cache during boot when no slab services are available yet */
......
...@@ -461,11 +461,13 @@ static void slob_free(void *block, int size) ...@@ -461,11 +461,13 @@ static void slob_free(void *block, int size)
spin_unlock_irqrestore(&slob_lock, flags); spin_unlock_irqrestore(&slob_lock, flags);
} }
#ifdef CONFIG_PRINTK
void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page) void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page)
{ {
kpp->kp_ptr = object; kpp->kp_ptr = object;
kpp->kp_page = page; kpp->kp_page = page;
} }
#endif
/* /*
* End of slob allocator proper. Begin kmem_cache_alloc and kmalloc frontend. * End of slob allocator proper. Begin kmem_cache_alloc and kmalloc frontend.
......
...@@ -3964,6 +3964,7 @@ int __kmem_cache_shutdown(struct kmem_cache *s) ...@@ -3964,6 +3964,7 @@ int __kmem_cache_shutdown(struct kmem_cache *s)
return 0; return 0;
} }
#ifdef CONFIG_PRINTK
void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page) void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page)
{ {
void *base; void *base;
...@@ -4003,6 +4004,7 @@ void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page) ...@@ -4003,6 +4004,7 @@ void kmem_obj_info(struct kmem_obj_info *kpp, void *object, struct page *page)
#endif #endif
#endif #endif
} }
#endif
/******************************************************************** /********************************************************************
* Kmalloc subsystem * Kmalloc subsystem
......
...@@ -983,6 +983,7 @@ int __weak memcmp_pages(struct page *page1, struct page *page2) ...@@ -983,6 +983,7 @@ int __weak memcmp_pages(struct page *page1, struct page *page2)
return ret; return ret;
} }
#ifdef CONFIG_PRINTK
/** /**
* mem_dump_obj - Print available provenance information * mem_dump_obj - Print available provenance information
* @object: object for which to find provenance information. * @object: object for which to find provenance information.
...@@ -1013,3 +1014,5 @@ void mem_dump_obj(void *object) ...@@ -1013,3 +1014,5 @@ void mem_dump_obj(void *object)
} }
pr_cont(" non-slab/vmalloc memory.\n"); pr_cont(" non-slab/vmalloc memory.\n");
} }
EXPORT_SYMBOL_GPL(mem_dump_obj);
#endif
...@@ -3450,6 +3450,7 @@ void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms) ...@@ -3450,6 +3450,7 @@ void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
#ifdef CONFIG_PRINTK
bool vmalloc_dump_obj(void *object) bool vmalloc_dump_obj(void *object)
{ {
struct vm_struct *vm; struct vm_struct *vm;
...@@ -3462,6 +3463,7 @@ bool vmalloc_dump_obj(void *object) ...@@ -3462,6 +3463,7 @@ bool vmalloc_dump_obj(void *object)
vm->nr_pages, (unsigned long)vm->addr, vm->caller); vm->nr_pages, (unsigned long)vm->addr, vm->caller);
return true; return true;
} }
#endif
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static void *s_start(struct seq_file *m, loff_t *pos) static void *s_start(struct seq_file *m, loff_t *pos)
......
...@@ -21,7 +21,6 @@ then ...@@ -21,7 +21,6 @@ then
awk -v ncpus=$ncpus '{ print ncpus * ($7 + $NF) / 100 }'` awk -v ncpus=$ncpus '{ print ncpus * ($7 + $NF) / 100 }'`
else else
# No mpstat command, so use all available CPUs. # No mpstat command, so use all available CPUs.
echo The mpstat command is not available, so greedily using all CPUs.
idlecpus=$ncpus idlecpus=$ncpus
fi fi
awk -v ncpus=$ncpus -v idlecpus=$idlecpus < /dev/null ' awk -v ncpus=$ncpus -v idlecpus=$idlecpus < /dev/null '
......
...@@ -5,10 +5,11 @@ ...@@ -5,10 +5,11 @@
# of this script is to inflict random OS jitter on a concurrently running # of this script is to inflict random OS jitter on a concurrently running
# test. # test.
# #
# Usage: jitter.sh me duration [ sleepmax [ spinmax ] ] # Usage: jitter.sh me jittering-path duration [ sleepmax [ spinmax ] ]
# #
# me: Random-number-generator seed salt. # me: Random-number-generator seed salt.
# duration: Time to run in seconds. # duration: Time to run in seconds.
# jittering-path: Path to file whose removal will stop this script.
# sleepmax: Maximum microseconds to sleep, defaults to one second. # sleepmax: Maximum microseconds to sleep, defaults to one second.
# spinmax: Maximum microseconds to spin, defaults to one millisecond. # spinmax: Maximum microseconds to spin, defaults to one millisecond.
# #
...@@ -17,9 +18,10 @@ ...@@ -17,9 +18,10 @@
# Authors: Paul E. McKenney <paulmck@linux.ibm.com> # Authors: Paul E. McKenney <paulmck@linux.ibm.com>
me=$(($1 * 1000)) me=$(($1 * 1000))
duration=$2 jittering=$2
sleepmax=${3-1000000} duration=$3
spinmax=${4-1000} sleepmax=${4-1000000}
spinmax=${5-1000}
n=1 n=1
...@@ -47,7 +49,7 @@ do ...@@ -47,7 +49,7 @@ do
fi fi
# Check for stop request. # Check for stop request.
if test -f "$TORTURE_STOPFILE" if ! test -f "$jittering"
then then
exit 1; exit 1;
fi fi
...@@ -67,10 +69,10 @@ do ...@@ -67,10 +69,10 @@ do
srand(n + me + systime()); srand(n + me + systime());
ncpus = split(cpus, ca); ncpus = split(cpus, ca);
curcpu = ca[int(rand() * ncpus + 1)]; curcpu = ca[int(rand() * ncpus + 1)];
mask = lshift(1, curcpu); z = "";
if (mask + 0 <= 0) for (i = 1; 4 * i <= curcpu; i++)
mask = 1; z = z "0";
printf("%#x\n", mask); print "0x" 2 ^ (curcpu % 4) z;
}' < /dev/null` }' < /dev/null`
n=$(($n+1)) n=$(($n+1))
if ! taskset -p $cpumask $$ > /dev/null 2>&1 if ! taskset -p $cpumask $$ > /dev/null 2>&1
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0+
#
# Start up the specified number of jitter.sh scripts in the background.
#
# Usage: . jitterstart.sh n jittering-dir duration [ sleepmax [ spinmax ] ]
#
# n: Number of jitter.sh scripts to start up.
# jittering-dir: Directory in which to put "jittering" file.
# duration: Time to run in seconds.
# sleepmax: Maximum microseconds to sleep, defaults to one second.
# spinmax: Maximum microseconds to spin, defaults to one millisecond.
#
# Copyright (C) 2021 Facebook, Inc.
#
# Authors: Paul E. McKenney <paulmck@kernel.org>
jitter_n=$1
if test -z "$jitter_n"
then
echo jitterstart.sh: Missing count of jitter.sh scripts to start.
exit 33
fi
jittering_dir=$2
if test -z "$jittering_dir"
then
echo jitterstart.sh: Missing directory in which to place jittering file.
exit 34
fi
shift
shift
touch ${jittering_dir}/jittering
for ((jitter_i = 1; jitter_i <= $jitter_n; jitter_i++))
do
jitter.sh $jitter_i "${jittering_dir}/jittering" "$@" &
done
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0+
#
# Remove the "jittering" file, signaling the jitter.sh scripts to stop,
# then wait for them to terminate.
#
# Usage: . jitterstop.sh jittering-dir
#
# jittering-dir: Directory containing "jittering" file.
#
# Copyright (C) 2021 Facebook, Inc.
#
# Authors: Paul E. McKenney <paulmck@kernel.org>
jittering_dir=$1
if test -z "$jittering_dir"
then
echo jitterstop.sh: Missing directory in which to place jittering file.
exit 34
fi
rm -f ${jittering_dir}/jittering
wait
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0+
#
# Rerun a series of tests under KVM.
#
# Usage: kvm-again.sh /path/to/old/run [ options ]
#
# Copyright (C) 2021 Facebook, Inc.
#
# Authors: Paul E. McKenney <paulmck@kernel.org>
scriptname=$0
args="$*"
T=${TMPDIR-/tmp}/kvm-again.sh.$$
trap 'rm -rf $T' 0
mkdir $T
if ! test -d tools/testing/selftests/rcutorture/bin
then
echo $scriptname must be run from top-level directory of kernel source tree.
exit 1
fi
oldrun=$1
shift
if ! test -d "$oldrun"
then
echo "Usage: $scriptname /path/to/old/run [ options ]"
exit 1
fi
if ! cp "$oldrun/batches" $T/batches.oldrun
then
# Later on, can reconstitute this from console.log files.
echo Prior run batches file does not exist: $oldrun/batches
exit 1
fi
if test -f "$oldrun/torture_suite"
then
torture_suite="`cat $oldrun/torture_suite`"
elif test -f "$oldrun/TORTURE_SUITE"
then
torture_suite="`cat $oldrun/TORTURE_SUITE`"
else
echo "Prior run torture_suite file does not exist: $oldrun/{torture_suite,TORTURE_SUITE}"
exit 1
fi
KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM
PATH=${KVM}/bin:$PATH; export PATH
. functions.sh
dryrun=
dur=
default_link="cp -R"
rundir="`pwd`/tools/testing/selftests/rcutorture/res/`date +%Y.%m.%d-%H.%M.%S-again`"
startdate="`date`"
starttime="`get_starttime`"
usage () {
echo "Usage: $scriptname $oldrun [ arguments ]:"
echo " --dryrun"
echo " --duration minutes | <seconds>s | <hours>h | <days>d"
echo " --link hard|soft|copy"
echo " --remote"
echo " --rundir /new/res/path"
exit 1
}
while test $# -gt 0
do
case "$1" in
--dryrun)
dryrun=1
;;
--duration)
checkarg --duration "(minutes)" $# "$2" '^[0-9][0-9]*\(s\|m\|h\|d\|\)$' '^error'
mult=60
if echo "$2" | grep -q 's$'
then
mult=1
elif echo "$2" | grep -q 'h$'
then
mult=3600
elif echo "$2" | grep -q 'd$'
then
mult=86400
fi
ts=`echo $2 | sed -e 's/[smhd]$//'`
dur=$(($ts*mult))
shift
;;
--link)
checkarg --link "hard|soft|copy" "$#" "$2" 'hard\|soft\|copy' '^--'
case "$2" in
copy)
arg_link="cp -R"
;;
hard)
arg_link="cp -Rl"
;;
soft)
arg_link="cp -Rs"
;;
esac
shift
;;
--remote)
arg_remote=1
default_link="cp -as"
;;
--rundir)
checkarg --rundir "(absolute pathname)" "$#" "$2" '^/' '^error'
rundir=$2
if test -e "$rundir"
then
echo "--rundir $2: Already exists."
usage
fi
shift
;;
*)
echo Unknown argument $1
usage
;;
esac
shift
done
if test -z "$arg_link"
then
arg_link="$default_link"
fi
echo ---- Re-run results directory: $rundir
# Copy old run directory tree over and adjust.
mkdir -p "`dirname "$rundir"`"
if ! $arg_link "$oldrun" "$rundir"
then
echo "Cannot copy from $oldrun to $rundir."
usage
fi
rm -f "$rundir"/*/{console.log,console.log.diags,qemu_pid,qemu-retval,Warnings,kvm-test-1-run.sh.out,kvm-test-1-run-qemu.sh.out,vmlinux} "$rundir"/log
echo $oldrun > "$rundir/re-run"
if ! test -d "$rundir/../../bin"
then
$arg_link "$oldrun/../../bin" "$rundir/../.."
fi
for i in $rundir/*/qemu-cmd
do
cp "$i" $T
qemu_cmd_dir="`dirname "$i"`"
kernel_dir="`echo $qemu_cmd_dir | sed -e 's/\.[0-9]\+$//'`"
jitter_dir="`dirname "$kernel_dir"`"
kvm-transform.sh "$kernel_dir/bzImage" "$qemu_cmd_dir/console.log" "$jitter_dir" $dur < $T/qemu-cmd > $i
if test -n "$arg_remote"
then
echo "# TORTURE_KCONFIG_GDB_ARG=''" >> $i
fi
done
# Extract settings from the last qemu-cmd file transformed above.
grep '^#' $i | sed -e 's/^# //' > $T/qemu-cmd-settings
. $T/qemu-cmd-settings
grep -v '^#' $T/batches.oldrun | awk '
BEGIN {
oldbatch = 1;
}
{
if (oldbatch != $1) {
print "kvm-test-1-run-batch.sh" curbatch;
curbatch = "";
oldbatch = $1;
}
curbatch = curbatch " " $2;
}
END {
print "kvm-test-1-run-batch.sh" curbatch
}' > $T/runbatches.sh
if test -n "$dryrun"
then
echo ---- Dryrun complete, directory: $rundir | tee -a "$rundir/log"
else
( cd "$rundir"; sh $T/runbatches.sh )
kcsan-collapse.sh "$rundir" | tee -a "$rundir/log"
echo | tee -a "$rundir/log"
echo ---- Results directory: $rundir | tee -a "$rundir/log"
kvm-recheck.sh "$rundir" > $T/kvm-recheck.sh.out 2>&1
ret=$?
cat $T/kvm-recheck.sh.out | tee -a "$rundir/log"
echo " --- Done at `date` (`get_starttime_duration $starttime`) exitcode $ret" | tee -a "$rundir/log"
exit $ret
fi
...@@ -30,7 +30,7 @@ do ...@@ -30,7 +30,7 @@ do
resdir=`echo $i | sed -e 's,/$,,' -e 's,/[^/]*$,,'` resdir=`echo $i | sed -e 's,/$,,' -e 's,/[^/]*$,,'`
head -1 $resdir/log head -1 $resdir/log
fi fi
TORTURE_SUITE="`cat $i/../TORTURE_SUITE`" TORTURE_SUITE="`cat $i/../torture_suite`"
configfile=`echo $i | sed -e 's,^.*/,,'` configfile=`echo $i | sed -e 's,^.*/,,'`
rm -f $i/console.log.*.diags rm -f $i/console.log.*.diags
kvm-recheck-${TORTURE_SUITE}.sh $i kvm-recheck-${TORTURE_SUITE}.sh $i
......
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0+
#
# Carry out a kvm-based run for the specified batch of scenarios, which
# might have been built by --build-only kvm.sh run.
#
# Usage: kvm-test-1-run-batch.sh SCENARIO [ SCENARIO ... ]
#
# Each SCENARIO is the name of a directory in the current directory
# containing a ready-to-run qemu-cmd file.
#
# Copyright (C) 2021 Facebook, Inc.
#
# Authors: Paul E. McKenney <paulmck@kernel.org>
T=${TMPDIR-/tmp}/kvm-test-1-run-batch.sh.$$
trap 'rm -rf $T' 0
mkdir $T
echo ---- Running batch $*
# Check arguments
runfiles=
for i in "$@"
do
if ! echo $i | grep -q '^[^/.a-z]\+\(\.[0-9]\+\)\?$'
then
echo Bad scenario name: \"$i\" 1>&2
exit 1
fi
if ! test -d "$i"
then
echo Scenario name not a directory: \"$i\" 1>&2
exit 2
fi
if ! test -f "$i/qemu-cmd"
then
echo Scenario lacks a command file: \"$i/qemu-cmd\" 1>&2
exit 3
fi
rm -f $i/build.*
touch $i/build.run
runfiles="$runfiles $i/build.run"
done
# Extract settings from the qemu-cmd file.
grep '^#' $1/qemu-cmd | sed -e 's/^# //' > $T/qemu-cmd-settings
. $T/qemu-cmd-settings
# Start up jitter, start each scenario, wait, end jitter.
echo ---- System running test: `uname -a`
echo ---- Starting kernels. `date` | tee -a log
$TORTURE_JITTER_START
for i in "$@"
do
echo ---- System running test: `uname -a` > $i/kvm-test-1-run-qemu.sh.out
echo > $i/kvm-test-1-run-qemu.sh.out
kvm-test-1-run-qemu.sh $i >> $i/kvm-test-1-run-qemu.sh.out 2>&1 &
done
for i in $runfiles
do
while ls $i > /dev/null 2>&1
do
:
done
done
echo ---- All kernel runs complete. `date` | tee -a log
$TORTURE_JITTER_STOP
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0+
#
# Carry out a kvm-based run for the specified qemu-cmd file, which might
# have been generated by --build-only kvm.sh run.
#
# Usage: kvm-test-1-run-qemu.sh qemu-cmd-dir
#
# qemu-cmd-dir provides the directory containing qemu-cmd file.
# This is assumed to be of the form prefix/ds/scenario, where
# "ds" is the top-level date-stamped directory and "scenario"
# is the scenario name. Any required adjustments to this file
# must have been made by the caller. The shell-command comments
# at the end of the qemu-cmd file are not optional.
#
# Copyright (C) 2021 Facebook, Inc.
#
# Authors: Paul E. McKenney <paulmck@kernel.org>
T=${TMPDIR-/tmp}/kvm-test-1-run-qemu.sh.$$
trap 'rm -rf $T' 0
mkdir $T
resdir="$1"
if ! test -d "$resdir"
then
echo $0: Nonexistent directory: $resdir
exit 1
fi
if ! test -f "$resdir/qemu-cmd"
then
echo $0: Nonexistent qemu-cmd file: $resdir/qemu-cmd
exit 1
fi
echo ' ---' `date`: Starting kernel, PID $$
# Obtain settings from the qemu-cmd file.
grep '^#' $resdir/qemu-cmd | sed -e 's/^# //' > $T/qemu-cmd-settings
. $T/qemu-cmd-settings
# Decorate qemu-cmd with redirection, backgrounding, and PID capture
sed -e 's/$/ 2>\&1 \&/' < $resdir/qemu-cmd > $T/qemu-cmd
echo 'echo $! > $resdir/qemu_pid' >> $T/qemu-cmd
# In case qemu refuses to run...
echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log
# Attempt to run qemu
kstarttime=`gawk 'BEGIN { print systime() }' < /dev/null`
( . $T/qemu-cmd; wait `cat $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) &
commandcompleted=0
if test -z "$TORTURE_KCONFIG_GDB_ARG"
then
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
base_resdir=`echo $resdir | sed -e 's/\.[0-9]\+$//'`
if ! test -f $base_resdir/vmlinux
then
base_resdir="`cat re-run`/$resdir"
if ! test -f $base_resdir/vmlinux
then
base_resdir=/path/to
fi
fi
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
if test -z "$qemu_pid" -a -s "$resdir/qemu_pid"
then
qemu_pid=`cat "$resdir/qemu_pid"`
fi
kruntime=`gawk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null`
if test -z "$qemu_pid" || kill -0 "$qemu_pid" > /dev/null 2>&1
then
if test -n "$TORTURE_KCONFIG_GDB_ARG"
then
:
elif test $kruntime -ge $seconds || test -f "$resdir/../STOP.1"
then
break;
fi
sleep 1
else
commandcompleted=1
if test $kruntime -lt $seconds
then
echo Completed in $kruntime vs. $seconds >> $resdir/Warnings 2>&1
grep "^(qemu) qemu:" $resdir/kvm-test-1-run.sh.out >> $resdir/Warnings 2>&1
killpid="`sed -n "s/^(qemu) qemu: terminating on signal [0-9]* from pid \([0-9]*\).*$/\1/p" $resdir/Warnings`"
if test -n "$killpid"
then
echo "ps -fp $killpid" >> $resdir/Warnings 2>&1
ps -fp $killpid >> $resdir/Warnings 2>&1
fi
else
echo ' ---' `date`: "Kernel done"
fi
break
fi
done
if test -z "$qemu_pid" -a -s "$resdir/qemu_pid"
then
qemu_pid=`cat "$resdir/qemu_pid"`
fi
if test $commandcompleted -eq 0 -a -n "$qemu_pid"
then
if ! test -f "$resdir/../STOP.1"
then
echo Grace period for qemu job at pid $qemu_pid
fi
oldline="`tail $resdir/console.log`"
while :
do
if test -f "$resdir/../STOP.1"
then
echo "PID $qemu_pid killed due to run STOP.1 request" >> $resdir/Warnings 2>&1
kill -KILL $qemu_pid
break
fi
kruntime=`gawk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null`
if kill -0 $qemu_pid > /dev/null 2>&1
then
:
else
break
fi
must_continue=no
newline="`tail $resdir/console.log`"
if test "$newline" != "$oldline" && echo $newline | grep -q ' [0-9]\+us : '
then
must_continue=yes
fi
last_ts="`tail $resdir/console.log | grep '^\[ *[0-9]\+\.[0-9]\+]' | tail -1 | sed -e 's/^\[ *//' -e 's/\..*$//'`"
if test -z "$last_ts"
then
last_ts=0
fi
if test "$newline" != "$oldline" -a "$last_ts" -lt $((seconds + $TORTURE_SHUTDOWN_GRACE))
then
must_continue=yes
fi
if test $must_continue = no -a $kruntime -ge $((seconds + $TORTURE_SHUTDOWN_GRACE))
then
echo "!!! PID $qemu_pid hung at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
kill -KILL $qemu_pid
break
fi
oldline=$newline
sleep 10
done
elif test -z "$qemu_pid"
then
echo Unknown PID, cannot kill qemu command
fi
# Tell the script that this run is done.
rm -f $resdir/build.run
parse-console.sh $resdir/console.log $title
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# #
# Transform a qemu-cmd file to allow reuse. # Transform a qemu-cmd file to allow reuse.
# #
# Usage: kvm-transform.sh bzImage console.log < qemu-cmd-in > qemu-cmd-out # Usage: kvm-transform.sh bzImage console.log jitter_dir [ seconds ] < qemu-cmd-in > qemu-cmd-out
# #
# bzImage: Kernel and initrd from the same prior kvm.sh run. # bzImage: Kernel and initrd from the same prior kvm.sh run.
# console.log: File into which to place console output. # console.log: File into which to place console output.
...@@ -29,20 +29,62 @@ then ...@@ -29,20 +29,62 @@ then
echo "Need console log file name." echo "Need console log file name."
exit 1 exit 1
fi fi
jitter_dir="$3"
if test -z "$jitter_dir" || ! test -d "$jitter_dir"
then
echo "Need valid jitter directory: '$jitter_dir'"
exit 1
fi
seconds="$4"
if test -n "$seconds" && echo $seconds | grep -q '[^0-9]'
then
echo "Invalid duration, should be numeric in seconds: '$seconds'"
exit 1
fi
awk -v image="$image" -v consolelog="$consolelog" -v jitter_dir="$jitter_dir" \
-v seconds="$seconds" '
/^# seconds=/ {
if (seconds == "")
print $0;
else
print "# seconds=" seconds;
next;
}
/^# TORTURE_JITTER_START=/ {
print "# TORTURE_JITTER_START=\". jitterstart.sh " $4 " " jitter_dir " " $6 " " $7;
next;
}
/^# TORTURE_JITTER_STOP=/ {
print "# TORTURE_JITTER_STOP=\". jitterstop.sh " " " jitter_dir " " $5;
next;
}
/^#/ {
print $0;
next;
}
awk -v image="$image" -v consolelog="$consolelog" '
{ {
line = ""; line = "";
for (i = 1; i <= NF; i++) { for (i = 1; i <= NF; i++) {
if (line == "") if ("" seconds != "" && $i ~ /\.shutdown_secs=[0-9]*$/) {
sub(/[0-9]*$/, seconds, $i);
if (line == "")
line = $i;
else
line = line " " $i;
} else if (line == "") {
line = $i; line = $i;
else } else {
line = line " " $i; line = line " " $i;
}
if ($i == "-serial") { if ($i == "-serial") {
i++; i++;
line = line " file:" consolelog; line = line " file:" consolelog;
} } else if ($i == "-kernel") {
if ($i == "-kernel") {
i++; i++;
line = line " " image; line = line " " image;
} }
......
...@@ -29,17 +29,21 @@ PATH=${KVM}/bin:$PATH; export PATH ...@@ -29,17 +29,21 @@ PATH=${KVM}/bin:$PATH; export PATH
TORTURE_ALLOTED_CPUS="`identify_qemu_vcpus`" TORTURE_ALLOTED_CPUS="`identify_qemu_vcpus`"
TORTURE_DEFCONFIG=defconfig TORTURE_DEFCONFIG=defconfig
TORTURE_BOOT_IMAGE="" TORTURE_BOOT_IMAGE=""
TORTURE_BUILDONLY=
TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD
TORTURE_KCONFIG_ARG="" TORTURE_KCONFIG_ARG=""
TORTURE_KCONFIG_GDB_ARG="" TORTURE_KCONFIG_GDB_ARG=""
TORTURE_BOOT_GDB_ARG="" TORTURE_BOOT_GDB_ARG=""
TORTURE_QEMU_GDB_ARG="" TORTURE_QEMU_GDB_ARG=""
TORTURE_JITTER_START=""
TORTURE_JITTER_STOP=""
TORTURE_KCONFIG_KASAN_ARG="" TORTURE_KCONFIG_KASAN_ARG=""
TORTURE_KCONFIG_KCSAN_ARG="" TORTURE_KCONFIG_KCSAN_ARG=""
TORTURE_KMAKE_ARG="" TORTURE_KMAKE_ARG=""
TORTURE_QEMU_MEM=512 TORTURE_QEMU_MEM=512
TORTURE_SHUTDOWN_GRACE=180 TORTURE_SHUTDOWN_GRACE=180
TORTURE_SUITE=rcu TORTURE_SUITE=rcu
TORTURE_MOD=rcutorture
TORTURE_TRUST_MAKE="" TORTURE_TRUST_MAKE=""
resdir="" resdir=""
configs="" configs=""
...@@ -100,7 +104,7 @@ do ...@@ -100,7 +104,7 @@ do
TORTURE_BUILDONLY=1 TORTURE_BUILDONLY=1
;; ;;
--configs|--config) --configs|--config)
checkarg --configs "(list of config files)" "$#" "$2" '^[^/]\+$' '^--' checkarg --configs "(list of config files)" "$#" "$2" '^[^/.a-z]\+$' '^--'
configs="$configs $2" configs="$configs $2"
shift shift
;; ;;
...@@ -116,7 +120,7 @@ do ...@@ -116,7 +120,7 @@ do
shift shift
;; ;;
--datestamp) --datestamp)
checkarg --datestamp "(relative pathname)" "$#" "$2" '^[a-zA-Z0-9._-/]*$' '^--' checkarg --datestamp "(relative pathname)" "$#" "$2" '^[a-zA-Z0-9._/-]*$' '^--'
ds=$2 ds=$2
shift shift
;; ;;
...@@ -215,6 +219,7 @@ do ...@@ -215,6 +219,7 @@ do
--torture) --torture)
checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuscale\|refscale\|scf\)$' '^--' checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuscale\|refscale\|scf\)$' '^--'
TORTURE_SUITE=$2 TORTURE_SUITE=$2
TORTURE_MOD="`echo $TORTURE_SUITE | sed -e 's/^\(lock\|rcu\|scf\)$/\1torture/'`"
shift shift
if test "$TORTURE_SUITE" = rcuscale || test "$TORTURE_SUITE" = refscale if test "$TORTURE_SUITE" = rcuscale || test "$TORTURE_SUITE" = refscale
then then
...@@ -381,6 +386,7 @@ TORTURE_QEMU_GDB_ARG="$TORTURE_QEMU_GDB_ARG"; export TORTURE_QEMU_GDB_ARG ...@@ -381,6 +386,7 @@ 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_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_KCONFIG_KCSAN_ARG="$TORTURE_KCONFIG_KCSAN_ARG"; export TORTURE_KCONFIG_KCSAN_ARG
TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG
TORTURE_MOD="$TORTURE_MOD"; export TORTURE_MOD
TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD
TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE
TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC
...@@ -399,12 +405,17 @@ echo Results directory: $resdir/$ds ...@@ -399,12 +405,17 @@ echo Results directory: $resdir/$ds
echo $scriptname $args echo $scriptname $args
touch $resdir/$ds/log touch $resdir/$ds/log
echo $scriptname $args >> $resdir/$ds/log echo $scriptname $args >> $resdir/$ds/log
echo ${TORTURE_SUITE} > $resdir/$ds/TORTURE_SUITE echo ${TORTURE_SUITE} > $resdir/$ds/torture_suite
pwd > $resdir/$ds/testid.txt echo Build directory: `pwd` > $resdir/$ds/testid.txt
if test -d .git if test -d .git
then then
echo Current commit: `git rev-parse HEAD` >> $resdir/$ds/testid.txt
echo >> $resdir/$ds/testid.txt
echo ' ---' Output of "'"git status"'": >> $resdir/$ds/testid.txt
git status >> $resdir/$ds/testid.txt git status >> $resdir/$ds/testid.txt
git rev-parse HEAD >> $resdir/$ds/testid.txt echo >> $resdir/$ds/testid.txt
echo >> $resdir/$ds/testid.txt
echo ' ---' Output of "'"git diff HEAD"'": >> $resdir/$ds/testid.txt
git diff HEAD >> $resdir/$ds/testid.txt git diff HEAD >> $resdir/$ds/testid.txt
fi fi
___EOF___ ___EOF___
...@@ -434,8 +445,17 @@ function dump(first, pastlast, batchnum) ...@@ -434,8 +445,17 @@ function dump(first, pastlast, batchnum)
print "echo ----Start batch " batchnum ": `date` | tee -a " rd "log"; print "echo ----Start batch " batchnum ": `date` | tee -a " rd "log";
print "needqemurun=" print "needqemurun="
jn=1 jn=1
njitter = 0;
split(jitter, ja);
if (ja[1] == -1 && ncpus == 0)
njitter = 1;
else if (ja[1] == -1)
njitter = ncpus;
else
njitter = ja[1];
print "TORTURE_JITTER_START=\". jitterstart.sh " njitter " " rd " " dur " " ja[2] " " ja[3] "\"; export TORTURE_JITTER_START";
print "TORTURE_JITTER_STOP=\". jitterstop.sh " rd " \"; export TORTURE_JITTER_STOP"
for (j = first; j < pastlast; j++) { for (j = first; j < pastlast; j++) {
builddir=KVM "/b" j - first + 1
cpusr[jn] = cpus[j]; cpusr[jn] = cpus[j];
if (cfrep[cf[j]] == "") { if (cfrep[cf[j]] == "") {
cfr[jn] = cf[j]; cfr[jn] = cf[j];
...@@ -444,15 +464,15 @@ function dump(first, pastlast, batchnum) ...@@ -444,15 +464,15 @@ function dump(first, pastlast, batchnum)
cfrep[cf[j]]++; cfrep[cf[j]]++;
cfr[jn] = cf[j] "." cfrep[cf[j]]; cfr[jn] = cf[j] "." cfrep[cf[j]];
} }
builddir=rd cfr[jn] "/build";
if (cpusr[jn] > ncpus && ncpus != 0) if (cpusr[jn] > ncpus && ncpus != 0)
ovf = "-ovf"; ovf = "-ovf";
else else
ovf = ""; ovf = "";
print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date` | tee -a " rd "log"; print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date` | tee -a " rd "log";
print "rm -f " builddir ".*";
print "touch " builddir ".wait";
print "mkdir " rd cfr[jn] " || :"; print "mkdir " rd cfr[jn] " || :";
print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" TORTURE_QEMU_ARG "\" \"" TORTURE_BOOTARGS "\" > " rd cfr[jn] "/kvm-test-1-run.sh.out 2>&1 &" print "touch " builddir ".wait";
print "kvm-test-1-run.sh " CONFIGDIR cf[j], rd cfr[jn], dur " \"" TORTURE_QEMU_ARG "\" \"" TORTURE_BOOTARGS "\" > " rd cfr[jn] "/kvm-test-1-run.sh.out 2>&1 &"
print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` | tee -a " rd "log"; print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` | tee -a " rd "log";
print "while test -f " builddir ".wait" print "while test -f " builddir ".wait"
print "do" print "do"
...@@ -461,23 +481,21 @@ function dump(first, pastlast, batchnum) ...@@ -461,23 +481,21 @@ function dump(first, pastlast, batchnum)
print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date` | tee -a " rd "log"; print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date` | tee -a " rd "log";
jn++; jn++;
} }
print "runfiles="
for (j = 1; j < jn; j++) { for (j = 1; j < jn; j++) {
builddir=KVM "/b" j builddir=rd cfr[j] "/build";
print "rm -f " builddir ".ready" if (TORTURE_BUILDONLY)
print "rm -f " builddir ".ready"
else
print "mv " builddir ".ready " builddir ".run"
print "runfiles=\"$runfiles " builddir ".run\""
fi
print "if test -f \"" rd cfr[j] "/builtkernel\"" print "if test -f \"" rd cfr[j] "/builtkernel\""
print "then" print "then"
print "\techo ----", cfr[j], cpusr[j] ovf ": Kernel present. `date` | tee -a " rd "log"; print "\techo ----", cfr[j], cpusr[j] ovf ": Kernel present. `date` | tee -a " rd "log";
print "\tneedqemurun=1" print "\tneedqemurun=1"
print "fi" print "fi"
} }
njitter = 0;
split(jitter, ja);
if (ja[1] == -1 && ncpus == 0)
njitter = 1;
else if (ja[1] == -1)
njitter = ncpus;
else
njitter = ja[1];
if (TORTURE_BUILDONLY && njitter != 0) { if (TORTURE_BUILDONLY && njitter != 0) {
njitter = 0; njitter = 0;
print "echo Build-only run, so suppressing jitter | tee -a " rd "log" print "echo Build-only run, so suppressing jitter | tee -a " rd "log"
...@@ -488,19 +506,18 @@ function dump(first, pastlast, batchnum) ...@@ -488,19 +506,18 @@ function dump(first, pastlast, batchnum)
print "if test -n \"$needqemurun\"" print "if test -n \"$needqemurun\""
print "then" print "then"
print "\techo ---- Starting kernels. `date` | tee -a " rd "log"; print "\techo ---- Starting kernels. `date` | tee -a " rd "log";
print "\techo > " rd "jitter_pids" print "\t$TORTURE_JITTER_START";
for (j = 0; j < njitter; j++) { print "\twhile ls $runfiles > /dev/null 2>&1"
print "\tjitter.sh " j " " dur " " ja[2] " " ja[3] "&" print "\tdo"
print "\techo $! >> " rd "jitter_pids" print "\t\t:"
} print "\tdone"
print "\twait" print "\t$TORTURE_JITTER_STOP";
print "\techo ---- All kernel runs complete. `date` | tee -a " rd "log"; print "\techo ---- All kernel runs complete. `date` | tee -a " rd "log";
print "else" print "else"
print "\twait" print "\twait"
print "\techo ---- No kernel runs. `date` | tee -a " rd "log"; print "\techo ---- No kernel runs. `date` | tee -a " rd "log";
print "fi" print "fi"
for (j = 1; j < jn; j++) { for (j = 1; j < jn; j++) {
builddir=KVM "/b" j
print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results: | tee -a " rd "log"; print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results: | tee -a " rd "log";
print "cat " rd cfr[j] "/kvm-test-1-run.sh.out | tee -a " rd "log"; print "cat " rd cfr[j] "/kvm-test-1-run.sh.out | tee -a " rd "log";
} }
...@@ -548,6 +565,18 @@ echo 'ret=$?' >> $T/script ...@@ -548,6 +565,18 @@ echo 'ret=$?' >> $T/script
echo "cat $T/kvm-recheck.sh.out | tee -a $resdir/$ds/log" >> $T/script echo "cat $T/kvm-recheck.sh.out | tee -a $resdir/$ds/log" >> $T/script
echo 'exit $ret' >> $T/script echo 'exit $ret' >> $T/script
# Extract the tests and their batches from the script.
egrep 'Start batch|Starting build\.' $T/script | grep -v ">>" |
sed -e 's/:.*$//' -e 's/^echo //' -e 's/-ovf//' |
awk '
/^----Start/ {
batchno = $3;
next;
}
{
print batchno, $1, $2
}' > $T/batches
if test "$dryrun" = script if test "$dryrun" = script
then then
cat $T/script cat $T/script
...@@ -566,21 +595,14 @@ then ...@@ -566,21 +595,14 @@ then
exit 0 exit 0
elif test "$dryrun" = batches elif test "$dryrun" = batches
then then
# Extract the tests and their batches from the script. cat $T/batches
egrep 'Start batch|Starting build\.' $T/script | grep -v ">>" | exit 0
sed -e 's/:.*$//' -e 's/^echo //' -e 's/-ovf//' |
awk '
/^----Start/ {
batchno = $3;
next;
}
{
print batchno, $1, $2
}'
else else
# Not a dryrun, so run the script. # Not a dryrun. Record the batches and the number of CPUs, then run the script.
bash $T/script bash $T/script
ret=$? ret=$?
cp $T/batches $resdir/$ds/batches
echo '#' cpus=$cpus >> $resdir/$ds/batches
echo " --- Done at `date` (`get_starttime_duration $starttime`) exitcode $ret" | tee -a $resdir/$ds/log echo " --- Done at `date` (`get_starttime_duration $starttime`) exitcode $ret" | tee -a $resdir/$ds/log
exit $ret exit $ret
fi fi
......
...@@ -374,7 +374,7 @@ done ...@@ -374,7 +374,7 @@ done
if test "$do_kvfree" = "yes" if test "$do_kvfree" = "yes"
then then
torture_bootargs="rcuscale.kfree_rcu_test=1 rcuscale.kfree_nthreads=16 rcuscale.holdoff=20 rcuscale.kfree_loops=10000 torture.disable_onoff_at_boot" torture_bootargs="rcuscale.kfree_rcu_test=1 rcuscale.kfree_nthreads=16 rcuscale.holdoff=20 rcuscale.kfree_loops=10000 torture.disable_onoff_at_boot"
torture_set "rcuscale-kvfree" tools/testing/selftests/rcutorture/bin/kvm.sh --torture rcuscale --allcpus --duration 10 --kconfig "CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --trust-make torture_set "rcuscale-kvfree" tools/testing/selftests/rcutorture/bin/kvm.sh --torture rcuscale --allcpus --duration 10 --kconfig "CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --memory 1G --trust-make
fi fi
echo " --- " $scriptname $args echo " --- " $scriptname $args
......
...@@ -7,8 +7,8 @@ TREE07 ...@@ -7,8 +7,8 @@ TREE07
TREE09 TREE09
SRCU-N SRCU-N
SRCU-P SRCU-P
SRCU-t SRCU-T
SRCU-u SRCU-U
TINY01 TINY01
TINY02 TINY02
TASKS01 TASKS01
......
...@@ -4,3 +4,4 @@ rcutree.gp_init_delay=3 ...@@ -4,3 +4,4 @@ rcutree.gp_init_delay=3
rcutree.gp_cleanup_delay=3 rcutree.gp_cleanup_delay=3
rcutree.kthread_prio=2 rcutree.kthread_prio=2
threadirqs threadirqs
tree.use_softirq=0
rcutree.rcu_fanout_leaf=4 nohz_full=1-7 rcutree.rcu_fanout_leaf=4 nohz_full=1-N
rcupdate.rcu_self_test=1 rcupdate.rcu_self_test=1
rcutree.rcu_fanout_exact=1 rcutree.rcu_fanout_exact=1
rcu_nocbs=0-7 rcu_nocbs=all
...@@ -12,5 +12,5 @@ ...@@ -12,5 +12,5 @@
# Adds per-version torture-module parameters to kernels supporting them. # Adds per-version torture-module parameters to kernels supporting them.
per_version_boot_params () { per_version_boot_params () {
echo $1 rcuscale.shutdown=1 \ echo $1 rcuscale.shutdown=1 \
rcuscale.verbose=1 rcuscale.verbose=0
} }
...@@ -12,5 +12,5 @@ ...@@ -12,5 +12,5 @@
# Adds per-version torture-module parameters to kernels supporting them. # Adds per-version torture-module parameters to kernels supporting them.
per_version_boot_params () { per_version_boot_params () {
echo $1 refscale.shutdown=1 \ echo $1 refscale.shutdown=1 \
refscale.verbose=1 refscale.verbose=0
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment