mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
Merge branch 'for-mingo-kcsan' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu into locking/core
Pull KCSAN changes from Paul E. McKenney: misc updates. Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
eedd634134
@ -1,3 +1,6 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
.. Copyright (C) 2019, Google LLC.
|
||||
|
||||
The Kernel Concurrency Sanitizer (KCSAN)
|
||||
========================================
|
||||
|
||||
|
@ -1,4 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* KCSAN access checks and modifiers. These can be used to explicitly check
|
||||
* uninstrumented accesses, or change KCSAN checking behaviour of accesses.
|
||||
*
|
||||
* Copyright (C) 2019, Google LLC.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_KCSAN_CHECKS_H
|
||||
#define _LINUX_KCSAN_CHECKS_H
|
||||
|
@ -1,4 +1,11 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* The Kernel Concurrency Sanitizer (KCSAN) infrastructure. Public interface and
|
||||
* data structures to set up runtime. See kcsan-checks.h for explicit checks and
|
||||
* modifiers. For more info please see Documentation/dev-tools/kcsan.rst.
|
||||
*
|
||||
* Copyright (C) 2019, Google LLC.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_KCSAN_H
|
||||
#define _LINUX_KCSAN_H
|
||||
|
@ -13,5 +13,5 @@ CFLAGS_core.o := $(call cc-option,-fno-conserve-stack) \
|
||||
obj-y := core.o debugfs.o report.o
|
||||
obj-$(CONFIG_KCSAN_SELFTEST) += selftest.o
|
||||
|
||||
CFLAGS_kcsan-test.o := $(CFLAGS_KCSAN) -g -fno-omit-frame-pointer
|
||||
obj-$(CONFIG_KCSAN_TEST) += kcsan-test.o
|
||||
CFLAGS_kcsan_test.o := $(CFLAGS_KCSAN) -g -fno-omit-frame-pointer
|
||||
obj-$(CONFIG_KCSAN_KUNIT_TEST) += kcsan_test.o
|
||||
|
@ -1,4 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Rules for implicitly atomic memory accesses.
|
||||
*
|
||||
* Copyright (C) 2019, Google LLC.
|
||||
*/
|
||||
|
||||
#ifndef _KERNEL_KCSAN_ATOMIC_H
|
||||
#define _KERNEL_KCSAN_ATOMIC_H
|
||||
|
@ -1,4 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* KCSAN core runtime.
|
||||
*
|
||||
* Copyright (C) 2019, Google LLC.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "kcsan: " fmt
|
||||
|
||||
@ -639,8 +644,6 @@ void __init kcsan_init(void)
|
||||
|
||||
BUG_ON(!in_task());
|
||||
|
||||
kcsan_debugfs_init();
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
per_cpu(kcsan_rand_state, cpu) = (u32)get_cycles();
|
||||
|
||||
|
@ -1,4 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* KCSAN debugfs interface.
|
||||
*
|
||||
* Copyright (C) 2019, Google LLC.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "kcsan: " fmt
|
||||
|
||||
@ -261,7 +266,9 @@ static const struct file_operations debugfs_ops =
|
||||
.release = single_release
|
||||
};
|
||||
|
||||
void __init kcsan_debugfs_init(void)
|
||||
static void __init kcsan_debugfs_init(void)
|
||||
{
|
||||
debugfs_create_file("kcsan", 0644, NULL, NULL, &debugfs_ops);
|
||||
}
|
||||
|
||||
late_initcall(kcsan_debugfs_init);
|
||||
|
@ -1,4 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* KCSAN watchpoint encoding.
|
||||
*
|
||||
* Copyright (C) 2019, Google LLC.
|
||||
*/
|
||||
|
||||
#ifndef _KERNEL_KCSAN_ENCODING_H
|
||||
#define _KERNEL_KCSAN_ENCODING_H
|
||||
|
@ -1,8 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/*
|
||||
* The Kernel Concurrency Sanitizer (KCSAN) infrastructure. For more info please
|
||||
* see Documentation/dev-tools/kcsan.rst.
|
||||
*
|
||||
* Copyright (C) 2019, Google LLC.
|
||||
*/
|
||||
|
||||
#ifndef _KERNEL_KCSAN_KCSAN_H
|
||||
@ -30,11 +31,6 @@ extern bool kcsan_enabled;
|
||||
void kcsan_save_irqtrace(struct task_struct *task);
|
||||
void kcsan_restore_irqtrace(struct task_struct *task);
|
||||
|
||||
/*
|
||||
* Initialize debugfs file.
|
||||
*/
|
||||
void kcsan_debugfs_init(void);
|
||||
|
||||
/*
|
||||
* Statistics counters displayed via debugfs; should only be modified in
|
||||
* slow-paths.
|
||||
|
@ -13,6 +13,8 @@
|
||||
* Author: Marco Elver <elver@google.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "kcsan_test: " fmt
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kcsan-checks.h>
|
||||
@ -951,22 +953,53 @@ static void test_atomic_builtins(struct kunit *test)
|
||||
}
|
||||
|
||||
/*
|
||||
* Each test case is run with different numbers of threads. Until KUnit supports
|
||||
* passing arguments for each test case, we encode #threads in the test case
|
||||
* name (read by get_num_threads()). [The '-' was chosen as a stylistic
|
||||
* preference to separate test name and #threads.]
|
||||
* Generate thread counts for all test cases. Values generated are in interval
|
||||
* [2, 5] followed by exponentially increasing thread counts from 8 to 32.
|
||||
*
|
||||
* The thread counts are chosen to cover potentially interesting boundaries and
|
||||
* corner cases (range 2-5), and then stress the system with larger counts.
|
||||
* corner cases (2 to 5), and then stress the system with larger counts.
|
||||
*/
|
||||
#define KCSAN_KUNIT_CASE(test_name) \
|
||||
{ .run_case = test_name, .name = #test_name "-02" }, \
|
||||
{ .run_case = test_name, .name = #test_name "-03" }, \
|
||||
{ .run_case = test_name, .name = #test_name "-04" }, \
|
||||
{ .run_case = test_name, .name = #test_name "-05" }, \
|
||||
{ .run_case = test_name, .name = #test_name "-08" }, \
|
||||
{ .run_case = test_name, .name = #test_name "-16" }
|
||||
static const void *nthreads_gen_params(const void *prev, char *desc)
|
||||
{
|
||||
long nthreads = (long)prev;
|
||||
|
||||
if (nthreads < 0 || nthreads >= 32)
|
||||
nthreads = 0; /* stop */
|
||||
else if (!nthreads)
|
||||
nthreads = 2; /* initial value */
|
||||
else if (nthreads < 5)
|
||||
nthreads++;
|
||||
else if (nthreads == 5)
|
||||
nthreads = 8;
|
||||
else
|
||||
nthreads *= 2;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_PREEMPT) || !IS_ENABLED(CONFIG_KCSAN_INTERRUPT_WATCHER)) {
|
||||
/*
|
||||
* Without any preemption, keep 2 CPUs free for other tasks, one
|
||||
* of which is the main test case function checking for
|
||||
* completion or failure.
|
||||
*/
|
||||
const long min_unused_cpus = IS_ENABLED(CONFIG_PREEMPT_NONE) ? 2 : 0;
|
||||
const long min_required_cpus = 2 + min_unused_cpus;
|
||||
|
||||
if (num_online_cpus() < min_required_cpus) {
|
||||
pr_err_once("Too few online CPUs (%u < %d) for test\n",
|
||||
num_online_cpus(), min_required_cpus);
|
||||
nthreads = 0;
|
||||
} else if (nthreads >= num_online_cpus() - min_unused_cpus) {
|
||||
/* Use negative value to indicate last param. */
|
||||
nthreads = -(num_online_cpus() - min_unused_cpus);
|
||||
pr_warn_once("Limiting number of threads to %ld (only %d online CPUs)\n",
|
||||
-nthreads, num_online_cpus());
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(desc, KUNIT_PARAM_DESC_SIZE, "threads=%ld", abs(nthreads));
|
||||
return (void *)nthreads;
|
||||
}
|
||||
|
||||
#define KCSAN_KUNIT_CASE(test_name) KUNIT_CASE_PARAM(test_name, nthreads_gen_params)
|
||||
static struct kunit_case kcsan_test_cases[] = {
|
||||
KCSAN_KUNIT_CASE(test_basic),
|
||||
KCSAN_KUNIT_CASE(test_concurrent_races),
|
||||
@ -996,24 +1029,6 @@ static struct kunit_case kcsan_test_cases[] = {
|
||||
|
||||
/* ===== End test cases ===== */
|
||||
|
||||
/* Get number of threads encoded in test name. */
|
||||
static bool __no_kcsan
|
||||
get_num_threads(const char *test, int *nthreads)
|
||||
{
|
||||
int len = strlen(test);
|
||||
|
||||
if (WARN_ON(len < 3))
|
||||
return false;
|
||||
|
||||
*nthreads = test[len - 1] - '0';
|
||||
*nthreads += (test[len - 2] - '0') * 10;
|
||||
|
||||
if (WARN_ON(*nthreads < 0))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Concurrent accesses from interrupts. */
|
||||
__no_kcsan
|
||||
static void access_thread_timer(struct timer_list *timer)
|
||||
@ -1076,9 +1091,6 @@ static int test_init(struct kunit *test)
|
||||
if (!torture_init_begin((char *)test->name, 1))
|
||||
return -EBUSY;
|
||||
|
||||
if (!get_num_threads(test->name, &nthreads))
|
||||
goto err;
|
||||
|
||||
if (WARN_ON(threads))
|
||||
goto err;
|
||||
|
||||
@ -1087,38 +1099,18 @@ static int test_init(struct kunit *test)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_PREEMPT) || !IS_ENABLED(CONFIG_KCSAN_INTERRUPT_WATCHER)) {
|
||||
/*
|
||||
* Without any preemption, keep 2 CPUs free for other tasks, one
|
||||
* of which is the main test case function checking for
|
||||
* completion or failure.
|
||||
*/
|
||||
const int min_unused_cpus = IS_ENABLED(CONFIG_PREEMPT_NONE) ? 2 : 0;
|
||||
const int min_required_cpus = 2 + min_unused_cpus;
|
||||
nthreads = abs((long)test->param_value);
|
||||
if (WARN_ON(!nthreads))
|
||||
goto err;
|
||||
|
||||
if (num_online_cpus() < min_required_cpus) {
|
||||
pr_err("%s: too few online CPUs (%u < %d) for test",
|
||||
test->name, num_online_cpus(), min_required_cpus);
|
||||
threads = kcalloc(nthreads + 1, sizeof(struct task_struct *), GFP_KERNEL);
|
||||
if (WARN_ON(!threads))
|
||||
goto err;
|
||||
|
||||
threads[nthreads] = NULL;
|
||||
for (i = 0; i < nthreads; ++i) {
|
||||
if (torture_create_kthread(access_thread, NULL, threads[i]))
|
||||
goto err;
|
||||
} else if (nthreads > num_online_cpus() - min_unused_cpus) {
|
||||
nthreads = num_online_cpus() - min_unused_cpus;
|
||||
pr_warn("%s: limiting number of threads to %d\n",
|
||||
test->name, nthreads);
|
||||
}
|
||||
}
|
||||
|
||||
if (nthreads) {
|
||||
threads = kcalloc(nthreads + 1, sizeof(struct task_struct *),
|
||||
GFP_KERNEL);
|
||||
if (WARN_ON(!threads))
|
||||
goto err;
|
||||
|
||||
threads[nthreads] = NULL;
|
||||
for (i = 0; i < nthreads; ++i) {
|
||||
if (torture_create_kthread(access_thread, NULL,
|
||||
threads[i]))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
torture_init_end();
|
||||
@ -1156,7 +1148,7 @@ static void test_exit(struct kunit *test)
|
||||
}
|
||||
|
||||
static struct kunit_suite kcsan_test_suite = {
|
||||
.name = "kcsan-test",
|
||||
.name = "kcsan",
|
||||
.test_cases = kcsan_test_cases,
|
||||
.init = test_init,
|
||||
.exit = test_exit,
|
@ -1,4 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* KCSAN reporting.
|
||||
*
|
||||
* Copyright (C) 2019, Google LLC.
|
||||
*/
|
||||
|
||||
#include <linux/debug_locks.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -1,4 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* KCSAN short boot-time selftests.
|
||||
*
|
||||
* Copyright (C) 2019, Google LLC.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "kcsan: " fmt
|
||||
|
||||
|
@ -69,8 +69,9 @@ config KCSAN_SELFTEST
|
||||
panic. Recommended to be enabled, ensuring critical functionality
|
||||
works as intended.
|
||||
|
||||
config KCSAN_TEST
|
||||
tristate "KCSAN test for integrated runtime behaviour"
|
||||
config KCSAN_KUNIT_TEST
|
||||
tristate "KCSAN test for integrated runtime behaviour" if !KUNIT_ALL_TESTS
|
||||
default KUNIT_ALL_TESTS
|
||||
depends on TRACEPOINTS && KUNIT
|
||||
select TORTURE_TEST
|
||||
help
|
||||
|
Loading…
Reference in New Issue
Block a user