summaryrefslogtreecommitdiffstats
path: root/tools/testing
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing')
-rwxr-xr-xtools/testing/ktest/ktest.pl581
-rw-r--r--tools/testing/ktest/sample.conf65
-rw-r--r--tools/testing/selftests/Makefile20
-rw-r--r--tools/testing/selftests/README.txt27
-rw-r--r--tools/testing/selftests/cpu-hotplug/Makefile3
-rw-r--r--tools/testing/selftests/cpu-hotplug/on-off-test.sh52
-rw-r--r--tools/testing/selftests/firmware/Makefile27
-rw-r--r--tools/testing/selftests/firmware/fw_filesystem.sh62
-rw-r--r--tools/testing/selftests/firmware/fw_userhelper.sh89
-rw-r--r--tools/testing/selftests/kcmp/kcmp_test.c2
-rw-r--r--tools/testing/selftests/memfd/.gitignore4
-rw-r--r--tools/testing/selftests/memfd/Makefile41
-rw-r--r--tools/testing/selftests/memfd/fuse_mnt.c110
-rw-r--r--tools/testing/selftests/memfd/fuse_test.c311
-rw-r--r--tools/testing/selftests/memfd/memfd_test.c913
-rw-r--r--tools/testing/selftests/memfd/run_fuse_test.sh14
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile3
-rw-r--r--tools/testing/selftests/memory-hotplug/on-off-test.sh8
-rw-r--r--tools/testing/selftests/mqueue/Makefile4
-rw-r--r--tools/testing/selftests/mqueue/mq_open_tests.c20
-rw-r--r--tools/testing/selftests/mqueue/mq_perf_tests.c40
-rw-r--r--tools/testing/selftests/powerpc/Makefile10
-rw-r--r--tools/testing/selftests/powerpc/pmu/Makefile19
-rw-r--r--tools/testing/selftests/powerpc/pmu/count_instructions.c30
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/Makefile5
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S271
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c91
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.c261
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.h1
-rw-r--r--tools/testing/selftests/powerpc/pmu/l3_bank_test.c48
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.c50
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.h1
-rw-r--r--tools/testing/selftests/powerpc/pmu/per_event_excludes.c114
-rw-r--r--tools/testing/selftests/ptrace/peeksiginfo.c4
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-recheck.sh8
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh9
-rw-r--r--tools/testing/selftests/rcutorture/bin/kvm.sh21
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE011
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE021
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE02-T1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE031
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE041
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE051
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE061
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE071
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE081
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08-T1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE091
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp1
-rw-r--r--tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt1
53 files changed, 2660 insertions, 695 deletions
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 40631569a0fd..55ab700f6ba5 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -72,7 +72,7 @@ my %default = (
"IGNORE_UNUSED" => 0,
);
-my $ktest_config;
+my $ktest_config = "ktest.conf";
my $version;
my $have_version = 0;
my $machine;
@@ -149,7 +149,6 @@ my $bisect_ret_abort;
my $bisect_ret_default;
my $in_patchcheck = 0;
my $run_test;
-my $redirect;
my $buildlog;
my $testlog;
my $dmesg;
@@ -522,7 +521,7 @@ sub read_ync {
return read_prompt 1, $prompt;
}
-sub get_ktest_config {
+sub get_mandatory_config {
my ($config) = @_;
my $ans;
@@ -553,29 +552,29 @@ sub get_ktest_config {
}
}
-sub get_ktest_configs {
- get_ktest_config("MACHINE");
- get_ktest_config("BUILD_DIR");
- get_ktest_config("OUTPUT_DIR");
+sub get_mandatory_configs {
+ get_mandatory_config("MACHINE");
+ get_mandatory_config("BUILD_DIR");
+ get_mandatory_config("OUTPUT_DIR");
if ($newconfig) {
- get_ktest_config("BUILD_OPTIONS");
+ get_mandatory_config("BUILD_OPTIONS");
}
# options required for other than just building a kernel
if (!$buildonly) {
- get_ktest_config("POWER_CYCLE");
- get_ktest_config("CONSOLE");
+ get_mandatory_config("POWER_CYCLE");
+ get_mandatory_config("CONSOLE");
}
# options required for install and more
if ($buildonly != 1) {
- get_ktest_config("SSH_USER");
- get_ktest_config("BUILD_TARGET");
- get_ktest_config("TARGET_IMAGE");
+ get_mandatory_config("SSH_USER");
+ get_mandatory_config("BUILD_TARGET");
+ get_mandatory_config("TARGET_IMAGE");
}
- get_ktest_config("LOCALVERSION");
+ get_mandatory_config("LOCALVERSION");
return if ($buildonly);
@@ -583,7 +582,7 @@ sub get_ktest_configs {
if (!defined($rtype)) {
if (!defined($opt{"GRUB_MENU"})) {
- get_ktest_config("REBOOT_TYPE");
+ get_mandatory_config("REBOOT_TYPE");
$rtype = $entered_configs{"REBOOT_TYPE"};
} else {
$rtype = "grub";
@@ -591,16 +590,16 @@ sub get_ktest_configs {
}
if ($rtype eq "grub") {
- get_ktest_config("GRUB_MENU");
+ get_mandatory_config("GRUB_MENU");
}
if ($rtype eq "grub2") {
- get_ktest_config("GRUB_MENU");
- get_ktest_config("GRUB_FILE");
+ get_mandatory_config("GRUB_MENU");
+ get_mandatory_config("GRUB_FILE");
}
if ($rtype eq "syslinux") {
- get_ktest_config("SYSLINUX_LABEL");
+ get_mandatory_config("SYSLINUX_LABEL");
}
}
@@ -1090,7 +1089,7 @@ sub read_config {
$test_case = __read_config $config, \$test_num;
# make sure we have all mandatory configs
- get_ktest_configs;
+ get_mandatory_configs;
# was a test specified?
if (!$test_case) {
@@ -1529,7 +1528,7 @@ sub fail {
}
sub run_command {
- my ($command) = @_;
+ my ($command, $redirect) = @_;
my $dolog = 0;
my $dord = 0;
my $pid;
@@ -2265,9 +2264,7 @@ sub build {
# Run old config regardless, to enforce min configurations
make_oldconfig;
- $redirect = "$buildlog";
- my $build_ret = run_command "$make $build_options";
- undef $redirect;
+ my $build_ret = run_command "$make $build_options", $buildlog;
if (defined($post_build)) {
# Because a post build may change the kernel version
@@ -2360,9 +2357,7 @@ sub child_run_test {
$poweroff_on_error = 0;
$die_on_failure = 1;
- $redirect = "$testlog";
- run_command $run_test or $failed = 1;
- undef $redirect;
+ run_command $run_test, $testlog or $failed = 1;
exit $failed;
}
@@ -2789,12 +2784,17 @@ my %dependency;
sub assign_configs {
my ($hash, $config) = @_;
+ doprint "Reading configs from $config\n";
+
open (IN, $config)
or dodie "Failed to read $config";
while (<IN>) {
+ chomp;
if (/^((CONFIG\S*)=.*)/) {
${$hash}{$2} = $1;
+ } elsif (/^(# (CONFIG\S*) is not set)/) {
+ ${$hash}{$2} = $1;
}
}
@@ -2807,27 +2807,6 @@ sub process_config_ignore {
assign_configs \%config_ignore, $config;
}
-sub read_current_config {
- my ($config_ref) = @_;
-
- %{$config_ref} = ();
- undef %{$config_ref};
-
- my @key = keys %{$config_ref};
- if ($#key >= 0) {
- print "did not delete!\n";
- exit;
- }
- open (IN, "$output_config");
-
- while (<IN>) {
- if (/^(CONFIG\S+)=(.*)/) {
- ${$config_ref}{$1} = $2;
- }
- }
- close(IN);
-}
-
sub get_dependencies {
my ($config) = @_;
@@ -2846,53 +2825,97 @@ sub get_dependencies {
return @deps;
}
+sub save_config {
+ my ($pc, $file) = @_;
+
+ my %configs = %{$pc};
+
+ doprint "Saving configs into $file\n";
+
+ open(OUT, ">$file") or dodie "Can not write to $file";
+
+ foreach my $config (keys %configs) {
+ print OUT "$configs{$config}\n";
+ }
+ close(OUT);
+}
+
sub create_config {
- my @configs = @_;
+ my ($name, $pc) = @_;
- open(OUT, ">$output_config") or dodie "Can not write to $output_config";
+ doprint "Creating old config from $name configs\n";
- foreach my $config (@configs) {
- print OUT "$config_set{$config}\n";
- my @deps = get_dependencies $config;
- foreach my $dep (@deps) {
- print OUT "$config_set{$dep}\n";
+ save_config $pc, $output_config;
+
+ make_oldconfig;
+}
+
+# compare two config hashes, and return configs with different vals.
+# It returns B's config values, but you can use A to see what A was.
+sub diff_config_vals {
+ my ($pa, $pb) = @_;
+
+ # crappy Perl way to pass in hashes.
+ my %a = %{$pa};
+ my %b = %{$pb};
+
+ my %ret;
+
+ foreach my $item (keys %a) {
+ if (defined($b{$item}) && $b{$item} ne $a{$item}) {
+ $ret{$item} = $b{$item};
}
}
- # turn off configs to keep off
- foreach my $config (keys %config_off) {
- print OUT "# $config is not set\n";
- }
+ return %ret;
+}
- # turn off configs that should be off for now
- foreach my $config (@config_off_tmp) {
- print OUT "# $config is not set\n";
- }
+# compare two config hashes and return the configs in B but not A
+sub diff_configs {
+ my ($pa, $pb) = @_;
+
+ my %ret;
+
+ # crappy Perl way to pass in hashes.
+ my %a = %{$pa};
+ my %b = %{$pb};
- foreach my $config (keys %config_ignore) {
- print OUT "$config_ignore{$config}\n";
+ foreach my $item (keys %b) {
+ if (!defined($a{$item})) {
+ $ret{$item} = $b{$item};
+ }
}
- close(OUT);
- make_oldconfig;
+ return %ret;
}
+# return if two configs are equal or not
+# 0 is equal +1 b has something a does not
+# +1 if a and b have a different item.
+# -1 if a has something b does not
sub compare_configs {
- my (%a, %b) = @_;
+ my ($pa, $pb) = @_;
- foreach my $item (keys %a) {
- if (!defined($b{$item})) {
- print "diff $item\n";
+ my %ret;
+
+ # crappy Perl way to pass in hashes.
+ my %a = %{$pa};
+ my %b = %{$pb};
+
+ foreach my $item (keys %b) {
+ if (!defined($a{$item})) {
+ return 1;
+ }
+ if ($a{$item} ne $b{$item}) {
return 1;
}
- delete $b{$item};
}
- my @keys = keys %b;
- if ($#keys) {
- print "diff2 $keys[0]\n";
+ foreach my $item (keys %a) {
+ if (!defined($b{$item})) {
+ return -1;
+ }
}
- return -1 if ($#keys >= 0);
return 0;
}
@@ -2900,24 +2923,13 @@ sub compare_configs {
sub run_config_bisect_test {
my ($type) = @_;
- return run_bisect_test $type, "oldconfig";
-}
+ my $ret = run_bisect_test $type, "oldconfig";
-sub process_passed {
- my (%configs) = @_;
-
- doprint "These configs had no failure: (Enabling them for further compiles)\n";
- # Passed! All these configs are part of a good compile.
- # Add them to the min options.
- foreach my $config (keys %configs) {
- if (defined($config_list{$config})) {
- doprint " removing $config\n";
- $config_ignore{$config} = $config_list{$config};
- delete $config_list{$config};
- }
+ if ($bisect_manual) {
+ $ret = answer_bisect;
}
- doprint "config copied to $outputdir/config_good\n";
- run_command "cp -f $output_config $outputdir/config_good";
+
+ return $ret;
}
sub process_failed {
@@ -2928,253 +2940,225 @@ sub process_failed {
doprint "***************************************\n\n";
}
-sub run_config_bisect {
+# used for config bisecting
+my $good_config;
+my $bad_config;
- my @start_list = keys %config_list;
+sub process_new_config {
+ my ($tc, $nc, $gc, $bc) = @_;
- if ($#start_list < 0) {
- doprint "No more configs to test!!!\n";
- return -1;
+ my %tmp_config = %{$tc};
+ my %good_configs = %{$gc};
+ my %bad_configs = %{$bc};
+
+ my %new_configs;
+
+ my $runtest = 1;
+ my $ret;
+
+ create_config "tmp_configs", \%tmp_config;
+ assign_configs \%new_configs, $output_config;
+
+ $ret = compare_configs \%new_configs, \%bad_configs;
+ if (!$ret) {
+ doprint "New config equals bad config, try next test\n";
+ $runtest = 0;
+ }
+
+ if ($runtest) {
+ $ret = compare_configs \%new_configs, \%good_configs;
+ if (!$ret) {
+ doprint "New config equals good config, try next test\n";
+ $runtest = 0;
+ }
}
- doprint "***** RUN TEST ***\n";
+ %{$nc} = %new_configs;
+
+ return $runtest;
+}
+
+sub run_config_bisect {
+ my ($pgood, $pbad) = @_;
+
my $type = $config_bisect_type;
+
+ my %good_configs = %{$pgood};
+ my %bad_configs = %{$pbad};
+
+ my %diff_configs = diff_config_vals \%good_configs, \%bad_configs;
+ my %b_configs = diff_configs \%good_configs, \%bad_configs;
+ my %g_configs = diff_configs \%bad_configs, \%good_configs;
+
+ my @diff_arr = keys %diff_configs;
+ my $len_diff = $#diff_arr + 1;
+
+ my @b_arr = keys %b_configs;
+ my $len_b = $#b_arr + 1;
+
+ my @g_arr = keys %g_configs;
+ my $len_g = $#g_arr + 1;
+
+ my $runtest = 1;
+ my %new_configs;
my $ret;
- my %current_config;
- my $count = $#start_list + 1;
- doprint " $count configs to test\n";
+ # First, lets get it down to a single subset.
+ # Is the problem with a difference in values?
+ # Is the problem with a missing config?
+ # Is the problem with a config that breaks things?
- my $half = int($#start_list / 2);
+ # Enable all of one set and see if we get a new bad
+ # or good config.
- do {
- my @tophalf = @start_list[0 .. $half];
+ # first set the good config to the bad values.
- # keep the bottom half off
- if ($half < $#start_list) {
- @config_off_tmp = @start_list[$half + 1 .. $#start_list];
- } else {
- @config_off_tmp = ();
- }
+ doprint "d=$len_diff g=$len_g b=$len_b\n";
- create_config @tophalf;
- read_current_config \%current_config;
-
- $count = $#tophalf + 1;
- doprint "Testing $count configs\n";
- my $found = 0;
- # make sure we test something
- foreach my $config (@tophalf) {
- if (defined($current_config{$config})) {
- logit " $config\n";
- $found = 1;
- }
- }
- if (!$found) {
- # try the other half
- doprint "Top half produced no set configs, trying bottom half\n";
-
- # keep the top half off
- @config_off_tmp = @tophalf;
- @tophalf = @start_list[$half + 1 .. $#start_list];
-
- create_config @tophalf;
- read_current_config \%current_config;
- foreach my $config (@tophalf) {
- if (defined($current_config{$config})) {
- logit " $config\n";
- $found = 1;
- }
- }
- if (!$found) {
- doprint "Failed: Can't make new config with current configs\n";
- foreach my $config (@start_list) {
- doprint " CONFIG: $config\n";
- }
- return -1;
+ # first lets enable things in bad config that are enabled in good config
+
+ if ($len_diff > 0) {
+ if ($len_b > 0 || $len_g > 0) {
+ my %tmp_config = %bad_configs;
+
+ doprint "Set tmp config to be bad config with good config values\n";
+ foreach my $item (@diff_arr) {
+ $tmp_config{$item} = $good_configs{$item};
}
- $count = $#tophalf + 1;
- doprint "Testing $count configs\n";
- }
- $ret = run_config_bisect_test $type;
- if ($bisect_manual) {
- $ret = answer_bisect;
- }
- if ($ret) {
- process_passed %current_config;
- return 0;
+ $runtest = process_new_config \%tmp_config, \%new_configs,
+ \%good_configs, \%bad_configs;
}
+ }
- doprint "This config had a failure.\n";
- doprint "Removing these configs that were not set in this config:\n";
- doprint "config copied to $outputdir/config_bad\n";
- run_command "cp -f $output_config $outputdir/config_bad";
+ if (!$runtest && $len_diff > 0) {
- # A config exists in this group that was bad.
- foreach my $config (keys %config_list) {
- if (!defined($current_config{$config})) {
- doprint " removing $config\n";
- delete $config_list{$config};
- }
+ if ($len_diff == 1) {
+ process_failed $diff_arr[0];
+ return 1;
}
+ my %tmp_config = %bad_configs;
- @start_list = @tophalf;
+ my $half = int($#diff_arr / 2);
+ my @tophalf = @diff_arr[0 .. $half];
- if ($#start_list == 0) {
- process_failed $start_list[0];
- return 1;
+ doprint "Settings bisect with top half:\n";
+ doprint "Set tmp config to be bad config with some good config values\n";
+ foreach my $item (@tophalf) {
+ $tmp_config{$item} = $good_configs{$item};
}
- # remove half the configs we are looking at and see if
- # they are good.
- $half = int($#start_list / 2);
- } while ($#start_list > 0);
+ $runtest = process_new_config \%tmp_config, \%new_configs,
+ \%good_configs, \%bad_configs;
- # we found a single config, try it again unless we are running manually
+ if (!$runtest) {
+ my %tmp_config = %bad_configs;
- if ($bisect_manual) {
- process_failed $start_list[0];
- return 1;
- }
+ doprint "Try bottom half\n";
- my @tophalf = @start_list[0 .. 0];
+ my @bottomhalf = @diff_arr[$half+1 .. $#diff_arr];
- $ret = run_config_bisect_test $type;
- if ($ret) {
- process_passed %current_config;
+ foreach my $item (@bottomhalf) {
+ $tmp_config{$item} = $good_configs{$item};
+ }
+
+ $runtest = process_new_config \%tmp_config, \%new_configs,
+ \%good_configs, \%bad_configs;
+ }
+ }
+
+ if ($runtest) {
+ $ret = run_config_bisect_test $type;
+ if ($ret) {
+ doprint "NEW GOOD CONFIG\n";
+ %good_configs = %new_configs;
+ run_command "mv $good_config ${good_config}.last";
+ save_config \%good_configs, $good_config;
+ %{$pgood} = %good_configs;
+ } else {
+ doprint "NEW BAD CONFIG\n";
+ %bad_configs = %new_configs;
+ run_command "mv $bad_config ${bad_config}.last";
+ save_config \%bad_configs, $bad_config;
+ %{$pbad} = %bad_configs;
+ }
return 0;
}
- process_failed $start_list[0];
- return 1;
+ fail "Hmm, need to do a mix match?\n";
+ return -1;
}
sub config_bisect {
my ($i) = @_;
- my $start_config = $config_bisect;
+ my $type = $config_bisect_type;
+ my $ret;
- my $tmpconfig = "$tmpdir/use_config";
+ $bad_config = $config_bisect;
if (defined($config_bisect_good)) {
- process_config_ignore $config_bisect_good;
- }
-
- # Make the file with the bad config and the min config
- if (defined($minconfig)) {
- # read the min config for things to ignore
- run_command "cp $minconfig $tmpconfig" or
- dodie "failed to copy $minconfig to $tmpconfig";
+ $good_config = $config_bisect_good;
+ } elsif (defined($minconfig)) {
+ $good_config = $minconfig;
} else {
- unlink $tmpconfig;
- }
-
- if (-f $tmpconfig) {
- load_force_config($tmpconfig);
- process_config_ignore $tmpconfig;
- }
-
- # now process the start config
- run_command "cp $start_config $output_config" or
- dodie "failed to copy $start_config to $output_config";
-
- # read directly what we want to check
- my %config_check;
- open (IN, $output_config)
- or dodie "failed to open $output_config";
-
- while (<IN>) {
- if (/^((CONFIG\S*)=.*)/) {
- $config_check{$2} = $1;
+ doprint "No config specified, checking if defconfig works";
+ $ret = run_bisect_test $type, "defconfig";
+ if (!$ret) {
+ fail "Have no good config to compare with, please set CONFIG_BISECT_GOOD";
+ return 1;
}
+ $good_config = $output_config;
}
- close(IN);
- # Now run oldconfig with the minconfig
- make_oldconfig;
+ # we don't want min configs to cause issues here.
+ doprint "Disabling 'MIN_CONFIG' for this test\n";
+ undef $minconfig;
- # check to see what we lost (or gained)
- open (IN, $output_config)
- or dodie "Failed to read $start_config";
+ my %good_configs;
+ my %bad_configs;
+ my %tmp_configs;
- my %removed_configs;
- my %added_configs;
+ doprint "Run good configs through make oldconfig\n";
+ assign_configs \%tmp_configs, $good_config;
+ create_config "$good_config", \%tmp_configs;
+ assign_configs \%good_configs, $output_config;
- while (<IN>) {
- if (/^((CONFIG\S*)=.*)/) {
- # save off all options
- $config_set{$2} = $1;
- if (defined($config_check{$2})) {
- if (defined($config_ignore{$2})) {
- $removed_configs{$2} = $1;
- } else {
- $config_list{$2} = $1;
- }
- } elsif (!defined($config_ignore{$2})) {
- $added_configs{$2} = $1;
- $config_list{$2} = $1;
- }
- } elsif (/^# ((CONFIG\S*).*)/) {
- # Keep these configs disabled
- $config_set{$2} = $1;
- $config_off{$2} = $1;
- }
- }
- close(IN);
+ doprint "Run bad configs through make oldconfig\n";
+ assign_configs \%tmp_configs, $bad_config;
+ create_config "$bad_config", \%tmp_configs;
+ assign_configs \%bad_configs, $output_config;
- my @confs = keys %removed_configs;
- if ($#confs >= 0) {
- doprint "Configs overridden by default configs and removed from check:\n";
- foreach my $config (@confs) {
- doprint " $config\n";
- }
- }
- @confs = keys %added_configs;
- if ($#confs >= 0) {
- doprint "Configs appearing in make oldconfig and added:\n";
- foreach my $config (@confs) {
- doprint " $config\n";
- }
- }
+ $good_config = "$tmpdir/good_config";
+ $bad_config = "$tmpdir/bad_config";
+
+ save_config \%good_configs, $good_config;
+ save_config \%bad_configs, $bad_config;
- my %config_test;
- my $once = 0;
- @config_off_tmp = ();
+ if (defined($config_bisect_check) && $config_bisect_check ne "0") {
+ if ($config_bisect_check ne "good") {
+ doprint "Testing bad config\n";
- # Sometimes kconfig does weird things. We must make sure
- # that the config we autocreate has everything we need
- # to test, otherwise we may miss testing configs, or
- # may not be able to create a new config.
- # Here we create a config with everything set.
- create_config (keys %config_list);
- read_current_config \%config_test;
- foreach my $config (keys %config_list) {
- if (!defined($config_test{$config})) {
- if (!$once) {
- $once = 1;
- doprint "Configs not produced by kconfig (will not be checked):\n";
+ $ret = run_bisect_test $type, "useconfig:$bad_config";
+ if ($ret) {
+ fail "Bad config succeeded when expected to fail!";
+ return 0;
}
- doprint " $config\n";
- delete $config_list{$config};
}
- }
- my $ret;
+ if ($config_bisect_check ne "bad") {
+ doprint "Testing good config\n";
- if (defined($config_bisect_check) && $config_bisect_check) {
- doprint " Checking to make sure bad config with min config fails\n";
- create_config keys %config_list;
- $ret = run_config_bisect_test $config_bisect_type;
- if ($ret) {
- doprint " FAILED! Bad config with min config boots fine\n";
- return -1;
+ $ret = run_bisect_test $type, "useconfig:$good_config";
+ if (!$ret) {
+ fail "Good config failed when expected to succeed!";
+ return 0;
+ }
}
- doprint " Bad config with min config fails as expected\n";
}
do {
- $ret = run_config_bisect;
+ $ret = run_config_bisect \%good_configs, \%bad_configs;
} while (!$ret);
return $ret if ($ret < 0);
@@ -3455,29 +3439,6 @@ sub read_depends {
read_kconfig($kconfig);
}
-sub read_config_list {
- my ($config) = @_;
-
- open (IN, $config)
- or dodie "Failed to read $config";
-
- while (<IN>) {
- if (/^((CONFIG\S*)=.*)/) {
- if (!defined($config_ignore{$2})) {
- $config_list{$2} = $1;
- }
- }
- }
-
- close(IN);
-}
-
-sub read_output_config {
- my ($config) = @_;
-
- assign_configs \%config_ignore, $config;
-}
-
sub make_new_config {
my @configs = @_;
@@ -3863,7 +3824,7 @@ sub make_warnings_file {
success $i;
}
-$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n";
+$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl [config-file]\n";
if ($#ARGV == 0) {
$ktest_config = $ARGV[0];
@@ -3873,8 +3834,6 @@ if ($#ARGV == 0) {
exit 0;
}
}
-} else {
- $ktest_config = "ktest.conf";
}
if (! -f $ktest_config) {
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index 172eec4517fb..911e45ad657a 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -1098,49 +1098,35 @@
#
# The way it works is this:
#
-# First it finds a config to work with. Since a different version, or
-# MIN_CONFIG may cause different dependecies, it must run through this
-# preparation.
+# You can specify a good config with CONFIG_BISECT_GOOD, otherwise it
+# will use the MIN_CONFIG, and if that's not specified, it will use
+# the config that comes with "make defconfig".
#
-# Overwrites any config set in the bad config with a config set in
-# either the MIN_CONFIG or ADD_CONFIG. Thus, make sure these configs
-# are minimal and do not disable configs you want to test:
-# (ie. # CONFIG_FOO is not set).
+# It runs both the good and bad configs through a make oldconfig to
+# make sure that they are set up for the kernel that is checked out.
#
-# An oldconfig is run on the bad config and any new config that
-# appears will be added to the configs to test.
+# It then reads the configs that are set, as well as the ones that are
+# not set for both the good and bad configs, and then compares them.
+# It will set half of the good configs within the bad config (note,
+# "set" means to make the bad config match the good config, a config
+# in the good config that is off, will be turned off in the bad
+# config. That is considered a "set").
#
-# Finally, it generates a config with the above result and runs it
-# again through make oldconfig to produce a config that should be
-# satisfied by kconfig.
+# It tests this new config and if it works, it becomes the new good
+# config, otherwise it becomes the new bad config. It continues this
+# process until there's only one config left and it will report that
+# config.
#
-# Then it starts the bisect.
+# The "bad config" can also be a config that is needed to boot but was
+# disabled because it depended on something that wasn't set.
#
-# The configs to test are cut in half. If all the configs in this
-# half depend on a config in the other half, then the other half
-# is tested instead. If no configs are enabled by either half, then
-# this means a circular dependency exists and the test fails.
+# During this process, it saves the current good and bad configs in
+# ${TMP_DIR}/good_config and ${TMP_DIR}/bad_config respectively.
+# If you stop the test, you can copy them to a new location to
+# reuse them again.
#
-# A config is created with the test half, and the bisect test is run.
-#
-# If the bisect succeeds, then all configs in the generated config
-# are removed from the configs to test and added to the configs that
-# will be enabled for all builds (they will be enabled, but not be part
-# of the configs to examine).
-#
-# If the bisect fails, then all test configs that were not enabled by
-# the config file are removed from the test. These configs will not
-# be enabled in future tests. Since current config failed, we consider
-# this to be a subset of the config that we started with.
-#
-# When we are down to one config, it is considered the bad config.
-#
-# Note, the config chosen may not be the true bad config. Due to
-# dependencies and selections of the kbuild system, mulitple
-# configs may be needed to cause a failure. If you disable the
-# config that was found and restart the test, if the test fails
-# again, it is recommended to rerun the config_bisect with a new
-# bad config without the found config enabled.
+# Although the MIN_CONFIG may be the config it starts with, the
+# MIN_CONFIG is ignored.
#
# The option BUILD_TYPE will be ignored.
#
@@ -1160,13 +1146,16 @@
# CONFIG_BISECT_GOOD (optional)
# If you have a good config to start with, then you
# can specify it with CONFIG_BISECT_GOOD. Otherwise
-# the MIN_CONFIG is the base.
+# the MIN_CONFIG is the base, if MIN_CONFIG is not set
+# It will build a config with "make defconfig"
#
# CONFIG_BISECT_CHECK (optional)
# Set this to 1 if you want to confirm that the config ktest
# generates (the bad config with the min config) is still bad.
# It may be that the min config fixes what broke the bad config
# and the test will not return a result.
+# Set it to "good" to test only the good config and set it
+# to "bad" to only test the bad config.
#
# Example:
# TEST_START
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 0a8a9db43d34..36ff2e4c7b6f 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -2,6 +2,7 @@ TARGETS = breakpoints
TARGETS += cpu-hotplug
TARGETS += efivarfs
TARGETS += kcmp
+TARGETS += memfd
TARGETS += memory-hotplug
TARGETS += mqueue
TARGETS += mount
@@ -12,6 +13,10 @@ TARGETS += vm
TARGETS += powerpc
TARGETS += user
TARGETS += sysctl
+TARGETS += firmware
+
+TARGETS_HOTPLUG = cpu-hotplug
+TARGETS_HOTPLUG += memory-hotplug
all:
for TARGET in $(TARGETS); do \
@@ -23,6 +28,21 @@ run_tests: all
make -C $$TARGET run_tests; \
done;
+hotplug:
+ for TARGET in $(TARGETS_HOTPLUG); do \
+ make -C $$TARGET; \
+ done;
+
+run_hotplug: hotplug
+ for TARGET in $(TARGETS_HOTPLUG); do \
+ make -C $$TARGET run_full_test; \
+ done;
+
+clean_hotplug:
+ for TARGET in $(TARGETS_HOTPLUG); do \
+ make -C $$TARGET clean; \
+ done;
+
clean:
for TARGET in $(TARGETS); do \
make -C $$TARGET clean; \
diff --git a/tools/testing/selftests/README.txt b/tools/testing/selftests/README.txt
index 5e2faf9c55d3..2660d5ff9179 100644
--- a/tools/testing/selftests/README.txt
+++ b/tools/testing/selftests/README.txt
@@ -4,8 +4,15 @@ The kernel contains a set of "self tests" under the tools/testing/selftests/
directory. These are intended to be small unit tests to exercise individual
code paths in the kernel.
-Running the selftests
-=====================
+On some systems, hot-plug tests could hang forever waiting for cpu and
+memory to be ready to be offlined. A special hot-plug target is created
+to run full range of hot-plug tests. In default mode, hot-plug tests run
+in safe mode with a limited scope. In limited mode, cpu-hotplug test is
+run on a single cpu as opposed to all hotplug capable cpus, and memory
+hotplug test is run on 2% of hotplug capable memory instead of 10%.
+
+Running the selftests (hotplug tests are run in limited mode)
+=============================================================
To build the tests:
@@ -18,14 +25,26 @@ To run the tests:
- note that some tests will require root privileges.
-
-To run only tests targetted for a single subsystem:
+To run only tests targeted for a single subsystem: (including
+hotplug targets in limited mode)
$ make -C tools/testing/selftests TARGETS=cpu-hotplug run_tests
See the top-level tools/testing/selftests/Makefile for the list of all possible
targets.
+Running the full range hotplug selftests
+========================================
+
+To build the tests:
+
+ $ make -C tools/testing/selftests hotplug
+
+To run the tests:
+
+ $ make -C tools/testing/selftests run_hotplug
+
+- note that some tests will require root privileges.
Contributing new tests
======================
diff --git a/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile
index 790c23a9db44..e9c28d8dc84b 100644
--- a/tools/testing/selftests/cpu-hotplug/Makefile
+++ b/tools/testing/selftests/cpu-hotplug/Makefile
@@ -3,4 +3,7 @@ all:
run_tests:
@/bin/bash ./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]"
+run_full_test:
+ @/bin/bash ./on-off-test.sh -a || echo "cpu-hotplug selftests: [FAIL]"
+
clean:
diff --git a/tools/testing/selftests/cpu-hotplug/on-off-test.sh b/tools/testing/selftests/cpu-hotplug/on-off-test.sh
index bdde7cf428bb..98b1d6565f2c 100644
--- a/tools/testing/selftests/cpu-hotplug/on-off-test.sh
+++ b/tools/testing/selftests/cpu-hotplug/on-off-test.sh
@@ -11,6 +11,8 @@ prerequisite()
exit 0
fi
+ taskset -p 01 $$
+
SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
if [ ! -d "$SYSFS" ]; then
@@ -22,6 +24,19 @@ prerequisite()
echo $msg cpu hotplug is not supported >&2
exit 0
fi
+
+ echo "CPU online/offline summary:"
+ online_cpus=`cat $SYSFS/devices/system/cpu/online`
+ online_max=${online_cpus##*-}
+ echo -e "\t Cpus in online state: $online_cpus"
+
+ offline_cpus=`cat $SYSFS/devices/system/cpu/offline`
+ if [[ "a$offline_cpus" = "a" ]]; then
+ offline_cpus=0
+ else
+ offline_max=${offline_cpus##*-}
+ fi
+ echo -e "\t Cpus in offline state: $offline_cpus"
}
#
@@ -113,15 +128,25 @@ offline_cpu_expect_fail()
}
error=-12
+allcpus=0
priority=0
+online_cpus=0
+online_max=0
+offline_cpus=0
+offline_max=0
-while getopts e:hp: opt; do
+while getopts e:ahp: opt; do
case $opt in
e)
error=$OPTARG
;;
+ a)
+ allcpus=1
+ ;;
h)
- echo "Usage $0 [ -e errno ] [ -p notifier-priority ]"
+ echo "Usage $0 [ -a ] [ -e errno ] [ -p notifier-priority ]"
+ echo -e "\t default offline one cpu"
+ echo -e "\t run with -a option to offline all cpus"
exit
;;
p)
@@ -138,6 +163,29 @@ fi
prerequisite
#
+# Safe test (default) - offline and online one cpu
+#
+if [ $allcpus -eq 0 ]; then
+ echo "Limited scope test: one hotplug cpu"
+ echo -e "\t (leaves cpu in the original state):"
+ echo -e "\t online to offline to online: cpu $online_max"
+ offline_cpu_expect_success $online_max
+ online_cpu_expect_success $online_max
+
+ if [[ $offline_cpus -gt 0 ]]; then
+ echo -e "\t offline to online to offline: cpu $offline_max"
+ online_cpu_expect_success $offline_max
+ offline_cpu_expect_success $offline_max
+ fi
+ exit 0
+else
+ echo "Full scope test: all hotplug cpus"
+ echo -e "\t online all offline cpus"
+ echo -e "\t offline all online cpus"
+ echo -e "\t online all offline cpus"
+fi
+
+#
# Online all hot-pluggable CPUs
#
for cpu in `hotplaggable_offline_cpus`; do
diff --git a/tools/testing/selftests/firmware/Makefile b/tools/testing/selftests/firmware/Makefile
new file mode 100644
index 000000000000..e23cce0bbc3a
--- /dev/null
+++ b/tools/testing/selftests/firmware/Makefile
@@ -0,0 +1,27 @@
+# Makefile for firmware loading selftests
+
+# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
+all:
+
+fw_filesystem:
+ @if /bin/sh ./fw_filesystem.sh ; then \
+ echo "fw_filesystem: ok"; \
+ else \
+ echo "fw_filesystem: [FAIL]"; \
+ exit 1; \
+ fi
+
+fw_userhelper:
+ @if /bin/sh ./fw_userhelper.sh ; then \
+ echo "fw_userhelper: ok"; \
+ else \
+ echo "fw_userhelper: [FAIL]"; \
+ exit 1; \
+ fi
+
+run_tests: all fw_filesystem fw_userhelper
+
+# Nothing to clean up.
+clean:
+
+.PHONY: all clean run_tests fw_filesystem fw_userhelper
diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh
new file mode 100644
index 000000000000..3fc6c10c2479
--- /dev/null
+++ b/tools/testing/selftests/firmware/fw_filesystem.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# This validates that the kernel will load firmware out of its list of
+# firmware locations on disk. Since the user helper does similar work,
+# we reset the custom load directory to a location the user helper doesn't
+# know so we can be sure we're not accidentally testing the user helper.
+set -e
+
+modprobe test_firmware
+
+DIR=/sys/devices/virtual/misc/test_firmware
+
+OLD_TIMEOUT=$(cat /sys/class/firmware/timeout)
+OLD_FWPATH=$(cat /sys/module/firmware_class/parameters/path)
+
+FWPATH=$(mktemp -d)
+FW="$FWPATH/test-firmware.bin"
+
+test_finish()
+{
+ echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
+ echo -n "$OLD_PATH" >/sys/module/firmware_class/parameters/path
+ rm -f "$FW"
+ rmdir "$FWPATH"
+}
+
+trap "test_finish" EXIT
+
+# Turn down the timeout so failures don't take so long.
+echo 1 >/sys/class/firmware/timeout
+# Set the kernel search path.
+echo -n "$FWPATH" >/sys/module/firmware_class/parameters/path
+
+# This is an unlikely real-world firmware content. :)
+echo "ABCD0123" >"$FW"
+
+NAME=$(basename "$FW")
+
+# Request a firmware that doesn't exist, it should fail.
+echo -n "nope-$NAME" >"$DIR"/trigger_request
+if diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not expected to match" >&2
+ exit 1
+else
+ echo "$0: timeout works"
+fi
+
+# This should succeed via kernel load or will fail after 1 second after
+# being handed over to the user helper, which won't find the fw either.
+if ! echo -n "$NAME" >"$DIR"/trigger_request ; then
+ echo "$0: could not trigger request" >&2
+ exit 1
+fi
+
+# Verify the contents are what we expect.
+if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not loaded" >&2
+ exit 1
+else
+ echo "$0: filesystem loading works"
+fi
+
+exit 0
diff --git a/tools/testing/selftests/firmware/fw_userhelper.sh b/tools/testing/selftests/firmware/fw_userhelper.sh
new file mode 100644
index 000000000000..6efbade12139
--- /dev/null
+++ b/tools/testing/selftests/firmware/fw_userhelper.sh
@@ -0,0 +1,89 @@
+#!/bin/sh
+# This validates that the kernel will fall back to using the user helper
+# to load firmware it can't find on disk itself. We must request a firmware
+# that the kernel won't find, and any installed helper (e.g. udev) also
+# won't find so that we can do the load ourself manually.
+set -e
+
+modprobe test_firmware
+
+DIR=/sys/devices/virtual/misc/test_firmware
+
+OLD_TIMEOUT=$(cat /sys/class/firmware/timeout)
+
+FWPATH=$(mktemp -d)
+FW="$FWPATH/test-firmware.bin"
+
+test_finish()
+{
+ echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout
+ rm -f "$FW"
+ rmdir "$FWPATH"
+}
+
+load_fw()
+{
+ local name="$1"
+ local file="$2"
+
+ # This will block until our load (below) has finished.
+ echo -n "$name" >"$DIR"/trigger_request &
+
+ # Give kernel a chance to react.
+ local timeout=10
+ while [ ! -e "$DIR"/"$name"/loading ]; do
+ sleep 0.1
+ timeout=$(( $timeout - 1 ))
+ if [ "$timeout" -eq 0 ]; then
+ echo "$0: firmware interface never appeared" >&2
+ exit 1
+ fi
+ done
+
+ echo 1 >"$DIR"/"$name"/loading
+ cat "$file" >"$DIR"/"$name"/data
+ echo 0 >"$DIR"/"$name"/loading
+
+ # Wait for request to finish.
+ wait
+}
+
+trap "test_finish" EXIT
+
+# This is an unlikely real-world firmware content. :)
+echo "ABCD0123" >"$FW"
+NAME=$(basename "$FW")
+
+# Test failure when doing nothing (timeout works).
+echo 1 >/sys/class/firmware/timeout
+echo -n "$NAME" >"$DIR"/trigger_request
+if diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not expected to match" >&2
+ exit 1
+else
+ echo "$0: timeout works"
+fi
+
+# Put timeout high enough for us to do work but not so long that failures
+# slow down this test too much.
+echo 4 >/sys/class/firmware/timeout
+
+# Load this script instead of the desired firmware.
+load_fw "$NAME" "$0"
+if diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not expected to match" >&2
+ exit 1
+else
+ echo "$0: firmware comparison works"
+fi
+
+# Do a proper load, which should work correctly.
+load_fw "$NAME" "$FW"
+if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then
+ echo "$0: firmware was not loaded" >&2
+ exit 1
+else
+ echo "$0: user helper firmware loading works"
+fi
+
+exit 0
diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c
index fa4f1b37e045..dbba4084869c 100644
--- a/tools/testing/selftests/kcmp/kcmp_test.c
+++ b/tools/testing/selftests/kcmp/kcmp_test.c
@@ -81,7 +81,7 @@ int main(int argc, char **argv)
/* Compare with self */
ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0);
if (ret) {
- printf("FAIL: 0 expected but %li returned (%s)\n",
+ printf("FAIL: 0 expected but %d returned (%s)\n",
ret, strerror(errno));
ret = -1;
} else
diff --git a/tools/testing/selftests/memfd/.gitignore b/tools/testing/selftests/memfd/.gitignore
new file mode 100644
index 000000000000..afe87c40ac80
--- /dev/null
+++ b/tools/testing/selftests/memfd/.gitignore
@@ -0,0 +1,4 @@
+fuse_mnt
+fuse_test
+memfd_test
+memfd-test-file
diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile
new file mode 100644
index 000000000000..6816c491c5ff
--- /dev/null
+++ b/tools/testing/selftests/memfd/Makefile
@@ -0,0 +1,41 @@
+uname_M := $(shell uname -m 2>/dev/null || echo not)
+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
+ifeq ($(ARCH),i386)
+ ARCH := X86
+endif
+ifeq ($(ARCH),x86_64)
+ ARCH := X86
+endif
+
+CFLAGS += -D_FILE_OFFSET_BITS=64
+CFLAGS += -I../../../../arch/x86/include/generated/uapi/
+CFLAGS += -I../../../../arch/x86/include/uapi/
+CFLAGS += -I../../../../include/uapi/
+CFLAGS += -I../../../../include/
+
+all:
+ifeq ($(ARCH),X86)
+ gcc $(CFLAGS) memfd_test.c -o memfd_test
+else
+ echo "Not an x86 target, can't build memfd selftest"
+endif
+
+run_tests: all
+ifeq ($(ARCH),X86)
+ gcc $(CFLAGS) memfd_test.c -o memfd_test
+endif
+ @./memfd_test || echo "memfd_test: [FAIL]"
+
+build_fuse:
+ifeq ($(ARCH),X86)
+ gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt
+ gcc $(CFLAGS) fuse_test.c -o fuse_test
+else
+ echo "Not an x86 target, can't build memfd selftest"
+endif
+
+run_fuse: build_fuse
+ @./run_fuse_test.sh || echo "fuse_test: [FAIL]"
+
+clean:
+ $(RM) memfd_test fuse_test
diff --git a/tools/testing/selftests/memfd/fuse_mnt.c b/tools/testing/selftests/memfd/fuse_mnt.c
new file mode 100644
index 000000000000..feacf1280fcd
--- /dev/null
+++ b/tools/testing/selftests/memfd/fuse_mnt.c
@@ -0,0 +1,110 @@
+/*
+ * memfd test file-system
+ * This file uses FUSE to create a dummy file-system with only one file /memfd.
+ * This file is read-only and takes 1s per read.
+ *
+ * This file-system is used by the memfd test-cases to force the kernel to pin
+ * pages during reads(). Due to the 1s delay of this file-system, this is a
+ * nice way to test race-conditions against get_user_pages() in the kernel.
+ *
+ * We use direct_io==1 to force the kernel to use direct-IO for this
+ * file-system.
+ */
+
+#define FUSE_USE_VERSION 26
+
+#include <fuse.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+static const char memfd_content[] = "memfd-example-content";
+static const char memfd_path[] = "/memfd";
+
+static int memfd_getattr(const char *path, struct stat *st)
+{
+ memset(st, 0, sizeof(*st));
+
+ if (!strcmp(path, "/")) {
+ st->st_mode = S_IFDIR | 0755;
+ st->st_nlink = 2;
+ } else if (!strcmp(path, memfd_path)) {
+ st->st_mode = S_IFREG | 0444;
+ st->st_nlink = 1;
+ st->st_size = strlen(memfd_content);
+ } else {
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int memfd_readdir(const char *path,
+ void *buf,
+ fuse_fill_dir_t filler,
+ off_t offset,
+ struct fuse_file_info *fi)
+{
+ if (strcmp(path, "/"))
+ return -ENOENT;
+
+ filler(buf, ".", NULL, 0);
+ filler(buf, "..", NULL, 0);
+ filler(buf, memfd_path + 1, NULL, 0);
+
+ return 0;
+}
+
+static int memfd_open(const char *path, struct fuse_file_info *fi)
+{
+ if (strcmp(path, memfd_path))
+ return -ENOENT;
+
+ if ((fi->flags & 3) != O_RDONLY)
+ return -EACCES;
+
+ /* force direct-IO */
+ fi->direct_io = 1;
+
+ return 0;
+}
+
+static int memfd_read(const char *path,
+ char *buf,
+ size_t size,
+ off_t offset,
+ struct fuse_file_info *fi)
+{
+ size_t len;
+
+ if (strcmp(path, memfd_path) != 0)
+ return -ENOENT;
+
+ sleep(1);
+
+ len = strlen(memfd_content);
+ if (offset < len) {
+ if (offset + size > len)
+ size = len - offset;
+
+ memcpy(buf, memfd_content + offset, size);
+ } else {
+ size = 0;
+ }
+
+ return size;
+}
+
+static struct fuse_operations memfd_ops = {
+ .getattr = memfd_getattr,
+ .readdir = memfd_readdir,
+ .open = memfd_open,
+ .read = memfd_read,
+};
+
+int main(int argc, char *argv[])
+{
+ return fuse_main(argc, argv, &memfd_ops, NULL);
+}
diff --git a/tools/testing/selftests/memfd/fuse_test.c b/tools/testing/selftests/memfd/fuse_test.c
new file mode 100644
index 000000000000..67908b18f035
--- /dev/null
+++ b/tools/testing/selftests/memfd/fuse_test.c
@@ -0,0 +1,311 @@
+/*
+ * memfd GUP test-case
+ * This tests memfd interactions with get_user_pages(). We require the
+ * fuse_mnt.c program to provide a fake direct-IO FUSE mount-point for us. This
+ * file-system delays _all_ reads by 1s and forces direct-IO. This means, any
+ * read() on files in that file-system will pin the receive-buffer pages for at
+ * least 1s via get_user_pages().
+ *
+ * We use this trick to race ADD_SEALS against a write on a memfd object. The
+ * ADD_SEALS must fail if the memfd pages are still pinned. Note that we use
+ * the read() syscall with our memory-mapped memfd object as receive buffer to
+ * force the kernel to write into our memfd object.
+ */
+
+#define _GNU_SOURCE
+#define __EXPORTED_HEADERS__
+
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <linux/falloc.h>
+#include <linux/fcntl.h>
+#include <linux/memfd.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define MFD_DEF_SIZE 8192
+#define STACK_SIZE 65535
+
+static int sys_memfd_create(const char *name,
+ unsigned int flags)
+{
+ return syscall(__NR_memfd_create, name, flags);
+}
+
+static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
+{
+ int r, fd;
+
+ fd = sys_memfd_create(name, flags);
+ if (fd < 0) {
+ printf("memfd_create(\"%s\", %u) failed: %m\n",
+ name, flags);
+ abort();
+ }
+
+ r = ftruncate(fd, sz);
+ if (r < 0) {
+ printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz);
+ abort();
+ }
+
+ return fd;
+}
+
+static __u64 mfd_assert_get_seals(int fd)
+{
+ long r;
+
+ r = fcntl(fd, F_GET_SEALS);
+ if (r < 0) {
+ printf("GET_SEALS(%d) failed: %m\n", fd);
+ abort();
+ }
+
+ return r;
+}
+
+static void mfd_assert_has_seals(int fd, __u64 seals)
+{
+ __u64 s;
+
+ s = mfd_assert_get_seals(fd);
+ if (s != seals) {
+ printf("%llu != %llu = GET_SEALS(%d)\n",
+ (unsigned long long)seals, (unsigned long long)s, fd);
+ abort();
+ }
+}
+
+static void mfd_assert_add_seals(int fd, __u64 seals)
+{
+ long r;
+ __u64 s;
+
+ s = mfd_assert_get_seals(fd);
+ r = fcntl(fd, F_ADD_SEALS, seals);
+ if (r < 0) {
+ printf("ADD_SEALS(%d, %llu -> %llu) failed: %m\n",
+ fd, (unsigned long long)s, (unsigned long long)seals);
+ abort();
+ }
+}
+
+static int mfd_busy_add_seals(int fd, __u64 seals)
+{
+ long r;
+ __u64 s;
+
+ r = fcntl(fd, F_GET_SEALS);
+ if (r < 0)
+ s = 0;
+ else
+ s = r;
+
+ r = fcntl(fd, F_ADD_SEALS, seals);
+ if (r < 0 && errno != EBUSY) {
+ printf("ADD_SEALS(%d, %llu -> %llu) didn't fail as expected with EBUSY: %m\n",
+ fd, (unsigned long long)s, (unsigned long long)seals);
+ abort();
+ }
+
+ return r;
+}
+
+static void *mfd_assert_mmap_shared(int fd)
+{
+ void *p;
+
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+
+ return p;
+}
+
+static void *mfd_assert_mmap_private(int fd)
+{
+ void *p;
+
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+
+ return p;
+}
+
+static int global_mfd = -1;
+static void *global_p = NULL;
+
+static int sealing_thread_fn(void *arg)
+{
+ int sig, r;
+
+ /*
+ * This thread first waits 200ms so any pending operation in the parent
+ * is correctly started. After that, it tries to seal @global_mfd as
+ * SEAL_WRITE. This _must_ fail as the parent thread has a read() into
+ * that memory mapped object still ongoing.
+ * We then wait one more second and try sealing again. This time it
+ * must succeed as there shouldn't be anyone else pinning the pages.
+ */
+
+ /* wait 200ms for FUSE-request to be active */
+ usleep(200000);
+
+ /* unmount mapping before sealing to avoid i_mmap_writable failures */
+ munmap(global_p, MFD_DEF_SIZE);
+
+ /* Try sealing the global file; expect EBUSY or success. Current
+ * kernels will never succeed, but in the future, kernels might
+ * implement page-replacements or other fancy ways to avoid racing
+ * writes. */
+ r = mfd_busy_add_seals(global_mfd, F_SEAL_WRITE);
+ if (r >= 0) {
+ printf("HURRAY! This kernel fixed GUP races!\n");
+ } else {
+ /* wait 1s more so the FUSE-request is done */
+ sleep(1);
+
+ /* try sealing the global file again */
+ mfd_assert_add_seals(global_mfd, F_SEAL_WRITE);
+ }
+
+ return 0;
+}
+
+static pid_t spawn_sealing_thread(void)
+{
+ uint8_t *stack;
+ pid_t pid;
+
+ stack = malloc(STACK_SIZE);
+ if (!stack) {
+ printf("malloc(STACK_SIZE) failed: %m\n");
+ abort();
+ }
+
+ pid = clone(sealing_thread_fn,
+ stack + STACK_SIZE,
+ SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM,
+ NULL);
+ if (pid < 0) {
+ printf("clone() failed: %m\n");
+ abort();
+ }
+
+ return pid;
+}
+
+static void join_sealing_thread(pid_t pid)
+{
+ waitpid(pid, NULL, 0);
+}
+
+int main(int argc, char **argv)
+{
+ static const char zero[MFD_DEF_SIZE];
+ int fd, mfd, r;
+ void *p;
+ int was_sealed;
+ pid_t pid;
+
+ if (argc < 2) {
+ printf("error: please pass path to file in fuse_mnt mount-point\n");
+ abort();
+ }
+
+ /* open FUSE memfd file for GUP testing */
+ printf("opening: %s\n", argv[1]);
+ fd = open(argv[1], O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ printf("cannot open(\"%s\"): %m\n", argv[1]);
+ abort();
+ }
+
+ /* create new memfd-object */
+ mfd = mfd_assert_new("kern_memfd_fuse",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+
+ /* mmap memfd-object for writing */
+ p = mfd_assert_mmap_shared(mfd);
+
+ /* pass mfd+mapping to a separate sealing-thread which tries to seal
+ * the memfd objects with SEAL_WRITE while we write into it */
+ global_mfd = mfd;
+ global_p = p;
+ pid = spawn_sealing_thread();
+
+ /* Use read() on the FUSE file to read into our memory-mapped memfd
+ * object. This races the other thread which tries to seal the
+ * memfd-object.
+ * If @fd is on the memfd-fake-FUSE-FS, the read() is delayed by 1s.
+ * This guarantees that the receive-buffer is pinned for 1s until the
+ * data is written into it. The racing ADD_SEALS should thus fail as
+ * the pages are still pinned. */
+ r = read(fd, p, MFD_DEF_SIZE);
+ if (r < 0) {
+ printf("read() failed: %m\n");
+ abort();
+ } else if (!r) {
+ printf("unexpected EOF on read()\n");
+ abort();
+ }
+
+ was_sealed = mfd_assert_get_seals(mfd) & F_SEAL_WRITE;
+
+ /* Wait for sealing-thread to finish and verify that it
+ * successfully sealed the file after the second try. */
+ join_sealing_thread(pid);
+ mfd_assert_has_seals(mfd, F_SEAL_WRITE);
+
+ /* *IF* the memfd-object was sealed at the time our read() returned,
+ * then the kernel did a page-replacement or canceled the read() (or
+ * whatever magic it did..). In that case, the memfd object is still
+ * all zero.
+ * In case the memfd-object was *not* sealed, the read() was successfull
+ * and the memfd object must *not* be all zero.
+ * Note that in real scenarios, there might be a mixture of both, but
+ * in this test-cases, we have explicit 200ms delays which should be
+ * enough to avoid any in-flight writes. */
+
+ p = mfd_assert_mmap_private(mfd);
+ if (was_sealed && memcmp(p, zero, MFD_DEF_SIZE)) {
+ printf("memfd sealed during read() but data not discarded\n");
+ abort();
+ } else if (!was_sealed && !memcmp(p, zero, MFD_DEF_SIZE)) {
+ printf("memfd sealed after read() but data discarded\n");
+ abort();
+ }
+
+ close(mfd);
+ close(fd);
+
+ printf("fuse: DONE\n");
+
+ return 0;
+}
diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c
new file mode 100644
index 000000000000..3634c909b1b0
--- /dev/null
+++ b/tools/testing/selftests/memfd/memfd_test.c
@@ -0,0 +1,913 @@
+#define _GNU_SOURCE
+#define __EXPORTED_HEADERS__
+
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <linux/falloc.h>
+#include <linux/fcntl.h>
+#include <linux/memfd.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#define MFD_DEF_SIZE 8192
+#define STACK_SIZE 65535
+
+static int sys_memfd_create(const char *name,
+ unsigned int flags)
+{
+ return syscall(__NR_memfd_create, name, flags);
+}
+
+static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
+{
+ int r, fd;
+
+ fd = sys_memfd_create(name, flags);
+ if (fd < 0) {
+ printf("memfd_create(\"%s\", %u) failed: %m\n",
+ name, flags);
+ abort();
+ }
+
+ r = ftruncate(fd, sz);
+ if (r < 0) {
+ printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz);
+ abort();
+ }
+
+ return fd;
+}
+
+static void mfd_fail_new(const char *name, unsigned int flags)
+{
+ int r;
+
+ r = sys_memfd_create(name, flags);
+ if (r >= 0) {
+ printf("memfd_create(\"%s\", %u) succeeded, but failure expected\n",
+ name, flags);
+ close(r);
+ abort();
+ }
+}
+
+static __u64 mfd_assert_get_seals(int fd)
+{
+ long r;
+
+ r = fcntl(fd, F_GET_SEALS);
+ if (r < 0) {
+ printf("GET_SEALS(%d) failed: %m\n", fd);
+ abort();
+ }
+
+ return r;
+}
+
+static void mfd_assert_has_seals(int fd, __u64 seals)
+{
+ __u64 s;
+
+ s = mfd_assert_get_seals(fd);
+ if (s != seals) {
+ printf("%llu != %llu = GET_SEALS(%d)\n",
+ (unsigned long long)seals, (unsigned long long)s, fd);
+ abort();
+ }
+}
+
+static void mfd_assert_add_seals(int fd, __u64 seals)
+{
+ long r;
+ __u64 s;
+
+ s = mfd_assert_get_seals(fd);
+ r = fcntl(fd, F_ADD_SEALS, seals);
+ if (r < 0) {
+ printf("ADD_SEALS(%d, %llu -> %llu) failed: %m\n",
+ fd, (unsigned long long)s, (unsigned long long)seals);
+ abort();
+ }
+}
+
+static void mfd_fail_add_seals(int fd, __u64 seals)
+{
+ long r;
+ __u64 s;
+
+ r = fcntl(fd, F_GET_SEALS);
+ if (r < 0)
+ s = 0;
+ else
+ s = r;
+
+ r = fcntl(fd, F_ADD_SEALS, seals);
+ if (r >= 0) {
+ printf("ADD_SEALS(%d, %llu -> %llu) didn't fail as expected\n",
+ fd, (unsigned long long)s, (unsigned long long)seals);
+ abort();
+ }
+}
+
+static void mfd_assert_size(int fd, size_t size)
+{
+ struct stat st;
+ int r;
+
+ r = fstat(fd, &st);
+ if (r < 0) {
+ printf("fstat(%d) failed: %m\n", fd);
+ abort();
+ } else if (st.st_size != size) {
+ printf("wrong file size %lld, but expected %lld\n",
+ (long long)st.st_size, (long long)size);
+ abort();
+ }
+}
+
+static int mfd_assert_dup(int fd)
+{
+ int r;
+
+ r = dup(fd);
+ if (r < 0) {
+ printf("dup(%d) failed: %m\n", fd);
+ abort();
+ }
+
+ return r;
+}
+
+static void *mfd_assert_mmap_shared(int fd)
+{
+ void *p;
+
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+
+ return p;
+}
+
+static void *mfd_assert_mmap_private(int fd)
+{
+ void *p;
+
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+
+ return p;
+}
+
+static int mfd_assert_open(int fd, int flags, mode_t mode)
+{
+ char buf[512];
+ int r;
+
+ sprintf(buf, "/proc/self/fd/%d", fd);
+ r = open(buf, flags, mode);
+ if (r < 0) {
+ printf("open(%s) failed: %m\n", buf);
+ abort();
+ }
+
+ return r;
+}
+
+static void mfd_fail_open(int fd, int flags, mode_t mode)
+{
+ char buf[512];
+ int r;
+
+ sprintf(buf, "/proc/self/fd/%d", fd);
+ r = open(buf, flags, mode);
+ if (r >= 0) {
+ printf("open(%s) didn't fail as expected\n");
+ abort();
+ }
+}
+
+static void mfd_assert_read(int fd)
+{
+ char buf[16];
+ void *p;
+ ssize_t l;
+
+ l = read(fd, buf, sizeof(buf));
+ if (l != sizeof(buf)) {
+ printf("read() failed: %m\n");
+ abort();
+ }
+
+ /* verify PROT_READ *is* allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+ munmap(p, MFD_DEF_SIZE);
+
+ /* verify MAP_PRIVATE is *always* allowed (even writable) */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+ munmap(p, MFD_DEF_SIZE);
+}
+
+static void mfd_assert_write(int fd)
+{
+ ssize_t l;
+ void *p;
+ int r;
+
+ /* verify write() succeeds */
+ l = write(fd, "\0\0\0\0", 4);
+ if (l != 4) {
+ printf("write() failed: %m\n");
+ abort();
+ }
+
+ /* verify PROT_READ | PROT_WRITE is allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+ *(char *)p = 0;
+ munmap(p, MFD_DEF_SIZE);
+
+ /* verify PROT_WRITE is allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+ *(char *)p = 0;
+ munmap(p, MFD_DEF_SIZE);
+
+ /* verify PROT_READ with MAP_SHARED is allowed and a following
+ * mprotect(PROT_WRITE) allows writing */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p == MAP_FAILED) {
+ printf("mmap() failed: %m\n");
+ abort();
+ }
+
+ r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE);
+ if (r < 0) {
+ printf("mprotect() failed: %m\n");
+ abort();
+ }
+
+ *(char *)p = 0;
+ munmap(p, MFD_DEF_SIZE);
+
+ /* verify PUNCH_HOLE works */
+ r = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ 0,
+ MFD_DEF_SIZE);
+ if (r < 0) {
+ printf("fallocate(PUNCH_HOLE) failed: %m\n");
+ abort();
+ }
+}
+
+static void mfd_fail_write(int fd)
+{
+ ssize_t l;
+ void *p;
+ int r;
+
+ /* verify write() fails */
+ l = write(fd, "data", 4);
+ if (l != -EPERM) {
+ printf("expected EPERM on write(), but got %d: %m\n", (int)l);
+ abort();
+ }
+
+ /* verify PROT_READ | PROT_WRITE is not allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p != MAP_FAILED) {
+ printf("mmap() didn't fail as expected\n");
+ abort();
+ }
+
+ /* verify PROT_WRITE is not allowed */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p != MAP_FAILED) {
+ printf("mmap() didn't fail as expected\n");
+ abort();
+ }
+
+ /* Verify PROT_READ with MAP_SHARED with a following mprotect is not
+ * allowed. Note that for r/w the kernel already prevents the mmap. */
+ p = mmap(NULL,
+ MFD_DEF_SIZE,
+ PROT_READ,
+ MAP_SHARED,
+ fd,
+ 0);
+ if (p != MAP_FAILED) {
+ r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE);
+ if (r >= 0) {
+ printf("mmap()+mprotect() didn't fail as expected\n");
+ abort();
+ }
+ }
+
+ /* verify PUNCH_HOLE fails */
+ r = fallocate(fd,
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ 0,
+ MFD_DEF_SIZE);
+ if (r >= 0) {
+ printf("fallocate(PUNCH_HOLE) didn't fail as expected\n");
+ abort();
+ }
+}
+
+static void mfd_assert_shrink(int fd)
+{
+ int r, fd2;
+
+ r = ftruncate(fd, MFD_DEF_SIZE / 2);
+ if (r < 0) {
+ printf("ftruncate(SHRINK) failed: %m\n");
+ abort();
+ }
+
+ mfd_assert_size(fd, MFD_DEF_SIZE / 2);
+
+ fd2 = mfd_assert_open(fd,
+ O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR);
+ close(fd2);
+
+ mfd_assert_size(fd, 0);
+}
+
+static void mfd_fail_shrink(int fd)
+{
+ int r;
+
+ r = ftruncate(fd, MFD_DEF_SIZE / 2);
+ if (r >= 0) {
+ printf("ftruncate(SHRINK) didn't fail as expected\n");
+ abort();
+ }
+
+ mfd_fail_open(fd,
+ O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR);
+}
+
+static void mfd_assert_grow(int fd)
+{
+ int r;
+
+ r = ftruncate(fd, MFD_DEF_SIZE * 2);
+ if (r < 0) {
+ printf("ftruncate(GROW) failed: %m\n");
+ abort();
+ }
+
+ mfd_assert_size(fd, MFD_DEF_SIZE * 2);
+
+ r = fallocate(fd,
+ 0,
+ 0,
+ MFD_DEF_SIZE * 4);
+ if (r < 0) {
+ printf("fallocate(ALLOC) failed: %m\n");
+ abort();
+ }
+
+ mfd_assert_size(fd, MFD_DEF_SIZE * 4);
+}
+
+static void mfd_fail_grow(int fd)
+{
+ int r;
+
+ r = ftruncate(fd, MFD_DEF_SIZE * 2);
+ if (r >= 0) {
+ printf("ftruncate(GROW) didn't fail as expected\n");
+ abort();
+ }
+
+ r = fallocate(fd,
+ 0,
+ 0,
+ MFD_DEF_SIZE * 4);
+ if (r >= 0) {
+ printf("fallocate(ALLOC) didn't fail as expected\n");
+ abort();
+ }
+}
+
+static void mfd_assert_grow_write(int fd)
+{
+ static char buf[MFD_DEF_SIZE * 8];
+ ssize_t l;
+
+ l = pwrite(fd, buf, sizeof(buf), 0);
+ if (l != sizeof(buf)) {
+ printf("pwrite() failed: %m\n");
+ abort();
+ }
+
+ mfd_assert_size(fd, MFD_DEF_SIZE * 8);
+}
+
+static void mfd_fail_grow_write(int fd)
+{
+ static char buf[MFD_DEF_SIZE * 8];
+ ssize_t l;
+
+ l = pwrite(fd, buf, sizeof(buf), 0);
+ if (l == sizeof(buf)) {
+ printf("pwrite() didn't fail as expected\n");
+ abort();
+ }
+}
+
+static int idle_thread_fn(void *arg)
+{
+ sigset_t set;
+ int sig;
+
+ /* dummy waiter; SIGTERM terminates us anyway */
+ sigemptyset(&set);
+ sigaddset(&set, SIGTERM);
+ sigwait(&set, &sig);
+
+ return 0;
+}
+
+static pid_t spawn_idle_thread(unsigned int flags)
+{
+ uint8_t *stack;
+ pid_t pid;
+
+ stack = malloc(STACK_SIZE);
+ if (!stack) {
+ printf("malloc(STACK_SIZE) failed: %m\n");
+ abort();
+ }
+
+ pid = clone(idle_thread_fn,
+ stack + STACK_SIZE,
+ SIGCHLD | flags,
+ NULL);
+ if (pid < 0) {
+ printf("clone() failed: %m\n");
+ abort();
+ }
+
+ return pid;
+}
+
+static void join_idle_thread(pid_t pid)
+{
+ kill(pid, SIGTERM);
+ waitpid(pid, NULL, 0);
+}
+
+/*
+ * Test memfd_create() syscall
+ * Verify syscall-argument validation, including name checks, flag validation
+ * and more.
+ */
+static void test_create(void)
+{
+ char buf[2048];
+ int fd;
+
+ /* test NULL name */
+ mfd_fail_new(NULL, 0);
+
+ /* test over-long name (not zero-terminated) */
+ memset(buf, 0xff, sizeof(buf));
+ mfd_fail_new(buf, 0);
+
+ /* test over-long zero-terminated name */
+ memset(buf, 0xff, sizeof(buf));
+ buf[sizeof(buf) - 1] = 0;
+ mfd_fail_new(buf, 0);
+
+ /* verify "" is a valid name */
+ fd = mfd_assert_new("", 0, 0);
+ close(fd);
+
+ /* verify invalid O_* open flags */
+ mfd_fail_new("", 0x0100);
+ mfd_fail_new("", ~MFD_CLOEXEC);
+ mfd_fail_new("", ~MFD_ALLOW_SEALING);
+ mfd_fail_new("", ~0);
+ mfd_fail_new("", 0x80000000U);
+
+ /* verify MFD_CLOEXEC is allowed */
+ fd = mfd_assert_new("", 0, MFD_CLOEXEC);
+ close(fd);
+
+ /* verify MFD_ALLOW_SEALING is allowed */
+ fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
+ close(fd);
+
+ /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
+ fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
+ close(fd);
+}
+
+/*
+ * Test basic sealing
+ * A very basic sealing test to see whether setting/retrieving seals works.
+ */
+static void test_basic(void)
+{
+ int fd;
+
+ fd = mfd_assert_new("kern_memfd_basic",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+
+ /* add basic seals */
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE);
+
+ /* add them again */
+ mfd_assert_add_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_WRITE);
+
+ /* add more seals and seal against sealing */
+ mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_GROW |
+ F_SEAL_WRITE |
+ F_SEAL_SEAL);
+
+ /* verify that sealing no longer works */
+ mfd_fail_add_seals(fd, F_SEAL_GROW);
+ mfd_fail_add_seals(fd, 0);
+
+ close(fd);
+
+ /* verify sealing does not work without MFD_ALLOW_SEALING */
+ fd = mfd_assert_new("kern_memfd_basic",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC);
+ mfd_assert_has_seals(fd, F_SEAL_SEAL);
+ mfd_fail_add_seals(fd, F_SEAL_SHRINK |
+ F_SEAL_GROW |
+ F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_SEAL);
+ close(fd);
+}
+
+/*
+ * Test SEAL_WRITE
+ * Test whether SEAL_WRITE actually prevents modifications.
+ */
+static void test_seal_write(void)
+{
+ int fd;
+
+ fd = mfd_assert_new("kern_memfd_seal_write",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE);
+
+ mfd_assert_read(fd);
+ mfd_fail_write(fd);
+ mfd_assert_shrink(fd);
+ mfd_assert_grow(fd);
+ mfd_fail_grow_write(fd);
+
+ close(fd);
+}
+
+/*
+ * Test SEAL_SHRINK
+ * Test whether SEAL_SHRINK actually prevents shrinking
+ */
+static void test_seal_shrink(void)
+{
+ int fd;
+
+ fd = mfd_assert_new("kern_memfd_seal_shrink",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK);
+
+ mfd_assert_read(fd);
+ mfd_assert_write(fd);
+ mfd_fail_shrink(fd);
+ mfd_assert_grow(fd);
+ mfd_assert_grow_write(fd);
+
+ close(fd);
+}
+
+/*
+ * Test SEAL_GROW
+ * Test whether SEAL_GROW actually prevents growing
+ */
+static void test_seal_grow(void)
+{
+ int fd;
+
+ fd = mfd_assert_new("kern_memfd_seal_grow",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_GROW);
+ mfd_assert_has_seals(fd, F_SEAL_GROW);
+
+ mfd_assert_read(fd);
+ mfd_assert_write(fd);
+ mfd_assert_shrink(fd);
+ mfd_fail_grow(fd);
+ mfd_fail_grow_write(fd);
+
+ close(fd);
+}
+
+/*
+ * Test SEAL_SHRINK | SEAL_GROW
+ * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
+ */
+static void test_seal_resize(void)
+{
+ int fd;
+
+ fd = mfd_assert_new("kern_memfd_seal_resize",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
+
+ mfd_assert_read(fd);
+ mfd_assert_write(fd);
+ mfd_fail_shrink(fd);
+ mfd_fail_grow(fd);
+ mfd_fail_grow_write(fd);
+
+ close(fd);
+}
+
+/*
+ * Test sharing via dup()
+ * Test that seals are shared between dupped FDs and they're all equal.
+ */
+static void test_share_dup(void)
+{
+ int fd, fd2;
+
+ fd = mfd_assert_new("kern_memfd_share_dup",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+
+ fd2 = mfd_assert_dup(fd);
+ mfd_assert_has_seals(fd2, 0);
+
+ mfd_assert_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE);
+
+ mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
+
+ mfd_assert_add_seals(fd, F_SEAL_SEAL);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
+
+ mfd_fail_add_seals(fd, F_SEAL_GROW);
+ mfd_fail_add_seals(fd2, F_SEAL_GROW);
+ mfd_fail_add_seals(fd, F_SEAL_SEAL);
+ mfd_fail_add_seals(fd2, F_SEAL_SEAL);
+
+ close(fd2);
+
+ mfd_fail_add_seals(fd, F_SEAL_GROW);
+ close(fd);
+}
+
+/*
+ * Test sealing with active mmap()s
+ * Modifying seals is only allowed if no other mmap() refs exist.
+ */
+static void test_share_mmap(void)
+{
+ int fd;
+ void *p;
+
+ fd = mfd_assert_new("kern_memfd_share_mmap",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+
+ /* shared/writable ref prevents sealing WRITE, but allows others */
+ p = mfd_assert_mmap_shared(fd);
+ mfd_fail_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, 0);
+ mfd_assert_add_seals(fd, F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd, F_SEAL_SHRINK);
+ munmap(p, MFD_DEF_SIZE);
+
+ /* readable ref allows sealing */
+ p = mfd_assert_mmap_private(fd);
+ mfd_assert_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
+ munmap(p, MFD_DEF_SIZE);
+
+ close(fd);
+}
+
+/*
+ * Test sealing with open(/proc/self/fd/%d)
+ * Via /proc we can get access to a separate file-context for the same memfd.
+ * This is *not* like dup(), but like a real separate open(). Make sure the
+ * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
+ */
+static void test_share_open(void)
+{
+ int fd, fd2;
+
+ fd = mfd_assert_new("kern_memfd_share_open",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+
+ fd2 = mfd_assert_open(fd, O_RDWR, 0);
+ mfd_assert_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE);
+
+ mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
+
+ close(fd);
+ fd = mfd_assert_open(fd2, O_RDONLY, 0);
+
+ mfd_fail_add_seals(fd, F_SEAL_SEAL);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
+
+ close(fd2);
+ fd2 = mfd_assert_open(fd, O_RDWR, 0);
+
+ mfd_assert_add_seals(fd2, F_SEAL_SEAL);
+ mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
+ mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
+
+ close(fd2);
+ close(fd);
+}
+
+/*
+ * Test sharing via fork()
+ * Test whether seal-modifications work as expected with forked childs.
+ */
+static void test_share_fork(void)
+{
+ int fd;
+ pid_t pid;
+
+ fd = mfd_assert_new("kern_memfd_share_fork",
+ MFD_DEF_SIZE,
+ MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ mfd_assert_has_seals(fd, 0);
+
+ pid = spawn_idle_thread(0);
+ mfd_assert_add_seals(fd, F_SEAL_SEAL);
+ mfd_assert_has_seals(fd, F_SEAL_SEAL);
+
+ mfd_fail_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_SEAL);
+
+ join_idle_thread(pid);
+
+ mfd_fail_add_seals(fd, F_SEAL_WRITE);
+ mfd_assert_has_seals(fd, F_SEAL_SEAL);
+
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ pid_t pid;
+
+ printf("memfd: CREATE\n");
+ test_create();
+ printf("memfd: BASIC\n");
+ test_basic();
+
+ printf("memfd: SEAL-WRITE\n");
+ test_seal_write();
+ printf("memfd: SEAL-SHRINK\n");
+ test_seal_shrink();
+ printf("memfd: SEAL-GROW\n");
+ test_seal_grow();
+ printf("memfd: SEAL-RESIZE\n");
+ test_seal_resize();
+
+ printf("memfd: SHARE-DUP\n");
+ test_share_dup();
+ printf("memfd: SHARE-MMAP\n");
+ test_share_mmap();
+ printf("memfd: SHARE-OPEN\n");
+ test_share_open();
+ printf("memfd: SHARE-FORK\n");
+ test_share_fork();
+
+ /* Run test-suite in a multi-threaded environment with a shared
+ * file-table. */
+ pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM);
+ printf("memfd: SHARE-DUP (shared file-table)\n");
+ test_share_dup();
+ printf("memfd: SHARE-MMAP (shared file-table)\n");
+ test_share_mmap();
+ printf("memfd: SHARE-OPEN (shared file-table)\n");
+ test_share_open();
+ printf("memfd: SHARE-FORK (shared file-table)\n");
+ test_share_fork();
+ join_idle_thread(pid);
+
+ printf("memfd: DONE\n");
+
+ return 0;
+}
diff --git a/tools/testing/selftests/memfd/run_fuse_test.sh b/tools/testing/selftests/memfd/run_fuse_test.sh
new file mode 100644
index 000000000000..69b930e1e041
--- /dev/null
+++ b/tools/testing/selftests/memfd/run_fuse_test.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+if test -d "./mnt" ; then
+ fusermount -u ./mnt
+ rmdir ./mnt
+fi
+
+set -e
+
+mkdir mnt
+./fuse_mnt ./mnt
+./fuse_test ./mnt/memfd
+fusermount -u ./mnt
+rmdir ./mnt
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
index 058c76f5d102..d46b8d489cd2 100644
--- a/tools/testing/selftests/memory-hotplug/Makefile
+++ b/tools/testing/selftests/memory-hotplug/Makefile
@@ -1,6 +1,9 @@
all:
run_tests:
+ @/bin/bash ./on-off-test.sh -r 2 || echo "memory-hotplug selftests: [FAIL]"
+
+run_full_test:
@/bin/bash ./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]"
clean:
diff --git a/tools/testing/selftests/memory-hotplug/on-off-test.sh b/tools/testing/selftests/memory-hotplug/on-off-test.sh
index a2816f631542..6cddde0b96f8 100644
--- a/tools/testing/selftests/memory-hotplug/on-off-test.sh
+++ b/tools/testing/selftests/memory-hotplug/on-off-test.sh
@@ -142,10 +142,16 @@ fi
prerequisite
+echo "Test scope: $ratio% hotplug memory"
+echo -e "\t online all hotplug memory in offline state"
+echo -e "\t offline $ratio% hotplug memory in online state"
+echo -e "\t online all hotplug memory in offline state"
+
#
# Online all hot-pluggable memory
#
for memory in `hotplaggable_offline_memory`; do
+ echo offline-online $memory
online_memory_expect_success $memory
done
@@ -154,6 +160,7 @@ done
#
for memory in `hotpluggable_online_memory`; do
if [ $((RANDOM % 100)) -lt $ratio ]; then
+ echo online-offline $memory
offline_memory_expect_success $memory
fi
done
@@ -162,6 +169,7 @@ done
# Online all hot-pluggable memory again
#
for memory in `hotplaggable_offline_memory`; do
+ echo offline-online $memory
online_memory_expect_success $memory
done
diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile
index 218a122c7951..8056e2e68fa4 100644
--- a/tools/testing/selftests/mqueue/Makefile
+++ b/tools/testing/selftests/mqueue/Makefile
@@ -1,6 +1,6 @@
all:
- gcc -O2 -lrt mq_open_tests.c -o mq_open_tests
- gcc -O2 -lrt -lpthread -lpopt -o mq_perf_tests mq_perf_tests.c
+ gcc -O2 mq_open_tests.c -o mq_open_tests -lrt
+ gcc -O2 -o mq_perf_tests mq_perf_tests.c -lrt -lpthread -lpopt
run_tests:
@./mq_open_tests /test1 || echo "mq_open_tests: [FAIL]"
diff --git a/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c
index 711cc2923047..9c1a5d359055 100644
--- a/tools/testing/selftests/mqueue/mq_open_tests.c
+++ b/tools/testing/selftests/mqueue/mq_open_tests.c
@@ -80,7 +80,8 @@ void shutdown(int exit_val, char *err_cause, int line_no)
if (in_shutdown++)
return;
- seteuid(0);
+ if (seteuid(0) == -1)
+ perror("seteuid() failed");
if (queue != -1)
if (mq_close(queue))
@@ -292,8 +293,10 @@ int main(int argc, char *argv[])
/* Tell the user our initial state */
printf("\nInitial system state:\n");
printf("\tUsing queue path:\t\t%s\n", queue_path);
- printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", saved_limits.rlim_cur);
- printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", saved_limits.rlim_max);
+ printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n",
+ (long) saved_limits.rlim_cur);
+ printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n",
+ (long) saved_limits.rlim_max);
printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
if (default_settings) {
@@ -308,8 +311,8 @@ int main(int argc, char *argv[])
validate_current_settings();
printf("Adjusted system state for testing:\n");
- printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", cur_limits.rlim_cur);
- printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", cur_limits.rlim_max);
+ printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur);
+ printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max);
printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
if (default_settings) {
@@ -454,7 +457,12 @@ int main(int argc, char *argv[])
else
printf("Queue open with total size > 2GB when euid = 0 "
"failed:\t\t\tPASS\n");
- seteuid(99);
+
+ if (seteuid(99) == -1) {
+ perror("seteuid() failed");
+ exit(1);
+ }
+
attr.mq_maxmsg = cur_max_msgs;
attr.mq_msgsize = cur_max_msgsize;
if (test_queue_fail(&attr, &result))
diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c
index 2fadd4b97045..94dae65eea41 100644
--- a/tools/testing/selftests/mqueue/mq_perf_tests.c
+++ b/tools/testing/selftests/mqueue/mq_perf_tests.c
@@ -296,9 +296,9 @@ static inline void open_queue(struct mq_attr *attr)
printf("\n\tQueue %s created:\n", queue_path);
printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ?
"O_NONBLOCK" : "(null)");
- printf("\t\tmq_maxmsg:\t\t\t%d\n", result.mq_maxmsg);
- printf("\t\tmq_msgsize:\t\t\t%d\n", result.mq_msgsize);
- printf("\t\tmq_curmsgs:\t\t\t%d\n", result.mq_curmsgs);
+ printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg);
+ printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize);
+ printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs);
}
void *fake_cont_thread(void *arg)
@@ -440,7 +440,7 @@ void *perf_test_thread(void *arg)
shutdown(2, "clock_getres()", __LINE__);
printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max);
- printf("\t\tClock resolution:\t\t%d nsec%s\n", res.tv_nsec,
+ printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec,
res.tv_nsec > 1 ? "s" : "");
@@ -454,20 +454,20 @@ void *perf_test_thread(void *arg)
recv_total.tv_nsec = 0;
for (i = 0; i < TEST1_LOOPS; i++)
do_send_recv();
- printf("\t\tSend msg:\t\t\t%d.%ds total time\n",
+ printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
send_total.tv_sec, send_total.tv_nsec);
nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
send_total.tv_nsec) / TEST1_LOOPS;
- printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
- printf("\t\tRecv msg:\t\t\t%d.%ds total time\n",
+ printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
+ printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
recv_total.tv_sec, recv_total.tv_nsec);
nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
recv_total.tv_nsec) / TEST1_LOOPS;
- printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
+ printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
- printf(cur_test->desc);
+ printf("%s:\n", cur_test->desc);
printf("\t\t(%d iterations)\n", TEST2_LOOPS);
prio_out = 0;
send_total.tv_sec = 0;
@@ -493,16 +493,16 @@ void *perf_test_thread(void *arg)
cur_test->func(&prio_out);
}
printf("done.\n");
- printf("\t\tSend msg:\t\t\t%d.%ds total time\n",
+ printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
send_total.tv_sec, send_total.tv_nsec);
nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
send_total.tv_nsec) / TEST2_LOOPS;
- printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
- printf("\t\tRecv msg:\t\t\t%d.%ds total time\n",
+ printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
+ printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
recv_total.tv_sec, recv_total.tv_nsec);
nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
recv_total.tv_nsec) / TEST2_LOOPS;
- printf("\t\t\t\t\t\t%d nsec/msg\n", nsec);
+ printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
printf("\t\tDraining queue...");
fflush(stdout);
clock_gettime(clock, &start);
@@ -653,8 +653,10 @@ int main(int argc, char *argv[])
/* Tell the user our initial state */
printf("\nInitial system state:\n");
printf("\tUsing queue path:\t\t\t%s\n", queue_path);
- printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n", saved_limits.rlim_cur);
- printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", saved_limits.rlim_max);
+ printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
+ (long) saved_limits.rlim_cur);
+ printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
+ (long) saved_limits.rlim_max);
printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
printf("\tNice value:\t\t\t\t%d\n", cur_nice);
@@ -667,10 +669,10 @@ int main(int argc, char *argv[])
printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
} else {
- printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n",
- cur_limits.rlim_cur);
- printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n",
- cur_limits.rlim_max);
+ printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
+ (long) cur_limits.rlim_cur);
+ printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
+ (long) cur_limits.rlim_max);
}
printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index 54833a791a44..74a78cedce37 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -17,10 +17,10 @@ TARGETS = pmu copyloops mm tm
endif
-all:
- @for TARGET in $(TARGETS); do \
- $(MAKE) -C $$TARGET all; \
- done;
+all: $(TARGETS)
+
+$(TARGETS):
+ $(MAKE) -k -C $@ all
run_tests: all
@for TARGET in $(TARGETS); do \
@@ -36,4 +36,4 @@ clean:
tags:
find . -name '*.c' -o -name '*.h' | xargs ctags
-.PHONY: all run_tests clean tags
+.PHONY: all run_tests clean tags $(TARGETS)
diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile
index b9ff0db42c79..c9f4263906a5 100644
--- a/tools/testing/selftests/powerpc/pmu/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/Makefile
@@ -1,10 +1,12 @@
noarg:
$(MAKE) -C ../
-PROGS := count_instructions
-EXTRA_SOURCES := ../harness.c event.c
+PROGS := count_instructions l3_bank_test per_event_excludes
+EXTRA_SOURCES := ../harness.c event.c lib.c
-all: $(PROGS) sub_all
+SUB_TARGETS = ebb
+
+all: $(PROGS) $(SUB_TARGETS)
$(PROGS): $(EXTRA_SOURCES)
@@ -20,13 +22,8 @@ run_tests: all sub_run_tests
clean: sub_clean
rm -f $(PROGS) loop.o
-
-SUB_TARGETS = ebb
-
-sub_all:
- @for TARGET in $(SUB_TARGETS); do \
- $(MAKE) -C $$TARGET all; \
- done;
+$(SUB_TARGETS):
+ $(MAKE) -k -C $@ all
sub_run_tests: all
@for TARGET in $(SUB_TARGETS); do \
@@ -38,4 +35,4 @@ sub_clean:
$(MAKE) -C $$TARGET clean; \
done;
-.PHONY: all run_tests clean sub_all sub_run_tests sub_clean
+.PHONY: all run_tests clean sub_run_tests sub_clean $(SUB_TARGETS)
diff --git a/tools/testing/selftests/powerpc/pmu/count_instructions.c b/tools/testing/selftests/powerpc/pmu/count_instructions.c
index 312b4f0fd27c..4622117b24c0 100644
--- a/tools/testing/selftests/powerpc/pmu/count_instructions.c
+++ b/tools/testing/selftests/powerpc/pmu/count_instructions.c
@@ -12,6 +12,7 @@
#include "event.h"
#include "utils.h"
+#include "lib.h"
extern void thirty_two_instruction_loop(u64 loops);
@@ -90,7 +91,7 @@ static u64 determine_overhead(struct event *events)
return overhead;
}
-static int count_instructions(void)
+static int test_body(void)
{
struct event events[2];
u64 overhead;
@@ -111,17 +112,23 @@ static int count_instructions(void)
overhead = determine_overhead(events);
printf("Overhead of null loop: %llu instructions\n", overhead);
- /* Run for 1M instructions */
- FAIL_IF(do_count_loop(events, 0x100000, overhead, true));
+ /* Run for 1Mi instructions */
+ FAIL_IF(do_count_loop(events, 1000000, overhead, true));
+
+ /* Run for 10Mi instructions */
+ FAIL_IF(do_count_loop(events, 10000000, overhead, true));
+
+ /* Run for 100Mi instructions */
+ FAIL_IF(do_count_loop(events, 100000000, overhead, true));
- /* Run for 10M instructions */
- FAIL_IF(do_count_loop(events, 0xa00000, overhead, true));
+ /* Run for 1Bi instructions */
+ FAIL_IF(do_count_loop(events, 1000000000, overhead, true));
- /* Run for 100M instructions */
- FAIL_IF(do_count_loop(events, 0x6400000, overhead, true));
+ /* Run for 16Bi instructions */
+ FAIL_IF(do_count_loop(events, 16000000000, overhead, true));
- /* Run for 1G instructions */
- FAIL_IF(do_count_loop(events, 0x40000000, overhead, true));
+ /* Run for 64Bi instructions */
+ FAIL_IF(do_count_loop(events, 64000000000, overhead, true));
event_close(&events[0]);
event_close(&events[1]);
@@ -129,6 +136,11 @@ static int count_instructions(void)
return 0;
}
+static int count_instructions(void)
+{
+ return eat_cpu(test_body);
+}
+
int main(void)
{
return test_harness(count_instructions, "count_instructions");
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
index edbba2affc2c..3dc4332698cb 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
@@ -13,11 +13,12 @@ PROGS := reg_access_test event_attributes_test cycles_test \
close_clears_pmcc_test instruction_count_test \
fork_cleanup_test ebb_on_child_test \
ebb_on_willing_child_test back_to_back_ebbs_test \
- lost_exception_test no_handler_test
+ lost_exception_test no_handler_test \
+ cycles_with_mmcr2_test
all: $(PROGS)
-$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c
+$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c busy_loop.S
instruction_count_test: ../loop.S
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S b/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S
new file mode 100644
index 000000000000..c7e4093f1cd3
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2014, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#include <ppc-asm.h>
+
+ .text
+
+FUNC_START(core_busy_loop)
+ stdu %r1, -168(%r1)
+ std r14, 160(%r1)
+ std r15, 152(%r1)
+ std r16, 144(%r1)
+ std r17, 136(%r1)
+ std r18, 128(%r1)
+ std r19, 120(%r1)
+ std r20, 112(%r1)
+ std r21, 104(%r1)
+ std r22, 96(%r1)
+ std r23, 88(%r1)
+ std r24, 80(%r1)
+ std r25, 72(%r1)
+ std r26, 64(%r1)
+ std r27, 56(%r1)
+ std r28, 48(%r1)
+ std r29, 40(%r1)
+ std r30, 32(%r1)
+ std r31, 24(%r1)
+
+ li r3, 0x3030
+ std r3, -96(%r1)
+ li r4, 0x4040
+ std r4, -104(%r1)
+ li r5, 0x5050
+ std r5, -112(%r1)
+ li r6, 0x6060
+ std r6, -120(%r1)
+ li r7, 0x7070
+ std r7, -128(%r1)
+ li r8, 0x0808
+ std r8, -136(%r1)
+ li r9, 0x0909
+ std r9, -144(%r1)
+ li r10, 0x1010
+ std r10, -152(%r1)
+ li r11, 0x1111
+ std r11, -160(%r1)
+ li r14, 0x1414
+ std r14, -168(%r1)
+ li r15, 0x1515
+ std r15, -176(%r1)
+ li r16, 0x1616
+ std r16, -184(%r1)
+ li r17, 0x1717
+ std r17, -192(%r1)
+ li r18, 0x1818
+ std r18, -200(%r1)
+ li r19, 0x1919
+ std r19, -208(%r1)
+ li r20, 0x2020
+ std r20, -216(%r1)
+ li r21, 0x2121
+ std r21, -224(%r1)
+ li r22, 0x2222
+ std r22, -232(%r1)
+ li r23, 0x2323
+ std r23, -240(%r1)
+ li r24, 0x2424
+ std r24, -248(%r1)
+ li r25, 0x2525
+ std r25, -256(%r1)
+ li r26, 0x2626
+ std r26, -264(%r1)
+ li r27, 0x2727
+ std r27, -272(%r1)
+ li r28, 0x2828
+ std r28, -280(%r1)
+ li r29, 0x2929
+ std r29, -288(%r1)
+ li r30, 0x3030
+ li r31, 0x3131
+
+ li r3, 0
+0: addi r3, r3, 1
+ cmpwi r3, 100
+ blt 0b
+
+ /* Return 1 (fail) unless we get through all the checks */
+ li r3, 1
+
+ /* Check none of our registers have been corrupted */
+ cmpwi r4, 0x4040
+ bne 1f
+ cmpwi r5, 0x5050
+ bne 1f
+ cmpwi r6, 0x6060
+ bne 1f
+ cmpwi r7, 0x7070
+ bne 1f
+ cmpwi r8, 0x0808
+ bne 1f
+ cmpwi r9, 0x0909
+ bne 1f
+ cmpwi r10, 0x1010
+ bne 1f
+ cmpwi r11, 0x1111
+ bne 1f
+ cmpwi r14, 0x1414
+ bne 1f
+ cmpwi r15, 0x1515
+ bne 1f
+ cmpwi r16, 0x1616
+ bne 1f
+ cmpwi r17, 0x1717
+ bne 1f
+ cmpwi r18, 0x1818
+ bne 1f
+ cmpwi r19, 0x1919
+ bne 1f
+ cmpwi r20, 0x2020
+ bne 1f
+ cmpwi r21, 0x2121
+ bne 1f
+ cmpwi r22, 0x2222
+ bne 1f
+ cmpwi r23, 0x2323
+ bne 1f
+ cmpwi r24, 0x2424
+ bne 1f
+ cmpwi r25, 0x2525
+ bne 1f
+ cmpwi r26, 0x2626
+ bne 1f
+ cmpwi r27, 0x2727
+ bne 1f
+ cmpwi r28, 0x2828
+ bne 1f
+ cmpwi r29, 0x2929
+ bne 1f
+ cmpwi r30, 0x3030
+ bne 1f
+ cmpwi r31, 0x3131
+ bne 1f
+
+ /* Load junk into all our registers before we reload them from the stack. */
+ li r3, 0xde
+ li r4, 0xad
+ li r5, 0xbe
+ li r6, 0xef
+ li r7, 0xde
+ li r8, 0xad
+ li r9, 0xbe
+ li r10, 0xef
+ li r11, 0xde
+ li r14, 0xad
+ li r15, 0xbe
+ li r16, 0xef
+ li r17, 0xde
+ li r18, 0xad
+ li r19, 0xbe
+ li r20, 0xef
+ li r21, 0xde
+ li r22, 0xad
+ li r23, 0xbe
+ li r24, 0xef
+ li r25, 0xde
+ li r26, 0xad
+ li r27, 0xbe
+ li r28, 0xef
+ li r29, 0xdd
+
+ ld r3, -96(%r1)
+ cmpwi r3, 0x3030
+ bne 1f
+ ld r4, -104(%r1)
+ cmpwi r4, 0x4040
+ bne 1f
+ ld r5, -112(%r1)
+ cmpwi r5, 0x5050
+ bne 1f
+ ld r6, -120(%r1)
+ cmpwi r6, 0x6060
+ bne 1f
+ ld r7, -128(%r1)
+ cmpwi r7, 0x7070
+ bne 1f
+ ld r8, -136(%r1)
+ cmpwi r8, 0x0808
+ bne 1f
+ ld r9, -144(%r1)
+ cmpwi r9, 0x0909
+ bne 1f
+ ld r10, -152(%r1)
+ cmpwi r10, 0x1010
+ bne 1f
+ ld r11, -160(%r1)
+ cmpwi r11, 0x1111
+ bne 1f
+ ld r14, -168(%r1)
+ cmpwi r14, 0x1414
+ bne 1f
+ ld r15, -176(%r1)
+ cmpwi r15, 0x1515
+ bne 1f
+ ld r16, -184(%r1)
+ cmpwi r16, 0x1616
+ bne 1f
+ ld r17, -192(%r1)
+ cmpwi r17, 0x1717
+ bne 1f
+ ld r18, -200(%r1)
+ cmpwi r18, 0x1818
+ bne 1f
+ ld r19, -208(%r1)
+ cmpwi r19, 0x1919
+ bne 1f
+ ld r20, -216(%r1)
+ cmpwi r20, 0x2020
+ bne 1f
+ ld r21, -224(%r1)
+ cmpwi r21, 0x2121
+ bne 1f
+ ld r22, -232(%r1)
+ cmpwi r22, 0x2222
+ bne 1f
+ ld r23, -240(%r1)
+ cmpwi r23, 0x2323
+ bne 1f
+ ld r24, -248(%r1)
+ cmpwi r24, 0x2424
+ bne 1f
+ ld r25, -256(%r1)
+ cmpwi r25, 0x2525
+ bne 1f
+ ld r26, -264(%r1)
+ cmpwi r26, 0x2626
+ bne 1f
+ ld r27, -272(%r1)
+ cmpwi r27, 0x2727
+ bne 1f
+ ld r28, -280(%r1)
+ cmpwi r28, 0x2828
+ bne 1f
+ ld r29, -288(%r1)
+ cmpwi r29, 0x2929
+ bne 1f
+
+ /* Load 0 (success) to return */
+ li r3, 0
+
+1: ld r14, 160(%r1)
+ ld r15, 152(%r1)
+ ld r16, 144(%r1)
+ ld r17, 136(%r1)
+ ld r18, 128(%r1)
+ ld r19, 120(%r1)
+ ld r20, 112(%r1)
+ ld r21, 104(%r1)
+ ld r22, 96(%r1)
+ ld r23, 88(%r1)
+ ld r24, 80(%r1)
+ ld r25, 72(%r1)
+ ld r26, 64(%r1)
+ ld r27, 56(%r1)
+ ld r28, 48(%r1)
+ ld r29, 40(%r1)
+ ld r30, 32(%r1)
+ ld r31, 24(%r1)
+ addi %r1, %r1, 168
+ blr
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c
new file mode 100644
index 000000000000..d43029b0800c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2014, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "ebb.h"
+
+
+/*
+ * Test of counting cycles while manipulating the user accessible bits in MMCR2.
+ */
+
+/* We use two values because the first freezes PMC1 and so we would get no EBBs */
+#define MMCR2_EXPECTED_1 0x4020100804020000UL /* (FC1P|FC2P|FC3P|FC4P|FC5P|FC6P) */
+#define MMCR2_EXPECTED_2 0x0020100804020000UL /* ( FC2P|FC3P|FC4P|FC5P|FC6P) */
+
+
+int cycles_with_mmcr2(void)
+{
+ struct event event;
+ uint64_t val, expected[2], actual;
+ int i;
+ bool bad_mmcr2;
+
+ event_init_named(&event, 0x1001e, "cycles");
+ event_leader_ebb_init(&event);
+
+ event.attr.exclude_kernel = 1;
+ event.attr.exclude_hv = 1;
+ event.attr.exclude_idle = 1;
+
+ FAIL_IF(event_open(&event));
+
+ ebb_enable_pmc_counting(1);
+ setup_ebb_handler(standard_ebb_callee);
+ ebb_global_enable();
+
+ FAIL_IF(ebb_event_enable(&event));
+
+ mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
+
+ /* XXX Set of MMCR2 must be after enable */
+ expected[0] = MMCR2_EXPECTED_1;
+ expected[1] = MMCR2_EXPECTED_2;
+ i = 0;
+ bad_mmcr2 = false;
+
+ /* Make sure we loop until we take at least one EBB */
+ while ((ebb_state.stats.ebb_count < 20 && !bad_mmcr2) ||
+ ebb_state.stats.ebb_count < 1)
+ {
+ mtspr(SPRN_MMCR2, expected[i % 2]);
+
+ FAIL_IF(core_busy_loop());
+
+ val = mfspr(SPRN_MMCR2);
+ if (val != expected[i % 2]) {
+ bad_mmcr2 = true;
+ actual = val;
+ }
+
+ i++;
+ }
+
+ ebb_global_disable();
+ ebb_freeze_pmcs();
+
+ count_pmc(1, sample_period);
+
+ dump_ebb_state();
+
+ event_close(&event);
+
+ FAIL_IF(ebb_state.stats.ebb_count == 0);
+
+ if (bad_mmcr2)
+ printf("Bad MMCR2 value seen is 0x%lx\n", actual);
+
+ FAIL_IF(bad_mmcr2);
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(cycles_with_mmcr2, "cycles_with_mmcr2");
+}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
index 1b46be94b64c..d7a72ce696b5 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
@@ -224,6 +224,7 @@ void dump_ebb_hw_state(void)
printf("HW state:\n" \
"MMCR0 0x%016x %s\n" \
+ "MMCR2 0x%016lx\n" \
"EBBHR 0x%016lx\n" \
"BESCR 0x%016llx %s\n" \
"PMC1 0x%016lx\n" \
@@ -233,10 +234,11 @@ void dump_ebb_hw_state(void)
"PMC5 0x%016lx\n" \
"PMC6 0x%016lx\n" \
"SIAR 0x%016lx\n",
- mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_EBBHR), bescr,
- decode_bescr(bescr), mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
- mfspr(SPRN_PMC3), mfspr(SPRN_PMC4), mfspr(SPRN_PMC5),
- mfspr(SPRN_PMC6), mfspr(SPRN_SIAR));
+ mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_MMCR2),
+ mfspr(SPRN_EBBHR), bescr, decode_bescr(bescr),
+ mfspr(SPRN_PMC1), mfspr(SPRN_PMC2), mfspr(SPRN_PMC3),
+ mfspr(SPRN_PMC4), mfspr(SPRN_PMC5), mfspr(SPRN_PMC6),
+ mfspr(SPRN_SIAR));
}
void dump_ebb_state(void)
@@ -335,257 +337,6 @@ void event_leader_ebb_init(struct event *e)
e->attr.pinned = 1;
}
-int core_busy_loop(void)
-{
- int rc;
-
- asm volatile (
- "li 3, 0x3030\n"
- "std 3, -96(1)\n"
- "li 4, 0x4040\n"
- "std 4, -104(1)\n"
- "li 5, 0x5050\n"
- "std 5, -112(1)\n"
- "li 6, 0x6060\n"
- "std 6, -120(1)\n"
- "li 7, 0x7070\n"
- "std 7, -128(1)\n"
- "li 8, 0x0808\n"
- "std 8, -136(1)\n"
- "li 9, 0x0909\n"
- "std 9, -144(1)\n"
- "li 10, 0x1010\n"
- "std 10, -152(1)\n"
- "li 11, 0x1111\n"
- "std 11, -160(1)\n"
- "li 14, 0x1414\n"
- "std 14, -168(1)\n"
- "li 15, 0x1515\n"
- "std 15, -176(1)\n"
- "li 16, 0x1616\n"
- "std 16, -184(1)\n"
- "li 17, 0x1717\n"
- "std 17, -192(1)\n"
- "li 18, 0x1818\n"
- "std 18, -200(1)\n"
- "li 19, 0x1919\n"
- "std 19, -208(1)\n"
- "li 20, 0x2020\n"
- "std 20, -216(1)\n"
- "li 21, 0x2121\n"
- "std 21, -224(1)\n"
- "li 22, 0x2222\n"
- "std 22, -232(1)\n"
- "li 23, 0x2323\n"
- "std 23, -240(1)\n"
- "li 24, 0x2424\n"
- "std 24, -248(1)\n"
- "li 25, 0x2525\n"
- "std 25, -256(1)\n"
- "li 26, 0x2626\n"
- "std 26, -264(1)\n"
- "li 27, 0x2727\n"
- "std 27, -272(1)\n"
- "li 28, 0x2828\n"
- "std 28, -280(1)\n"
- "li 29, 0x2929\n"
- "std 29, -288(1)\n"
- "li 30, 0x3030\n"
- "li 31, 0x3131\n"
-
- "li 3, 0\n"
- "0: "
- "addi 3, 3, 1\n"
- "cmpwi 3, 100\n"
- "blt 0b\n"
-
- /* Return 1 (fail) unless we get through all the checks */
- "li 0, 1\n"
-
- /* Check none of our registers have been corrupted */
- "cmpwi 4, 0x4040\n"
- "bne 1f\n"
- "cmpwi 5, 0x5050\n"
- "bne 1f\n"
- "cmpwi 6, 0x6060\n"
- "bne 1f\n"
- "cmpwi 7, 0x7070\n"
- "bne 1f\n"
- "cmpwi 8, 0x0808\n"
- "bne 1f\n"
- "cmpwi 9, 0x0909\n"
- "bne 1f\n"
- "cmpwi 10, 0x1010\n"
- "bne 1f\n"
- "cmpwi 11, 0x1111\n"
- "bne 1f\n"
- "cmpwi 14, 0x1414\n"
- "bne 1f\n"
- "cmpwi 15, 0x1515\n"
- "bne 1f\n"
- "cmpwi 16, 0x1616\n"
- "bne 1f\n"
- "cmpwi 17, 0x1717\n"
- "bne 1f\n"
- "cmpwi 18, 0x1818\n"
- "bne 1f\n"
- "cmpwi 19, 0x1919\n"
- "bne 1f\n"
- "cmpwi 20, 0x2020\n"
- "bne 1f\n"
- "cmpwi 21, 0x2121\n"
- "bne 1f\n"
- "cmpwi 22, 0x2222\n"
- "bne 1f\n"
- "cmpwi 23, 0x2323\n"
- "bne 1f\n"
- "cmpwi 24, 0x2424\n"
- "bne 1f\n"
- "cmpwi 25, 0x2525\n"
- "bne 1f\n"
- "cmpwi 26, 0x2626\n"
- "bne 1f\n"
- "cmpwi 27, 0x2727\n"
- "bne 1f\n"
- "cmpwi 28, 0x2828\n"
- "bne 1f\n"
- "cmpwi 29, 0x2929\n"
- "bne 1f\n"
- "cmpwi 30, 0x3030\n"
- "bne 1f\n"
- "cmpwi 31, 0x3131\n"
- "bne 1f\n"
-
- /* Load junk into all our registers before we reload them from the stack. */
- "li 3, 0xde\n"
- "li 4, 0xad\n"
- "li 5, 0xbe\n"
- "li 6, 0xef\n"
- "li 7, 0xde\n"
- "li 8, 0xad\n"
- "li 9, 0xbe\n"
- "li 10, 0xef\n"
- "li 11, 0xde\n"
- "li 14, 0xad\n"
- "li 15, 0xbe\n"
- "li 16, 0xef\n"
- "li 17, 0xde\n"
- "li 18, 0xad\n"
- "li 19, 0xbe\n"
- "li 20, 0xef\n"
- "li 21, 0xde\n"
- "li 22, 0xad\n"
- "li 23, 0xbe\n"
- "li 24, 0xef\n"
- "li 25, 0xde\n"
- "li 26, 0xad\n"
- "li 27, 0xbe\n"
- "li 28, 0xef\n"
- "li 29, 0xdd\n"
-
- "ld 3, -96(1)\n"
- "cmpwi 3, 0x3030\n"
- "bne 1f\n"
- "ld 4, -104(1)\n"
- "cmpwi 4, 0x4040\n"
- "bne 1f\n"
- "ld 5, -112(1)\n"
- "cmpwi 5, 0x5050\n"
- "bne 1f\n"
- "ld 6, -120(1)\n"
- "cmpwi 6, 0x6060\n"
- "bne 1f\n"
- "ld 7, -128(1)\n"
- "cmpwi 7, 0x7070\n"
- "bne 1f\n"
- "ld 8, -136(1)\n"
- "cmpwi 8, 0x0808\n"
- "bne 1f\n"
- "ld 9, -144(1)\n"
- "cmpwi 9, 0x0909\n"
- "bne 1f\n"
- "ld 10, -152(1)\n"
- "cmpwi 10, 0x1010\n"
- "bne 1f\n"
- "ld 11, -160(1)\n"
- "cmpwi 11, 0x1111\n"
- "bne 1f\n"
- "ld 14, -168(1)\n"
- "cmpwi 14, 0x1414\n"
- "bne 1f\n"
- "ld 15, -176(1)\n"
- "cmpwi 15, 0x1515\n"
- "bne 1f\n"
- "ld 16, -184(1)\n"
- "cmpwi 16, 0x1616\n"
- "bne 1f\n"
- "ld 17, -192(1)\n"
- "cmpwi 17, 0x1717\n"
- "bne 1f\n"
- "ld 18, -200(1)\n"
- "cmpwi 18, 0x1818\n"
- "bne 1f\n"
- "ld 19, -208(1)\n"
- "cmpwi 19, 0x1919\n"
- "bne 1f\n"
- "ld 20, -216(1)\n"
- "cmpwi 20, 0x2020\n"
- "bne 1f\n"
- "ld 21, -224(1)\n"
- "cmpwi 21, 0x2121\n"
- "bne 1f\n"
- "ld 22, -232(1)\n"
- "cmpwi 22, 0x2222\n"
- "bne 1f\n"
- "ld 23, -240(1)\n"
- "cmpwi 23, 0x2323\n"
- "bne 1f\n"
- "ld 24, -248(1)\n"
- "cmpwi 24, 0x2424\n"
- "bne 1f\n"
- "ld 25, -256(1)\n"
- "cmpwi 25, 0x2525\n"
- "bne 1f\n"
- "ld 26, -264(1)\n"
- "cmpwi 26, 0x2626\n"
- "bne 1f\n"
- "ld 27, -272(1)\n"
- "cmpwi 27, 0x2727\n"
- "bne 1f\n"
- "ld 28, -280(1)\n"
- "cmpwi 28, 0x2828\n"
- "bne 1f\n"
- "ld 29, -288(1)\n"
- "cmpwi 29, 0x2929\n"
- "bne 1f\n"
-
- /* Load 0 (success) to return */
- "li 0, 0\n"
-
- "1: mr %0, 0\n"
-
- : "=r" (rc)
- : /* no inputs */
- : "3", "4", "5", "6", "7", "8", "9", "10", "11", "14",
- "15", "16", "17", "18", "19", "20", "21", "22", "23",
- "24", "25", "26", "27", "28", "29", "30", "31",
- "memory"
- );
-
- return rc;
-}
-
-int core_busy_loop_with_freeze(void)
-{
- int rc;
-
- mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
- rc = core_busy_loop();
- mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
-
- return rc;
-}
-
int ebb_child(union pipe read_pipe, union pipe write_pipe)
{
struct event event;
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.h b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
index e62bde05bf78..e44eee5d97ca 100644
--- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
@@ -70,7 +70,6 @@ int ebb_check_mmcr0(void);
extern u64 sample_period;
int core_busy_loop(void);
-int core_busy_loop_with_freeze(void);
int ebb_child(union pipe read_pipe, union pipe write_pipe);
int catch_sigill(void (*func)(void));
void write_pmc1(void);
diff --git a/tools/testing/selftests/powerpc/pmu/l3_bank_test.c b/tools/testing/selftests/powerpc/pmu/l3_bank_test.c
new file mode 100644
index 000000000000..77472f31441e
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/l3_bank_test.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "event.h"
+#include "utils.h"
+
+#define MALLOC_SIZE (0x10000 * 10) /* Ought to be enough .. */
+
+/*
+ * Tests that the L3 bank handling is correct. We fixed it in commit e9aaac1.
+ */
+static int l3_bank_test(void)
+{
+ struct event event;
+ char *p;
+ int i;
+
+ p = malloc(MALLOC_SIZE);
+ FAIL_IF(!p);
+
+ event_init(&event, 0x84918F);
+
+ FAIL_IF(event_open(&event));
+
+ for (i = 0; i < MALLOC_SIZE; i += 0x10000)
+ p[i] = i;
+
+ event_read(&event);
+ event_report(&event);
+
+ FAIL_IF(event.result.running == 0);
+ FAIL_IF(event.result.enabled == 0);
+
+ event_close(&event);
+ free(p);
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(l3_bank_test, "l3_bank_test");
+}
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c
index 0f6a4731d546..9768dea37bf3 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.c
+++ b/tools/testing/selftests/powerpc/pmu/lib.c
@@ -5,10 +5,15 @@
#define _GNU_SOURCE /* For CPU_ZERO etc. */
+#include <elf.h>
#include <errno.h>
+#include <fcntl.h>
+#include <link.h>
#include <sched.h>
#include <setjmp.h>
#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/wait.h>
#include "utils.h"
@@ -177,8 +182,8 @@ struct addr_range libc, vdso;
int parse_proc_maps(void)
{
+ unsigned long start, end;
char execute, name[128];
- uint64_t start, end;
FILE *f;
int rc;
@@ -250,3 +255,46 @@ out_close:
out:
return rc;
}
+
+static char auxv[4096];
+
+void *get_auxv_entry(int type)
+{
+ ElfW(auxv_t) *p;
+ void *result;
+ ssize_t num;
+ int fd;
+
+ fd = open("/proc/self/auxv", O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ return NULL;
+ }
+
+ result = NULL;
+
+ num = read(fd, auxv, sizeof(auxv));
+ if (num < 0) {
+ perror("read");
+ goto out;
+ }
+
+ if (num > sizeof(auxv)) {
+ printf("Overflowed auxv buffer\n");
+ goto out;
+ }
+
+ p = (ElfW(auxv_t) *)auxv;
+
+ while (p->a_type != AT_NULL) {
+ if (p->a_type == type) {
+ result = (void *)p->a_un.a_val;
+ break;
+ }
+
+ p++;
+ }
+out:
+ close(fd);
+ return result;
+}
diff --git a/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h
index ca5d72ae3be6..0f0339c8a6f6 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.h
+++ b/tools/testing/selftests/powerpc/pmu/lib.h
@@ -29,6 +29,7 @@ extern int notify_parent(union pipe write_pipe);
extern int notify_parent_of_error(union pipe write_pipe);
extern pid_t eat_cpu(int (test_function)(void));
extern bool require_paranoia_below(int level);
+extern void *get_auxv_entry(int type);
struct addr_range {
uint64_t first, last;
diff --git a/tools/testing/selftests/powerpc/pmu/per_event_excludes.c b/tools/testing/selftests/powerpc/pmu/per_event_excludes.c
new file mode 100644
index 000000000000..fddbbc9cae2f
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/per_event_excludes.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2014, Michael Ellerman, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#define _GNU_SOURCE
+
+#include <elf.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/prctl.h>
+
+#include "event.h"
+#include "lib.h"
+#include "utils.h"
+
+/*
+ * Test that per-event excludes work.
+ */
+
+static int per_event_excludes(void)
+{
+ struct event *e, events[4];
+ char *platform;
+ int i;
+
+ platform = (char *)get_auxv_entry(AT_BASE_PLATFORM);
+ FAIL_IF(!platform);
+ SKIP_IF(strcmp(platform, "power8") != 0);
+
+ /*
+ * We need to create the events disabled, otherwise the running/enabled
+ * counts don't match up.
+ */
+ e = &events[0];
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
+ PERF_TYPE_HARDWARE, "instructions");
+ e->attr.disabled = 1;
+
+ e = &events[1];
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
+ PERF_TYPE_HARDWARE, "instructions(k)");
+ e->attr.disabled = 1;
+ e->attr.exclude_user = 1;
+ e->attr.exclude_hv = 1;
+
+ e = &events[2];
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
+ PERF_TYPE_HARDWARE, "instructions(h)");
+ e->attr.disabled = 1;
+ e->attr.exclude_user = 1;
+ e->attr.exclude_kernel = 1;
+
+ e = &events[3];
+ event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS,
+ PERF_TYPE_HARDWARE, "instructions(u)");
+ e->attr.disabled = 1;
+ e->attr.exclude_hv = 1;
+ e->attr.exclude_kernel = 1;
+
+ FAIL_IF(event_open(&events[0]));
+
+ /*
+ * The open here will fail if we don't have per event exclude support,
+ * because the second event has an incompatible set of exclude settings
+ * and we're asking for the events to be in a group.
+ */
+ for (i = 1; i < 4; i++)
+ FAIL_IF(event_open_with_group(&events[i], events[0].fd));
+
+ /*
+ * Even though the above will fail without per-event excludes we keep
+ * testing in order to be thorough.
+ */
+ prctl(PR_TASK_PERF_EVENTS_ENABLE);
+
+ /* Spin for a while */
+ for (i = 0; i < INT_MAX; i++)
+ asm volatile("" : : : "memory");
+
+ prctl(PR_TASK_PERF_EVENTS_DISABLE);
+
+ for (i = 0; i < 4; i++) {
+ FAIL_IF(event_read(&events[i]));
+ event_report(&events[i]);
+ }
+
+ /*
+ * We should see that all events have enabled == running. That
+ * shows that they were all on the PMU at once.
+ */
+ for (i = 0; i < 4; i++)
+ FAIL_IF(events[i].result.running != events[i].result.enabled);
+
+ /*
+ * We can also check that the result for instructions is >= all the
+ * other counts. That's because it is counting all instructions while
+ * the others are counting a subset.
+ */
+ for (i = 1; i < 4; i++)
+ FAIL_IF(events[0].result.value < events[i].result.value);
+
+ for (i = 0; i < 4; i++)
+ event_close(&events[i]);
+
+ return 0;
+}
+
+int main(void)
+{
+ return test_harness(per_event_excludes, "per_event_excludes");
+}
diff --git a/tools/testing/selftests/ptrace/peeksiginfo.c b/tools/testing/selftests/ptrace/peeksiginfo.c
index d46558b1f58d..c34cd8ac8aaa 100644
--- a/tools/testing/selftests/ptrace/peeksiginfo.c
+++ b/tools/testing/selftests/ptrace/peeksiginfo.c
@@ -31,6 +31,10 @@ static int sys_ptrace(int request, pid_t pid, void *addr, void *data)
#define TEST_SICODE_PRIV -1
#define TEST_SICODE_SHARE -2
+#ifndef PAGE_SIZE
+#define PAGE_SIZE sysconf(_SC_PAGESIZE)
+#endif
+
#define err(fmt, ...) \
fprintf(stderr, \
"Error (%s:%d): " fmt, \
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
index ee1f6cae3d70..3f6c9b78d177 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
@@ -54,10 +54,16 @@ do
if test -f "$i/qemu-cmd"
then
print_bug qemu failed
+ echo " $i"
+ elif test -f "$i/buildonly"
+ then
+ echo Build-only run, no boot/test
+ configcheck.sh $i/.config $i/ConfigFragment
+ parse-build.sh $i/Make.out $configfile
else
print_bug Build failed
+ echo " $i"
fi
- echo " $i"
fi
done
done
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
index 27e544e29510..0f69dcbf9def 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -42,6 +42,7 @@ grace=120
T=/tmp/kvm-test-1-run.sh.$$
trap 'rm -rf $T' 0
+touch $T
. $KVM/bin/functions.sh
. $KVPATH/ver_functions.sh
@@ -131,7 +132,10 @@ boot_args=$6
cd $KVM
kstarttime=`awk 'BEGIN { print systime() }' < /dev/null`
-echo ' ---' `date`: Starting kernel
+if test -z "$TORTURE_BUILDONLY"
+then
+ echo ' ---' `date`: Starting kernel
+fi
# Generate -smp qemu argument.
qemu_args="-nographic $qemu_args"
@@ -157,12 +161,13 @@ boot_args="`configfrag_boot_params "$boot_args" "$config_template"`"
# Generate kernel-version-specific boot parameters
boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`"
-echo $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
if test -n "$TORTURE_BUILDONLY"
then
echo Build-only run specified, boot/test omitted.
+ touch $resdir/buildonly
exit 0
fi
+echo $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
( $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) &
qemu_pid=$!
commandcompleted=0
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index 40285c58653e..589e9c38413b 100644
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -340,12 +340,18 @@ function dump(first, pastlast)
for (j = 1; j < jn; j++) {
builddir=KVM "/b" j
print "rm -f " builddir ".ready"
- print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`";
- print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log";
+ print "if test -z \"$TORTURE_BUILDONLY\""
+ print "then"
+ print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`";
+ print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log";
+ print "fi"
}
print "wait"
- print "echo ---- All kernel runs complete. `date`";
- print "echo ---- All kernel runs complete. `date` >> " rd "/log";
+ print "if test -z \"$TORTURE_BUILDONLY\""
+ print "then"
+ print "\techo ---- All kernel runs complete. `date`";
+ print "\techo ---- All kernel runs complete. `date` >> " rd "/log";
+ print "fi"
for (j = 1; j < jn; j++) {
builddir=KVM "/b" j
print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:";
@@ -385,10 +391,7 @@ echo
echo
echo " --- `date` Test summary:"
echo Results directory: $resdir/$ds
-if test -z "$TORTURE_BUILDONLY"
-then
- kvm-recheck.sh $resdir/$ds
-fi
+kvm-recheck.sh $resdir/$ds
___EOF___
if test "$dryrun" = script
@@ -403,7 +406,7 @@ then
sed -e 's/:.*$//' -e 's/^echo //'
exit 0
else
- # Not a dryru, so run the script.
+ # Not a dryrun, so run the script.
sh $T/script
fi
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
index 9c827ec59a97..063b7079c621 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
@@ -15,7 +15,6 @@ CONFIG_RCU_FANOUT_EXACT=n
CONFIG_RCU_NOCB_CPU=y
CONFIG_RCU_NOCB_CPU_ZERO=y
CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02
index 1a777b5f68b5..ea119ba2f7d4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02
@@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_EXACT=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=n
-CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=y
CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
index 61c8d9ce5bb2..19cf9485f48a 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
@@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_EXACT=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=n
-CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=y
CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03
index c1f111c1561b..f4567fb3e332 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03
@@ -14,7 +14,6 @@ CONFIG_RCU_FANOUT_LEAF=4
CONFIG_RCU_FANOUT_EXACT=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
index 7dbd27ce17a4..0a262fbb0c12 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
@@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_LEAF=2
CONFIG_RCU_FANOUT_EXACT=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=y
CONFIG_RCU_CPU_STALL_VERBOSE=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
index d0f32e574743..3a06b97e9a73 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
@@ -18,7 +18,6 @@ CONFIG_RCU_NOCB_CPU_NONE=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=y
CONFIG_PROVE_RCU=y
-CONFIG_PROVE_RCU_DELAY=y
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
index 2e477dfb9c57..8f084cca91bf 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE06
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
@@ -19,7 +19,6 @@ CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=y
CONFIG_PROVE_RCU=y
-CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
index 042f86ef362a..ab6225506909 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
@@ -17,7 +17,6 @@ CONFIG_RCU_FANOUT_LEAF=2
CONFIG_RCU_FANOUT_EXACT=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=y
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08
index 3438cee1e3c5..69a2e255bf98 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08
@@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_LEAF=2
CONFIG_RCU_NOCB_CPU=y
CONFIG_RCU_NOCB_CPU_ALL=y
CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
index bf4523d3e44c..a0f32fb8f17e 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
@@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_LEAF=2
CONFIG_RCU_NOCB_CPU=y
CONFIG_RCU_NOCB_CPU_ALL=y
CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 b/tools/testing/selftests/rcutorture/configs/rcu/TREE09
index 81e4f7c0bf0b..b7a62a540ad1 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE09
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE09
@@ -13,7 +13,6 @@ CONFIG_SUSPEND=n
CONFIG_HIBERNATION=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n
-CONFIG_PROVE_RCU_DELAY=n
CONFIG_RCU_CPU_STALL_INFO=n
CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..a55c00877fe4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
@@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
#CHECK#CONFIG_TREE_PREEMPT_RCU=y
CONFIG_DEBUG_KERNEL=y
-CONFIG_PROVE_RCU_DELAY=y
CONFIG_DEBUG_OBJECTS=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
CONFIG_RT_MUTEXES=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..a55c00877fe4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
@@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
#CHECK#CONFIG_TREE_PREEMPT_RCU=y
CONFIG_DEBUG_KERNEL=y
-CONFIG_PROVE_RCU_DELAY=y
CONFIG_DEBUG_OBJECTS=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
CONFIG_RT_MUTEXES=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..a55c00877fe4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
@@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
#CHECK#CONFIG_TREE_PREEMPT_RCU=y
CONFIG_DEBUG_KERNEL=y
-CONFIG_PROVE_RCU_DELAY=y
CONFIG_DEBUG_OBJECTS=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
CONFIG_RT_MUTEXES=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
index ef624ce73d8e..a55c00877fe4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
+++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
@@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
#CHECK#CONFIG_TREE_PREEMPT_RCU=y
CONFIG_DEBUG_KERNEL=y
-CONFIG_PROVE_RCU_DELAY=y
CONFIG_DEBUG_OBJECTS=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
CONFIG_RT_MUTEXES=y
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
index adbb76cffb49..3e588db86a17 100644
--- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
+++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
@@ -14,7 +14,6 @@ CONFIG_NO_HZ_FULL_SYSIDLE -- Do one.
CONFIG_PREEMPT -- Do half. (First three and #8.)
CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not.
CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING.
-CONFIG_PROVE_RCU_DELAY -- Do one.
CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU.
CONFIG_RCU_BOOST_PRIO -- set to 2 for _BOOST testing.
CONFIG_RCU_CPU_STALL_INFO -- do one with and without _VERBOSE.