blob: ff140ccfed4173b95dddf7bfee935408e77816f7 [file] [log] [blame]
1 Overview
~~~~~~~~~~
This is a set of scripts and tools for verifying Linux kernel patches.
Most of the scripts accept "-h" or "--help" options, which you can use
to get an idea what different scripts do.
It is important to know that all the scripts are written so that:
* all the debugging and verbose (-v) cruft is printed to stderr
* all the user-friendly output is printed to stdout
Thus, if you for example run "./aiaiai-test-patchset -v .... 2>log", then the
"log" file will contain all the unreadable debugging cruft and the nice
output will be visible on the console.
Also it is useful to know that the scripts never modify the repositories
you specify and the scripts remove all the temporary files upon exit,
Ctrl-C interruption, or error (unless -p option is specified).
The layout of the repository.
* aiaiai/email/
All the scripts related to emails handling. If you use Aiaiai locally
you do not need these scripts.
* aiaiai/helpers/
Variouls programs and scripts which Aiaiai users should not usually use
directly. Instead, Aiaiai scripts use them internally.
* aiaiai/doc
Some documentation.
* aiaiai/tests/
Unit-tests.
* aiaiai/
The root repository directory contains the scripts which do all the
patch checking work. The central script is 'aiaiai-test-patchset' which
uses all the other scripts as helpers.
Let's briefly review the contents of the repository.
1.1 E-mail-related scripts
~~~~~~~~~~~~~~~~~~~~~~~~~~
* email/aiaiai-email-lda
This is Aiaiai's local delivery agent script which receives the incoming
emails from the mail server (via a pipe), processes them (drops all e-mails
which do not start with [PATCH*], detects and collects patch-sets), and
puts them to the "queue" sub-directory of the work directory. This
should, in turn, wake up the "aiaiai-email-dispatcher" script which will
take further care of the patch or patch-set.
* email/aiaiai-email-dispatcher
This script waits for the incoming patch-sets in the "queue" directory and
runs a user-defined command for every incoming patch-set. The role of this
script is to limit the amount of patch-sets we can run at a time. You
can configure this via command line options.
As it was already said, in our setup 'aiaiai-email-dispatcher' runs
'aiaiai-email-test-patchset'.
* email/aiaiai-email-dispatcher-helper
This is a private helper script for 'aiaiai-email-dispatcher'.
* email/aiaiai-email-test-patchset
This script parses the incoming e-mail (in mbox format), finds out which
kernel tree has to be used, sends a notification to the sender, runs
the 'aiaiai-test-patchset' script with the right command-line arguments, and
sends the results of 'aiaiai-test-patchset' back to the patch submitter.
* email/aiaiai.cfg
This is an example of 'aiaiai-email-test-patchset' configuration file. It
describes the projects Aiaiai supports and their parameters. Take a
look inside - the file is self-descriptive.
Here is how all these scripts work together. When you send an e-mail to the
server which runs Aiaiai, the MTA pipes it to 'aiaiai-email-lda'. We used the
postfix MTA, and the 'aiaiai' Linux user had the following file in its home
directory:
$ cat $HOME/.forward
|/home/aiaiai/bin/my-aiaiai-lda
Which made sure that all e-mails coming to aiaiai@our-domain.ququ were piped
to the my-aiaiai-lda script. The script simply ran aiaiai-email-lda with
the options we needed:
$ cat /home/aiaiai/bin/my-aiaiai-lda
#!/bin/sh
$HOME/git/email/aiaiai-email-lda -v --reap-archive=43200 --reap-incomplete=10 -- $HOME/aiaiai-workdir >> "$HOME/aiaiai-logs/email-lda.log" 2>&1
So, aiaiai-email-lda collects patches belonging to the patch-sets, and when it
has all of them, it squashes them into one mbox file and moves them to the
queue directory. This will wake up the 'aiaiai-email-dispatcher' script, which
will execute 'aiaiai-email-test-patchset' for this mbox (unless there are
already too many jobs, in which case it will wait).
The 'aiaiai-email-test-patchset' will parse the patch-set, find out which
kernel it has to be tested against using the configuration file, send a
notification e-mail to the patch sender, and execute the 'aiaiai-test-patchset'
script.
The 'aiaiai-test-patchset' script does all the testing work and outputs the
test results to stdout. 'aiaiai-email-test-patchset' captures the output and
sends it back to the patch submitter.
A more complicated mail setup dealing with forwards and multi-part emails
would be :
$ cat /home/aiaiai/bin/my-aiaiai-lda
#!/bin/sh
formail_opt=""
mail=$(mktemp)
cat > $mail
to="$(formail -c -z -x "To:" < $mail)"
[ -n "$to" ] && formail_opt="$formail_opt -I \"To: $to\""
project="$(formail -c -z -x "X-Aiaiai-Project:" < $mail)"
[ -n "$project" ] && formail_opt="$formail_opt -I \"X-Aiaiai-Project: $project\""
commit="$(formail -c -z -x "X-Aiaiai-Commit:" < $mail)"
[ -n "$commit" ] && formail_opt="$formail_opt -I \"X-Aiaiai-Commit: $commit\""
cat "$mail" | eval formail $formail_opt -d -s "$HOME/git/email/aiaiai-email-lda" \
-v --reap-archive=43200 --reap-incomplete=10 -- "$HOME/aiaiai-workdir" \
>> "$HOME/aiaiai-logs/email-lda.log" 2>&1
1.2 Email Configuration
~~~~~~~~~~~~~~~~~~~~~~~
aiaiai-email scripts use a common configuration file, which is documented in
doc/email/example-aiaiai.cfg
By default aiaiai expects email targeting a specific project to be delivered to
a specific aiaiai recipient address which includes it, e.g:
aiaiai+foo@domain.tld.
In case you would want to use the same aiaiai recipient email address for all
projects, you need to create a hook file which will be looking at the
X-Aiaiai-Project header in the mbox file, and output it to stdout (see:
email/aiaiai-email-test-patchset). An example hook script could look like this:
#!/bin/sh
CFGFILE="$1"
MBOX="$2"
grep "X-Aiaiai-Project" $MBOX
ret=$?
1.3 Non-e-mail scripts
~~~~~~~~~~~~~~~~~~~~~~
* aiaiai-test-patchset
The central script which tests a patch-set is 'aiaiai-test-patchset'. You
should use it if you want to test your patches locally. It accepts patches
in the mbox format. You should specify various input parameters like the
path to the kernel to test against, the commit id to test against, which
tests to run, etc.
* aiaiai-make-kernel
Low-level scripts which builds the kernel. It has several switches which
change its behavior, e.g., you can select whether you want to run
sparse/smatch/cppcheck/coccinelle tools or not.
'aiaiai-make-kernel' utilizes the 'aiaiai-locker' utility to make
sure the build logs of parallel builds are not scrambled and stay readable.
* aiaiai-locker
This utility was inspired by Eric Melski's blog-post I found in the Internet.
We use this tool to make Linux kernel build logs saner than parallel build
produces (e.g., "make -j 20"). Indeed, parallel make scrambles all the
lines which makes build logs not comparable and not readable.
The idea is to run all make commands via the 'aiaiai-locker' utility using
the GNU make 'SHELL' variable re-definition. 'aiaiai-locker' intercepts the
stdout and stderr output of commands, gathers all the output until the
command finishes, and locks a common lockfile, and prints the intercepted
output. So the effect of this is that the in the build log the output of
one program goes as one big block and it is not mixed with the output of
another command.
* aiaiai-checker
A helper script for 'aiaiai-make-kernel' which runs
sparse/smatch/cppcheck/coccinelle tools. The reason we need it is because
the kernel build system allows only one checking program at a time, but we
want to run multiple of them.
* aiaiai-diff-log
Compares 2 build logs and provides the differences. This script used the
'helpers/remap-log' tool to re-map line numbers in the warnings of the
first build log to correspond to line numbers in the second build-log.
* aiaiai-diff-log-helper
A helper script for aiaiai-diff-log which sorts 2 build logs and compares
them. Written in Python because the shell version was too slow.
* helpers/remap-log
This is a small C program originally written by Al Viro which helps
comparing 2 build logs by remapping line numbers. Roughly speaking,
'remap-log' takes the build log of the pre-patched kernel and the patch and
changes line numbers in the build log to match line numbers in the build
log of the patched kernel. For example, supposed that you have the
following warning in the pre-patched kernel:
driver.c:100 Unused variable 'ret'
and your patch adds a new include to the driver.c file, so the patched
kernel will produce the following warning:
driver.c:101 Unused variable 'ret'
Obviously, you do not want to bug the patch author about this warning
because it was not his patch which introduced it. And if you used a plain
diff, it would produce something like:
-driver.c:100 Unused variable 'ret'
+driver.c:101 Unused variable 'ret'
But we pass the build log for the pre-patched kernel via 'remap-log' and it
transforms that warning into
driver.c:101 Unused variable 'ret'
so the build logs of the pre-patched and patched kernels will contain the
same line and the diff won't show anything.
* aiaiai-test-bisectability
Accepts a patch-set as the input and checks that the patch-set does not
break compilation at any step. This is achieved by applying every patch in
the series one-by-one, compiling the kernel and checking that compilation
was successful.
* aiaiai-decode-rfc-2047
A small helper script which decodes unreadable patch subjects encoded with
RFC-2047 MIME encoding.
* aiaiai-concat-mboxes
A little helper script which concatenates multiple mbox files into one.
* aiaiai-match-keywords
A simple script which can be used to match certain unwelcom keywords in
patches.
To summarize:
* 'aiaiai-test-patchset' is the central script
* it runs 'checkpatch.pl'
* it runs 'aiaiai-test-bisectability'
* for every configuration specified by the user, it builds the kernel
before and after the patch using the 'aiaiai-make-kernel' script, then
compares the build log using the 'aiaiai-diff-log' script.
* Things are done in parallel.
* The results of all tests are collected and printed to stdout
* The "verbose" contents is printed to stderr
* Many of the jobs above are run in parallel
The 'aiaiai-diff-log' script which compares 2 logs. It uses the 'remap-log'
tool for comparing 2 build logs the smart way.
2 Using Aiaiai locally
~~~~~~~~~~~~~~~~~~~~~~
If you just want to test a patch-set locally, you should use the
'aiaiai-test-patchset' script. Do not forget to build the remap-log.c file in
the 'helpers' subdirectory.
Here are some examples.
1. Test a patch or a patch-set p.mbox against the linux-vfs kernel tree,
against the 'origin/next' branch, and use the 'i386_defconfig'
defconfig, the architecture is i386 (translates to 'make ARCH=i386'). Use
16 jobs.
cat p.mbox | ./aiaiai-test-patchset --bisectability --sparse --smatch \
--cppcheck --coccinelle -j 16 -c origin/next \
/<path>/linux-vfs i386_defconfig,i386
2. Test a patch or a patch-set p.mbox against the linux-omap kernel tree,
against the master branch, use the 'omap2plus_defconfig' defconfig,
'arm' architecture and 'arm-eabi-' cross-compiler prefix (translates to
'make CROSS_COMPILE=arm-eabi-').
cat p.mbox | ./aiaiai-test-patchset --bisectability --sparse --smatch \
--cppcheck --coccinelle -j 16 -c master \
/<path>/linux-omap omap2plus_defconfig,arm,arm-eabi-
3. If you are a maintainer you may want to test patches for more than one
architecture. You can do this - you'll just need to maintain defconfigs.
E.g., to test p.mbox against both i386_defconfig (Intel i386) and
omap2plus_defconfig (ARM-based SoC), you can run:
cat p.mbox | ./aiaiai-test-patchset --bisectability --sparse --smatch \
--cppcheck --coccinelle -j 16 -c master /<path>/linux-my \
i386_defconfig,i386 omap2plus_defconfig,arm,arm-eabi-
IOW, just specify defconfigs, architectures, and cross-compiler prefixes at
the end.
4. Test a patch or a patch-set p.mbox against the net-next kernel tree,
against the 'origin/master' branch, using a randomly generated config, the
architecture is i386 (translates to 'make ARCH=i386'). Use 16 jobs.
cat p.mbox | ./aiaiai-test-patchset --bisectability --sparse --smatch \
--cppcheck --coccinelle -j 16 -c origin/master \
/<path>/net-next randconfig,i386
Note, the 'aiaiai-test-patchset' script accepts one mbox file via stdio or the
'-i' option. If you have several files belonging to one patch-set and you want
to test them all, you need to concatenate them. Use the 'aiaiai-concat-mboxes'
script for this. E.g., if you have '01.mbox' and '02.mbox' comprising a
patch-set, you can test do like this:
$ aiaiai-concat-mboxes 01.mbox 02.mbox | aiaiai-test-patchset ....
Patches generated with 'git format-patch' are also mbox files so you can test
them with 'aiaiai-test-patchset' as well. Just remember to use the '--thread'
option to make 'git format-patch' generate "Message-Id:" and "In-Reply-To:"
headers. For example:
$ git format-patch --thread HEAD~10
$ aiaiai-concat-mboxes 00* | aiaiai-test-patchset ...
I usually run 'aiaiai-test-patchset' with the lowest priority in order to make
sure the machine is still usable for other things:
$ nice -n19 ionice -c3 aiaiai-test-patchset ...
And for the kernel trees I test frequently against, I usually have a helper
script so that I do not have to type the 'aiaiai-test-patchset' options over
and over again.
3 Dependencies
~~~~~~~~~~~~~~
3.1 smatch
~~~~~~~~~~
Project homepage: http://smatch.sourceforge.net
I do not think this tool is a part of Linux distributions. I found it very
useful. To use it, you have to clone it, patch it, and install in your system.
$ git clone git://repo.or.cz/smatch.git
$ cd smatch
$ make PREFIX=$HOME/programs/smatch all install
$ export PATH="$PATH:/home/aiaiai/programs/smatch/bin"
These commands will install smatch to "/home/aiaiai/programs/smatch". Of
course, you should specify your path and make sure smatch is in your "PATH"
environment variable.
3.2 sparse
~~~~~~~~~~
Similarly to smatch, you need to install it manually. This is what I did:
$ git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git
$ cd sparse
$ make
$ cp sparse $HOME/bin
$ export PATH="$HOME/bin:$PATH"
3.3 coccinelle
~~~~~~~~~~~~~~
Coccinelle or "spatch" is a great semantic patch tool, very useful on its own.
The Linux kernel contains a bunch of coccinelle semantic patches which catch
various types of API abuses etc. We store a copy of these scripts in the
"helpers" subdirectory.
The "spatch" tool is part of distributions like Debian and Fedora, so you most
probably just need to install the corresponding package. The binary program is
called "spatch".
You may find a lot of information about this awesome tool by Googling.
3.4 Dependencies
~~~~~~~~~~~~~~~~
The scripts use many external programs which are usually part of the Linux
distribution. Here are they are, but the list is not complete - if you spot
a missing dependency - please, let me know or send a patch against the README
file.
gcc
make
cppcheck
formail
perl
python
mutt
sed
grep
awk
git
lockfile
diff
patch
inotifywait
3.5 Code conventions
~~~~~~~~~~~~~~~~~~~~
The scripts have been written for the "dash" shell and they do not use
any "bashizm" and should be very portable. Please, keep this in mind
when changing them. The scripts try to follow a uniform coding style
and conventions. Below are some of them.
* Stdout is used only for user-friendly stuff. In many cases it is assumed that
the higher-level scripts just capture the stdout of lower-level scripts and
provide that to the user. For example, 'aiaiai-test-patchset' captures stdout
of the 'aiaiai-test-bisectability' scripts and uses it for reporting to the
user. In turn, the 'aiaiai-email-test-patchset' script captures stdout of the
'aiaiai-test-patchset' script and sends it back to the user via e-mail.
* Stderr is use for all the debugging, verbose and additional prints.
* The scripts use the "-e" shell option and in case of any error (non-zero
return code from any program) we exit immediately. This allows us simplify
the scripts and avoid handling errors for all the commands which is very
convenient.
Well, the automatic exit does not work if the errorred command is in a
pipeline, and not the last. But this is not a big deal in most cases.
And sometimes we do not want the whole script to error out if a command
returns non zero (e.g., grep returns 1 if it did not match the pattern),
in which case we usually use "||:" after the command.
* We use "-u" shell option to make sure our scripts are of good quality.
* We try to be more secure and use the "-f" shell option whenever we can.
* We make use of the external "libshell" library which is part of the Alt
Linux project and is extremely useful.
* All the temporary files should be remover upon exit or interruption
(ctrl-C must be handled gracefully)
* Users' git repository have to be treated as read-only and no modifications
should be made there. All the work has to be done in a clone of the original
repository.