| 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); |