From 8962049bb2880af841eaa965bc455e9aec141413 Mon Sep 17 00:00:00 2001 From: Douglas Raillard Date: Thu, 30 Mar 2023 19:04:10 +0100 Subject: [PATCH] lisa._kmod: Add a from_proc_config() kernel tree loader FEATURE from_sysfs_headers() uses both /proc/config.gz and /sys/kernel/kheaders.tar.xz to patch the user-provided tree. If that results in a build failure, the fallback is from_user_tree() that just asssumes the tree is ready. If the tree is almost ready but the config is wrong, the module build using from_user_tree() might error if e.g. a config option such as CONFIG_SCHED_AUTOGROUP is enabled in the .config but not on the board, leading to trying to access to a non-existant struct member that will still be defined from BTF blob. Instead of falling back to from_user_tree() straight away, fall back first to from_proc_config() that will use /proc/config.gz, which is very likely to be successful and has much higher chances of producing a working module. --- lisa/_kmod.py | 60 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/lisa/_kmod.py b/lisa/_kmod.py index 61e88aec3..fe3a3000b 100644 --- a/lisa/_kmod.py +++ b/lisa/_kmod.py @@ -1180,29 +1180,30 @@ class KernelTree(Loggable, SerializeViaConstructor): raise ValueError(f'Building from /lib/modules/.../build/ is only supported for local targets') @contextlib.contextmanager - def from_sysfs_headers(): + def _from_target_sources(configs, pull): """ - From /sys/kheaders.tar.xz + Overlay some content taken from the target on the user tree, such + as /proc/config.gz """ version = kernel_info['version'] config = kernel_info['config'] - if not ( - config.get('CONFIG_IKHEADERS') == KernelConfigTristate.YES and - config.get('CONFIG_IKCONFIG_PROC') == KernelConfigTristate.YES + if not all( + config.get(conf) == KernelConfigTristate.YES + for conf in configs ): - raise ValueError('Needs CONFIG_IKHEADERS=y and CONFIG_IKCONFIG_PROC=y') + configs = ' and '.join( + f'{conf}=y' + for conf in configs + ) + raise ValueError(f'Needs {configs}') else: with tempfile.TemporaryDirectory() as temp: temp = Path(temp) - target.cached_pull('/proc/config.gz', str(temp)) - target.cached_pull('/sys/kernel/kheaders.tar.xz', str(temp), via_temp=True) + overlays = pull(target, temp) with cls.from_overlays( version=version, - overlays={ - FileOverlay.from_path(temp / 'config.gz', decompress=True): '.config', - TarOverlay.from_path(temp / 'kheaders.tar.xz'): '.', - }, + overlays=overlays, make_vars=make_vars, cache=cache, tree_path=tree_path, @@ -1211,6 +1212,39 @@ class KernelTree(Loggable, SerializeViaConstructor): ) as tree: yield tree._to_spec() + def from_sysfs_headers(): + """ + From /sys/kernel/kheaders.tar.xz and /proc/config.gz + """ + def pull(target, temp): + target.cached_pull('/proc/config.gz', str(temp)) + target.cached_pull('/sys/kernel/kheaders.tar.xz', str(temp), via_temp=True) + + return { + FileOverlay.from_path(temp / 'config.gz', decompress=True): '.config', + TarOverlay.from_path(temp / 'kheaders.tar.xz'): '.', + } + + return _from_target_sources( + configs=['CONFIG_IKHEADERS', 'CONFIG_IKCONFIG_PROC'], + pull=pull, + ) + + def from_proc_config(): + """ + From /proc/config.gz + """ + def pull(target, temp): + target.cached_pull('/proc/config.gz', str(temp)) + return { + FileOverlay.from_path(temp / 'config.gz', decompress=True): '.config', + } + + return _from_target_sources( + configs=['CONFIG_IKCONFIG_PROC'], + pull=pull, + ) + @contextlib.contextmanager def from_user_tree(): """ @@ -1268,7 +1302,7 @@ class KernelTree(Loggable, SerializeViaConstructor): raise ValueError(f'Could not load kernel trees:\n{excep_str}') # Try these loaders in the given order, until one succeeds - loaders = [from_installed_headers, from_sysfs_headers, from_user_tree] + loaders = [from_installed_headers, from_sysfs_headers, from_proc_config, from_user_tree] return cls( path_cm=functools.partial(try_loaders, loaders), -- GitLab