Submitting your first patch to the Linux kernel

Finding things we can contribute to

Let’s address the initial question first: what should we actually work on?

Can’t think of anything? Documentation is always an option!

If you don’t know where to begin, or you don’t yet feel ready to send patches updating the kernel itself, there is another sure-fire way to contribute to the Linux kernel: improving its documentation. The Linux kernel has a large corpus of documentation, which is in fact checked into the source tree in the form of reStructuredText files. Contributing to the Linux kernel’s documentation is a great way to get used to the upstream code review process, while also providing a lot of value to the global Linux community.

Creating a patch

Learning the guidelines for Linux kernel contributions

That answers the question of how to choose something to work on. Next, we need to learn how to actually create patches and send them for review. The first step to doing that is learning how to be an effective members of the upstream Linux kernel community, by reading through (some, not all of) the Introduction to Kernel Development documentation list. Again, you definitely do not have to read through this whole list — I have not and almost certainly never will, and after a certain point it’s largely just a reference manual rather than an “introduction” anyways. What you certainly should read, however, are the pages that describe how to interact with the upstream community, and how to write high quality patches. At a minimum, I recommend that you read through the following resources:

  • A guide to the kernel development process. This is quite long, but is full of accurate and important information. This will give you an overview of the software development processes driving all Linux kernel development. For example, it describes what it means for code to be in the “mainline” kernel, and when you can submit new features to the mainline kernel (during a “merge window”). You must read this if you want to understand how patches make it into the Linux kernel at the end of the day, and in general, how to do development the “Linux way”..
  • Linux kernel coding style. This one is medium-long, but is of course an absolute necessity. This is a massive software project with a highly distributed collaboration model. Know what the coding style expectations are, or risk your patch being rejected (and looking silly for not having read this).
  • Submitting patches. This one is similarly medium-long, but is full of 100% accurate information that all contributors will expect you to have read. This page is also somewhat process oriented, and describes all the things you have to keep in mind when submitting a patch.

Creating a patch from a commit

We’ve now done our necessary background reading, and are ready to start coding! What you work on is of course up to you, so at this point I’ll assume that you have some code that you’re ready to commit, and send out for patch review.

commit 5ef3dd20555e8e878ac390a71e658db5fd02845c (HEAD)
Author: David Vernet <void@manifault.com>
Date: Tue Dec 21 07:39:31 2021 -0800

livepatch: Fix kobject refcount bug on klp_init_patch_early failure path

When enabling a klp patch with klp_enable_patch(), klp_init_patch_early()
is invoked to initialize the kobjects for the patch itself, as well as the
'struct klp_object' and 'struct klp_func' objects that comprise it.
However, there are some error paths in klp_enable_patch() where some
kobjects may have been initialized with kobject_init(), but an error code
is still returned due to e.g. a 'struct klp_object' having a NULL funcs
pointer.

...
<snip>
...

Signed-off-by: David Vernet <void@manifault.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Acked-by: Miroslav Benes <mbenes@suse.cz>
Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>

diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 335d988bd811..7d228cdb44c5 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -862,14 +862,11 @@ static void klp_init_object_early(struct klp_patch *patch,
list_add_tail(&obj->node, &patch->obj_list);
}

-static int klp_init_patch_early(struct klp_patch *patch)
+static void klp_init_patch_early(struct klp_patch *patch)

<truncated>
...
$ git format-patch HEAD~1 -o /tmp
/tmp/0001-livepatch-Fix-kobject-refcount-bug-on-klp_init_patch.patch
$ cat /tmp/0001-livepatch-Fix-kobject-refcount-bug-on-klp_init_patch.patch
From 5ef3dd20555e8e878ac390a71e658db5fd02845c Mon Sep 17 00:00:00 2001
From: David Vernet <void@manifault.com>
Date: Tue, 21 Dec 2021 07:39:31 -0800
Subject: [PATCH] livepatch: Fix kobject refcount bug on klp_init_patch_early
failure path

When enabling a klp patch with klp_enable_patch(), klp_init_patch_early()
is invoked to initialize the kobjects for the patch itself, as well as the
'struct klp_object' and 'struct klp_func' objects that comprise it.
However, there are some error paths in klp_enable_patch() where some
kobjects may have been initialized with kobject_init(), but an error code
is still returned due to e.g. a 'struct klp_object' having a NULL funcs
pointer.

