Beginner–Intermediate
Linux 6.x
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.plto automatically validate your code - How to use
indentto 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
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.
Your module or driver code
Auto style validation
Create patch file
Subsystem maintainer review
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.
static int my_probe(struct platform_device *pdev)
{
int ret;
if (condition) {
ret = do_something();
}
return ret;
}
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.
ret = platform_driver_register(&my_platform_driver, THIS_MODULE, dev_name(&pdev->dev), &my_ops);
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.
if (error)
{
return -EINVAL;
}
if (error) {
return -EINVAL;
}
/* Function definition — opening brace on its OWN line */
static int my_init(void)
{
return 0;
}
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 Type | Convention | Example |
|---|---|---|
| Local variables | Short, lowercase | ret, len, i |
| Function names | Lowercase with underscores | ep_sensor_probe() |
| Global/exported symbols | Descriptive lowercase | ep_sensor_read_data() |
| Macros and constants | ALL_CAPS with underscores | MAX_BUFFER_SIZE |
| Struct typedefs (avoid) | Kernel avoids typedef for structs | Use struct my_device not MyDevice |
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:
| Severity | Keyword | Meaning |
|---|---|---|
| High | ERROR | A definite violation. Your patch will not be accepted with these present. Fix all errors before submitting. |
| Medium | WARNING | A 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. |
| Low | CHECK | A 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)
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
a == b, not a==b. Space before and after binary operators.func() not func (). No space between function name and opening paren./* */ 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:
// 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;
}
/*
* 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.
| Function | When to Use | Example 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:
| Section | URL Path | Covers |
|---|---|---|
| Core API | core-api/ | Memory allocation, printk, linked lists, data structures |
| Driver API | driver-api/ | Device model, I2C, SPI, GPIO, interrupt handling |
| Process | process/ | Patch submission, coding style, development workflow |
| Admin Guide | admin-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
Iterate quickly outside kernel tree for development speed
Subject line + blank line + explanation + Signed-off-by
Use
scripts/get_maintainer.pl to identify who reviews your subsystem
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
typedeffor structures. Writestruct my_deviceeverywhere. - Use
/* */comments. Use kernel-doc/** */for exported functions. - Run
scripts/checkpatch.pl --no-tree -f your_driver.cbefore every commit. Fix all ERRORs; aim to fix all WARNINGs too. - Integrate
checkpatchandindenttargets into your Makefile for a smooth workflow. - Use
dev_err()/dev_info()when you have a device context; usepr_err()/pr_info()for module-level messages.
Frequently Asked Questions
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.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.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..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._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
- Linux Kernel Coding Style (Official Documentation)
- Submitting Patches to the Linux Kernel (kernel.org)
- Writing Kernel-doc Comments (kernel.org)
- Linux Kernel Development Process (kernel.org)
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