Add a selftest that exercises kernel module dependency generation across recipes. Two external module recipes are added to meta-selftest: kernel-module-testfoo exports a symbol and kernel-module-testbar consumes it (DEPENDS on testfoo). The test builds both and asserts that the consumer's real, KERNEL_VERSION-suffixed package RDEPENDS the exporter's suffixed package - and not the empty unsuffixed kernel-module-testfoo package - and that the suffixed package RPROVIDES the unsuffixed virtual.
This is the failure mode originally reported in [YOCTO #12290], where the generated dependency resolved to the empty package after the KERNEL_VERSION suffix was introduced. It works on current master; this test guards against regressing it again. The kernel version is derived from the produced package list rather than KERNEL_VERSION, which is unset at parse time when the modules are restored from sstate. Signed-off-by: Siva Balasubramanian <[email protected]> --- .../kernel-module-cross/files/Makefile.bar | 14 ++++ .../kernel-module-cross/files/Makefile.foo | 14 ++++ .../kernel-module-cross/files/testbar.c | 19 +++++ .../kernel-module-cross/files/testfoo.c | 23 ++++++ .../kernel-module-testbar_0.1.bb | 20 ++++++ .../kernel-module-testfoo_0.1.bb | 16 +++++ .../oeqa/selftest/cases/kernelmodulesplit.py | 72 +++++++++++++++++++ 7 files changed, 178 insertions(+) create mode 100644 meta-selftest/recipes-test/kernel-module-cross/files/Makefile.bar create mode 100644 meta-selftest/recipes-test/kernel-module-cross/files/Makefile.foo create mode 100644 meta-selftest/recipes-test/kernel-module-cross/files/testbar.c create mode 100644 meta-selftest/recipes-test/kernel-module-cross/files/testfoo.c create mode 100644 meta-selftest/recipes-test/kernel-module-cross/kernel-module-testbar_0.1.bb create mode 100644 meta-selftest/recipes-test/kernel-module-cross/kernel-module-testfoo_0.1.bb create mode 100644 meta/lib/oeqa/selftest/cases/kernelmodulesplit.py diff --git a/meta-selftest/recipes-test/kernel-module-cross/files/Makefile.bar b/meta-selftest/recipes-test/kernel-module-cross/files/Makefile.bar new file mode 100644 index 0000000000..1d4409bf3a --- /dev/null +++ b/meta-selftest/recipes-test/kernel-module-cross/files/Makefile.bar @@ -0,0 +1,14 @@ +obj-m := testbar.o + +SRC := $(shell pwd) + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(SRC) + +modules_install: + $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install + +clean: + rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c *.mod + rm -f Module.markers Module.symvers modules.order + rm -rf .tmp_versions Modules.symvers diff --git a/meta-selftest/recipes-test/kernel-module-cross/files/Makefile.foo b/meta-selftest/recipes-test/kernel-module-cross/files/Makefile.foo new file mode 100644 index 0000000000..1720b239c0 --- /dev/null +++ b/meta-selftest/recipes-test/kernel-module-cross/files/Makefile.foo @@ -0,0 +1,14 @@ +obj-m := testfoo.o + +SRC := $(shell pwd) + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(SRC) + +modules_install: + $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install + +clean: + rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c *.mod + rm -f Module.markers Module.symvers modules.order + rm -rf .tmp_versions Modules.symvers diff --git a/meta-selftest/recipes-test/kernel-module-cross/files/testbar.c b/meta-selftest/recipes-test/kernel-module-cross/files/testbar.c new file mode 100644 index 0000000000..98470c407f --- /dev/null +++ b/meta-selftest/recipes-test/kernel-module-cross/files/testbar.c @@ -0,0 +1,19 @@ +#include <linux/module.h> +#include <linux/init.h> + +extern int testfoo_value(void); + +static int __init testbar_init(void) +{ + pr_info("testbar loaded, foo says %d\n", testfoo_value()); + return 0; +} + +static void __exit testbar_exit(void) +{ + pr_info("testbar unloaded\n"); +} + +module_init(testbar_init); +module_exit(testbar_exit); +MODULE_LICENSE("GPL"); diff --git a/meta-selftest/recipes-test/kernel-module-cross/files/testfoo.c b/meta-selftest/recipes-test/kernel-module-cross/files/testfoo.c new file mode 100644 index 0000000000..e438db49cb --- /dev/null +++ b/meta-selftest/recipes-test/kernel-module-cross/files/testfoo.c @@ -0,0 +1,23 @@ +#include <linux/module.h> +#include <linux/init.h> + +int testfoo_value(void) +{ + return 42; +} +EXPORT_SYMBOL(testfoo_value); + +static int __init testfoo_init(void) +{ + pr_info("testfoo loaded\n"); + return 0; +} + +static void __exit testfoo_exit(void) +{ + pr_info("testfoo unloaded\n"); +} + +module_init(testfoo_init); +module_exit(testfoo_exit); +MODULE_LICENSE("GPL"); diff --git a/meta-selftest/recipes-test/kernel-module-cross/kernel-module-testbar_0.1.bb b/meta-selftest/recipes-test/kernel-module-cross/kernel-module-testbar_0.1.bb new file mode 100644 index 0000000000..bf465169f5 --- /dev/null +++ b/meta-selftest/recipes-test/kernel-module-cross/kernel-module-testbar_0.1.bb @@ -0,0 +1,20 @@ +SUMMARY = "Cross-recipe kernel module dependency test: consumer (Bug 12290)" +LICENSE = "GPL-2.0-only" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6" + +inherit module + +# This pulls in foo's Module.symvers via KBUILD_EXTRA_SYMBOLS (module.bbclass +# __anonymous) so modpost records testfoo as a dependency of testbar. +DEPENDS = "kernel-module-testfoo" + +SRC_URI = "\ + file://testbar.c \ + file://Makefile.bar \ +" + +S = "${UNPACKDIR}" + +do_configure:prepend() { + cp ${UNPACKDIR}/Makefile.bar ${UNPACKDIR}/Makefile +} diff --git a/meta-selftest/recipes-test/kernel-module-cross/kernel-module-testfoo_0.1.bb b/meta-selftest/recipes-test/kernel-module-cross/kernel-module-testfoo_0.1.bb new file mode 100644 index 0000000000..8ea3ad3618 --- /dev/null +++ b/meta-selftest/recipes-test/kernel-module-cross/kernel-module-testfoo_0.1.bb @@ -0,0 +1,16 @@ +SUMMARY = "Cross-recipe kernel module dependency test: exporter (Bug 12290)" +LICENSE = "GPL-2.0-only" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6" + +inherit module + +SRC_URI = "\ + file://testfoo.c \ + file://Makefile.foo \ +" + +S = "${UNPACKDIR}" + +do_configure:prepend() { + cp ${UNPACKDIR}/Makefile.foo ${UNPACKDIR}/Makefile +} diff --git a/meta/lib/oeqa/selftest/cases/kernelmodulesplit.py b/meta/lib/oeqa/selftest/cases/kernelmodulesplit.py new file mode 100644 index 0000000000..1627748a98 --- /dev/null +++ b/meta/lib/oeqa/selftest/cases/kernelmodulesplit.py @@ -0,0 +1,72 @@ +# +# Copyright OpenEmbedded Contributors +# +# SPDX-License-Identifier: MIT +# + +import re + +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import bitbake, runCmd + + +class KernelModuleSplit(OESelftestTestCase): + """ + Tests for cross-recipe kernel module dependency generation. + """ + + def real_module_package(self, recipe): + """ + Return the name of the real (.ko-containing) package for a kernel + module recipe, i.e. the one suffixed with ${KERNEL_VERSION}. The version + is read from the produced package list rather than from KERNEL_VERSION, + which can be unset at parse time when the module is restored from sstate. + """ + packages = runCmd("oe-pkgdata-util list-pkgs -p %s" % recipe).output.split() + version_re = re.compile(r"^%s-(\d[^/]*)$" % re.escape(recipe)) + matches = [p for p in packages if version_re.match(p)] + self.assertEqual(len(matches), 1, + "Expected exactly one %s-<version> package, found: %s" % (recipe, matches)) + return matches[0] + + def test_cross_recipe_module_dependency(self): + """ + Summary: Regression test for Yocto bug 12290. When one external + kernel module recipe consumes an exported symbol from + another, the consumer's auto-generated RDEPENDS must point + at the exporter's real (-${KERNEL_VERSION}) package, not at + the empty unsuffixed kernel-module-* package. + Expected: kernel-module-testbar-${KERNEL_VERSION} RDEPENDS + kernel-module-testfoo-${KERNEL_VERSION}, does not depend on + the bare kernel-module-testfoo package, and RPROVIDES the + unsuffixed kernel-module-testbar virtual. + Product: OE-Core + """ + consumer_recipe = "kernel-module-testbar" + exporter_recipe = "kernel-module-testfoo" + + bitbake("%s %s" % (consumer_recipe, exporter_recipe)) + + consumer_pkg = self.real_module_package(consumer_recipe) + exporter_pkg = self.real_module_package(exporter_recipe) + + rdepends = runCmd("oe-pkgdata-util read-value RDEPENDS %s" % consumer_pkg).output.split() + + # The consumer must depend on the real (.ko-containing) exporter + # package, i.e. the one suffixed with KERNEL_VERSION ... + self.assertIn(exporter_pkg, rdepends, + "%s does not RDEPEND the real exporter package %s (got: %s)" + % (consumer_pkg, exporter_pkg, rdepends)) + + # ... and never on the bare, empty unsuffixed exporter package, which + # was the failure mode of bug 12290. + self.assertNotIn(exporter_recipe, rdepends, + "%s RDEPENDS the empty unsuffixed package %s (bug 12290 regression)" + % (consumer_pkg, exporter_recipe)) + + # The real package must virtual-provide the unsuffixed name so that + # existing references to kernel-module-testbar still resolve. + rprovides = runCmd("oe-pkgdata-util read-value RPROVIDES %s" % consumer_pkg).output.split() + self.assertIn(consumer_recipe, rprovides, + "%s does not RPROVIDE the virtual %s (got: %s)" + % (consumer_pkg, consumer_recipe, rprovides)) -- 2.34.1
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#239169): https://lists.openembedded.org/g/openembedded-core/message/239169 Mute This Topic: https://lists.openembedded.org/mt/119882796/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
