How to Contribute to the Linux Kernel Mainline – Best Linux Device Drivers Course

 

 

EmbeddedPathashala › Linux Kernel Programming › Contributing to the Linux Kernel Mainline

How to Contribute to the Linux Kernel Mainline

A beginner-friendly, practical guide from your free Linux kernel development course

Level
Intermediate
Read Time
~18 min
Course
Free & Open
Updated
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.pl and sparse to verify your patch
  • How to use git send-email to 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

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.

Linux Kernel Contribution Model
Developer
Writes patch
locally
 
checkpatch.pl
+ sparse

Code quality
checks
 
git send-email
Patch sent to
mailing list
→
Subsystem
Maintainer

Reviews &
comments
 
Developer
revises (v2, v3…)

Addresses
feedback
 
Linus Torvalds
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:

✓
Writing Linux kernel modules (LKM framework) using module_init / module_exit
✓
Basic Git operations: clone, branch, commit, rebase, format-patch
✓
C programming: pointers, structs, bitwise operations, function pointers
✓
Building the kernel from source with make menuconfig and make -jN
✓
Reading kernel headers and understanding kernel data structures
✓
Familiarity with dmesg, printk, and kernel log levels
TipIf you are brand new to kernel programming, start with the earlier modules of this free Linux kernel development course covering module parameters, EXPORT_SYMBOL, and kernel Makefiles first.

4. 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:

1
Identify something to fix or addA bug, a kernel documentation error, a coding style issue, a missing feature, or a new driver for a hardware device you own.
2
Clone the relevant kernel treeYou work against the linux-next tree or the specific subsystem maintainer tree, not an arbitrary distro kernel.
3
Create a focused branch and write your fixOne logical change per patch. Do not bundle unrelated changes.
4
Test on real hardware and under QEMURun the kernel with your patch. Test with a debug kernel (CONFIG_DEBUG_KERNEL=y, KASAN, lockdep).
5
Run checkpatch.pl and fix all warningsThe maintainer will reject patches that fail checkpatch with errors.
6
Write a clear, structured commit messageThis is more important than most beginners think. The commit message is permanent history.
7
Run get_maintainer.pl to identify recipientsFind who maintains the files your patch touches.
8
Send with git send-email to the mailing listNever attach patches as files. Inline plain text only.
9
Respond to review comments promptly and politelyRevise and resubmit as v2, v3 … until accepted or declined.
10
Wait for merge windowOnce a maintainer queues your patch, Linus pulls it during the next merge window (every ~10 weeks).

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;
}
NoteNotice that function definitions have the opening brace on its own line, while 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
WarningDo not submit patches against your distribution kernel (Ubuntu, Fedora, etc.). Distribution kernels carry patches that are not in mainline, making your diff meaningless to upstream maintainers. Always use 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>
Pro TipWrite the commit body in the present tense when describing the problem (“The driver does not handle…”) and use imperative mood in the subject line (“Fix null dereference…”). This is the established Linux kernel convention.

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.

Linux Kernel Maintainer Hierarchy
Linus Torvalds (linux/kernel/git/torvalds/linux)
 
Networking
maintainer
 
Ethernet drivers
Wireless drivers
Bluetooth
Filesystems
maintainer
 
ext4 / btrfs
NFS / tmpfs
VFS layer
ARM / arch
maintainer
 
Device Tree
Platform code
Boot code
IIO / HID
maintainer
 
Sensors
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
WarningAlways subscribe to the mailing list you are sending to before your first submission. Some lists reject posts from non-subscribers. Also, never send HTML email — configure your mail client to send plain text only. The kernel community will ignore HTML-formatted patches.

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(-)
NoteThe --- 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

✗
Sending against a distro kernel — always use linux-next or the subsystem tree
✗
Forgetting Signed-off-by — this is mandatory. The kernel bot will bounce your patch.
✗
Mixing unrelated changes in one patch — one logical fix per commit, always.
✗
Subject line starting with capital or ending with period — “Fix foo” not “Fixed foo.”
✗
Not running checkpatch.pl — automated bots will reply with the errors if you skip this.
✗
Sending HTML email — the entire patch becomes unreadable to the community.
✗
No testing — at minimum, the kernel must build without errors with your patch applied.
✗
Silently ignoring review feedback — always reply, even to say you need time to understand the comment.

13. 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), and CONFIG_LOCKDEP=y enabled. 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-next for conflicts. Between submitting and getting merged, someone else might change the same files. Rebase against linux-next before 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.pl must report zero errors before you submit. sparse should also be clean.
  • Commit messages are permanent history. Write them carefully in the subject: subsystem: component: imperative summary format.
  • scripts/get_maintainer.pl identifies who should receive your patch.
  • git send-email is 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

Q1: Do I need to be an expert to contribute to the Linux kernel?
No. In fact, the 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.
Q2: How long does it take for a kernel patch to get merged?
It varies widely. The Linux kernel follows a roughly 10-week release cycle (about 2 weeks merge window + 8 weeks stabilization). A straightforward bug fix might get picked up by a maintainer within days and merged in the next cycle. A larger feature might take 2-4 cycles of review and revision. A first-time submitter should budget 1-3 months for their first patch to land.
Q3: What is the Developer Certificate of Origin (DCO) and why is Signed-off-by required?
The Developer Certificate of Origin is a legal statement that you have the right to contribute the code and that you agree it can be distributed under the kernel’s license (GPL-2.0). The 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.
Q4: Can I contribute to the Linux kernel from Windows?
Technically possible via WSL2 (Windows Subsystem for Linux 2), but not recommended for serious kernel development. Building the kernel, testing with QEMU, running real hardware tests, and working in a native Linux environment is far more reliable. A dedicated Linux development machine or a Linux virtual machine is the standard setup used by kernel developers globally.
Q5: What is the difference between linux-next and linux-stable?
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.
Q6: What is the staging tree and why is it good for beginners?
The 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.
Q7: How do I know which kernel tree to base my patch on?
Use 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.
Q8: Is it okay to use AI tools to write kernel patches?
This is a topic of active community discussion. The general position in the kernel community is: you are responsible for every line of code you submit under your Signed-off-by. If an AI tool generates a patch with a subtle bug and you submit it, you are accountable for that bug. AI tools can help you understand code or suggest ideas, but the final patch must be thoroughly understood, tested, and verified by you personally before submission.
Q9: What happens after my patch is accepted by a maintainer?
The maintainer queues your patch in their subsystem tree. During Linus’s next merge window (which opens right after each -rc1 tag), subsystem maintainers send their trees to Linus via pull requests. Linus reviews and merges them. Your commit then appears in the next -rc1 tag and eventually in the final release. You can track it on patchwork.kernel.org or by searching lore.kernel.org.
Q10: How does this free Linux kernel development course compare to paid courses?
EmbeddedPathashala’s free Linux kernel development course and free Linux device drivers course cover the same topics as commercial alternatives — from module basics through memory management, synchronisation, interrupts, and device drivers. The difference is access: everything here is free, permanently. Paid courses often provide live support; here you can ask questions via the community and course comments. The technical depth is comparable to any commercial offering.

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

Leave a Reply

Your email address will not be published. Required fields are marked *