Linux Kernel Coding Style: A Complete Guide for Kernel Module Developers

Linux Kernel Coding Style Guide: Rules, checkpatch.pl & Best Practices | EmbeddedPathashala

Linux Kernel Coding Style
Rules, checkpatch.pl, Naming Conventions & Upstream Patch Submission — Free Linux Kernel Development Course
Level
Beginner–Intermediate
Kernel
Linux 6.x
Course
Free

Linux Kernel Coding Style: A Complete Guide for Kernel Module Developers

One of the first surprises for developers new to Linux kernel programming is just how strict the community is about coding style. This is not bureaucracy for its own sake. The Linux kernel is one of the largest and most actively developed codebases in the world, with thousands of contributors across hundreds of organizations. A consistent coding style makes it easier for any developer to read code written by someone they have never met, in a subsystem they are unfamiliar with.

If you are taking a free Linux kernel development course or working toward submitting your first driver to the mainline kernel, understanding and following coding style guidelines is not optional — it is a hard requirement. Patches that fail the style check are sent back without review.

🎓 What You Will Learn

  • The key rules of the Linux kernel coding style (indentation, line length, naming, braces)
  • How to use checkpatch.pl to automatically validate your code
  • How to use indent to auto-format your kernel C code
  • Common style violations and how to fix them
  • How coding style relates to the upstream patch submission process
  • How to integrate style checking into your Makefile workflow
Prerequisites: Basic C programming knowledge, familiarity with writing and loading Linux kernel modules, and a Linux development environment. Having the Linux kernel source tree available locally is helpful but not required for this tutorial.

Why Kernel Coding Style Matters in Linux Kernel Development

The Linux kernel community follows a style guide that Linus Torvalds originally described as reflecting a healthy attitude towards coding — where the visual appearance of code is considered part of its quality. Code that looks clean and consistent is easier to review, easier to spot bugs in, and easier to maintain over years by different people.

More practically: if you write a Linux device driver and want to have it accepted into the mainline kernel (so it is distributed with every Linux distro and maintained by the community), your code must pass the style checker. Reviewers on LKML (Linux Kernel Mailing List) will reject patches on style grounds alone, sometimes quite bluntly. Learning the style before you write code is much easier than reformatting thousands of lines later.

Linux Kernel Patch Submission Path
✍
Write Code
Your module or driver code
→
📊
checkpatch.pl
Auto style validation
→
📄
git format-patch
Create patch file
→
📧
Send to LKML
Subsystem maintainer review
→
🚀
Merged to Mainline
Your code in the kernel!

Core Linux Kernel Coding Style Rules

The official Linux kernel coding style is documented at kernel.org/doc/html/latest/process/codingstyle.html. Here are the most important rules you need to know as a kernel module developer.

Rule 1: Indentation — Tabs, Not Spaces

The Linux kernel uses hard tabs (one tab character) for indentation, not spaces. Each tab is set to display as 8 characters wide. This is deliberately wide — if your code is indented 5 or 6 levels deep, that is a sign you need to refactor it into smaller functions.

❌ WRONG — Using spaces for indentation
static int my_probe(struct platform_device *pdev)
{
    int ret;
    if (condition) {
        ret = do_something();
    }
    return ret;
}
✅ CORRECT — Using tab characters
static int my_probe(struct platform_device *pdev)
{
	int ret;

	if (condition) {
		ret = do_something();
	}
	return ret;
}

Rule 2: Line Length — 80 Characters (Relaxed to 100 in Recent Kernels)

Historically, all lines had to fit within 80 columns. Since Linux 5.7, the community relaxed this to allow lines up to 100 characters when breaking them would make the code harder to read. However, 80 columns is still the preferred target, and checkpatch.pl will warn on lines exceeding 100 characters.

