151b1130eSPaul E. McKenney /* 251b1130eSPaul E. McKenney * Common functions for in-kernel torture tests. 351b1130eSPaul E. McKenney * 451b1130eSPaul E. McKenney * This program is free software; you can redistribute it and/or modify 551b1130eSPaul E. McKenney * it under the terms of the GNU General Public License as published by 651b1130eSPaul E. McKenney * the Free Software Foundation; either version 2 of the License, or 751b1130eSPaul E. McKenney * (at your option) any later version. 851b1130eSPaul E. McKenney * 951b1130eSPaul E. McKenney * This program is distributed in the hope that it will be useful, 1051b1130eSPaul E. McKenney * but WITHOUT ANY WARRANTY; without even the implied warranty of 1151b1130eSPaul E. McKenney * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1251b1130eSPaul E. McKenney * GNU General Public License for more details. 1351b1130eSPaul E. McKenney * 1451b1130eSPaul E. McKenney * You should have received a copy of the GNU General Public License 1551b1130eSPaul E. McKenney * along with this program; if not, you can access it online at 1651b1130eSPaul E. McKenney * http://www.gnu.org/licenses/gpl-2.0.html. 1751b1130eSPaul E. McKenney * 1851b1130eSPaul E. McKenney * Copyright (C) IBM Corporation, 2014 1951b1130eSPaul E. McKenney * 2051b1130eSPaul E. McKenney * Author: Paul E. McKenney <paulmck@us.ibm.com> 2151b1130eSPaul E. McKenney * Based on kernel/rcu/torture.c. 2251b1130eSPaul E. McKenney */ 2351b1130eSPaul E. McKenney #include <linux/types.h> 2451b1130eSPaul E. McKenney #include <linux/kernel.h> 2551b1130eSPaul E. McKenney #include <linux/init.h> 2651b1130eSPaul E. McKenney #include <linux/module.h> 2751b1130eSPaul E. McKenney #include <linux/kthread.h> 2851b1130eSPaul E. McKenney #include <linux/err.h> 2951b1130eSPaul E. McKenney #include <linux/spinlock.h> 3051b1130eSPaul E. McKenney #include <linux/smp.h> 3151b1130eSPaul E. McKenney #include <linux/interrupt.h> 3251b1130eSPaul E. McKenney #include <linux/sched.h> 3351b1130eSPaul E. McKenney #include <linux/atomic.h> 3451b1130eSPaul E. McKenney #include <linux/bitops.h> 3551b1130eSPaul E. McKenney #include <linux/completion.h> 3651b1130eSPaul E. McKenney #include <linux/moduleparam.h> 3751b1130eSPaul E. McKenney #include <linux/percpu.h> 3851b1130eSPaul E. McKenney #include <linux/notifier.h> 3951b1130eSPaul E. McKenney #include <linux/reboot.h> 4051b1130eSPaul E. McKenney #include <linux/freezer.h> 4151b1130eSPaul E. McKenney #include <linux/cpu.h> 4251b1130eSPaul E. McKenney #include <linux/delay.h> 4351b1130eSPaul E. McKenney #include <linux/stat.h> 4451b1130eSPaul E. McKenney #include <linux/slab.h> 4551b1130eSPaul E. McKenney #include <linux/trace_clock.h> 4651b1130eSPaul E. McKenney #include <asm/byteorder.h> 4751b1130eSPaul E. McKenney #include <linux/torture.h> 4851b1130eSPaul E. McKenney 4951b1130eSPaul E. McKenney MODULE_LICENSE("GPL"); 5051b1130eSPaul E. McKenney MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>"); 5151b1130eSPaul E. McKenney 52f67a3356SPaul E. McKenney int fullstop = FULLSTOP_RMMOD; 53f67a3356SPaul E. McKenney EXPORT_SYMBOL_GPL(fullstop); 54f67a3356SPaul E. McKenney DEFINE_MUTEX(fullstop_mutex); 55f67a3356SPaul E. McKenney EXPORT_SYMBOL_GPL(fullstop_mutex); 56f67a3356SPaul E. McKenney 5751b1130eSPaul E. McKenney #define TORTURE_RANDOM_MULT 39916801 /* prime */ 5851b1130eSPaul E. McKenney #define TORTURE_RANDOM_ADD 479001701 /* prime */ 5951b1130eSPaul E. McKenney #define TORTURE_RANDOM_REFRESH 10000 6051b1130eSPaul E. McKenney 6151b1130eSPaul E. McKenney /* 6251b1130eSPaul E. McKenney * Crude but fast random-number generator. Uses a linear congruential 6351b1130eSPaul E. McKenney * generator, with occasional help from cpu_clock(). 6451b1130eSPaul E. McKenney */ 6551b1130eSPaul E. McKenney unsigned long 6651b1130eSPaul E. McKenney torture_random(struct torture_random_state *trsp) 6751b1130eSPaul E. McKenney { 6851b1130eSPaul E. McKenney if (--trsp->trs_count < 0) { 6951b1130eSPaul E. McKenney trsp->trs_state += (unsigned long)local_clock(); 7051b1130eSPaul E. McKenney trsp->trs_count = TORTURE_RANDOM_REFRESH; 7151b1130eSPaul E. McKenney } 7251b1130eSPaul E. McKenney trsp->trs_state = trsp->trs_state * TORTURE_RANDOM_MULT + 7351b1130eSPaul E. McKenney TORTURE_RANDOM_ADD; 7451b1130eSPaul E. McKenney return swahw32(trsp->trs_state); 7551b1130eSPaul E. McKenney } 7651b1130eSPaul E. McKenney EXPORT_SYMBOL_GPL(torture_random); 77f67a3356SPaul E. McKenney 78f67a3356SPaul E. McKenney /* 79*3808dc9fSPaul E. McKenney * Variables for shuffling. The idea is to ensure that each CPU stays 80*3808dc9fSPaul E. McKenney * idle for an extended period to test interactions with dyntick idle, 81*3808dc9fSPaul E. McKenney * as well as interactions with any per-CPU varibles. 82*3808dc9fSPaul E. McKenney */ 83*3808dc9fSPaul E. McKenney struct shuffle_task { 84*3808dc9fSPaul E. McKenney struct list_head st_l; 85*3808dc9fSPaul E. McKenney struct task_struct *st_t; 86*3808dc9fSPaul E. McKenney }; 87*3808dc9fSPaul E. McKenney 88*3808dc9fSPaul E. McKenney static long shuffle_interval; /* In jiffies. */ 89*3808dc9fSPaul E. McKenney static struct task_struct *shuffler_task; 90*3808dc9fSPaul E. McKenney static cpumask_var_t shuffle_tmp_mask; 91*3808dc9fSPaul E. McKenney static int shuffle_idle_cpu; /* Force all torture tasks off this CPU */ 92*3808dc9fSPaul E. McKenney static struct list_head shuffle_task_list = LIST_HEAD_INIT(shuffle_task_list); 93*3808dc9fSPaul E. McKenney static DEFINE_MUTEX(shuffle_task_mutex); 94*3808dc9fSPaul E. McKenney 95*3808dc9fSPaul E. McKenney /* 96*3808dc9fSPaul E. McKenney * Register a task to be shuffled. If there is no memory, just splat 97*3808dc9fSPaul E. McKenney * and don't bother registering. 98*3808dc9fSPaul E. McKenney */ 99*3808dc9fSPaul E. McKenney void torture_shuffle_task_register(struct task_struct *tp) 100*3808dc9fSPaul E. McKenney { 101*3808dc9fSPaul E. McKenney struct shuffle_task *stp; 102*3808dc9fSPaul E. McKenney 103*3808dc9fSPaul E. McKenney if (WARN_ON_ONCE(tp == NULL)) 104*3808dc9fSPaul E. McKenney return; 105*3808dc9fSPaul E. McKenney stp = kmalloc(sizeof(*stp), GFP_KERNEL); 106*3808dc9fSPaul E. McKenney if (WARN_ON_ONCE(stp == NULL)) 107*3808dc9fSPaul E. McKenney return; 108*3808dc9fSPaul E. McKenney stp->st_t = tp; 109*3808dc9fSPaul E. McKenney mutex_lock(&shuffle_task_mutex); 110*3808dc9fSPaul E. McKenney list_add(&stp->st_l, &shuffle_task_list); 111*3808dc9fSPaul E. McKenney mutex_unlock(&shuffle_task_mutex); 112*3808dc9fSPaul E. McKenney } 113*3808dc9fSPaul E. McKenney EXPORT_SYMBOL_GPL(torture_shuffle_task_register); 114*3808dc9fSPaul E. McKenney 115*3808dc9fSPaul E. McKenney /* 116*3808dc9fSPaul E. McKenney * Unregister all tasks, for example, at the end of the torture run. 117*3808dc9fSPaul E. McKenney */ 118*3808dc9fSPaul E. McKenney static void torture_shuffle_task_unregister_all(void) 119*3808dc9fSPaul E. McKenney { 120*3808dc9fSPaul E. McKenney struct shuffle_task *stp; 121*3808dc9fSPaul E. McKenney struct shuffle_task *p; 122*3808dc9fSPaul E. McKenney 123*3808dc9fSPaul E. McKenney mutex_lock(&shuffle_task_mutex); 124*3808dc9fSPaul E. McKenney list_for_each_entry_safe(stp, p, &shuffle_task_list, st_l) { 125*3808dc9fSPaul E. McKenney list_del(&stp->st_l); 126*3808dc9fSPaul E. McKenney kfree(stp); 127*3808dc9fSPaul E. McKenney } 128*3808dc9fSPaul E. McKenney mutex_unlock(&shuffle_task_mutex); 129*3808dc9fSPaul E. McKenney } 130*3808dc9fSPaul E. McKenney 131*3808dc9fSPaul E. McKenney /* Shuffle tasks such that we allow shuffle_idle_cpu to become idle. 132*3808dc9fSPaul E. McKenney * A special case is when shuffle_idle_cpu = -1, in which case we allow 133*3808dc9fSPaul E. McKenney * the tasks to run on all CPUs. 134*3808dc9fSPaul E. McKenney */ 135*3808dc9fSPaul E. McKenney static void torture_shuffle_tasks(void) 136*3808dc9fSPaul E. McKenney { 137*3808dc9fSPaul E. McKenney struct shuffle_task *stp; 138*3808dc9fSPaul E. McKenney 139*3808dc9fSPaul E. McKenney cpumask_setall(shuffle_tmp_mask); 140*3808dc9fSPaul E. McKenney get_online_cpus(); 141*3808dc9fSPaul E. McKenney 142*3808dc9fSPaul E. McKenney /* No point in shuffling if there is only one online CPU (ex: UP) */ 143*3808dc9fSPaul E. McKenney if (num_online_cpus() == 1) { 144*3808dc9fSPaul E. McKenney put_online_cpus(); 145*3808dc9fSPaul E. McKenney return; 146*3808dc9fSPaul E. McKenney } 147*3808dc9fSPaul E. McKenney 148*3808dc9fSPaul E. McKenney /* Advance to the next CPU. Upon overflow, don't idle any CPUs. */ 149*3808dc9fSPaul E. McKenney shuffle_idle_cpu = cpumask_next(shuffle_idle_cpu, shuffle_tmp_mask); 150*3808dc9fSPaul E. McKenney if (shuffle_idle_cpu >= nr_cpu_ids) 151*3808dc9fSPaul E. McKenney shuffle_idle_cpu = -1; 152*3808dc9fSPaul E. McKenney if (shuffle_idle_cpu != -1) { 153*3808dc9fSPaul E. McKenney cpumask_clear_cpu(shuffle_idle_cpu, shuffle_tmp_mask); 154*3808dc9fSPaul E. McKenney if (cpumask_empty(shuffle_tmp_mask)) { 155*3808dc9fSPaul E. McKenney put_online_cpus(); 156*3808dc9fSPaul E. McKenney return; 157*3808dc9fSPaul E. McKenney } 158*3808dc9fSPaul E. McKenney } 159*3808dc9fSPaul E. McKenney 160*3808dc9fSPaul E. McKenney mutex_lock(&shuffle_task_mutex); 161*3808dc9fSPaul E. McKenney list_for_each_entry(stp, &shuffle_task_list, st_l) 162*3808dc9fSPaul E. McKenney set_cpus_allowed_ptr(stp->st_t, shuffle_tmp_mask); 163*3808dc9fSPaul E. McKenney mutex_unlock(&shuffle_task_mutex); 164*3808dc9fSPaul E. McKenney 165*3808dc9fSPaul E. McKenney put_online_cpus(); 166*3808dc9fSPaul E. McKenney } 167*3808dc9fSPaul E. McKenney 168*3808dc9fSPaul E. McKenney /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the 169*3808dc9fSPaul E. McKenney * system to become idle at a time and cut off its timer ticks. This is meant 170*3808dc9fSPaul E. McKenney * to test the support for such tickless idle CPU in RCU. 171*3808dc9fSPaul E. McKenney */ 172*3808dc9fSPaul E. McKenney static int torture_shuffle(void *arg) 173*3808dc9fSPaul E. McKenney { 174*3808dc9fSPaul E. McKenney VERBOSE_TOROUT_STRING("torture_shuffle task started"); 175*3808dc9fSPaul E. McKenney do { 176*3808dc9fSPaul E. McKenney schedule_timeout_interruptible(shuffle_interval); 177*3808dc9fSPaul E. McKenney torture_shuffle_tasks(); 178*3808dc9fSPaul E. McKenney torture_shutdown_absorb("torture_shuffle"); 179*3808dc9fSPaul E. McKenney } while (!torture_must_stop()); 180*3808dc9fSPaul E. McKenney VERBOSE_TOROUT_STRING("torture_shuffle task stopping"); 181*3808dc9fSPaul E. McKenney return 0; 182*3808dc9fSPaul E. McKenney } 183*3808dc9fSPaul E. McKenney 184*3808dc9fSPaul E. McKenney /* 185*3808dc9fSPaul E. McKenney * Start the shuffler, with shuffint in jiffies. 186*3808dc9fSPaul E. McKenney */ 187*3808dc9fSPaul E. McKenney int torture_shuffle_init(long shuffint) 188*3808dc9fSPaul E. McKenney { 189*3808dc9fSPaul E. McKenney int ret; 190*3808dc9fSPaul E. McKenney 191*3808dc9fSPaul E. McKenney shuffle_interval = shuffint; 192*3808dc9fSPaul E. McKenney 193*3808dc9fSPaul E. McKenney shuffle_idle_cpu = -1; 194*3808dc9fSPaul E. McKenney 195*3808dc9fSPaul E. McKenney if (!alloc_cpumask_var(&shuffle_tmp_mask, GFP_KERNEL)) { 196*3808dc9fSPaul E. McKenney VERBOSE_TOROUT_ERRSTRING("Failed to alloc mask"); 197*3808dc9fSPaul E. McKenney return -ENOMEM; 198*3808dc9fSPaul E. McKenney } 199*3808dc9fSPaul E. McKenney 200*3808dc9fSPaul E. McKenney /* Create the shuffler thread */ 201*3808dc9fSPaul E. McKenney shuffler_task = kthread_run(torture_shuffle, NULL, "torture_shuffle"); 202*3808dc9fSPaul E. McKenney if (IS_ERR(shuffler_task)) { 203*3808dc9fSPaul E. McKenney ret = PTR_ERR(shuffler_task); 204*3808dc9fSPaul E. McKenney free_cpumask_var(shuffle_tmp_mask); 205*3808dc9fSPaul E. McKenney VERBOSE_TOROUT_ERRSTRING("Failed to create shuffler"); 206*3808dc9fSPaul E. McKenney shuffler_task = NULL; 207*3808dc9fSPaul E. McKenney return ret; 208*3808dc9fSPaul E. McKenney } 209*3808dc9fSPaul E. McKenney torture_shuffle_task_register(shuffler_task); 210*3808dc9fSPaul E. McKenney return 0; 211*3808dc9fSPaul E. McKenney } 212*3808dc9fSPaul E. McKenney EXPORT_SYMBOL_GPL(torture_shuffle_init); 213*3808dc9fSPaul E. McKenney 214*3808dc9fSPaul E. McKenney /* 215*3808dc9fSPaul E. McKenney * Stop the shuffling. 216*3808dc9fSPaul E. McKenney */ 217*3808dc9fSPaul E. McKenney void torture_shuffle_cleanup(void) 218*3808dc9fSPaul E. McKenney { 219*3808dc9fSPaul E. McKenney torture_shuffle_task_unregister_all(); 220*3808dc9fSPaul E. McKenney if (shuffler_task) { 221*3808dc9fSPaul E. McKenney VERBOSE_TOROUT_STRING("Stopping torture_shuffle task"); 222*3808dc9fSPaul E. McKenney kthread_stop(shuffler_task); 223*3808dc9fSPaul E. McKenney free_cpumask_var(shuffle_tmp_mask); 224*3808dc9fSPaul E. McKenney } 225*3808dc9fSPaul E. McKenney shuffler_task = NULL; 226*3808dc9fSPaul E. McKenney } 227*3808dc9fSPaul E. McKenney EXPORT_SYMBOL_GPL(torture_shuffle_cleanup); 228*3808dc9fSPaul E. McKenney 229*3808dc9fSPaul E. McKenney /* 230f67a3356SPaul E. McKenney * Absorb kthreads into a kernel function that won't return, so that 231f67a3356SPaul E. McKenney * they won't ever access module text or data again. 232f67a3356SPaul E. McKenney */ 233f67a3356SPaul E. McKenney void torture_shutdown_absorb(const char *title) 234f67a3356SPaul E. McKenney { 235f67a3356SPaul E. McKenney while (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) { 236f67a3356SPaul E. McKenney pr_notice( 237f67a3356SPaul E. McKenney "torture thread %s parking due to system shutdown\n", 238f67a3356SPaul E. McKenney title); 239f67a3356SPaul E. McKenney schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT); 240f67a3356SPaul E. McKenney } 241f67a3356SPaul E. McKenney } 242f67a3356SPaul E. McKenney EXPORT_SYMBOL_GPL(torture_shutdown_absorb); 243