In these paths, the initial reference of the kobject of the 'struct
klp_patch' may never be released, along with one or more of its objects and
their functions, as kobject_put() is not invoked on the cleanup path if
klp_init_patch_early() returns an error code.

For example, if an object entry such as the following were added to the
sample livepatch module's klp patch, it would cause the vmlinux klp_object,
and its klp_func which updates 'cmdline_proc_show', to never be released:

static struct klp_object objs[] = {
{
/* name being NULL means vmlinux */
.funcs = funcs,
},
{
/* NULL funcs -- would cause reference leak */
.name = "kvm",
}, { }
};

Without this change, if CONFIG_DEBUG_KOBJECT is enabled, and the sample klp
patch is loaded, the kobjects (the patch, the vmlinux 'struct klp_object',
and its func) are observed as initialized, but never released, in the dmesg
log output. With the change, these kobject references no longer fail to be
released as the error case is properly handled before they are initialized.

Signed-off-by: David Vernet <void@manifault.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Acked-by: Miroslav Benes <mbenes@suse.cz>
Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/livepatch/core.c | 31 +++++++++++++------------------
1 file changed, 13 insertions(+), 18 deletions(-)

diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 335d988bd811..7d228cdb44c5 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -862,14 +862,11 @@ static void klp_init_object_early(struct klp_patch *patch,
list_add_tail(&obj->node, &patch->obj_list);
}

-static int klp_init_patch_early(struct klp_patch *patch)
+static void klp_init_patch_early(struct klp_patch *patch)
{
struct klp_object *obj;
struct klp_func *func;

- if (!patch->objs)
- return -EINVAL;
-
INIT_LIST_HEAD(&patch->list);
INIT_LIST_HEAD(&patch->obj_list);
kobject_init(&patch->kobj, &klp_ktype_patch);
@@ -879,20 +876,12 @@ static int klp_init_patch_early(struct klp_patch *patch)
init_completion(&patch->finish);

klp_for_each_object_static(patch, obj) {
- if (!obj->funcs)
- return -EINVAL;
-
klp_init_object_early(patch, obj);

klp_for_each_func_static(obj, func) {
klp_init_func_early(obj, func);
}
}
-
- if (!try_module_get(patch->mod))
- return -ENODEV;
-
- return 0;
}