❌ WRONG — Excessively long single line
ret = platform_driver_register(&my_platform_driver, THIS_MODULE, dev_name(&pdev->dev), &my_ops);
✅ CORRECT — Broken across lines sensibly
ret = platform_driver_register(&my_platform_driver,
			       THIS_MODULE,
			       dev_name(&pdev->dev),
			       &my_ops);

Rule 3: Brace Placement — K&R Style

The kernel uses K&R (Kernighan and Ritchie) brace style. Opening braces go on the same line as the statement (for non-function blocks). Closing braces go on their own line. The only exception is function definitions — the opening brace goes on a new line.

❌ WRONG — Allman style (opening brace on new line for if/for)
if (error)
{
	return -EINVAL;
}
✅ CORRECT — K&R style for control flow
if (error) {
	return -EINVAL;
}

/* Function definition — opening brace on its OWN line */
static int my_init(void)
{
	return 0;
}
💡 Single-statement bodies: If your if body is a single statement, you can omit braces. However, if the else branch uses braces, both branches must use braces. When in doubt, always use braces for clarity.

Rule 4: Naming Conventions

The kernel uses lowercase with underscores (snake_case) for all function and variable names. No camelCase, no Hungarian notation, no type-encoded prefixes. Names should be descriptive enough that a reader can understand the purpose without needing a comment.

Identifier TypeConventionExample
Local variablesShort, lowercaseret, len, i
Function namesLowercase with underscoresep_sensor_probe()
Global/exported symbolsDescriptive lowercaseep_sensor_read_data()
Macros and constantsALL_CAPS with underscoresMAX_BUFFER_SIZE
Struct typedefs (avoid)Kernel avoids typedef for structsUse struct my_device not MyDevice
⚠ Avoid typedef for structures: The Linux kernel style strongly discourages using typedef to create aliases for structures. Write struct my_device *dev, not MyDevice *dev. Typedefs hide the actual type and make code harder to understand at a glance.

Rule 5: Comments — Use /* */ Not //

