Linux kernel: Preparing a patch for submission
This is a spin-off from my old post about git in general, and it contains my notes to self for preparing a patch for submission to the Linux kernel.
See Documentation/SubmittingPatches in the Linux tree.
First, clone the main git that appears in the MAINTAINERS part for the subsystem the patch is going to. Probably better, add the repo to the existing main Linux repository, initially fetched with
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Remember: The patch must apply (as in “git am”) against the “next” branch of the relevant subsystem’s repository.
Make the changes, verify that the latest version of sparse doesn’t complain with e.g.
$ make M=drivers/mydriver C=2
The C=2 forces as sparse run even on files that need no compilation. C=1 only checks modified files.
Always grab the latest version of sparse and check against the latest possible kernel. Really. I really had new warnings popping up just by checking against a newer kernel.
When all is well, commit. If the patch is a response to a bug report, add a “Reported-by:” header at the end of the commit message manually. Same goes for Tested-by, Suggested-by and Reviewed-by. There is no automatic mechanism for this (like –signoff).
If the patch fixes a bug, add a Fixes: header as well, with a commit ID and title of where the bug first occurs. If the bug was there from the beginning, put the commit ID where the file was inserted. The decision on whether the patch should be applied to stable kernels as well is made based upon this.
Also: Always have something meaningful written in the commit description. Just a title isn’t good enough (Greg rejected a very short patch of mine on the grounds that it had only a subject and no “changelog information”).
$ git commit -a $ git format-patch master -o patch --signoff
This will create a directory called “patch” and put the patch there. If several commits are made, a different patch file is created for each. That what the commit -a is for.
To get all commits in one patch, use the –to-stdout flag, and of course redirect stdout to a file.
If this is a second submission (version 2 = v2), use
$ git format-patch master -o patch --signoff --subject-prefix="PATCH v2"
It’s also a desired to add a short description on the difference from earlier versions. The place to do it, is under the “—” mark of the signoff. This can be done manually, or with git notes (see below) for creating a note for a commit, and then use the –notes flag with git format-patch. The result in the patch file is something like this:
Signed-off-by: Eli Billauer <eli.billauer@example.com> --- Notes: This is a really horrible patch
Check the patch with (run from kernel tree’s root)
$ scripts/checkpatch.pl --strict patch/0001-name-of-patch
(note that checkpatch.pl has a -f flag, allowing to check a source file rather than a patch)
I marked the –strict flag red, because I forgot to use it in an important occasion. It’s turned on automatically, by the way, when checkpatch detects that the target directory is one of drivers/net, net/ or drivers/staging/. Yes, the directories are hardcoded in the script itself. Perl or not?
Whitespace cleanup:
$ scripts/cleanpatch patch/0001-name-of-patch
Send it through email (the way the kernel guys like it)
git send-email --to 'linux-kernel@vger.kernel.org' patch/0001-name-of-patch
Add a –cc flag to send a copy to someone else than yourself. The mail won’t kick off before confirming it, so don’t worry…
Now, since I’m using my Gmail address as the “From”, the mail must come from a Gmail mail server. In order to relay the mail through their servers (and not my own), there’s a whole story about that. See this post.
Checking with clang
It’s also a good idea to check the code with clang before submitting it, as it can detect mistakes that gcc doesn’t. I had a patch rejected because of a silly bug I made and clang found.
Unfortunately, the kernel environment is quite picky with clang version used (requires version >=15.0.0 with kernel v7.1, for example). Note to self: Use “typ”.
clang is an alternative compiler, so it’s impossible to test-compile modules on a kernel compiled with gcc. So clone a copy of the entire kernel tree (or clean it with git clean -xd -f). Install the required tools if necessary (that’s ~ 1GB):
# apt install clang llvm lld flex bison libssl-dev libelf-dev
Prepare the kernel for module compilation:
$ make LLVM=1 olddefconfig $ make LLVM=1 modules_prepare
And then compile the module(s) with
$ make LLVM=1 M=drivers/mydriver && echo Success
The MODPOST phase fails because the kernel hasn’t been compiled, and that’s irrelevant, as the purpose is only to get the warnings from clang. The existence of the relevant symbols is checked with the “regular” compilation.
Or compile the entire kernel with clang.
git notes
This is a neat mechanism for adding extra information to commits. Its main use is for change log information to patches, so they appear in the email but not in the commit (if and when it’s applied).
To make thing simple, this is the only command needed to maintain notes:
$ git notes edit
It adds and/or edits the notes for the current commit with the selected editor.
As of gitk that goes along with 2.17.1 (2016 edition? It doesn’t say its version), the notes appear at the commit view, below the commit title, after a hard update (Ctrl-Shift-F5). There are also small yellow boxes next to the commit title in the tree view to mark that there are notes related to the commit.
Following the suggestion on this page, add the following lines to .git/config of the relevant repository.
[notes "rewrite"]
amend = true
rebase = true
[notes]
rewriteRef = refs/notes/commits
The problem this solves: Notes refer to commits by their object ID, which changes when the commit is rebased or amended. As a result, the note becomes detached from the commit it related to. This chunk tells git to update the notes’ refs to follow the commits.
It’s also possible to add it to ~/.gitconfig, but if rebasing or commit amending is done on a repository that doesn’t have any notes, one gets a “warning: notes ref refs/notes/commits is invalid”.