static int klp_init_patch(struct klp_patch *patch)
@@ -1024,10 +1013,17 @@ static int __klp_enable_patch(struct klp_patch *patch)
int klp_enable_patch(struct klp_patch *patch)
{
int ret;
+ struct klp_object *obj;

- if (!patch || !patch->mod)
+ if (!patch || !patch->mod || !patch->objs)
return -EINVAL;

+ klp_for_each_object_static(patch, obj) {
+ if (!obj->funcs)
+ return -EINVAL;
+ }
+
+
if (!is_livepatch_module(patch->mod)) {
pr_err("module %s is not marked as a livepatch module\n",
patch->mod->name);
@@ -1051,11 +1047,10 @@ int klp_enable_patch(struct klp_patch *patch)
return -EINVAL;
}

- ret = klp_init_patch_early(patch);
- if (ret) {
- mutex_unlock(&klp_mutex);
- return ret;
- }
+ if (!try_module_get(patch->mod))
+ return -ENODEV;
+
+ klp_init_patch_early(patch);

ret = klp_init_patch(patch);
if (ret)
--
2.25.1

Sanity checking the patch

Before you send the patch to upstream you should always 100% without fail run the scripts/check_patch.pl script on your patch to make sure it looks OK:

$ ./scripts/checkpatch.pl /tmp/0001-livepatch-Fix-kobject-refcount-bug-on-klp_init_patch.patch

total: 0 errors, 0 warnings, 68 lines checked

/tmp/0001-livepatch-Fix-kobject-refcount-bug-on-klp_init_patch.patch has no obvious style problems and is ready for submission.

Sending the patch, and iterating with reviewers

We’ve created our commit with a good commit summary, transformed it into a patch with git format-patch, and checked it with scripts/check_patch.pl. We’re now all set to send it out for a review. To do that, we’ll use git send-email.

Sending the patch

There are two a few things you need to do to email the patch:

$ ./scripts/get_maintainer.pl /tmp/0001-livepatch-Fix-kobject-refcount-bug-on-klp_init_patch.patch

Josh Poimboeuf <jpoimboe@redhat.com> (maintainer:LIVE PATCHING)
Jiri Kosina <jikos@kernel.org> (maintainer:LIVE PATCHING)
Miroslav Benes <mbenes@suse.cz> (maintainer:LIVE PATCHING)
Petr Mladek <pmladek@suse.com> (maintainer:LIVE PATCHING)
Joe Lawrence <joe.lawrence@redhat.com> (reviewer:LIVE PATCHING)
live-patching@vger.kernel.org (open list:LIVE PATCHING)
linux-kernel@vger.kernel.org (open list)
$ sudo apt install git-email -y

$ git config --global sendemail.transferEncoding 7bit
$ git send-email --to jpoimboe@redhat.com --to jikos@kernel.org --to mbenes@suse.cz --to pmladek@suse.com --to joe.lawrence@redhat.com --to live-patching@vger.kernel.org --to linux-kernel@vger.kernel.org /tmp/0001-livepatch-Fix-kobject-refcount-bug-on-klp_init_patch.patch

From: David Vernet <void@manifault.com>
To: jpoimboe@redhat.com,
jikos@kernel.org,
mbenes@suse.cz,
pmladek@suse.com,
joe.lawrence@redhat.com,
live-patching@vger.kernel.org,
linux-kernel@vger.kernel.org
Cc: David Vernet <void@manifault.com>
Subject: [PATCH] livepatch: Fix kobject refcount bug on klp_init_patch_early failure path
Date: Sun, 6 Mar 2022 12:51:27 -0500
Message-Id: <20220306175127.5570-1-void@manifault.com>
X-Mailer: git-send-email 2.25.1
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): q

Interacting with reviewers

Congratulations, you’ve sent out your first patch! We’re not quite done, though. Almost without fail, a reviewer will have a suggestion for how your patch can be improved. This is just a reality about Linux kernel development, and at the end of the day is a good thing as it keeps the bar high, and maximizes the quality of your code.

$ git format-patch HEAD~1 -v 2 -o /tmp
/tmp/v2-0001-livepatch-Fix-kobject-refcount-bug-on-klp_init_pa.patch
$ cat /tmp/v2-0001-livepatch-Fix-kobject-refcount-bug-on-klp_init_pa.patch | grep PATCH
Subject: [PATCH v2] livepatch: Fix kobject refcount bug on klp_init_patch_early
failure path

Quick aside — using kmail

If you’re like me and you find it tiresome to invoke scripts/get_maintainer.pl and manually include the names when invoking git send-email, you can use a tool that I wrote called kmail to do it for you. I won’t describe the tool in much detail here to avoid scope creep in the post. The main point is that it automatically calls scripts/get_maintainer.pl for you, and then invokes git send-email with all of the necessary email addresses.

Merging the patch

Once the patch has been fully reviewed (and received the necessary Acked-by: <> and Reviewed-by: <> tags by the reviewers), your job is finished! One of the maintainers that has write ownership for the subsystem’s repository will manually apply your patch. Then, at some point, it will make its way into Linus’ tree and the mainline kernel!

What to do if nobody responds to your email

Unfortunately, sometimes your patch may go unanswered. If this happens, first make sure that your patch actually made it to the lists you sent it to. For example, the email may silently fail if you don’t use plain-text encoding in the email.

Don’t be nervous, just do your best, and assume good intent

One more thing I wanted to mention before wrapping up: if you’re feeling nervous or intimidated about sending patches to the Linux kernel, that is totally normal, and should not discourage you from contributing and becoming a member of the community. If you take a closer look at the first patch that I linked above, you’ll notice that it was “v3”, or the third version of the patch. While two upstream reviewers accepted the v3 version with some encouraging words, it took a bit of back and forth to get the patch to a reasonable state.

Wrapping up

That’s all there is to it. Once you’ve written, submitted, and merged your first patch, you’re officially a Linux kernel contributor! Happy hacking, and thanks for reading!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store