The kernel traditionally uses C89-style block comments (/* */) rather than C99 double-slash comments (//). For multi-line comments, the preferred style is:

/*
 * This function initialises the sensor hardware and
 * configures the interrupt lines.
 * Returns 0 on success, negative errno on failure.
 */
static int ep_sensor_hw_init(struct ep_sensor *sensor)
{
	/* Single-line block comment for in-function notes */
	int ret;

	...
}

Rule 6: Return Value Conventions

Kernel functions that can fail should return negative errno values on failure and zero (or a positive value) on success. Never invent your own error codes. Use the standard ones from <linux/errno.h>.

/* Common return value patterns in kernel modules */
static int ep_driver_open(struct inode *inode, struct file *file)
{
	if (!device_ready)
		return -ENODEV;   /* Device not available */

	if (access_denied)
		return -EACCES;   /* Permission denied */

	if (!buffer)
		return -ENOMEM;   /* Out of memory */

	return 0;  /* Success */
}

Using checkpatch.pl to Validate Your Kernel Module Code

The Linux kernel source tree includes a powerful Perl script at scripts/checkpatch.pl that automatically checks your C code against the kernel coding style rules. Running this on your kernel module code before building or submitting is one of the most valuable habits you can develop in Linux kernel module programming.

Running checkpatch.pl on Your Module Source File

By default, checkpatch.pl expects a git-format patch as input. To run it directly against a standalone C file (which is what you have for an out-of-tree module), use the --no-tree and -f flags:

# Run checkpatch.pl against your module source file
$ /path/to/linux-src/scripts/checkpatch.pl --no-tree -f my_driver.c

# If you have the kernel source at /usr/src/linux:
$ /usr/src/linux-$(uname -r)/scripts/checkpatch.pl --no-tree -f my_driver.c

# Example output showing a style violation:
WARNING: line over 80 characters
#54: FILE: my_driver.c:54:
+	ret = some_long_function_name(param_one, param_two, param_three, param_four);

ERROR: space required after that ',' (ctx:VxV)
#62: FILE: my_driver.c:62:
+	if (a == 1&&b == 2) {

total: 1 errors, 1 warnings, 89 lines checked

Understanding checkpatch.pl Output

The script reports issues at three severity levels:

SeverityKeywordMeaning
HighERRORA definite violation. Your patch will not be accepted with these present. Fix all errors before submitting.
MediumWARNINGA likely problem. Should be fixed. Occasionally there is a legitimate reason to ignore one, but you need to be prepared to justify it to reviewers.
LowCHECKA stylistic suggestion. Not as critical but worth addressing for cleaner code.

Running checkpatch.pl on a git Patch

When you have committed your changes to git and want to run the check on the patch as reviewers will see it:

# Create a patch for the last commit
$ git format-patch -1 HEAD

# Run checkpatch on the generated patch file
$ scripts/checkpatch.pl 0001-add-my-driver.patch

# Or pipe directly
$ git format-patch -1 HEAD --stdout | scripts/checkpatch.pl -

Integrating checkpatch.pl into Your Makefile

For module development, it is very convenient to add checkpatch as a Makefile target so you can run it with a simple make checkpatch command:

# In your module's Makefile

KDIR ?= /lib/modules/$(shell uname -r)/build
CHECKPATCH := $(KDIR)/source/scripts/checkpatch.pl

obj-m += my_driver.o

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

# Style checking targets
checkpatch:
	$(CHECKPATCH) --no-tree -f $(wildcard *.c) $(wildcard *.h)

indent:
	indent -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1 $(wildcard *.c)
💡 Tip: The indent target uses the GNU indent tool configured for kernel style (-kr = K&R, -i8 = 8-space indent, -ts8 = 8-char tab). Run make indent to auto-format your C files, then make checkpatch to verify. This saves a lot of manual formatting work.

Common checkpatch.pl Errors and How to Fix Them

Most Common checkpatch.pl Errors in Kernel Module Code
✖ Spaces for indentation
Use hard tabs only. Configure your editor to insert tabs when you press Tab in C files.
✖ Missing space around operators
Write a == b, not a==b. Space before and after binary operators.
✖ Space after function name
Write func() not func (). No space between function name and opening paren.
✖ Trailing whitespace
No spaces or tabs at end of lines. Most editors can highlight and remove these automatically.
✖ Line too long
Lines over 100 characters generate warnings. Break long lines at logical points.
✖ Using // comments
Use /* */ style comments throughout. The // C99 style is not preferred in kernel code.

Detailed Example: Before and After checkpatch.pl

Here is a realistic example of a kernel module function with multiple style issues, and the corrected version:

❌ BEFORE — Multiple style violations
// This function reads data from the sensor
int ReadSensorData(struct MySensor* dev, u8* buf, int len){
    int result=0;
    if(len > MAX_SIZE) {
        return -1;
    }
    result = i2c_master_recv( dev->client, buf, len );
    if(result < 0){
        printk("Read failed %d\n",result);
    }
    return result;
}
✅ AFTER — Kernel style compliant
/*
 * ep_sensor_read - Read data from sensor over I2C
 * @dev: pointer to sensor device structure
 * @buf: output buffer to fill
 * @len: number of bytes to read
 *
 * Returns number of bytes read on success, negative errno on failure.
 */
static int ep_sensor_read(struct ep_sensor *dev, u8 *buf, int len)
{
	int ret;

	if (len > EP_SENSOR_MAX_READ_SIZE)
		return -EINVAL;

	ret = i2c_master_recv(dev->client, buf, len);
	if (ret client->dev, "I2C read failed: %d\n", ret);
		return ret;
	}

	return ret;
}

Changes made: switched from // to /* */ comment and added a proper kernel-doc style header; renamed to snake_case with a subsystem prefix; used struct ep_sensor * properly; replaced -1 with proper errno -EINVAL; fixed spacing around operators and parentheses; used dev_err() instead of printk(); made the function static.

Printing Messages the Right Way: dev_err vs printk

In older kernel code (and many tutorials you might find online), you will see printk(KERN_ERR "some message\n"). While this still works, the modern preferred approach is to use the device-aware logging macros that automatically include the device name in the log output.

FunctionWhen to UseExample Output
pr_info()General module-level info without a device context[my_driver] Module loaded
pr_err()Module-level error without a device context[my_driver] Failed to allocate memory
dev_info(dev, ...)Info message when you have a struct device *ep_sensor 1-0048: Sensor initialised
dev_err(dev, ...)Error when you have a struct device *ep_sensor 1-0048: I2C read failed: -5
dev_dbg(dev, ...)Debug info (compiled out unless DEBUG is defined)Shown only with CONFIG_DYNAMIC_DEBUG enabled
/* Module init - no device context yet, use pr_ macros */
static int __init ep_sensor_init(void)
{
	pr_info("EP Sensor driver version %s loaded\n", EP_DRIVER_VERSION);
	return i2c_add_driver(&ep_sensor_i2c_driver);
}

/* Probe function - device context available, use dev_ macros */
static int ep_sensor_probe(struct i2c_client *client)
{
	struct ep_sensor *sensor;

	sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
	if (!sensor) {
		dev_err(&client->dev, "Failed to allocate sensor struct\n");
		return -ENOMEM;
	}

	dev_info(&client->dev, "EP Sensor detected and probed successfully\n");
	return 0;
}

Accessing Linux Kernel Documentation

The Linux kernel source tree contains comprehensive documentation that every Linux kernel module programming developer needs to know how to navigate. This documentation is maintained alongside the code and is therefore more reliable and up-to-date than many third-party resources.

Rendered Online Documentation

The official documentation is rendered and browsable at kernel.org/doc/html/latest/. Key sections for module developers:

SectionURL PathCovers
Core APIcore-api/Memory allocation, printk, linked lists, data structures
Driver APIdriver-api/Device model, I2C, SPI, GPIO, interrupt handling
Processprocess/Patch submission, coding style, development workflow
Admin Guideadmin-guide/Module signing, sysctl, security features

Building Documentation Locally

You can also build and browse the documentation locally from your kernel source tree. This is especially useful when working on a specific kernel version:

# Install Sphinx documentation tool
$ sudo apt install python3-sphinx python3-sphinx-rtd-theme

# Build HTML documentation from kernel source
$ cd /path/to/linux-source
$ make htmldocs

# Browse at: Documentation/output/index.html

Kernel-doc Comments

When you write exported functions in your module, you should add kernel-doc style comments. These can be extracted by the documentation build system and are a requirement for functions you export with EXPORT_SYMBOL:

/**
 * ep_sensor_read_temperature - Read temperature from sensor
 * @sensor: Pointer to the ep_sensor device structure
 * @temp_mC: Output parameter, temperature in milli-Celsius
 *
 * Reads the current temperature measurement from the hardware
 * register and converts it to milli-Celsius.
 *
 * Return: 0 on success, -ENODEV if sensor not ready,
 *         -EIO on communication error.
 */
int ep_sensor_read_temperature(struct ep_sensor *sensor, s32 *temp_mC)
{
	/* implementation */
}
EXPORT_SYMBOL_GPL(ep_sensor_read_temperature);

Preparing for Upstream Kernel Contribution

Contributing to the mainline Linux kernel is an achievable goal for any serious Linux device driver course graduate. The process requires patience and attention to detail, but the community is welcoming to well-prepared contributors.

The Kernel Developer Workflow

Out-of-Tree to Upstream: Developer Workflow
1. Develop out-of-tree module
Iterate quickly outside kernel tree for development speed
↓
2. Run checkpatch.pl — fix all ERRORs and WARNINGs
↓
3. Write good commit message
Subject line + blank line + explanation + Signed-off-by
↓
4. Find the right maintainer
Use scripts/get_maintainer.pl to identify who reviews your subsystem
↓
5. Send patch via git send-email
To maintainer + relevant mailing list (e.g., linux-i2c@vger.kernel.org)

Summary and Key Takeaways

  • Linux kernel coding style is enforced by the community and is a hard requirement for upstream contributions.
  • Use hard tabs (8-character width) for indentation — not spaces.
  • Keep lines under 80–100 characters. Break long lines at logical points.
  • Use K&R brace style: opening brace on same line as control flow statement, on its own line for function definitions.
  • Name everything in lowercase with underscores. Use ALL_CAPS for macros and constants only.
  • Avoid typedef for structures. Write struct my_device everywhere.
  • Use /* */ comments. Use kernel-doc /** */ for exported functions.
  • Run scripts/checkpatch.pl --no-tree -f your_driver.c before every commit. Fix all ERRORs; aim to fix all WARNINGs too.
  • Integrate checkpatch and indent targets into your Makefile for a smooth workflow.
  • Use dev_err() / dev_info() when you have a device context; use pr_err() / pr_info() for module-level messages.

Frequently Asked Questions

Q1: Do I need to follow kernel coding style for out-of-tree drivers that will never be upstreamed?
Technically no — out-of-tree drivers are not subject to review. However, following kernel style is still a good idea. It makes your code easier to compare with in-tree drivers when debugging, easier for colleagues familiar with the kernel to read, and easier to eventually upstream if requirements change.
Q2: Can I configure VS Code or Vim to follow kernel coding style automatically?
Yes. For VS Code, set the language settings for C to use tabs with tab size 8. There are also EditorConfig files you can add to your project. For Vim, add set tabstop=8 shiftwidth=8 noexpandtab to your .vimrc or a project-specific .vimrc. The kernel source tree itself ships with an EditorConfig file that many editors pick up automatically.
Q3: Why does the kernel use 8-character tabs? That seems very wide.
It is intentional. Wide indentation makes deeply nested code visually uncomfortable. If your function has 5 or 6 indentation levels, the code is visually cramped and that discomfort signals that you should refactor — break the inner logic into separate helper functions. It is a design pressure tool.
Q4: checkpatch.pl shows hundreds of warnings on my driver. Where do I start?
Start with ERRORs first — fix all of those before touching WARNINGs. Then tackle WARNINGs from the top of the file down. Often fixing one indentation issue fixes 50 warnings at once. The make indent trick (using GNU indent with kernel flags) can auto-fix many formatting issues in one shot, then run checkpatch again to see what needs manual attention.
Q5: What is a Signed-off-by line and why is it required?
A Signed-off-by line is a legally meaningful statement (under the Developer Certificate of Origin) that you wrote this code and have the right to submit it under the kernel’s open-source licence. It looks like: Signed-off-by: Your Name <you@email.com> at the end of your commit message. Without it, the kernel community will reject your patch.
Q6: Is there an automated way to get checkpatch running on every git commit?
Yes. You can add a git pre-commit hook. Create a file at .git/hooks/pre-commit containing a call to checkpatch.pl. If checkpatch returns a non-zero exit code, git will refuse the commit. This enforces clean style before the code ever enters your version history.
Q7: The kernel uses C89 style in some areas but C11 in others. What standard should I write to?
The Linux kernel build system has officially required at minimum C11 (with GNU extensions) since Linux 5.18. You can use C11 features like designated initialisers, compound literals, and _Static_assert. However, avoid C11 features that have no kernel equivalent — stick to what you see used in the subsystem you are writing for, and checkpatch will flag anything problematic.

Official References and Further Reading

Master Linux Kernel Development for Free

EmbeddedPathashala is your go-to free platform for learning Linux kernel programming, Linux device drivers, and embedded systems from scratch. No cost, no paywalls — just high-quality technical education.

Visit EmbeddedPathashala

Leave a Reply

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