diff --git a/lisa/_cli_tools/lisa_load_kmod.py b/lisa/_cli_tools/lisa_load_kmod.py index 0d4b8a65b60e6a4e3e0f0a97bf5a2b26c8018fd8..eade26171bcbfda9a979861813a302391d43a0ab 100755 --- a/lisa/_cli_tools/lisa_load_kmod.py +++ b/lisa/_cli_tools/lisa_load_kmod.py @@ -64,6 +64,7 @@ def main(): def _main(args, target): + logger = logging.getLogger('lisa-load-kmod') features = args.feature keep_loaded = not bool(args.cmd) @@ -78,31 +79,31 @@ def _main(args, target): kmod = target.get_kmod(LISADynamicKmod) pretty_events = ', '.join(kmod.defined_events) - logging.info(f'Kernel module provides the following ftrace events: {pretty_events}') + logger.info(f'Kernel module provides the following ftrace events: {pretty_events}') _kmod_cm = kmod.run(kmod_params=kmod_params) if keep_loaded: @contextlib.contextmanager def cm(): - logging.info('Compiling and loading kernel module ...') + logger.info('Loading kernel module ...') yield _kmod_cm.__enter__() - logging.info(f'Loaded kernel module as "{kmod.mod_name}"') + logger.info(f'Loaded kernel module as "{kmod.mod_name}"') else: @contextlib.contextmanager def cm(): with _kmod_cm: - logging.info('Compiling and loading kernel module ...') + logger.info('Loading kernel module ...') try: yield finally: - logging.info('Unloading kernel module') + logger.info('Unloading kernel module') kmod_cm = cm() def run_cmd(): if cmd: pretty_cmd = ' '.join(map(shlex.quote, cmd)) - logging.info(f'Running command: {pretty_cmd}') + logger.info(f'Running command: {pretty_cmd}') return subprocess.run(cmd).returncode else: return 0 diff --git a/lisa/_kmod.py b/lisa/_kmod.py index ba2c7cc7ff3b254ab2f6da90dd387edce55cdf2c..00afd4d8f9ac774940d1f378af9926a4b750f9d2 100644 --- a/lisa/_kmod.py +++ b/lisa/_kmod.py @@ -3003,9 +3003,10 @@ class DynamicKmod(Loggable): def _memoized_compile(self, make_vars): make_vars = dict(make_vars) - compile_ = self._do_compile.__func__ if self._compile_needs_root: - compile_ = ensure_root(compile_, inline=True) + compile_ = ensure_root(self._do_compile_subprocess.__func__, inline=True) + else: + compile_ = self._do_compile.__func__ bin_, spec = compile_(self, make_vars=make_vars) # Get back _KernelBuildEnv._to_spec() and update the _KernelBuildEnv we have in @@ -3016,6 +3017,15 @@ class DynamicKmod(Loggable): self.kernel_build_env._update_spec(spec) return bin_ + def _do_compile_subprocess(self, *args, **kwargs): + # We are running in a separate subprocess, so the target we got was + # pickled and sent to us. It is best to disconnect explicitly to avoid + # running into problems when objects are garbage collected as the + # interpreter is shutting down and parts of the stdlib are not + # available anymore. + with self.target.closing(): + return self._do_compile(*args, **kwargs) + def _do_compile(self, make_vars=None): kernel_build_env = self.kernel_build_env @@ -3434,18 +3444,23 @@ class LISADynamicKmod(FtraceDynamicKmod): return preinstalled_unsuitable() else: kmod_path = kmod_path.strip() - if len((kmod_paths := kmod_path.splitlines())) > 1: - return preinstalled_unsuitable(ValueError(f'Multiple paths found for {kmod_filename}: {", ".join(kmod_paths)}')) - else: - # We found an installed module that could maybe be suitable, so - # we try to load it. - try: - return self._install(nullcontext(kmod_path), kmod_params=kmod_params) - except (subprocess.CalledProcessError, KmodVersionError) as e: - # Turns out to not be suitable, so we build our own - return preinstalled_unsuitable(e) + if kmod_path: + if len((kmod_paths := kmod_path.splitlines())) > 1: + return preinstalled_unsuitable(ValueError(f'Multiple paths found for {kmod_filename}: {", ".join(kmod_paths)}')) else: - logger.warning(f'Loaded "{self.mod_name}" module from pre-installed location: {kmod_path}. This implies that the module was compiled by a 3rd party, which is available but unsupported. If you experience issues related to module version mismatch in the future, please contact them for updating the module. This may break at any time, without notice, and regardless of the general backward compatibility policy of LISA.') - return None + # We found an installed module that could maybe be suitable, so + # we try to load it. + try: + return self._install(nullcontext(kmod_path), kmod_params=kmod_params) + except (subprocess.CalledProcessError, KmodVersionError) as e: + # Turns out to not be suitable, so we build our own + return preinstalled_unsuitable(e) + else: + logger.warning(f'Loaded "{self.mod_name}" module from pre-installed location: {kmod_path}. This implies that the module was compiled by a 3rd party, which is available but unsupported. If you experience issues related to module version mismatch in the future, please contact them for updating the module. This may break at any time, without notice, and regardless of the general backward compatibility policy of LISA.') + return None + # If base_path exists, busybox find will simply an empty stdout + # rather than return with a non-zero exit status. + else: + return preinstalled_unsuitable() # vim :set tabstop=4 shiftwidth=4 expandtab textwidth=80