blob: e369aa8d35abc81bc307777d6442bbf4ec5c0ad3 [file] [log] [blame]
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Will McVicker <willmcvicker@google.com>
Date: Thu, 19 Nov 2020 13:46:37 -0800
Subject: NOUPSTREAM: ANDROID: modules: introduce the MODULE_SCMVERSION config
Config MODULE_SCMVERSION introduces a new module attribute --
`scmversion` -- which can be used to identify a given module's SCM
version. This is very useful for developers that update their kernel
independently from their kernel modules or vice-versa since the SCM
version provided by UTS_RELEASE (`uname -r`) will now differ from the
module's vermagic attribute.
For example, we have a CI setup that tests new kernel changes on the
hikey960 and db845c devices without updating their kernel modules. When
these tests fail, we need to be able to identify the exact device
configuration the test was using. By including MODULE_SCMVERSION, we can
identify the exact kernel and modules' SCM versions for debugging the
failures.
Additionally, by exposing the SCM version via the sysfs node
/sys/module/MODULENAME/scmversion, one can also verify the SCM versions
of the modules loaded from the initramfs. Currently, modinfo can only
retrieve module attributes from the module's ko on disk and not from the
actual module that is loaded in RAM.
You can retrieve the SCM version in two ways,
1) By using modinfo:
> modinfo -F scmversion MODULENAME
2) By module sysfs node:
> cat /sys/module/MODULENAME/scmversion
[CPNOTE: 03/06/21] Lee: NACKed on the upstream MLs
Bug: 180027765
Link: https://lkml.org/lkml/2021/1/21/1388
Signed-off-by: Will McVicker <willmcvicker@google.com>
Change-Id: Ib7c72c72f95c4545adb7cd4e842729557039ce3a
---
Documentation/ABI/stable/sysfs-module | 18 ++++++++++++++++++
include/linux/module.h | 1 +
init/Kconfig | 14 ++++++++++++++
kernel/module.c | 2 ++
scripts/Makefile.modpost | 12 ++++++++++++
scripts/mod/modpost.c | 22 +++++++++++++++++++++-
6 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/stable/sysfs-module b/Documentation/ABI/stable/sysfs-module
--- a/Documentation/ABI/stable/sysfs-module
+++ b/Documentation/ABI/stable/sysfs-module
@@ -45,3 +45,21 @@ Date: Jun 2005
Description:
If the module source has MODULE_VERSION, this file will contain
the version of the source code.
+
+What: /sys/module/MODULENAME/scmversion
+Date: November 2020
+KernelVersion: Android Common Kernel -- android12-5.10+
+Contact: Will McVicker <willmcvicker@google.com>
+Description: This read-only file will appear if modpost was supplied with an
+ SCM version for the module. It can be enabled with the config
+ MODULE_SCMVERSION. The SCM version is retrieved by
+ scripts/setlocalversion, which means that the presence of this
+ file depends on CONFIG_LOCALVERSION_AUTO=y. When read, the SCM
+ version that the module was compiled with is returned. The SCM
+ version is returned in the following format::
+
+ ===
+ Git: g[a-f0-9]\+(-dirty)\?
+ Mercurial: hg[a-f0-9]\+(-dirty)\?
+ Subversion: svn[0-9]\+
+ ===
diff --git a/include/linux/module.h b/include/linux/module.h
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -380,6 +380,7 @@ struct module {
struct module_attribute *modinfo_attrs;
const char *version;
const char *srcversion;
+ const char *scmversion;
struct kobject *holders_dir;
/* Exported symbols */
diff --git a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -2149,6 +2149,20 @@ config MODULE_SRCVERSION_ALL
the version). With this option, such a "srcversion" field
will be created for all modules. If unsure, say N.
+config MODULE_SCMVERSION
+ bool "SCM version for modules"
+ depends on LOCALVERSION_AUTO
+ help
+ This enables the module attribute "scmversion" which can be used
+ by developers to identify the SCM version of a given module, e.g.
+ git sha1 or hg sha1. The SCM version can be queried by modinfo or
+ via the sysfs node: /sys/modules/MODULENAME/scmversion. This is
+ useful when the kernel or kernel modules are updated separately
+ since that causes the vermagic of the kernel and the module to
+ differ.
+
+ If unsure, say N.
+
config MODULE_SIG
bool "Module signature verification"
select MODULE_SIG_FORMAT
diff --git a/kernel/module.c b/kernel/module.c
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -743,6 +743,7 @@ static struct module_attribute modinfo_##field = { \
MODINFO_ATTR(version);
MODINFO_ATTR(srcversion);
+MODINFO_ATTR(scmversion);
static char last_unloaded_module[MODULE_NAME_LEN+1];
@@ -1206,6 +1207,7 @@ static struct module_attribute *modinfo_attrs[] = {
&module_uevent,
&modinfo_version,
&modinfo_srcversion,
+ &modinfo_scmversion,
&modinfo_initstate,
&modinfo_coresize,
&modinfo_initsize,
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -66,6 +66,7 @@ ifeq ($(KBUILD_EXTMOD),)
input-symdump := vmlinux.symvers
output-symdump := modules-only.symvers
+module_srcpath := $(srctree)
quiet_cmd_cat = GEN $@
cmd_cat = cat $(real-prereqs) > $@
@@ -95,9 +96,20 @@ MODPOST += -e
input-symdump := Module.symvers $(KBUILD_EXTRA_SYMBOLS)
output-symdump := $(KBUILD_EXTMOD)/Module.symvers
+module_srcpath := $(KBUILD_EXTMOD)
endif
+ifeq ($(CONFIG_MODULE_SCMVERSION),y)
+# Get the SCM version of the module. `sed` verifies setlocalversion returns
+# a proper revision based on the SCM type, e.g. git, mercurial, or svn.
+module_scmversion := $(shell $(srctree)/scripts/setlocalversion $(module_srcpath) | \
+ sed -n 's/.*-\(\(g\|hg\)[a-fA-F0-9]\+\(-dirty\)\?\|svn[0-9]\+\).*/\1/p')
+ifneq ($(module_scmversion),)
+MODPOST += -v $(module_scmversion)
+endif
+endif
+
existing-input-symdump := $(wildcard $(input-symdump))
# modpost options for modules (both in-kernel and external)
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -28,6 +28,8 @@ static int modversions = 0;
static int all_versions = 0;
/* If we are modposting external module set to 1 */
static int external_module = 0;
+#define MODULE_SCMVERSION_SIZE 64
+static char module_scmversion[MODULE_SCMVERSION_SIZE];
/* Only warn about unresolved symbols */
static int warn_unresolved = 0;
/* How a symbol is exported */
@@ -2233,6 +2235,20 @@ static void add_intree_flag(struct buffer *b, int is_intree)
buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
}
+/**
+ * add_scmversion() - Adds the MODULE_INFO macro for the scmversion.
+ * @b: Buffer to append to.
+ *
+ * This function fills in the module attribute `scmversion` for the kernel
+ * module. This is useful for determining a given module's SCM version on
+ * device via /sys/modules/<module>/scmversion and/or using the modinfo tool.
+ */
+static void add_scmversion(struct buffer *b)
+{
+ if (module_scmversion[0] != '\0')
+ buf_printf(b, "\nMODULE_INFO(scmversion, \"%s\");\n", module_scmversion);
+}
+
/* Cannot check for assembler */
static void add_retpoline(struct buffer *b)
{
@@ -2502,7 +2518,7 @@ int main(int argc, char **argv)
struct dump_list *dump_read_start = NULL;
struct dump_list **dump_read_iter = &dump_read_start;
- while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) {
+ while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:v:")) != -1) {
switch (opt) {
case 'e':
external_module = 1;
@@ -2540,6 +2556,9 @@ int main(int argc, char **argv)
case 'd':
missing_namespace_deps = optarg;
break;
+ case 'v':
+ strncpy(module_scmversion, optarg, sizeof(module_scmversion) - 1);
+ break;
default:
exit(1);
}
@@ -2579,6 +2598,7 @@ int main(int argc, char **argv)
add_depends(&buf, mod);
add_moddevtable(&buf, mod);
add_srcversion(&buf, mod);
+ add_scmversion(&buf);
sprintf(fname, "%s.mod.c", mod->name);
write_if_changed(&buf, fname);