ANDROID: modules: re-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

Bug: 180027765
Link: https://lore.kernel.org/all/20210121213641.3477522-1-willmcvicker@google.com/
Signed-off-by: Will McVicker <willmcvicker@google.com>
Change-Id: Ib7c72c72f95c4545adb7cd4e842729557039ce3a
This commit is contained in:
Will McVicker 2020-11-19 13:46:37 -08:00 committed by Todd Kjos
parent e6284969d9
commit d834db9f2c
6 changed files with 71 additions and 1 deletions

View File

@ -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: 5.12
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]\+
===

View File

@ -379,6 +379,7 @@ struct module {
struct module_attribute *modinfo_attrs;
const char *version;
const char *srcversion;
const char *scmversion;
struct kobject *holders_dir;
/* Exported symbols */

View File

@ -88,6 +88,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

View File

@ -527,6 +527,7 @@ static struct module_attribute modinfo_##field = { \
MODINFO_ATTR(version);
MODINFO_ATTR(srcversion);
MODINFO_ATTR(scmversion);
static struct {
char name[MODULE_NAME_LEN + 1];
@ -974,6 +975,7 @@ struct module_attribute *modinfo_attrs[] = {
&module_uevent,
&modinfo_version,
&modinfo_srcversion,
&modinfo_scmversion,
&modinfo_initstate,
&modinfo_coresize,
#ifdef CONFIG_ARCH_WANTS_MODULES_DATA_IN_VMALLOC

View File

@ -53,6 +53,33 @@ ifneq ($(findstring i,$(filter-out --%,$(MAKEFLAGS))),)
modpost-args += -n
endif
ifeq ($(CONFIG_MODULE_SCMVERSION),y)
ifeq ($(KBUILD_EXTMOD),)
module_srcpath := $(srctree)
else
# Get the external module's source path. KBUILD_EXTMOD could either be an
# absolute path or relative path from $(srctree). This makes sure that we
# aren't using a relative path from a separate working directory (O= or
# KBUILD_OUTPUT) since that may not be the actual module's SCM project path. So
# check the path relative to $(srctree) first.
ifneq ($(realpath $(srctree)/$(KBUILD_EXTMOD) 2>/dev/null),)
module_srcpath := $(srctree)/$(KBUILD_EXTMOD)
else
module_srcpath := $(KBUILD_EXTMOD)
endif
endif
# 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.
# Note: relative M= paths are not supported when building the kernel out of the
# srctree since setlocalversion won't be able to find the module srctree.
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-args += -v $(module_scmversion)
endif
endif
ifeq ($(KBUILD_EXTMOD),)
# Generate the list of in-tree objects in vmlinux

View File

@ -29,6 +29,8 @@ static bool modversions;
static bool all_versions;
/* If we are modposting external module set to 1 */
static bool external_module;
#define MODULE_SCMVERSION_SIZE 64
static char module_scmversion[MODULE_SCMVERSION_SIZE];
/* Only warn about unresolved symbols */
static bool warn_unresolved;
@ -1999,6 +2001,9 @@ static void add_header(struct buffer *b, struct module *mod)
if (!external_module)
buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
if (module_scmversion[0] != '\0')
buf_printf(b, "\nMODULE_INFO(scmversion, \"%s\");\n", module_scmversion);
buf_printf(b,
"\n"
"#ifdef CONFIG_RETPOLINE\n"
@ -2327,7 +2332,7 @@ int main(int argc, char **argv)
LIST_HEAD(dump_lists);
struct dump_list *dl, *dl2;
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 = true;
@ -2364,6 +2369,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);
}