static cpumask_var_t bind_readers; // Bind the readers to the specified set of CPUs. static cpumask_var_t bind_writers; // Bind the writers to the specified set of CPUs.
// Parse a cpumask kernel parameter. If there are more users later on, // this might need to got to a more central location. staticint param_set_cpumask(constchar *val, conststruct kernel_param *kp)
{
cpumask_var_t *cm_bind = kp->arg; int ret; char *s;
if (!alloc_cpumask_var(cm_bind, GFP_KERNEL)) {
s = "Out of memory";
ret = -ENOMEM; goto out_err;
}
ret = cpulist_parse(val, *cm_bind); if (!ret) return ret;
s = "Bad CPU range";
out_err:
pr_warn("%s: %s, all CPUs set\n", kp->name, s);
cpumask_setall(*cm_bind); return ret;
}
staticint torture_lock_busted_write_lock(int tid __maybe_unused)
{ return0; /* BUGGY, do not use in real life!!! */
}
staticvoid torture_lock_busted_write_delay(struct torture_random_state *trsp)
{ /* We want a long delay occasionally to force massive contention. */ if (long_hold && !(torture_random(trsp) % (cxt.nrealwriters_stress * 2000 * long_hold)))
mdelay(long_hold); if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
torture_preempt_schedule(); /* Allow test to be preempted. */
}
staticvoid torture_lock_busted_write_unlock(int tid __maybe_unused)
{ /* BUGGY, do not use in real life!!! */
}
/* We want a short delay mostly to emulate likely code, and *wewantalongdelayoccasionallytoforcemassivecontention.
*/ if (long_hold && !(torture_random(trsp) % (cxt.nrealwriters_stress * 2000 * long_hold)))
mdelay(long_hold); else
udelay(shortdelay_us);
}
staticvoid torture_rwlock_write_unlock(int tid __maybe_unused)
__releases(torture_rwlock)
{
write_unlock(&torture_rwlock);
}
staticint torture_rwlock_read_lock(int tid __maybe_unused)
__acquires(torture_rwlock)
{
read_lock(&torture_rwlock); return0;
}
/* We want a short delay mostly to emulate likely code, and *wewantalongdelayoccasionallytoforcemassivecontention.
*/ if (long_hold && !(torture_random(trsp) % (cxt.nrealreaders_stress * 2000 * long_hold)))
mdelay(long_hold); else
udelay(shortdelay_us);
}
staticvoid torture_rwlock_read_unlock(int tid __maybe_unused)
__releases(torture_rwlock)
{
read_unlock(&torture_rwlock);
}
for (i = 0; i < MAX_NESTED_LOCKS; i++)
__mutex_init(&torture_nested_mutexes[i], __func__,
&nested_mutex_keys[i]);
}
staticint torture_mutex_nested_lock(int tid __maybe_unused,
u32 lockset)
{ int i;
for (i = 0; i < nested_locks; i++) if (lockset & (1 << i))
mutex_lock(&torture_nested_mutexes[i]); return0;
}
staticint torture_mutex_lock(int tid __maybe_unused)
__acquires(torture_mutex)
{
mutex_lock(&torture_mutex); return0;
}
staticvoid torture_mutex_delay(struct torture_random_state *trsp)
{ /* We want a long delay occasionally to force massive contention. */ if (long_hold && !(torture_random(trsp) % (cxt.nrealwriters_stress * 2000 * long_hold)))
mdelay(long_hold * 5); if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
torture_preempt_schedule(); /* Allow test to be preempted. */
}
staticvoid torture_mutex_unlock(int tid __maybe_unused)
__releases(torture_mutex)
{
mutex_unlock(&torture_mutex);
}
staticvoid torture_mutex_nested_unlock(int tid __maybe_unused,
u32 lockset)
{ int i;
for (i = nested_locks - 1; i >= 0; i--) if (lockset & (1 << i))
mutex_unlock(&torture_nested_mutexes[i]);
}
ww_acquire_ctxs = kmalloc_array(cxt.nrealwriters_stress, sizeof(*ww_acquire_ctxs),
GFP_KERNEL); if (!ww_acquire_ctxs)
VERBOSE_TOROUT_STRING("ww_acquire_ctx: Out of memory");
}
staticvoid torture_rwsem_write_delay(struct torture_random_state *trsp)
{ /* We want a long delay occasionally to force massive contention. */ if (long_hold && !(torture_random(trsp) % (cxt.nrealwriters_stress * 2000 * long_hold)))
mdelay(long_hold * 10); if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
torture_preempt_schedule(); /* Allow test to be preempted. */
}
staticvoid torture_rwsem_up_write(int tid __maybe_unused)
__releases(torture_rwsem)
{
up_write(&torture_rwsem);
}
staticint torture_rwsem_down_read(int tid __maybe_unused)
__acquires(torture_rwsem)
{
down_read(&torture_rwsem); return0;
}
staticvoid torture_rwsem_read_delay(struct torture_random_state *trsp)
{ /* We want a long delay occasionally to force massive contention. */ if (long_hold && !(torture_random(trsp) % (cxt.nrealreaders_stress * 2000 * long_hold)))
mdelay(long_hold * 2); else
mdelay(long_hold / 2); if (!(torture_random(trsp) % (cxt.nrealreaders_stress * 20000)))
torture_preempt_schedule(); /* Allow test to be preempted. */
}
staticvoid torture_rwsem_up_read(int tid __maybe_unused)
__releases(torture_rwsem)
{
up_read(&torture_rwsem);
}
// If requested, maintain call_rcu() chains to keep a grace period always // in flight. These increase the probability of getting an RCU CPU stall // warning and associated diagnostics when a locking primitive stalls.
if (!smp_load_acquire(&crcp->crc_stop)) {
(void)start_poll_synchronize_rcu(); // Start one grace period...
call_rcu(&crcp->crc_rh, call_rcu_chain_cb); // ... and later start another.
}
}
// Start the requested number of call_rcu() chains. staticint call_rcu_chain_init(void)
{ int i;
if (call_rcu_chains <= 0) return0;
call_rcu_chain_list = kcalloc(call_rcu_chains, sizeof(*call_rcu_chain_list), GFP_KERNEL); if (!call_rcu_chain_list) return -ENOMEM; for (i = 0; i < call_rcu_chains; i++) {
call_rcu_chain_list[i].crc_stop = false;
call_rcu(&call_rcu_chain_list[i].crc_rh, call_rcu_chain_cb);
} return0;
}
// Stop all of the call_rcu() chains. staticvoid call_rcu_chain_cleanup(void)
{ int i;
if (!call_rcu_chain_list) return; for (i = 0; i < call_rcu_chains; i++)
smp_store_release(&call_rcu_chain_list[i].crc_stop, true);
rcu_barrier();
kfree(call_rcu_chain_list);
call_rcu_chain_list = NULL;
}
if (writer_tasks) { for (i = 0; i < cxt.nrealwriters_stress; i++)
torture_stop_kthread(lock_torture_writer, writer_tasks[i]);
kfree(writer_tasks);
writer_tasks = NULL;
}
if (reader_tasks) { for (i = 0; i < cxt.nrealreaders_stress; i++)
torture_stop_kthread(lock_torture_reader,
reader_tasks[i]);
kfree(reader_tasks);
reader_tasks = NULL;
}
torture_stop_kthread(lock_torture_stats, stats_task);
lock_torture_stats_print(); /* -After- the stats thread is stopped! */
if (atomic_read(&cxt.n_lock_torture_errors))
lock_torture_print_module_parms(cxt.cur_ops, "End of test: FAILURE"); elseif (torture_onoff_failures())
lock_torture_print_module_parms(cxt.cur_ops, "End of test: LOCK_HOTPLUG"); else
lock_torture_print_module_parms(cxt.cur_ops, "End of test: SUCCESS");
if (!torture_init_begin(torture_type, verbose)) return -EBUSY;
/* Process args and tell the world that the torturer is on the job. */ for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
cxt.cur_ops = torture_ops[i]; if (strcmp(torture_type, cxt.cur_ops->name) == 0) break;
} if (i == ARRAY_SIZE(torture_ops)) {
pr_alert("lock-torture: invalid torture type: \"%s\"\n",
torture_type);
pr_alert("lock-torture types:"); for (i = 0; i < ARRAY_SIZE(torture_ops); i++)
pr_alert(" %s", torture_ops[i]->name);
pr_alert("\n");
firsterr = -EINVAL; goto unwind;
}
if (nwriters_stress == 0 &&
(!cxt.cur_ops->readlock || nreaders_stress == 0)) {
pr_alert("lock-torture: must run at least one locking thread\n");
firsterr = -EINVAL; goto unwind;
}
if (cxt.cur_ops->init) {
cxt.cur_ops->init();
cxt.init_called = true;
}
#ifdef CONFIG_DEBUG_MUTEXES if (str_has_prefix(torture_type, "mutex"))
cxt.debug_lock = true; #endif #ifdef CONFIG_DEBUG_RT_MUTEXES if (str_has_prefix(torture_type, "rtmutex"))
cxt.debug_lock = true; #endif #ifdef CONFIG_DEBUG_SPINLOCK if ((str_has_prefix(torture_type, "spin")) ||
(str_has_prefix(torture_type, "rw_lock")))
cxt.debug_lock = true; #endif
/* Initialize the statistics so that each run gets its own numbers. */ if (nwriters_stress) {
lock_is_write_held = false;
cxt.lwsa = kmalloc_array(cxt.nrealwriters_stress, sizeof(*cxt.lwsa),
GFP_KERNEL); if (cxt.lwsa == NULL) {
VERBOSE_TOROUT_STRING("cxt.lwsa: Out of memory");
firsterr = -ENOMEM; goto unwind;
}
for (i = 0; i < cxt.nrealwriters_stress; i++) {
cxt.lwsa[i].n_lock_fail = 0;
cxt.lwsa[i].n_lock_acquired = 0;
}
}
if (cxt.cur_ops->readlock) { if (nreaders_stress >= 0)
cxt.nrealreaders_stress = nreaders_stress; else { /* *Bydefaultdistributeevenlythenumberof *readersandwriters.Westillrunthesamenumber *ofthreadsasthewriter-onlylocksdefault.
*/ if (nwriters_stress < 0) /* user doesn't care */
cxt.nrealwriters_stress = num_online_cpus();
cxt.nrealreaders_stress = cxt.nrealwriters_stress;
}
if (nreaders_stress) {
cxt.lrsa = kmalloc_array(cxt.nrealreaders_stress, sizeof(*cxt.lrsa),
GFP_KERNEL); if (cxt.lrsa == NULL) {
VERBOSE_TOROUT_STRING("cxt.lrsa: Out of memory");
firsterr = -ENOMEM;
kfree(cxt.lwsa);
cxt.lwsa = NULL; goto unwind;
}
for (i = 0; i < cxt.nrealreaders_stress; i++) {
cxt.lrsa[i].n_lock_fail = 0;
cxt.lrsa[i].n_lock_acquired = 0;
}
}
}
firsterr = call_rcu_chain_init(); if (torture_init_error(firsterr)) goto unwind;
lock_torture_print_module_parms(cxt.cur_ops, "Start of test");
/* Prepare torture context. */ if (onoff_interval > 0) {
firsterr = torture_onoff_init(onoff_holdoff * HZ,
onoff_interval * HZ, NULL); if (torture_init_error(firsterr)) goto unwind;
} if (shuffle_interval > 0) {
firsterr = torture_shuffle_init(shuffle_interval); if (torture_init_error(firsterr)) goto unwind;
} if (shutdown_secs > 0) {
firsterr = torture_shutdown_init(shutdown_secs,
lock_torture_cleanup); if (torture_init_error(firsterr)) goto unwind;
} if (stutter > 0) {
firsterr = torture_stutter_init(stutter, stutter); if (torture_init_error(firsterr)) goto unwind;
}
if (nwriters_stress) {
writer_tasks = kcalloc(cxt.nrealwriters_stress, sizeof(writer_tasks[0]),
GFP_KERNEL); if (writer_tasks == NULL) {
TOROUT_ERRSTRING("writer_tasks: Out of memory");
firsterr = -ENOMEM; goto unwind;
}
}
/* cap nested_locks to MAX_NESTED_LOCKS */ if (nested_locks > MAX_NESTED_LOCKS)
nested_locks = MAX_NESTED_LOCKS;
if (cxt.cur_ops->readlock) {
reader_tasks = kcalloc(cxt.nrealreaders_stress, sizeof(reader_tasks[0]),
GFP_KERNEL); if (reader_tasks == NULL) {
TOROUT_ERRSTRING("reader_tasks: Out of memory");
kfree(writer_tasks);
writer_tasks = NULL;
firsterr = -ENOMEM; goto unwind;
}
}
/* *Createthekthreadsandstarttorturing(oh,thosepoorlittlelocks). * *TODO:Notethatweinterleavewriterswithreaders,givingwritersa *slightadvantage,bycreatingitskthreadfirst.Thiscanbemodified *forveryspecificneeds,orevenlettheuserchoosethepolicy,if *everwanted.
*/ for (i = 0, j = 0; i < cxt.nrealwriters_stress ||
j < cxt.nrealreaders_stress; i++, j++) { if (i >= cxt.nrealwriters_stress) goto create_reader;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.