How to Contribute to the Linux Kernel Mainline
A beginner-friendly, practical guide from your free Linux kernel development course
Intermediate
~18 min
Free & Open
Kernel 6.x
What You Will Learn
Contributing to the Linux kernel mainline is one of the most valuable skills you can develop as an embedded systems or Linux developer. In this free Linux kernel development course module you will learn exactly what it means to “upstream” a kernel patch, why it matters, and how to do it correctly with modern tools.
- What “upstream” and “mainline” mean in the Linux kernel world
- The full lifecycle of a kernel patch — from idea to merged commit
- How to write kernel-quality code following Linux coding style rules
- How to use
checkpatch.plandsparseto verify your patch - How to use
git send-emailto submit patches to maintainers - How to find the right maintainer for your subsystem
- Common mistakes beginners make and how to avoid them
- Best practices for writing excellent commit messages
Table of Contents
- What Does “Contributing Upstream” Mean?
- Why Contribute to the Linux Kernel?
- Prerequisites
- The Linux Kernel Patch Lifecycle
- Linux Kernel Coding Style
- Writing Your First Kernel Patch
- Verifying with checkpatch.pl
- Writing a Good Commit Message
- Finding the Right Maintainer
- Sending Your Patch with git send-email
- Surviving the Review Process
- Common Mistakes to Avoid
- Best Practices
- Summary & Key Takeaways
- FAQ
1. What Does “Contributing Upstream” Mean?
In Linux kernel development, the term upstream refers to the official Linux kernel source tree maintained by Linus Torvalds and the network of subsystem maintainers. When you write code that becomes part of this official tree, your code is described as having been upstreamed or merged into mainline.
Most day-to-day kernel development — including what you do during a free Linux kernel development course — happens out-of-tree: you write a Loadable Kernel Module (LKM) and compile it against your installed kernel headers without touching the kernel source tree itself. That is perfectly fine for learning and for product-specific drivers. However, when your code could benefit the whole Linux community, contributing it upstream is the right thing to do.
Think of it like writing a recipe you have perfected in your own kitchen and then publishing it in a community cookbook so everyone benefits. The community cookbook is maintained by editors (subsystem maintainers) who check quality before accepting your contribution.
Writes patch
locally
+ sparse
Code quality
checks
Patch sent to
mailing list
Maintainer
Reviews &
comments
revises (v2, v3…)
Addresses
feedback
merges
Mainline
kernel!
2. Why Contribute to the Linux Kernel?
You might be thinking: “I am just learning through a free Linux device drivers course — why would I submit patches?” There are very good reasons to start thinking about upstream contribution early:
- Career impact: Merged kernel commits are a powerful signal to employers like Qualcomm, Texas Instruments, ARM, and Google. They prove real-world competence, not just theoretical knowledge.
- Code quality discipline: The kernel community’s review process is exceptionally rigorous. Going through it even once will permanently raise your coding standards.
- Maintenance avoidance: If your driver or fix lives out-of-tree, you must keep rebasing it every time the kernel changes. Upstream code is maintained by the community.
- Community membership: Linux is the world’s largest collaborative software project. Contributing connects you to a global network of expert engineers.
- Bug fixes benefit everyone: A kernel bug you fix might affect millions of embedded devices, servers, and smartphones around the world.
3. Prerequisites
Before attempting to contribute to the Linux kernel mainline, make sure you are comfortable with the following:
module_init / module_exitmake menuconfig and make -jNdmesg, printk, and kernel log levels4. The Linux Kernel Patch Lifecycle
Understanding how a patch travels from your keyboard to the mainline kernel is essential before you write a single line. The journey typically looks like this:
linux-next tree or the specific subsystem maintainer tree, not an arbitrary distro kernel.CONFIG_DEBUG_KERNEL=y, KASAN, lockdep).5. Linux Kernel Coding Style
The Linux kernel has strict coding conventions documented in Documentation/process/coding-style.rst inside the kernel source tree. These are not optional suggestions — patches that violate them are rejected. Here are the most important rules:
| Rule | Requirement | Common Mistake |
|---|---|---|
| Indentation | Tabs, not spaces. 8-character tab width. | Using 4-space indentation from habits in userspace C |
| Line length | Maximum 100 characters (was 80, relaxed in 2020) | Wrapping lines too aggressively at 80 chars |
| Braces | Opening brace on same line for control flow; new line for functions | Allman style (brace on its own line for if/while) |
| Naming | lowercase_with_underscores for functions and variables | camelCase from other languages |
| Comments | /* C-style block comments */ only; no C++ // style | Using // comments throughout the file |
| Typedefs | Avoid typedef for structs; use struct foo directly |
Hiding struct behind a typedef unnecessarily |
| printk | Always use a log level: pr_info(), pr_err(), dev_err() |
Bare printk() with no log level |
Quick Coding Style Example
Compare these two versions of the same function — one violates kernel style, one is correct:
/* WRONG - violates kernel coding style */
typedef struct myDevice {
int id;
char name[32];
} myDevice_t; // C++ style comment — not allowed
int initializeMyDevice(myDevice_t *dev, int deviceId) { // camelCase — not allowed
if(dev == NULL) // no space before '(' in if
{ // brace on new line — wrong for control flow
return -1;
}
dev->id = deviceId;
return 0;
}
/* CORRECT - kernel coding style */
struct my_device {
int id;
char name[32];
};
/*
* init_my_device - initialise a my_device instance
* @dev: pointer to the device structure to initialise
* @device_id: the numeric ID to assign
*
* Returns 0 on success, -EINVAL if @dev is NULL.
*/
static int init_my_device(struct my_device *dev, int device_id)
{
if (!dev)
return -EINVAL;
dev->id = device_id;
return 0;
}
if, while, and for statements have the brace on the same line as the statement. This is specific to Linux kernel style and differs from most other C style guides.6. Writing Your First Kernel Patch — Where to Start
Many beginners ask: “What should my first patch fix?” The honest answer is: start small. The goal of your first submission is to learn the process, not to add a major feature. Here are excellent starting points:
Documentation fixes
Typos, grammar errors, or outdated information in Documentation/ files. Easy to find, low-risk, and maintainers appreciate them.
checkpatch warnings
Run checkpatch.pl across staging drivers (drivers/staging/). Fixing style issues there is explicitly encouraged for new contributors.
TODO / FIXME comments
Search the kernel tree for /* FIXME */ and /* TODO */ comments in areas you understand.
Bug from syzbot
The kernel’s automated fuzzing infrastructure (syzbot) publishes open bugs. Pick one in a subsystem you know.
New device driver
If you own a hardware device that has no upstream driver, write one. This is advanced but most impactful.
Missing error handling
Many drivers do not check return values of memory allocations or I/O operations. Adding this is valuable and straightforward.
Setting Up Your Kernel Development Environment
You need to work against the correct kernel source tree. For most new contributors, linux-next is the right starting point because subsystem maintainer trees are merged into it daily, and it represents the current state of the development branch:
# Clone linux-next (the integration tree for ongoing kernel development)
git clone https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
cd linux-next
# Always work on a separate branch — never commit to master/main directly
git checkout -b my-first-fix origin/master
# Confirm your kernel version
head -5 Makefile
linux-next or the relevant subsystem tree.Making Your Change
Let us say you found a documentation typo in Documentation/process/coding-style.rst. Edit the file, then:
# Stage your change
git add Documentation/process/coding-style.rst
# Commit with a well-structured message (see next section for the format)
git commit -s
The -s flag adds your Signed-off-by: line automatically. This is mandatory for all kernel patches. It is your legal statement that you have the right to contribute this code under the kernel’s license (GPL-2.0-only / GPL-2.0-or-later).
7. Verifying Your Patch with checkpatch.pl
The checkpatch.pl script lives in the kernel source tree at scripts/checkpatch.pl. It is a Perl script that checks your patch for coding style violations, common errors, and suspicious patterns. Running it is not optional — it is a required step in the Linux kernel contribution process.
# First, generate a patch file from your last commit
git format-patch -1 HEAD
# This creates a file like 0001-doc-fix-typo-in-coding-style.patch
# Now run checkpatch against it
./scripts/checkpatch.pl 0001-doc-fix-typo-in-coding-style.patch
A clean patch produces output like:
total: 0 errors, 0 warnings, 15 lines checked
0001-doc-fix-typo-in-coding-style.patch has no obvious style problems and is ready for submission.
If you see errors or warnings, fix them before sending. Here is what different message types mean:
| Message Type | Meaning | Action Required |
|---|---|---|
ERROR: |
Definite violation of kernel coding rules | Must fix. Maintainers will reject without fixing. |
WARNING: |
Probable style issue or suspicious pattern | Should fix. Explain in cover letter if not fixing. |
CHECK: |
Minor advisory suggestion | Consider fixing. Not blocking but good practice. |
Additional Static Analysis Tools
Beyond checkpatch, the kernel community expects patches to pass sparse (the kernel’s static type-checker) for anything touching kernel code (not just docs):
# Install sparse
sudo apt-get install sparse
# Build the modified file with sparse checking enabled
make C=1 drivers/your/modified_file.o
# C=1 means: run sparse on files being recompiled
# C=2 means: run sparse on ALL C files (very thorough but slow)
8. Writing a Good Kernel Commit Message
The commit message in a Linux kernel patch is not an afterthought — it is permanent history attached to the commit forever. A poorly written commit message will get your patch rejected even if the code itself is correct. Here is the required format:
subsystem: component: short imperative summary of what changes (max ~72 chars)
Paragraph explaining the problem this patch solves. Write this as if
explaining to a colleague who has no context. What was wrong? What
were the symptoms? How did you discover it?
Paragraph explaining your solution and why this approach was chosen
over alternatives. If the fix is non-obvious, explain the logic.
If applicable, note the commit that introduced the bug using:
Fixes: aabbccdd1234 ("original commit subject line")
Signed-off-by: Your Name <your.email@example.com>
Let us look at what each part means:
| Part | Purpose | Example |
|---|---|---|
| Subject line | One line summary. Use imperative mood (“fix” not “fixed”). | net: ethernet: fix null-deref in rx path when skb is NULL |
| Body paragraph 1 | Describe the problem, not the solution. What is broken? | “When the device receives a packet during shutdown, the rx handler dereferences skb without checking for NULL…” |
| Body paragraph 2 | Describe your solution and why it works. | “Add a NULL check before dereferencing skb and return early with NETDEV_TX_OK…” |
| Fixes tag | Links your patch to the commit that caused the bug (triggers stable backports). | Fixes: c3f90e2a1b45 ("net: add rx handler callback") |
| Signed-off-by | Developer Certificate of Origin. Mandatory. | Signed-off-by: Ravi Kumar <ravi@example.com> |
9. Finding the Right Maintainer for Linux Kernel Contribution
The Linux kernel is maintained by hundreds of subsystem maintainers. Each subsystem has one or more maintainers listed in the MAINTAINERS file at the root of the kernel source tree. You must send your patch to the correct maintainer — sending it to the wrong person wastes everyone’s time.
The kernel provides a helper script that does this work for you:
# For a patch file you have already generated:
./scripts/get_maintainer.pl 0001-your-patch.patch
# For a specific file in the tree (useful during development):
./scripts/get_maintainer.pl --file drivers/net/ethernet/intel/igb/igb_main.c
The output looks like this:
Jeff Kirsher <jeffrey.t.kirsher@intel.com> (maintainer:INTEL 1GbE ETHERNET DRIVER)
Alexander Duyck <alexanderduyck@fb.com> (reviewer:INTEL 1GbE ETHERNET DRIVER)
intel-wired-lan@lists.osuosl.org (open list:INTEL 1GbE ETHERNET DRIVER)
netdev@vger.kernel.org (open list:NETWORKING DRIVERS)
linux-kernel@vger.kernel.org (open list)
Send your patch to all addresses listed: the maintainer, any reviewers, and all relevant mailing lists. The community review happens on public mailing lists — that is by design.
maintainer
Wireless drivers
Bluetooth
maintainer
NFS / tmpfs
VFS layer
maintainer
Platform code
Boot code
maintainer
Input devices
USB HID
10. Sending Your Patch with git send-email
The Linux kernel patch submission process uses email — specifically plain-text inline patches sent to mailing lists. Do not use web-based git interfaces like GitHub pull requests for upstream kernel submissions. The kernel community uses email exclusively.
One-Time git send-email Configuration
# Configure your email settings in ~/.gitconfig
git config --global sendemail.smtpserver smtp.gmail.com
git config --global sendemail.smtpserverport 587
git config --global sendemail.smtpencryption tls
git config --global sendemail.smtpuser your.email@gmail.com
# Install git-email package if not present
sudo apt-get install git-email
Generating and Sending a Single Patch
# Generate the patch from your last commit
git format-patch -1 HEAD -o /tmp/patches/
# Preview what will be sent (dry run — always do this first!)
git send-email --dry-run --to="maintainer@kernel.org" \
--cc="subsystem-list@vger.kernel.org" \
--cc="linux-kernel@vger.kernel.org" \
/tmp/patches/0001-your-patch.patch
# Send for real when you are satisfied
git send-email --to="maintainer@kernel.org" \
--cc="subsystem-list@vger.kernel.org" \
--cc="linux-kernel@vger.kernel.org" \
/tmp/patches/0001-your-patch.patch
Sending a Patch Series (Multiple Patches)
When your contribution spans multiple commits, use a cover letter:
# Generate patches for the last 3 commits, with a cover letter
git format-patch -3 HEAD --cover-letter -o /tmp/patches/
# Edit the cover letter (0000-cover-letter.patch) — explain the series purpose
# Then send the whole series
git send-email --to="maintainer@kernel.org" \
--cc="list@vger.kernel.org" \
/tmp/patches/*.patch
11. Surviving the Review Process
Once your patch is on the mailing list, experienced kernel developers will review it and leave comments. This is where many beginners get discouraged. A few things to keep in mind:
- Feedback is not personal. The kernel community is direct and sometimes blunt. A reviewer saying “this is wrong” is not attacking you — they are helping your patch reach the quality standard required.
- Respond to every comment. Even if you disagree, explain why. Silence is the worst response.
- Version your patch as v2, v3, … when you resubmit after changes. Add a changelog below the
---line in the patch (this section does not go into the commit history). - Do not rebase your work unnecessarily while review is ongoing — it confuses reviewers following the thread.
Adding a Changelog to a Revised Patch
subsystem: component: fix null-deref in probe
Description of the fix...
Signed-off-by: Your Name <your@email.com>
---
v3:
- Removed redundant NULL check on line 42 (per David Miller's comment)
- Used dev_err() instead of pr_err() for device-scoped logging
v2:
- Added missing Fixes: tag
- Corrected commit subject line format
drivers/net/foo/foo_main.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
--- line separates the commit message (which goes into git history) from the patch metadata and changelog (which the git am tool strips out). Always put your version changelog below --- so it does not pollute the commit message.12. Common Mistakes in Linux Kernel Contribution
linux-next or the subsystem tree13. Best Practices for Linux Kernel Contribution
- Read before writing. Spend at least two weeks reading the mailing list for the subsystem you want to contribute to. Understand the communication style and ongoing discussions.
- Use a debug kernel. Always test with
CONFIG_DEBUG_KERNEL=y,CONFIG_KASAN=y(AddressSanitizer), andCONFIG_LOCKDEP=yenabled. These catch bugs that a standard build misses. - Run the kernel self-tests. The kernel includes a test suite under
tools/testing/selftests/. Run the tests for the subsystem your patch touches. - Keep patches small and focused. A 10-line patch that solves one problem is infinitely better than a 500-line patch that touches five subsystems.
- Use QEMU for safe testing. Test your kernel on QEMU before risking your physical development machine during early iteration.
- Monitor
linux-nextfor conflicts. Between submitting and getting merged, someone else might change the same files. Rebase againstlinux-nextbefore resubmitting. - Be patient. Your first patch might take 2-4 kernel release cycles to get merged. This is normal, not a rejection.
14. Summary & Key Takeaways
In this module of the free Linux kernel development course, you learned the complete workflow for contributing to the Linux kernel mainline:
- Upstream contribution means getting your code into the official kernel source tree maintained by Linus Torvalds and subsystem maintainers.
- The patch lifecycle goes from idea → write → checkpatch → commit message → get_maintainer → git send-email → review → revise → merge.
- Linux kernel coding style is enforced strictly: 8-character tabs, 100-char line limit, lowercase_underscores naming, C89 comments only.
checkpatch.plmust report zero errors before you submit.sparseshould also be clean.- Commit messages are permanent history. Write them carefully in the subject: subsystem: component: imperative summary format.
scripts/get_maintainer.plidentifies who should receive your patch.git send-emailis the only acceptable submission method — plain-text, inline, to the mailing list.- Review feedback is a normal part of the process. Respond to every comment, version your revisions, and be patient.
Frequently Asked Questions
drivers/staging/ directory exists specifically for beginners. It contains drivers that are not yet ready for mainline, and fixing coding style issues or TODOs in staging drivers is an officially encouraged way to get started. Your first contribution can be a one-line documentation typo fix — what matters is following the process correctly.Signed-off-by: Name <email> line at the end of every commit message is your digital signature for this certificate. Without it, the patch will be rejected automatically.linux-next is the integration tree where all subsystem trees are merged daily. It represents what the next kernel release is likely to look like. New development targets linux-next. linux-stable is the long-term stable branch where only critical bug fixes and security patches are backported from mainline. If you fix a serious bug in mainline, stable maintainers may automatically apply it to stable releases using your Fixes: tag.drivers/staging/ directory in the kernel source contains drivers that work but do not yet meet the quality bar for mainline. They are kept there while developers improve them incrementally. Each staging driver has a TODO file listing what needs to be fixed. This makes staging an ideal sandbox for new contributors — the bar for each individual patch is lower, and the maintainers (Greg Kroah-Hartman’s team) are known for being welcoming to first-time contributors.scripts/get_maintainer.pl --file path/to/file.c and look at the T: field in the output — it shows the git tree the maintainer uses. Base your patch on the HEAD of that tree. If no specific tree is listed, base it on linux-next. Never base patches on a released kernel tag (like v6.10) for new feature submissions — those are already closed for additions.-rc1 tag and eventually in the final release. You can track it on patchwork.kernel.org or by searching lore.kernel.org.Authoritative References
Continue Your Free Linux Kernel Development Journey
EmbeddedPathashala offers a completely free Linux kernel development course, free Linux device drivers course, and free embedded systems course — no cost, no paywall, forever.
View Full Course Index Device Drivers Course