From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org
Cc: Alexander Potapenko <glider@google.com>,
Andrey Konovalov <andreyknvl@gmail.com>,
Chuck Wolber <chuck@wolber.net>,
Dmitry Vyukov <dvyukov@google.com>,
kasan-dev@googlegroups.com, Marco Elver <elver@google.com>,
Masami Hiramatsu <mhiramat@kernel.org>,
Peter Oberparleiter <oberpar@linux.ibm.com>,
Peter Zijlstra <peterz@infradead.org>,
Thomas Gleixner <tglx@kernel.org>
Subject: [RFC PATCH 03/20] coverage: add a common debugfs interface
Date: Wed, 28 Oct 2026 07:59:27 -0400 [thread overview]
Message-ID: <20261028120034.871983-4-sashal@kernel.org> (raw)
In-Reply-To: <20261028120034.871983-1-sashal@kernel.org>
Each coverage implementation creates its own top-level debugfs entry
with its own conventions: /sys/kernel/debug/gcov/ and
/sys/kernel/debug/kcov. Give them a common root,
/sys/kernel/debug/coverage/, which contains:
backend name of the selected code coverage measurement implementation
reset write to reset all coverage data of that implementation
gcov symlink to ../gcov when gcov is enabled
kcov symlink to ../kcov when KCOV is enabled
backend and reset are only present when a code coverage measurement
implementation is selected, so a kernel with only KCOV just has the kcov
symlink. The data formats are defined by the respective toolchains and
stay implementation specific. The existing paths are kept as they are,
since lcov, distribution tooling and syzkaller rely on them; the gcov
reset file now shares its implementation with the common one.
The common reset never touches KCOV, whose coverage buffers are owned
by the tasks that set them up.
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
MAINTAINERS | 8 +++++
kernel/coverage/Makefile | 1 +
kernel/coverage/core.c | 71 ++++++++++++++++++++++++++++++++++++++
kernel/coverage/coverage.h | 22 ++++++++++++
kernel/coverage/gcov/fs.c | 21 ++++++++---
kernel/coverage/kcov.c | 3 ++
6 files changed, 122 insertions(+), 4 deletions(-)
create mode 100644 kernel/coverage/core.c
create mode 100644 kernel/coverage/coverage.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 3cedde9ecaac3..573ac65304f7c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6589,6 +6589,14 @@ S: Maintained
F: Documentation/devicetree/bindings/media/coda.yaml
F: drivers/media/platform/chips-media/coda
+CODE COVERAGE
+M: Sasha Levin <sashal@kernel.org>
+S: Maintained
+F: kernel/coverage/Kconfig
+F: kernel/coverage/Makefile
+F: kernel/coverage/core.c
+F: kernel/coverage/coverage.h
+
CODE OF CONDUCT
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
S: Supported
diff --git a/kernel/coverage/Makefile b/kernel/coverage/Makefile
index a4cd8cc18d9bc..881fada442bd1 100644
--- a/kernel/coverage/Makefile
+++ b/kernel/coverage/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(or $(CONFIG_COVERAGE_KERNEL),$(CONFIG_KCOV)) += core.o
obj-$(CONFIG_GCOV_KERNEL) += gcov/
obj-$(CONFIG_KCOV) += kcov.o
diff --git a/kernel/coverage/core.c b/kernel/coverage/core.c
new file mode 100644
index 0000000000000..f90dd78fce557
--- /dev/null
+++ b/kernel/coverage/core.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common debugfs interface of the kernel's code coverage implementations.
+ *
+ * /sys/kernel/debug/coverage/ is the root for all of them. The selected
+ * code coverage measurement implementation registers itself as the
+ * backend, which provides the "backend" and "reset" files.
+ */
+
+#include <linux/bug.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+
+#include "coverage.h"
+
+static struct dentry *coverage_root;
+static const struct coverage_backend *coverage_backend;
+
+struct dentry *coverage_debugfs_root(void)
+{
+ return coverage_root;
+}
+
+static int backend_show(struct seq_file *m, void *unused)
+{
+ seq_puts(m, coverage_backend->name);
+ if (coverage_backend->features)
+ seq_printf(m, " %s", coverage_backend->features);
+ seq_putc(m, '\n');
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(backend);
+
+static ssize_t reset_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *pos)
+{
+ coverage_backend->reset();
+ return len;
+}
+
+/* Allow reads so that a recursive copy of the directory doesn't fail. */
+static ssize_t reset_read(struct file *file, char __user *buf, size_t len,
+ loff_t *pos)
+{
+ return 0;
+}
+
+static const struct file_operations reset_fops = {
+ .write = reset_write,
+ .read = reset_read,
+ .llseek = noop_llseek,
+};
+
+void __init coverage_register_backend(const struct coverage_backend *backend)
+{
+ if (WARN_ON(coverage_backend))
+ return;
+
+ coverage_backend = backend;
+ debugfs_create_file("backend", 0444, coverage_root, NULL, &backend_fops);
+ debugfs_create_file("reset", 0600, coverage_root, NULL, &reset_fops);
+}
+
+static int __init coverage_init(void)
+{
+ coverage_root = debugfs_create_dir("coverage", NULL);
+ return 0;
+}
+fs_initcall(coverage_init);
diff --git a/kernel/coverage/coverage.h b/kernel/coverage/coverage.h
new file mode 100644
index 0000000000000..1b7e3ce25b686
--- /dev/null
+++ b/kernel/coverage/coverage.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _KERNEL_COVERAGE_H
+#define _KERNEL_COVERAGE_H
+
+struct dentry;
+
+/**
+ * struct coverage_backend - code coverage measurement implementation
+ * @name: name reported by /sys/kernel/debug/coverage/backend
+ * @features: optional space separated list of enabled features
+ * @reset: reset all coverage data collected so far
+ */
+struct coverage_backend {
+ const char *name;
+ const char *features;
+ void (*reset)(void);
+};
+
+struct dentry *coverage_debugfs_root(void);
+void coverage_register_backend(const struct coverage_backend *backend);
+
+#endif /* _KERNEL_COVERAGE_H */
diff --git a/kernel/coverage/gcov/fs.c b/kernel/coverage/gcov/fs.c
index 1d19b1be207a7..23d366dcfc2f7 100644
--- a/kernel/coverage/gcov/fs.c
+++ b/kernel/coverage/gcov/fs.c
@@ -28,6 +28,7 @@
#include <linux/seq_file.h>
#include <linux/mm.h>
#include "gcov.h"
+#include "../coverage.h"
/**
* struct gcov_node - represents a debugfs entry
@@ -628,11 +629,10 @@ static struct gcov_node *get_child_by_name(struct gcov_node *parent,
}
/*
- * write() implementation for reset file. Reset all profiling data to zero
- * and remove nodes for which all associated object files are unloaded.
+ * Reset all profiling data to zero and remove nodes for which all associated
+ * object files are unloaded.
*/
-static ssize_t reset_write(struct file *file, const char __user *addr,
- size_t len, loff_t *pos)
+static void gcov_reset_all(void)
{
struct gcov_node *node;
@@ -648,7 +648,13 @@ static ssize_t reset_write(struct file *file, const char __user *addr,
}
}
mutex_unlock(&node_lock);
+}
+/* write() implementation for reset file. */
+static ssize_t reset_write(struct file *file, const char __user *addr,
+ size_t len, loff_t *pos)
+{
+ gcov_reset_all();
return len;
}
@@ -859,6 +865,11 @@ void gcov_event(enum gcov_action action, struct gcov_info *info)
mutex_unlock(&node_lock);
}
+static const struct coverage_backend gcov_backend = {
+ .name = "gcov",
+ .reset = gcov_reset_all,
+};
+
/* Create debugfs entries. */
static __init int gcov_fs_init(void)
{
@@ -874,6 +885,8 @@ static __init int gcov_fs_init(void)
*/
debugfs_create_file("reset", 0600, root_node.dentry, NULL,
&gcov_reset_fops);
+ debugfs_create_symlink("gcov", coverage_debugfs_root(), "../gcov");
+ coverage_register_backend(&gcov_backend);
/* Replay previous events to get our fs hierarchy up-to-date. */
gcov_enable_events();
return 0;
diff --git a/kernel/coverage/kcov.c b/kernel/coverage/kcov.c
index 35420f0ac524d..b6707f478f3d8 100644
--- a/kernel/coverage/kcov.c
+++ b/kernel/coverage/kcov.c
@@ -27,6 +27,8 @@
#include <linux/log2.h>
#include <asm/setup.h>
+#include "coverage.h"
+
#define kcov_debug(fmt, ...) pr_debug("%s: " fmt, __func__, ##__VA_ARGS__)
/* Number of 64-bit words written per one comparison: */
@@ -1149,6 +1151,7 @@ static int __init kcov_init(void)
* use of debugfs_create_file_unsafe() is actually safe here.
*/
debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops);
+ debugfs_create_symlink("kcov", coverage_debugfs_root(), "../kcov");
#ifdef CONFIG_KCOV_SELFTEST
selftest();
--
2.53.0
next prev parent reply other threads:[~2026-10-28 12:00 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 11:59 [RFC PATCH 00/20] Unify code coverage and add Clang source-based coverage with MC/DC Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 01/20] coverage: move gcov and kcov under kernel/coverage/ Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 02/20] kbuild: unify static coverage instrumentation as COVERAGE_PROFILE Sasha Levin
2026-10-28 11:59 ` Sasha Levin [this message]
2026-10-28 11:59 ` [RFC PATCH 04/20] compiler_types.h: Don't instrument __always_inline functions for coverage Sasha Levin
2026-10-28 13:51 ` Peter Zijlstra
2026-10-28 14:01 ` Peter Zijlstra
2026-10-28 16:45 ` Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 05/20] context_tracking: Always inline the empty stubs called from noinstr code Sasha Levin
2026-10-28 13:52 ` Peter Zijlstra
2026-10-28 11:59 ` [RFC PATCH 06/20] lockdep: " Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 07/20] perf: Always inline the empty perf_lopwr_cb() stub Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 08/20] rseq: Always inline the empty rseq_note_user_irq_entry() stub Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 09/20] x86: Always inline empty stubs called from noinstr code Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 10/20] x86/sev: Use non-instrumented bitops in the GHCB accessors Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 11/20] objtool: Detect code coverage instrumentation in noinstr code Sasha Levin
2026-10-28 14:11 ` Peter Zijlstra
2026-10-28 16:45 ` Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 12/20] x86/sev: Stop excluding noinstr.o from code coverage Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 13/20] x86/entry: Stop excluding the entry code from KCOV Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 14/20] coverage: add Clang's source-based code coverage Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 15/20] x86: Enable " Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 16/20] coverage: add MC/DC measurement Sasha Levin
2026-10-28 19:14 ` Nathan Chancellor
2026-10-28 20:39 ` Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 17/20] gcov: fix gcov_info_add() merge semantics for IOR counters Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 18/20] kconfig: add CC_HAS_CONDITION_COVERAGE for MC/DC support detection Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 19/20] gcov: add MC/DC condition coverage support Sasha Levin
2026-10-28 11:59 ` [RFC PATCH 20/20] Documentation: dev-tools: document the common code coverage interface Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261028120034.871983-4-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=andreyknvl@gmail.com \
--cc=chuck@wolber.net \
--cc=dvyukov@google.com \
--cc=elver@google.com \
--cc=glider@google.com \
--cc=kasan-dev@googlegroups.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mhiramat@kernel.org \
--cc=oberpar@linux.ibm.com \
--cc=peterz@infradead.org \
--cc=tglx@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®