Commit aebdd82e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-ktest

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-ktest:
  ktest: Fix bug when ADD_CONFIG is set but MIN_CONFIG is not
  ktest: Keep fonud configs separate from default configs
  ktest: Add prompt to use OUTPUT_MIN_CONFIG
  ktest: Use Kconfig dependencies to shorten time to make min_config
  ktest: Add test type make_min_config
  ktest: Require one TEST_START in config file
  ktest: Add helper function to avoid duplicate code
  ktest: Add IGNORE_WARNINGS to ignore warnings in some patches
  ktest: Fix tar extracting of modules to target
  ktest: Have the testing tmp dir include machine name
  ktest: Add POST/PRE_BUILD options
  ktest: Allow initrd processing without modules defined
  ktest: Have LOG_FILE evaluate options as well
  ktest: Have wait on stdio honor bug timeout
  ktest: Implement our own force min config
  ktest: Add TEST_NAME option
  ktest: Add CONFIG_BISECT_GOOD option
  ktest: Add detection of triple faults
  ktest: Notify reason to break out of monitoring boot
parents f01ef569 250bae8b
......@@ -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;
......
......@@ -293,6 +293,38 @@
# or on some systems:
#POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
# If there is a script that you require to run before the build is done
# you can specify it with PRE_BUILD.
#
# One example may be if you must add a temporary patch to the build to
# fix a unrelated bug to perform a patchcheck test. This will apply the
# patch before each build that is made. Use the POST_BUILD to do a git reset --hard
# to remove the patch.
#
# (default undef)
#PRE_BUILD = cd ${BUILD_DIR} && patch -p1 < /tmp/temp.patch
# To specify if the test should fail if the PRE_BUILD fails,
# PRE_BUILD_DIE needs to be set to 1. Otherwise the PRE_BUILD
# result is ignored.
# (default 0)
# PRE_BUILD_DIE = 1
# If there is a script that should run after the build is done
# you can specify it with POST_BUILD.
#
# As the example in PRE_BUILD, POST_BUILD can be used to reset modifications
# made by the PRE_BUILD.
#
# (default undef)
#POST_BUILD = cd ${BUILD_DIR} && git reset --hard
# To specify if the test should fail if the POST_BUILD fails,
# POST_BUILD_DIE needs to be set to 1. Otherwise the POST_BUILD
# result is ignored.
# (default 0)
#POST_BUILD_DIE = 1
# Way to reboot the box to the test kernel.
# Only valid options so far are "grub" and "script"
# (default grub)
......@@ -360,8 +392,8 @@
#ADD_CONFIG = /home/test/config-broken
# The location on the host where to write temp files
# (default /tmp/ktest)
#TMP_DIR = /tmp/ktest
# (default /tmp/ktest/${MACHINE})
#TMP_DIR = /tmp/ktest/${MACHINE}
# Optional log file to write the status (recommended)
# Note, this is a DEFAULT section only option.
......@@ -518,6 +550,16 @@
# The variables SSH_USER and MACHINE are defined.
#REBOOT = ssh $SSH_USER@$MACHINE reboot
# The way triple faults are detected is by testing the kernel
# banner. If the kernel banner for the kernel we are testing is
# found, and then later a kernel banner for another kernel version
# is found, it is considered that we encountered a triple fault,
# and there is no panic or callback, but simply a reboot.
# To disable this (because it did a false positive) set the following
# to 0.
# (default 1)
#DETECT_TRIPLE_FAULT = 0
#### Per test run options ####
# The following options are only allowed in TEST_START sections.
# They are ignored in the DEFAULTS sections.
......@@ -535,6 +577,12 @@
# all preceding tests until a new CHECKOUT is set.
#
#
# TEST_NAME = name
#
# If you want the test to have a name that is displayed in
# the test result banner at the end of the test, then use this
# option. This is useful to search for the RESULT keyword and
# not have to translate a test number to a test in the config.
#
# For TEST_TYPE = patchcheck
#
......@@ -556,7 +604,12 @@
# build, boot, test.
#
# Note, the build test will look for warnings, if a warning occurred
# in a file that a commit touches, the build will fail.
# in a file that a commit touches, the build will fail, unless
# IGNORE_WARNINGS is set for the given commit's sha1
#
# IGNORE_WARNINGS can be used to disable the failure of patchcheck
# on a particuler commit (SHA1). You can add more than one commit
# by adding a list of SHA1s that are space delimited.
#
# If BUILD_NOCLEAN is set, then make mrproper will not be run on
# any of the builds, just like all other TEST_TYPE tests. But
......@@ -571,6 +624,7 @@
# PATCHCHECK_TYPE = boot
# PATCHCHECK_START = 747e94ae3d1b4c9bf5380e569f614eb9040b79e7
# PATCHCHECK_END = HEAD~2
# IGNORE_WARNINGS = 42f9c6b69b54946ffc0515f57d01dc7f5c0e4712 0c17ca2c7187f431d8ffc79e81addc730f33d128
#
#
#
......@@ -739,13 +793,18 @@
# boot - bad builds but fails to boot
# test - bad boots but fails a test
#
# CONFIG_BISECT is the config that failed to boot
# CONFIG_BISECT is the config that failed to boot
#
# If BISECT_MANUAL is set, it will pause between iterations.
# This is useful to use just ktest.pl just for the config bisect.
# If you set it to build, it will run the bisect and you can
# control what happens in between iterations. It will ask you if
# the test succeeded or not and continue the config bisect.
# If BISECT_MANUAL is set, it will pause between iterations.
# This is useful to use just ktest.pl just for the config bisect.
# If you set it to build, it will run the bisect and you can
# control what happens in between iterations. It will ask you if
# the test succeeded or not and continue the config bisect.
#
# 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.
#
# Example:
# TEST_START
......@@ -755,3 +814,68 @@
# MIN_CONFIG = /home/test/config-min
# BISECT_MANUAL = 1
#
#
#
# For TEST_TYPE = make_min_config
#
# After doing a make localyesconfig, your kernel configuration may
# not be the most useful minimum configuration. Having a true minimum
# config that you can use against other configs is very useful if
# someone else has a config that breaks on your code. By only forcing
# those configurations that are truly required to boot your machine
# will give you less of a chance that one of your set configurations
# will make the bug go away. This will give you a better chance to
# be able to reproduce the reported bug matching the broken config.
#
# Note, this does take some time, and may require you to run the
# test over night, or perhaps over the weekend. But it also allows
# you to interrupt it, and gives you the current minimum config
# that was found till that time.
#
# Note, this test automatically assumes a BUILD_TYPE of oldconfig
# and its test type acts like boot.
# TODO: add a test version that makes the config do more than just
# boot, like having network access.
#
# To save time, the test does not just grab any option and test
# it. The Kconfig files are examined to determine the dependencies
# of the configs. If a config is chosen that depends on another
# config, that config will be checked first. By checking the
# parents first, we can eliminate whole groups of configs that
# may have been enabled.
#
# For example, if a USB device config is chosen and depends on CONFIG_USB,
# the CONFIG_USB will be tested before the device. If CONFIG_USB is
# found not to be needed, it, as well as all configs that depend on
# it, will be disabled and removed from the current min_config.
#
# OUTPUT_MIN_CONFIG is the path and filename of the file that will
# be created from the MIN_CONFIG. If you interrupt the test, set
# this file as your new min config, and use it to continue the test.
# This file does not need to exist on start of test.
# This file is not created until a config is found that can be removed.
# If this file exists, you will be prompted if you want to use it
# as the min_config (overriding MIN_CONFIG) if START_MIN_CONFIG
# is not defined.
# (required field)
#
# START_MIN_CONFIG is the config to use to start the test with.
# you can set this as the same OUTPUT_MIN_CONFIG, but if you do
# the OUTPUT_MIN_CONFIG file must exist.
# (default MIN_CONFIG)
#
# IGNORE_CONFIG is used to specify a config file that has configs that
# you already know must be set. Configs are written here that have
# been tested and proved to be required. It is best to define this
# file if you intend on interrupting the test and running it where
# it left off. New configs that it finds will be written to this file
# and will not be tested again in later runs.
# (optional)
#
# Example:
#
# TEST_TYPE = make_min_config
# OUTPUT_MIN_CONFIG = /path/to/config-new-min
# START_MIN_CONFIG = /path/to/config-min
# IGNORE_CONFIG = /path/to/config-tested
#
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment