Lab 7: Your First Patch (Milestone 8)

Background

Everything so far was rehearsal. This lab sends a real patch, to a real mailing list, read by real people who will read your name for the first time.

It is deliberately small. The point is not the change — it is that the whole pipeline works: correct recipients, correct base, correct format, uncorrupted transport, and a commit message that answers the question before it is asked. Getting a one-line fix merged proves the machinery. The interesting patches come after, and they come much more easily once the machinery is boring.

Start this in week 9, not week 18. The community's clock runs in weeks and it does not start until you press send.

Why This Lab Matters

  • Your first patch is your first impression, and it is archived forever on lore.
  • Every mechanical failure mode — wrong list, mangled patch, wrong tree, missing sign-off — costs a round trip, and a round trip costs a week.
  • Once the mechanics are automatic, the only remaining variable is the quality of your idea, which is where you want to be spending attention.

Prerequisites

  • All five contribution chapters read.
  • Documentation/process/submitting-patches.rst read end to end. Not skimmed.
  • git send-email configured, and the round-trip test passed.
  • b4 installed.
  • A real name and a working email address in git config.

Predict First

  1. How long until you get a reply? Give a number and a confidence.
  2. What is the single most likely mechanical thing to go wrong with your first send?
  3. If your patch is applied, how long until it is in a tagged release?
  4. If nobody replies for two weeks, what will you do — precisely?
  5. What fraction of first patches from newcomers get a "please split this" or "wrong tree" reply?

Write all five down. You will check them against reality in the validation step.


Step-by-Step Tasks

Step 1: Find something real

This is the hard part of the lab, and the constraint that makes it hard is deliberate:

The change must be real. Not a whitespace fix. Not a checkpatch cleanup in code you have not read. Not a typo in a comment nobody reads. Something that, if a user or a developer hit it, would have cost them time.

Good first patches, in rough order of value:

KindHow to find one
A documentation error you can proveRead Documentation/ for a subsystem you now know, and check each claim against the code. Docs drift; you will find something.
A stale or wrong commentgit log -S the code near a comment. If the code changed and the comment did not, that is a real defect.
A wrong error message or errnoA path that returns -EINVAL where the code clearly means -ENOMEM, or a dev_err naming the wrong thing
A missing MODULE_DESCRIPTIONRecent kernels warn about these; there is a real, finite list
Dead code you can prove is dead#ifdef on a symbol that no longer exists; a function with no callers
A checkpatch finding in code you were reading anywayOnly if you understand the code
cd ~/kernel/linux

# Documentation that references something that no longer exists:
rg -o -N '`\w+\(\)`' Documentation/driver-api/ | sort -u | head -40
#   ...then check a few: does that function still exist?
rg -n "\bsome_function\b" --type c | head

# Comments referring to a function that was renamed:
git log --oneline -S'old_function_name' | head

# Missing module descriptions (a real, finite list):
make O=../build allmodconfig >/dev/null 2>&1
make O=../build -j"$(nproc)" 2>&1 | grep -i "missing MODULE_DESCRIPTION" | head

# What has recently been accepted in your area — calibrate on this:
git log --oneline --since="3 months ago" -- <your subsystem> | head -30

Warning: Do not go looking for TODO and FIXME comments to fix. They are almost always there because the fix is hard, contentious, or blocked on something, and a newcomer's patch "fixing" one usually reveals they did not know why it was there. Find a defect, not a marker.

Step 2: Verify it is actually a bug

Before writing anything:

# 1. Is it already fixed in a tree you are not looking at?
git fetch linux-next --tags
git log --oneline linux-next/master --since="3 months ago" -- <the file>

# 2. Has someone already sent a patch for it?
#    Search lore.kernel.org for the file name and the function name.

# 3. Was it done deliberately? The commit message will say.
git log --format='%h %s%n%n%b' -3 -- <the file>
git blame -L '/the_line/,+1' <the file>

Finding that it is already fixed is a success: you spent ten minutes instead of a week and a public round trip.

Step 3: Target it

./scripts/get_maintainer.pl --scm --status -f <the file>

# Is the subsystem alive?
git log --oneline --since="6 months ago" -- <the dir> | wc -l

# Is there a profile with extra rules?
grep -B 5 -A 20 "<the dir>" MAINTAINERS | grep -E '^[PQTLS]:'
ls Documentation/process/maintainer-*.rst

# Base on the tree the T: line names.
git remote add <subsys> <the T: URL>
git fetch <subsys>
git branch -r | grep <subsys>            # branch names vary: main, for-next, ...
git switch -c my-first-fix <subsys>/<branch>

Step 4: Write it

One logical change. Nothing else in the diff — no whitespace, no unrelated tidying.

$EDITOR <the file>
git add -p                               # stage ONLY the intended hunks
git diff --cached                        # read every line of it

Step 5: Write the message

This is where a first patch is usually won or lost.

git commit -s                            # -s adds Signed-off-by
subsys: fix the specific thing

Describe what is wrong TODAY: under what conditions, and what a reader
would observe. Someone who has never seen this code should be able to
tell whether they are affected.

Then what you changed and why this is the right fix.

Then how you know: what you built, what you ran, on what.

Fixes: abc123def456 ("subsys: the commit that introduced it")
Signed-off-by: Your Real Name <you@example.com>
# Get the subject prefix from the file's own history — do not invent one.
git log --oneline -20 -- <the file>

# If it is a bug fix, find the commit that introduced it:
git log -S'the broken thing' --oneline -- <the file>
git log -1 --pretty=fixes <that sha>     # emits a correctly formatted Fixes: line

Step 6: Check it

./scripts/checkpatch.pl --strict -g HEAD~1..HEAD
make O=../build -j"$(nproc)"                       # it builds
make O=../build C=2 W=1 <the/dir>/                 # sparse + extra warnings
# If it touches code that can be built as a module:
make O=../build-all allmodconfig && make O=../build-all -j"$(nproc)"

And, if it is a behavioral change rather than documentation: boot it.

PROFILE=paranoid ~/kernel-labs/scripts/build-kernel.sh
~/kernel-labs/scripts/run-qemu.sh

Step 7: Produce and self-review

git format-patch -1 --base=auto
cat 0001-*.patch                          # READ IT. All of it. Out loud.

Read it as a stranger would. Does the subject say what it does? Does the message explain why? Is there anything in the diff you cannot justify?

Step 8: The self-send

Non-negotiable, even though you already did the round-trip test once — because this is the actual patch.

git send-email --to=you@example.com --suppress-cc=all 0001-*.patch
# fetch the raw message, then:
git am /tmp/received.eml && git show --stat HEAD

Step 9: Send it

./scripts/get_maintainer.pl 0001-*.patch          # decide, do not just pipe

git send-email --dry-run \
  --to='Maintainer Name <maint@example.com>' \
  --cc='subsystem-list@vger.kernel.org' \
  --cc='linux-kernel@vger.kernel.org' \
  0001-*.patch

# Read the dry-run output. Then, once:
git send-email --to=... --cc=... 0001-*.patch

Check the cycle position first:

git fetch origin --tags && git describe --tags origin/master

Step 10: Record and wait

# It should appear within minutes:
#   https://lore.kernel.org/all/?q=<your subject>
# Save the message-ID. That is the permanent identity of your patch.

# And the Patchwork entry, if the subsystem has one (the Q: line):
#   https://patchwork.kernel.org/project/<project>/list/?submitter=<you>

Then wait. Two weeks before a single ping. Meanwhile, do Lab 9 — reviewing someone else's patch is the best possible use of the waiting time, and it is how you become a name people recognize.


Implementation Requirements / Deliverables

  • A real change: you can state, in one sentence, who it helps and how.
  • Verified not already fixed in linux-next and not already posted on lore.
  • Based on the tree the MAINTAINERS T: line names, on the right branch.
  • The subsystem's profile document read, if it has one.
  • One logical change; nothing else in the diff.
  • Commit message: problem, fix, testing — in that order, imperative mood, wrapped at ~72.
  • Signed-off-by: present, and you have read the DCO text it certifies.
  • Fixes: present if it is a bug fix, in the exact format.
  • checkpatch --strict -g clean.
  • Builds; C=2 W=1 clean for the files touched; allmodconfig if applicable.
  • The self-send round trip performed on this exact patch, and git am applied it.
  • Sent with git send-email, plain text, correct To: and Cc:.
  • Sent at a sensible point in the cycle.
  • The lore message-ID recorded.
  • Your five predictions recorded, with results filled in as they arrive.

Expected Output

$ ./scripts/checkpatch.pl --strict -g HEAD~1..HEAD
total: 0 errors, 0 warnings, 0 checks, 14 lines checked

Commit abc1234def56 ("subsys: fix the specific thing") has no obvious style problems
and is ready for submission.

$ git send-email --dry-run --to=... --cc=... 0001-*.patch
Dry-OK. Log says:
Server: smtp.example.com
MAIL FROM:<you@example.com>
RCPT TO:<maint@example.com>
RCPT TO:<subsystem-list@vger.kernel.org>
From: Your Real Name <you@example.com>
Subject: [PATCH] subsys: fix the specific thing

Within minutes, on lore.kernel.org:

[PATCH] subsys: fix the specific thing
Your Real Name  Thu, 12 Jun 2026 14:02:11 +0000

And a reply, in anything from an hour to three weeks:

On Thu, Jun 12, 2026 at 02:02:11PM +0000, Your Real Name wrote:
> Fixes: abc123def456 ("subsys: the original")

Applied to subsys/for-next, thanks.

Debugging Steps

It never appeared on lore

It did not arrive. Your SMTP failed silently, or a gateway dropped it. Re-run the self-send test and read the git send-email output rather than assuming it worked.

checkpatch complains about lines you did not touch

You used -f <file> instead of -g <commits>. Only your changes are your responsibility.

"Does not apply"

Wrong base. --base=auto in format-patch records what you built on; check it against the branch the maintainer named, and rebase.

"Please split this patch"

Two logical changes. Go back to patch craft and apply the two questions.

"This should go to "

get_maintainer.pl under-included, which happens when a change has cross-subsystem implications. Resend to the right people, briefly apologising, with a Link: to the original.

A reply says the patch is corrupted / does not apply for them

Your mail path mangled it. You skipped the self-send test, or you tested a different patch. Fix the path, then resend as v2 with a note.

A robot mails you about an architecture you have never used

That is the 0-day bot doing its job. Read the report — it usually names the exact config — fix it, and send v2 with a brief thanks. This is completely normal and not a failure.

Two weeks of silence

Work the table in Review and Etiquette, in order, before doing anything.


Experiment

CLAIM. The mechanical failure modes of a first patch are predictable, and you can measure how common they are rather than guessing.

METHOD. Before you send, go to lore.kernel.org and find ten first-time contributors' patches in any subsystem. (First-timers are identifiable: no prior posts, and often a reply explaining a mechanical rule.) For each, record:

#Outcome
Applied with no comment
Applied after a technical revision
Asked to split
Wrong tree / wrong recipients
Format problem (HTML, attachment, corrupted)
Style/checkpatch comment
NAK on the merits
No reply at all

PREDICTION. Fill in the counts you expect before you look.

RESULT. Then compare with your prediction, and — the actual point — check your own patch against every category that appeared. Most people discover that the mechanical failures outnumber the technical ones, which is exactly why this lab is mostly mechanics.


Test

The test for this lab is external and slow, so make the parts you control checkable:

cat > ~/kernel-labs/scripts/presend.sh <<'EOF'
#!/usr/bin/env bash
# Everything checkable about a patch, before it leaves your machine.
set -euo pipefail
KTREE="${KTREE:-$HOME/kernel/linux}"
RANGE="${1:-HEAD~1..HEAD}"
cd "$KTREE"
rc=0

echo "== checkpatch"
./scripts/checkpatch.pl --strict -g "$RANGE" || rc=1

echo "== every commit builds"
git rebase --exec "make -s -j$(nproc) O=../build" "${RANGE%%..*}" || rc=1

echo "== sign-off present on every commit"
for c in $(git rev-list "$RANGE"); do
  git show -s --format='%b' "$c" | grep -q '^Signed-off-by:' || {
    echo "  MISSING Signed-off-by on $c"; rc=1; }
done

echo "== recipients"
git format-patch "$RANGE" -o /tmp/presend >/dev/null
./scripts/get_maintainer.pl /tmp/presend/*.patch

echo "== base-commit recorded"
grep -q '^base-commit:' /tmp/presend/*.patch || { echo "  no base-commit (use --base=auto)"; rc=1; }

[ $rc -eq 0 ] && echo "PRESEND OK" || echo "PRESEND FOUND PROBLEMS"
exit $rc
EOF
chmod +x ~/kernel-labs/scripts/presend.sh
~/kernel-labs/scripts/presend.sh

Verify it can fail: remove your Signed-off-by and re-run. If it still passes, the script is wrong.


Challenge Extensions

  1. Do it with b4 instead. b4 prep --new, b4 prep --edit-cover, b4 send. Compare the workflow with raw git send-email and decide which you will use going forward.

  2. Find the same bug in three other places. Most defects are patterns. A Coccinelle script that finds yours tree-wide (make coccicheck MODE=report COCCI=...) turns one patch into a series and is a genuinely respected kind of contribution.

  3. Follow your patch all the way. Every week, check: is it in the maintainer's tree? In linux-next? In a tagged release? Record the dates. That timeline is the answer to prediction 3, and having measured it once removes the anxiety permanently.

  4. Read the applied version. When it lands, diff what was applied against what you sent (git range-diff or by hand). Maintainers often adjust the subject, the message, or whitespace. Every difference is a lesson about what they wanted.

  5. Send a second one immediately. The first patch is about mechanics; the second is where you find out whether the mechanics are actually automatic. Do not wait for the first to land.

  6. Volunteer for an Orphan. Find a MAINTAINERS entry with S: Orphan in an area you understand, fix something in it, and offer to take it on. This is how a surprising number of maintainers started.


Validation / Self-check

  1. Why must a first patch be a real change rather than a whitespace or checkpatch fix?
  2. Why is hunting for TODO/FIXME comments bad advice?
  3. Name three checks to run before writing a line, to avoid duplicating work.
  4. How do you find the right tree and branch, and what happens if you base on master instead?
  5. What are the three parts of the commit message body, in order?
  6. Where do you get the subject-line prefix?
  7. What exactly does the self-send test prove, and why do it on this specific patch even though you already tested your setup?
  8. Why checkpatch -g rather than -f?
  9. You get a mail from the kernel test robot about a build failure on an architecture you do not have. What is the correct response, and what does ignoring it signal?
  10. Your patch has had no reply in fifteen days. What, precisely, do you do — in order?
  11. How long, realistically, from sending to a tagged release? Compare with your prediction.
  12. Of the eight outcomes in the experiment, which were most common, and which of them could you have prevented mechanically?

Next: Lab 8 — A Patch Series, where one change becomes several and bisectability becomes a hard requirement.