aboutsummaryrefslogtreecommitdiff
path: root/tools/testing/ktest/ktest.pl
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/ktest/ktest.pl')
-rwxr-xr-xtools/testing/ktest/ktest.pl970
1 files changed, 830 insertions, 140 deletions
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index cef28e6632b..8d02ccb10c5 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -27,7 +27,7 @@ $default{"TEST_TYPE"} = "test";
$default{"BUILD_TYPE"} = "randconfig";
$default{"MAKE_CMD"} = "make";
$default{"TIMEOUT"} = 120;
-$default{"TMP_DIR"} = "/tmp/ktest";
+$default{"TMP_DIR"} = "/tmp/ktest/\${MACHINE}";
$default{"SLEEP_TIME"} = 60; # sleep time between tests
$default{"BUILD_NOCLEAN"} = 0;
$default{"REBOOT_ON_ERROR"} = 0;
@@ -41,6 +41,7 @@ $default{"CLEAR_LOG"} = 0;
$default{"BISECT_MANUAL"} = 0;
$default{"BISECT_SKIP"} = 1;
$default{"SUCCESS_LINE"} = "login:";
+$default{"DETECT_TRIPLE_FAULT"} = 1;
$default{"BOOTED_TIMEOUT"} = 1;
$default{"DIE_ON_FAILURE"} = 1;
$default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND";
@@ -62,6 +63,10 @@ my $output_config;
my $test_type;
my $build_type;
my $build_options;
+my $pre_build;
+my $post_build;
+my $pre_build_die;
+my $post_build_die;
my $reboot_type;
my $reboot_script;
my $power_cycle;
@@ -81,12 +86,17 @@ my $make;
my $post_install;
my $noclean;
my $minconfig;
+my $start_minconfig;
+my $start_minconfig_defined;
+my $output_minconfig;
+my $ignore_config;
my $addconfig;
my $in_bisect = 0;
my $bisect_bad = "";
my $reverse_bisect;
my $bisect_manual;
my $bisect_skip;
+my $config_bisect_good;
my $in_patchcheck = 0;
my $run_test;
my $redirect;
@@ -98,9 +108,12 @@ my $monitor_cnt = 0;
my $sleep_time;
my $bisect_sleep_time;
my $patchcheck_sleep_time;
+my $ignore_warnings;
my $store_failures;
+my $test_name;
my $timeout;
my $booted_timeout;
+my $detect_triplefault;
my $console;
my $success_line;
my $stop_after_success;
@@ -115,6 +128,7 @@ my $successes = 0;
my %entered_configs;
my %config_help;
my %variable;
+my %force_config;
$config_help{"MACHINE"} = << "EOF"
The machine hostname that you will test.
@@ -204,6 +218,26 @@ $config_help{"REBOOT_SCRIPT"} = << "EOF"
EOF
;
+sub read_yn {
+ my ($prompt) = @_;
+
+ my $ans;
+
+ for (;;) {
+ print "$prompt [Y/n] ";
+ $ans = <STDIN>;
+ chomp $ans;
+ if ($ans =~ /^\s*$/) {
+ $ans = "y";
+ }
+ last if ($ans =~ /^y$/i || $ans =~ /^n$/i);
+ print "Please answer either 'y' or 'n'.\n";
+ }
+ if ($ans !~ /^y$/i) {
+ return 0;
+ }
+ return 1;
+}
sub get_ktest_config {
my ($config) = @_;
@@ -335,6 +369,7 @@ sub read_config {
my $num_tests_set = 0;
my $skip = 0;
my $rest;
+ my $test_case = 0;
while (<IN>) {
@@ -360,6 +395,7 @@ sub read_config {
$rest = $1;
$skip = 1;
} else {
+ $test_case = 1;
$skip = 0;
}
@@ -464,6 +500,15 @@ sub read_config {
# make sure we have all mandatory configs
get_ktest_configs;
+ # was a test specified?
+ if (!$test_case) {
+ print "No test case specified.\n";
+ print "What test case would you like to run?\n";
+ my $ans = <STDIN>;
+ chomp $ans;
+ $default{"TEST_TYPE"} = $ans;
+ }
+
# set any defaults
foreach my $default (keys %default) {
@@ -473,6 +518,69 @@ sub read_config {
}
}
+sub __eval_option {
+ my ($option, $i) = @_;
+
+ # Add space to evaluate the character before $
+ $option = " $option";
+ my $retval = "";
+
+ while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) {
+ my $start = $1;
+ my $var = $2;
+ my $end = $3;
+
+ # Append beginning of line
+ $retval = "$retval$start";
+
+ # If the iteration option OPT[$i] exists, then use that.
+ # otherwise see if the default OPT (without [$i]) exists.
+
+ my $o = "$var\[$i\]";
+
+ if (defined($opt{$o})) {
+ $o = $opt{$o};
+ $retval = "$retval$o";
+ } elsif (defined($opt{$var})) {
+ $o = $opt{$var};
+ $retval = "$retval$o";
+ } else {
+ $retval = "$retval\$\{$var\}";
+ }
+
+ $option = $end;
+ }
+
+ $retval = "$retval$option";
+
+ $retval =~ s/^ //;
+
+ return $retval;
+}
+
+sub eval_option {
+ my ($option, $i) = @_;
+
+ my $prev = "";
+
+ # Since an option can evaluate to another option,
+ # keep iterating until we do not evaluate any more
+ # options.
+ my $r = 0;
+ while ($prev ne $option) {
+ # Check for recursive evaluations.
+ # 100 deep should be more than enough.
+ if ($r++ > 100) {
+ die "Over 100 evaluations accurred with $option\n" .
+ "Check for recursive variables\n";
+ }
+ $prev = $option;
+ $option = __eval_option($option, $i);
+ }
+
+ return $option;
+}
+
sub _logit {
if (defined($opt{"LOG_FILE"})) {
open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
@@ -617,9 +725,15 @@ sub fail {
end_monitor;
}
+ my $name = "";
+
+ if (defined($test_name)) {
+ $name = " ($test_name)";
+ }
+
doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
- doprint "KTEST RESULT: TEST $i Failed: ", @_, "\n";
+ doprint "KTEST RESULT: TEST $i$name Failed: ", @_, "\n";
doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
@@ -836,17 +950,35 @@ sub monitor {
my $failure_start;
my $monitor_start = time;
my $done = 0;
+ my $version_found = 0;
while (!$done) {
- if ($booted) {
+ if ($bug && defined($stop_after_failure) &&
+ $stop_after_failure >= 0) {
+ my $time = $stop_after_failure - (time - $failure_start);
+ $line = wait_for_input($monitor_fp, $time);
+ if (!defined($line)) {
+ doprint "bug timed out after $booted_timeout seconds\n";
+ doprint "Test forced to stop after $stop_after_failure seconds after failure\n";
+ last;
+ }
+ } elsif ($booted) {
$line = wait_for_input($monitor_fp, $booted_timeout);
+ if (!defined($line)) {
+ my $s = $booted_timeout == 1 ? "" : "s";
+ doprint "Successful boot found: break after $booted_timeout second$s\n";
+ last;
+ }
} else {
$line = wait_for_input($monitor_fp);
+ if (!defined($line)) {
+ my $s = $timeout == 1 ? "" : "s";
+ doprint "Timed out after $timeout second$s\n";
+ last;
+ }
}
- last if (!defined($line));
-
doprint $line;
print DMESG $line;
@@ -896,6 +1028,22 @@ sub monitor {
$bug = 1;
}
+ # Detect triple faults by testing the banner
+ if ($full_line =~ /\bLinux version (\S+).*\n/) {
+ if ($1 eq $version) {
+ $version_found = 1;
+ } elsif ($version_found && $detect_triplefault) {
+ # We already booted into the kernel we are testing,
+ # but now we booted into another kernel?
+ # Consider this a triple fault.
+ doprint "Aleady booted in Linux kernel $version, but now\n";
+ doprint "we booted into Linux kernel $1.\n";
+ doprint "Assuming that this is a triple fault.\n";
+ doprint "To disable this: set DETECT_TRIPLE_FAULT to 0\n";
+ last;
+ }
+ }
+
if ($line =~ /\n/) {
$full_line = "";
}
@@ -923,6 +1071,16 @@ sub monitor {
return 1;
}
+sub do_post_install {
+
+ return if (!defined($post_install));
+
+ my $cp_post_install = $post_install;
+ $cp_post_install =~ s/\$KERNEL_VERSION/$version/g;
+ run_command "$cp_post_install" or
+ dodie "Failed to run post install";
+}
+
sub install {
run_scp "$outputdir/$build_target", "$target_image" or
@@ -942,6 +1100,7 @@ sub install {
close(IN);
if (!$install_mods) {
+ do_post_install;
doprint "No modules needed\n";
return;
}
@@ -964,17 +1123,29 @@ sub install {
unlink "$tmpdir/$modtar";
- run_ssh "'(cd / && tar xf /tmp/$modtar)'" or
+ run_ssh "'(cd / && tar xjf /tmp/$modtar)'" or
dodie "failed to tar modules";
run_ssh "rm -f /tmp/$modtar";
- return if (!defined($post_install));
+ do_post_install;
+}
- my $cp_post_install = $post_install;
- $cp_post_install =~ s/\$KERNEL_VERSION/$version/g;
- run_command "$cp_post_install" or
- dodie "Failed to run post install";
+sub get_version {
+ # get the release name
+ doprint "$make kernelrelease ... ";
+ $version = `$make kernelrelease | tail -1`;
+ chomp($version);
+ doprint "$version\n";
+}
+
+sub start_monitor_and_boot {
+ get_grub_index;
+ get_version;
+ install;
+
+ start_monitor;
+ return monitor;
}
sub check_buildlog {
@@ -1009,24 +1180,84 @@ sub check_buildlog {
return 1;
}
+sub apply_min_config {
+ my $outconfig = "$output_config.new";
+
+ # Read the config file and remove anything that
+ # is in the force_config hash (from minconfig and others)
+ # then add the force config back.
+
+ doprint "Applying minimum configurations into $output_config.new\n";
+
+ open (OUT, ">$outconfig") or
+ dodie "Can't create $outconfig";
+
+ if (-f $output_config) {
+ open (IN, $output_config) or
+ dodie "Failed to open $output_config";
+ while (<IN>) {
+ if (/^(# )?(CONFIG_[^\s=]*)/) {
+ next if (defined($force_config{$2}));
+ }
+ print OUT;
+ }
+ close IN;
+ }
+ foreach my $config (keys %force_config) {
+ print OUT "$force_config{$config}\n";
+ }
+ close OUT;
+
+ run_command "mv $outconfig $output_config";
+}
+
sub make_oldconfig {
- my ($defconfig) = @_;
- if (!run_command "$defconfig $make oldnoconfig") {
+ my @force_list = keys %force_config;
+
+ if ($#force_list >= 0) {
+ apply_min_config;
+ }
+
+ if (!run_command "$make oldnoconfig") {
# Perhaps oldnoconfig doesn't exist in this version of the kernel
# try a yes '' | oldconfig
doprint "oldnoconfig failed, trying yes '' | make oldconfig\n";
- run_command "yes '' | $defconfig $make oldconfig" or
+ run_command "yes '' | $make oldconfig" or
dodie "failed make config oldconfig";
}
}
+# read a config file and use this to force new configs.
+sub load_force_config {
+ my ($config) = @_;
+
+ open(IN, $config) or
+ dodie "failed to read $config";
+ while (<IN>) {
+ chomp;
+ if (/^(CONFIG[^\s=]*)(\s*=.*)/) {
+ $force_config{$1} = $_;
+ } elsif (/^# (CONFIG_\S*) is not set/) {
+ $force_config{$1} = $_;
+ }
+ }
+ close IN;
+}
+
sub build {
my ($type) = @_;
- my $defconfig = "";
unlink $buildlog;
+ if (defined($pre_build)) {
+ my $ret = run_command $pre_build;
+ if (!$ret && defined($pre_build_die) &&
+ $pre_build_die) {
+ dodie "failed to pre_build\n";
+ }
+ }
+
if ($type =~ /^useconfig:(.*)/) {
run_command "cp $1 $output_config" or
dodie "could not copy $1 to .config";
@@ -1063,24 +1294,33 @@ sub build {
close(OUT);
if (defined($minconfig)) {
- $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
+ load_force_config($minconfig);
}
- if ($type eq "oldnoconfig") {
- make_oldconfig $defconfig;
- } else {
- run_command "$defconfig $make $type" or
+ if ($type ne "oldnoconfig") {
+ run_command "$make $type" or
dodie "failed make config";
}
+ # Run old config regardless, to enforce min configurations
+ make_oldconfig;
$redirect = "$buildlog";
- if (!run_command "$make $build_options") {
- undef $redirect;
+ my $build_ret = run_command "$make $build_options";
+ undef $redirect;
+
+ if (defined($post_build)) {
+ my $ret = run_command $post_build;
+ if (!$ret && defined($post_build_die) &&
+ $post_build_die) {
+ dodie "failed to post_build\n";
+ }
+ }
+
+ if (!$build_ret) {
# bisect may need this to pass
return 0 if ($in_bisect);
fail "failed build" and return 0;
}
- undef $redirect;
return 1;
}
@@ -1102,9 +1342,15 @@ sub success {
$successes++;
+ my $name = "";
+
+ if (defined($test_name)) {
+ $name = " ($test_name)";
+ }
+
doprint "\n\n*******************************************\n";
doprint "*******************************************\n";
- doprint "KTEST RESULT: TEST $i SUCCESS!!!! **\n";
+ doprint "KTEST RESULT: TEST $i$name SUCCESS!!!! **\n";
doprint "*******************************************\n";
doprint "*******************************************\n";
@@ -1117,14 +1363,6 @@ sub success {
}
}
-sub get_version {
- # get the release name
- doprint "$make kernelrelease ... ";
- $version = `$make kernelrelease | tail -1`;
- chomp($version);
- doprint "$version\n";
-}
-
sub answer_bisect {
for (;;) {
doprint "Pass or fail? [p/f]";
@@ -1289,12 +1527,7 @@ sub run_bisect_test {
dodie "Failed on build" if $failed;
# Now boot the box
- get_grub_index;
- get_version;
- install;
-
- start_monitor;
- monitor or $failed = 1;
+ start_monitor_and_boot or $failed = 1;
if ($type ne "boot") {
if ($failed && $bisect_skip) {
@@ -1473,21 +1706,27 @@ my %null_config;
my %dependency;
-sub process_config_ignore {
- my ($config) = @_;
+sub assign_configs {
+ my ($hash, $config) = @_;
open (IN, $config)
or dodie "Failed to read $config";
while (<IN>) {
if (/^((CONFIG\S*)=.*)/) {
- $config_ignore{$2} = $1;
+ ${$hash}{$2} = $1;
}
}
close(IN);
}
+sub process_config_ignore {
+ my ($config) = @_;
+
+ assign_configs \%config_ignore, $config;
+}
+
sub read_current_config {
my ($config_ref) = @_;
@@ -1546,7 +1785,7 @@ sub create_config {
close(OUT);
# exit;
- make_oldconfig "";
+ make_oldconfig;
}
sub compare_configs {
@@ -1718,6 +1957,10 @@ sub config_bisect {
my $tmpconfig = "$tmpdir/use_config";
+ 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
@@ -1727,15 +1970,8 @@ sub config_bisect {
unlink $tmpconfig;
}
- # Add other configs
- if (defined($addconfig)) {
- run_command "cat $addconfig >> $tmpconfig" or
- dodie "failed to append $addconfig";
- }
-
- my $defconfig = "";
if (-f $tmpconfig) {
- $defconfig = "KCONFIG_ALLCONFIG=$tmpconfig";
+ load_force_config($tmpconfig);
process_config_ignore $tmpconfig;
}
@@ -1755,8 +1991,8 @@ sub config_bisect {
}
close(IN);
- # Now run oldconfig with the minconfig (and addconfigs)
- make_oldconfig $defconfig;
+ # Now run oldconfig with the minconfig
+ make_oldconfig;
# check to see what we lost (or gained)
open (IN, $output_config)
@@ -1882,6 +2118,13 @@ sub patchcheck {
@list = reverse @list;
my $save_clean = $noclean;
+ my %ignored_warnings;
+
+ if (defined($ignore_warnings)) {
+ foreach my $sha1 (split /\s+/, $ignore_warnings) {
+ $ignored_warnings{$sha1} = 1;
+ }
+ }
$in_patchcheck = 1;
foreach my $item (@list) {
@@ -1908,18 +2151,16 @@ sub patchcheck {
build "oldconfig" or return 0;
}
- check_buildlog $sha1 or return 0;
- next if ($type eq "build");
+ if (!defined($ignored_warnings{$sha1})) {
+ check_buildlog $sha1 or return 0;
+ }
- get_grub_index;
- get_version;
- install;
+ next if ($type eq "build");
my $failed = 0;
- start_monitor;
- monitor or $failed = 1;
+ start_monitor_and_boot or $failed = 1;
if (!$failed && $type ne "boot"){
do_run_test or $failed = 1;
@@ -1936,24 +2177,505 @@ sub patchcheck {
return 1;
}
+my %depends;
+my $iflevel = 0;
+my @ifdeps;
+
+# prevent recursion
+my %read_kconfigs;
+
+# taken from streamline_config.pl
+sub read_kconfig {
+ my ($kconfig) = @_;
+
+ my $state = "NONE";
+ my $config;
+ my @kconfigs;
+
+ my $cont = 0;
+ my $line;
+
+
+ if (! -f $kconfig) {
+ doprint "file $kconfig does not exist, skipping\n";
+ return;
+ }
+
+ open(KIN, "$kconfig")
+ or die "Can't open $kconfig";
+ while (<KIN>) {
+ chomp;
+
+ # Make sure that lines ending with \ continue
+ if ($cont) {
+ $_ = $line . " " . $_;
+ }
+
+ if (s/\\$//) {
+ $cont = 1;
+ $line = $_;
+ next;
+ }
+
+ $cont = 0;
+
+ # collect any Kconfig sources
+ if (/^source\s*"(.*)"/) {
+ $kconfigs[$#kconfigs+1] = $1;
+ }
+
+ # configs found
+ if (/^\s*(menu)?config\s+(\S+)\s*$/) {
+ $state = "NEW";
+ $config = $2;
+
+ for (my $i = 0; $i < $iflevel; $i++) {
+ if ($i) {
+ $depends{$config} .= " " . $ifdeps[$i];
+ } else {
+ $depends{$config} = $ifdeps[$i];
+ }
+ $state = "DEP";
+ }
+
+ # collect the depends for the config
+ } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
+
+ if (defined($depends{$1})) {
+ $depends{$config} .= " " . $1;
+ } else {
+ $depends{$config} = $1;
+ }
+
+ # Get the configs that select this config
+ } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
+ if (defined($depends{$1})) {
+ $depends{$1} .= " " . $config;
+ } else {
+ $depends{$1} = $config;
+ }
+
+ # Check for if statements
+ } elsif (/^if\s+(.*\S)\s*$/) {
+ my $deps = $1;
+ # remove beginning and ending non text
+ $deps =~ s/^[^a-zA-Z0-9_]*//;
+ $deps =~ s/[^a-zA-Z0-9_]*$//;
+
+ my @deps = split /[^a-zA-Z0-9_]+/, $deps;
+
+ $ifdeps[$iflevel++] = join ':', @deps;
+
+ } elsif (/^endif/) {
+
+ $iflevel-- if ($iflevel);
+
+ # stop on "help"
+ } elsif (/^\s*help\s*$/) {
+ $state = "NONE";
+ }
+ }
+ close(KIN);
+
+ # read in any configs that were found.
+ foreach $kconfig (@kconfigs) {
+ if (!defined($read_kconfigs{$kconfig})) {
+ $read_kconfigs{$kconfig} = 1;
+ read_kconfig("$builddir/$kconfig");
+ }
+ }
+}
+
+sub read_depends {
+ # find out which arch this is by the kconfig file
+ open (IN, $output_config)
+ or dodie "Failed to read $output_config";
+ my $arch;
+ while (<IN>) {
+ if (m,Linux/(\S+)\s+\S+\s+Kernel Configuration,) {
+ $arch = $1;
+ last;
+ }
+ }
+ close IN;
+
+ if (!defined($arch)) {
+ doprint "Could not find arch from config file\n";
+ doprint "no dependencies used\n";
+ return;
+ }
+
+ # arch is really the subarch, we need to know
+ # what directory to look at.
+ if ($arch eq "i386" || $arch eq "x86_64") {
+ $arch = "x86";
+ } elsif ($arch =~ /^tile/) {
+ $arch = "tile";
+ }
+
+ my $kconfig = "$builddir/arch/$arch/Kconfig";
+
+ if (! -f $kconfig && $arch =~ /\d$/) {
+ my $orig = $arch;
+ # some subarchs have numbers, truncate them
+ $arch =~ s/\d*$//;
+ $kconfig = "$builddir/arch/$arch/Kconfig";
+ if (! -f $kconfig) {
+ doprint "No idea what arch dir $orig is for\n";
+ doprint "no dependencies used\n";
+ return;
+ }
+ }
+
+ 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 = @_;
+
+ open (OUT, ">$output_config")
+ or dodie "Failed to write $output_config";
+
+ foreach my $config (@configs) {
+ print OUT "$config\n";
+ }
+ close OUT;
+}
+
+sub get_depends {
+ my ($dep) = @_;
+
+ my $kconfig = $dep;
+ $kconfig =~ s/CONFIG_//;
+
+ $dep = $depends{"$kconfig"};
+
+ # the dep string we have saves the dependencies as they
+ # were found, including expressions like ! && ||. We
+ # want to split this out into just an array of configs.
+
+ my $valid = "A-Za-z_0-9";
+
+ my @configs;
+
+ while ($dep =~ /[$valid]/) {
+
+ if ($dep =~ /^[^$valid]*([$valid]+)/) {
+ my $conf = "CONFIG_" . $1;
+
+ $configs[$#configs + 1] = $conf;
+
+ $dep =~ s/^[^$valid]*[$valid]+//;
+ } else {
+ die "this should never happen";
+ }
+ }
+
+ return @configs;
+}
+
+my %min_configs;
+my %keep_configs;
+my %save_configs;
+my %processed_configs;
+my %nochange_config;
+
+sub test_this_config {
+ my ($config) = @_;
+
+ my $found;
+
+ # if we already processed this config, skip it
+ if (defined($processed_configs{$config})) {
+ return undef;
+ }
+ $processed_configs{$config} = 1;
+
+ # if this config failed during this round, skip it
+ if (defined($nochange_config{$config})) {
+ return undef;
+ }
+
+ my $kconfig = $config;
+ $kconfig =~ s/CONFIG_//;
+
+ # Test dependencies first
+ if (defined($depends{"$kconfig"})) {
+ my @parents = get_depends $config;
+ foreach my $parent (@parents) {
+ # if the parent is in the min config, check it first
+ next if (!defined($min_configs{$parent}));
+ $found = test_this_config($parent);
+ if (defined($found)) {
+ return $found;
+ }
+ }
+ }
+
+ # Remove this config from the list of configs
+ # do a make oldnoconfig and then read the resulting
+ # .config to make sure it is missing the config that
+ # we had before
+ my %configs = %min_configs;
+ delete $configs{$config};
+ make_new_config ((values %configs), (values %keep_configs));
+ make_oldconfig;
+ undef %configs;
+ assign_configs \%configs, $output_config;
+
+ return $config if (!defined($configs{$config}));
+
+ doprint "disabling config $config did not change .config\n";
+
+ $nochange_config{$config} = 1;
+
+ return undef;
+}
+
+sub make_min_config {
+ my ($i) = @_;
+
+ if (!defined($output_minconfig)) {
+ fail "OUTPUT_MIN_CONFIG not defined" and return;
+ }
+
+ # If output_minconfig exists, and the start_minconfig
+ # came from min_config, than ask if we should use
+ # that instead.
+ if (-f $output_minconfig && !$start_minconfig_defined) {
+ print "$output_minconfig exists\n";
+ if (read_yn " Use it as minconfig?") {
+ $start_minconfig = $output_minconfig;
+ }
+ }
+
+ if (!defined($start_minconfig)) {
+ fail "START_MIN_CONFIG or MIN_CONFIG not defined" and return;
+ }
+
+ my $temp_config = "$tmpdir/temp_config";
+
+ # First things first. We build an allnoconfig to find
+ # out what the defaults are that we can't touch.
+ # Some are selections, but we really can't handle selections.
+
+ my $save_minconfig = $minconfig;
+ undef $minconfig;
+
+ run_command "$make allnoconfig" or return 0;
+
+ read_depends;
+
+ process_config_ignore $output_config;
+
+ undef %save_configs;
+ undef %min_configs;
+
+ if (defined($ignore_config)) {
+ # make sure the file exists
+ `touch $ignore_config`;
+ assign_configs \%save_configs, $ignore_config;
+ }
+
+ %keep_configs = %save_configs;
+
+ doprint "Load initial configs from $start_minconfig\n";
+
+ # Look at the current min configs, and save off all the
+ # ones that were set via the allnoconfig
+ assign_configs \%min_configs, $start_minconfig;
+
+ my @config_keys = keys %min_configs;
+
+ # Remove anything that was set by the make allnoconfig
+ # we shouldn't need them as they get set for us anyway.
+ foreach my $config (@config_keys) {
+ # Remove anything in the ignore_config
+ if (defined($keep_configs{$config})) {
+ my $file = $ignore_config;
+ $file =~ s,.*/(.*?)$,$1,;
+ doprint "$config set by $file ... ignored\n";
+ delete $min_configs{$config};
+ next;
+ }
+ # But make sure the settings are the same. If a min config
+ # sets a selection, we do not want to get rid of it if
+ # it is not the same as what we have. Just move it into
+ # the keep configs.
+ if (defined($config_ignore{$config})) {
+ if ($config_ignore{$config} ne $min_configs{$config}) {
+ doprint "$config is in allnoconfig as '$config_ignore{$config}'";
+ doprint " but it is '$min_configs{$config}' in minconfig .. keeping\n";
+ $keep_configs{$config} = $min_configs{$config};
+ } else {
+ doprint "$config set by allnoconfig ... ignored\n";
+ }
+ delete $min_configs{$config};
+ }
+ }
+
+ my $done = 0;
+ my $take_two = 0;
+
+ while (!$done) {
+
+ my $config;
+ my $found;
+
+ # Now disable each config one by one and do a make oldconfig
+ # till we find a config that changes our list.
+
+ # Put configs that did not modify the config at the end.
+ my @test_configs = keys %min_configs;
+ my $reset = 1;
+ for (my $i = 0; $i < $#test_configs; $i++) {
+ if (!defined($nochange_config{$test_configs[0]})) {
+ $reset = 0;
+ last;
+ }
+ # This config didn't change the .config last time.
+ # Place it at the end
+ my $config = shift @test_configs;
+ push @test_configs, $config;
+ }
+
+ # if every test config has failed to modify the .config file
+ # in the past, then reset and start over.
+ if ($reset) {
+ undef %nochange_config;
+ }
+
+ undef %processed_configs;
+
+ foreach my $config (@test_configs) {
+
+ $found = test_this_config $config;
+
+ last if (defined($found));
+
+ # oh well, try another config
+ }
+
+ if (!defined($found)) {
+ # we could have failed due to the nochange_config hash
+ # reset and try again
+ if (!$take_two) {
+ undef %nochange_config;
+ $take_two = 1;
+ next;
+ }
+ doprint "No more configs found that we can disable\n";
+ $done = 1;
+ last;
+ }
+ $take_two = 0;
+
+ $config = $found;
+
+ doprint "Test with $config disabled\n";
+
+ # set in_bisect to keep build and monitor from dieing
+ $in_bisect = 1;
+
+ my $failed = 0;
+ build "oldconfig";
+ start_monitor_and_boot or $failed = 1;
+ end_monitor;
+
+ $in_bisect = 0;
+
+ if ($failed) {
+ doprint "$min_configs{$config} is needed to boot the box... keeping\n";
+ # this config is needed, add it to the ignore list.
+ $keep_configs{$config} = $min_configs{$config};
+ $save_configs{$config} = $min_configs{$config};
+ delete $min_configs{$config};
+
+ # update new ignore configs
+ if (defined($ignore_config)) {
+ open (OUT, ">$temp_config")
+ or die "Can't write to $temp_config";
+ foreach my $config (keys %save_configs) {
+ print OUT "$save_configs{$config}\n";
+ }
+ close OUT;
+ run_command "mv $temp_config $ignore_config" or
+ dodie "failed to copy update to $ignore_config";
+ }
+
+ } else {
+ # We booted without this config, remove it from the minconfigs.
+ doprint "$config is not needed, disabling\n";
+
+ delete $min_configs{$config};
+
+ # Also disable anything that is not enabled in this config
+ my %configs;
+ assign_configs \%configs, $output_config;
+ my @config_keys = keys %min_configs;
+ foreach my $config (@config_keys) {
+ if (!defined($configs{$config})) {
+ doprint "$config is not set, disabling\n";
+ delete $min_configs{$config};
+ }
+ }
+
+ # Save off all the current mandidory configs
+ open (OUT, ">$temp_config")
+ or die "Can't write to $temp_config";
+ foreach my $config (keys %keep_configs) {
+ print OUT "$keep_configs{$config}\n";
+ }
+ foreach my $config (keys %min_configs) {
+ print OUT "$min_configs{$config}\n";
+ }
+ close OUT;
+
+ run_command "mv $temp_config $output_minconfig" or
+ dodie "failed to copy update to $output_minconfig";
+ }
+
+ doprint "Reboot and wait $sleep_time seconds\n";
+ reboot;
+ start_monitor;
+ wait_for_monitor $sleep_time;
+ end_monitor;
+ }
+
+ success $i;
+ return 1;
+}
+
$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n";
if ($#ARGV == 0) {
$ktest_config = $ARGV[0];
if (! -f $ktest_config) {
print "$ktest_config does not exist.\n";
- my $ans;
- for (;;) {
- print "Create it? [Y/n] ";
- $ans = <STDIN>;
- chomp $ans;
- if ($ans =~ /^\s*$/) {
- $ans = "y";
- }
- last if ($ans =~ /^y$/i || $ans =~ /^n$/i);
- print "Please answer either 'y' or 'n'.\n";
- }
- if ($ans !~ /^y$/i) {
+ if (!read_yn "Create it?") {
exit 0;
}
}
@@ -1977,6 +2699,10 @@ EOF
}
read_config $ktest_config;
+if (defined($opt{"LOG_FILE"})) {
+ $opt{"LOG_FILE"} = eval_option($opt{"LOG_FILE"}, -1);
+}
+
# Append any configs entered in manually to the config file.
my @new_configs = keys %entered_configs;
if ($#new_configs >= 0) {
@@ -2045,70 +2771,13 @@ sub __set_test_option {
return undef;
}
-sub eval_option {
- my ($option, $i) = @_;
-
- # Add space to evaluate the character before $
- $option = " $option";
- my $retval = "";
-
- while ($option =~ /(.*?[^\\])\$\{(.*?)\}(.*)/) {
- my $start = $1;
- my $var = $2;
- my $end = $3;
-
- # Append beginning of line
- $retval = "$retval$start";
-
- # If the iteration option OPT[$i] exists, then use that.
- # otherwise see if the default OPT (without [$i]) exists.
-
- my $o = "$var\[$i\]";
-
- if (defined($opt{$o})) {
- $o = $opt{$o};
- $retval = "$retval$o";
- } elsif (defined($opt{$var})) {
- $o = $opt{$var};
- $retval = "$retval$o";
- } else {
- $retval = "$retval\$\{$var\}";
- }
-
- $option = $end;
- }
-
- $retval = "$retval$option";
-
- $retval =~ s/^ //;
-
- return $retval;
-}
-
sub set_test_option {
my ($name, $i) = @_;
my $option = __set_test_option($name, $i);
return $option if (!defined($option));
- my $prev = "";
-
- # Since an option can evaluate to another option,
- # keep iterating until we do not evaluate any more
- # options.
- my $r = 0;
- while ($prev ne $option) {
- # Check for recursive evaluations.
- # 100 deep should be more than enough.
- if ($r++ > 100) {
- die "Over 100 evaluations accurred with $name\n" .
- "Check for recursive variables\n";
- }
- $prev = $option;
- $option = eval_option($option, $i);
- }
-
- return $option;
+ return eval_option($option, $i);
}
# First we need to do is the builds
@@ -2126,10 +2795,17 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
$test_type = set_test_option("TEST_TYPE", $i);
$build_type = set_test_option("BUILD_TYPE", $i);
$build_options = set_test_option("BUILD_OPTIONS", $i);
+ $pre_build = set_test_option("PRE_BUILD", $i);
+ $post_build = set_test_option("POST_BUILD", $i);
+ $pre_build_die = set_test_option("PRE_BUILD_DIE", $i);
+ $post_build_die = set_test_option("POST_BUILD_DIE", $i);
$power_cycle = set_test_option("POWER_CYCLE", $i);
$reboot = set_test_option("REBOOT", $i);
$noclean = set_test_option("BUILD_NOCLEAN", $i);
$minconfig = set_test_option("MIN_CONFIG", $i);
+ $output_minconfig = set_test_option("OUTPUT_MIN_CONFIG", $i);
+ $start_minconfig = set_test_option("START_MIN_CONFIG", $i);
+ $ignore_config = set_test_option("IGNORE_CONFIG", $i);
$run_test = set_test_option("TEST", $i);
$addconfig = set_test_option("ADD_CONFIG", $i);
$reboot_type = set_test_option("REBOOT_TYPE", $i);
@@ -2145,12 +2821,16 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
$sleep_time = set_test_option("SLEEP_TIME", $i);
$bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i);
$patchcheck_sleep_time = set_test_option("PATCHCHECK_SLEEP_TIME", $i);
+ $ignore_warnings = set_test_option("IGNORE_WARNINGS", $i);
$bisect_manual = set_test_option("BISECT_MANUAL", $i);
$bisect_skip = set_test_option("BISECT_SKIP", $i);
+ $config_bisect_good = set_test_option("CONFIG_BISECT_GOOD", $i);
$store_failures = set_test_option("STORE_FAILURES", $i);
+ $test_name = set_test_option("TEST_NAME", $i);
$timeout = set_test_option("TIMEOUT", $i);
$booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
$console = set_test_option("CONSOLE", $i);
+ $detect_triplefault = set_test_option("DETECT_TRIPLE_FAULT", $i);
$success_line = set_test_option("SUCCESS_LINE", $i);
$stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
$stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
@@ -2161,6 +2841,13 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
$target_image = set_test_option("TARGET_IMAGE", $i);
$localversion = set_test_option("LOCALVERSION", $i);
+ $start_minconfig_defined = 1;
+
+ if (!defined($start_minconfig)) {
+ $start_minconfig_defined = 0;
+ $start_minconfig = $minconfig;
+ }
+
chdir $builddir || die "can't change directory to $builddir";
if (!-d $tmpdir) {
@@ -2193,6 +2880,10 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
$run_type = $opt{"CONFIG_BISECT_TYPE[$i]"};
}
+ if ($test_type eq "make_min_config") {
+ $run_type = "";
+ }
+
# mistake in config file?
if (!defined($run_type)) {
$run_type = "ERROR";
@@ -2204,11 +2895,12 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
unlink $dmesg;
unlink $buildlog;
- if (!defined($minconfig)) {
- $minconfig = $addconfig;
-
- } elsif (defined($addconfig)) {
- run_command "cat $addconfig $minconfig > $tmpdir/add_config" or
+ if (defined($addconfig)) {
+ my $min = $minconfig;
+ if (!defined($minconfig)) {
+ $min = "";
+ }
+ run_command "cat $addconfig $min > $tmpdir/add_config" or
dodie "Failed to create temp config";
$minconfig = "$tmpdir/add_config";
}
@@ -2228,6 +2920,9 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
} elsif ($test_type eq "patchcheck") {
patchcheck $i;
next;
+ } elsif ($test_type eq "make_min_config") {
+ make_min_config $i;
+ next;
}
if ($build_type ne "nobuild") {
@@ -2235,13 +2930,8 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
}
if ($test_type ne "build") {
- get_grub_index;
- get_version;
- install;
-
my $failed = 0;
- start_monitor;
- monitor or $failed = 1;;
+ start_monitor_and_boot or $failed = 1;
if (!$failed && $test_type ne "boot" && defined($run_test)) {
do_run_test or $failed = 1;