From 0a08b41fb247fc892c44319ce7674e7102fe5ac0 Mon Sep 17 00:00:00 2001 From: Richard Li Date: Fri, 13 Dec 2024 00:44:08 +0000 Subject: [PATCH] corelens: add support for multiple kmods in skip_unless_have_kmods skip_unless_have_kmods can now take a list of modules as strings. Skip if any of the modules in the list are not present. Orabug: 37389765 Signed-off-by: Richard Li --- drgn_tools/corelens.py | 39 ++++++++++++++++++++------------------ drgn_tools/dm.py | 2 +- drgn_tools/ext4_dirlock.py | 2 +- drgn_tools/nfs_tools.py | 2 +- drgn_tools/rds.py | 2 +- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/drgn_tools/corelens.py b/drgn_tools/corelens.py index 33514c5..b896d09 100644 --- a/drgn_tools/corelens.py +++ b/drgn_tools/corelens.py @@ -95,15 +95,15 @@ def add_args(self, parser: argparse.ArgumentParser) -> None: pass @property - def skip_unless_have_kmod(self) -> Optional[str]: + def skip_unless_have_kmods(self) -> Optional[List[str]]: """ - If specified, skip this when the kmod is not present in the kernel + If specified, skip this when the kmods are not present in the kernel - This field, when specified, is a string naming a kernel module (referred + This field, when specified, is a list of strings naming kernel modules (referred to as kmod in these docs to avoid confusing with "corelens module"). - This kmod is expected to signify the presence of the subsystem that this - module is dealing with. If the kmod is not loaded in the kernel, then - this module is skipped by corelens. If the kmod is loaded, but no + This kmod(s) is expected to signify the presence of the subsystem that this + module is dealing with. If the kmod(s) is not loaded in the kernel, then + this module is skipped by corelens. If the kmod(s) is loaded, but no debuginfo is present, the module is skipped and an error is raised. """ return None @@ -116,7 +116,7 @@ def debuginfo_kmods(self) -> List[str]: This field, when specified, is a list of strings. Each string could be a kmod name, or a :mod:`fnmatch` pattern which matches several kmods. - Unlike :attr:`skip_unless_have_kmod`, we don't require that the kmods + Unlike :attr:`skip_unless_have_kmods`, we don't require that the kmods here are loaded. Instead, we just require that *if* the modules are loaded, they must have debuginfo present. @@ -198,10 +198,11 @@ def _notes(self) -> List[str]: notes.append("Requires DWARF debuginfo.") if not self.live_ok: notes.append("Live kernel not supported.") - if self.skip_unless_have_kmod: + if self.skip_unless_have_kmods: notes.append( - f'Skipped unless "{self.skip_unless_have_kmod}" ' - "kernel module is loaded." + "Skipped unless '{}' kernel module(s) are loaded.".format( + ", ".join(self.skip_unless_have_kmods) + ) ) if self.run_when == "verbose": notes.append("Detailed module (runs with -A)") @@ -460,13 +461,14 @@ def _check_module_debuginfo( for mod, args in candidate_modules: # Corelens modules that depend on a particular subsystem module being # present, should should be skipped if it is not present. - if mod.skip_unless_have_kmod is not None and ( - mod.skip_unless_have_kmod not in all_kmod_names + if mod.skip_unless_have_kmods is not None and ( + not all(m in all_kmod_names for m in mod.skip_unless_have_kmods) ): if warn_not_present: warnings.append( - f"{mod.name} skipped because '{mod.skip_unless_have_kmod}'" - " was not loaded in the kernel" + "{} skipped because '{}' was (were) not (all) loaded in the kernel".format( + mod.name, ", ".join(mod.skip_unless_have_kmods) + ) ) continue @@ -493,12 +495,13 @@ def _check_module_debuginfo( modules_to_run.append((mod, args)) continue - if mod.skip_unless_have_kmod is not None and ( - mod.skip_unless_have_kmod not in loaded_kmods + if mod.skip_unless_have_kmods is not None and ( + not all(m in loaded_kmods for m in mod.skip_unless_have_kmods) ): errors.append( - f"{mod.name} skipped because '{mod.skip_unless_have_kmod}'" - " did not have debuginfo loaded" + "{} skipped because '{}' did not have (all) debuginfo loaded".format( + mod.name, ", ".join(mod.skip_unless_have_kmods) + ) ) continue skip = False diff --git a/drgn_tools/dm.py b/drgn_tools/dm.py index 88ce7ee..1dc8f32 100644 --- a/drgn_tools/dm.py +++ b/drgn_tools/dm.py @@ -318,7 +318,7 @@ class Dm(CorelensModule): """Display info about device mapper devices""" name = "dm" - skip_unless_have_kmod = "dm_mod" + skip_unless_have_kmods = ["dm_mod"] def run(self, prog: Program, args: argparse.Namespace) -> None: show_dm(prog) diff --git a/drgn_tools/ext4_dirlock.py b/drgn_tools/ext4_dirlock.py index 235fe20..805e709 100644 --- a/drgn_tools/ext4_dirlock.py +++ b/drgn_tools/ext4_dirlock.py @@ -190,7 +190,7 @@ class Ext4DirLock(CorelensModule): """Scan processes hung by ext4 directory inode lock""" name = "ext4_dirlock_scan" - skip_unless_have_kmod = "ext4" + skip_unless_have_kmods = ["ext4"] def add_args(self, parser: argparse.ArgumentParser) -> None: parser.add_argument( diff --git a/drgn_tools/nfs_tools.py b/drgn_tools/nfs_tools.py index cc01186..18ee82c 100644 --- a/drgn_tools/nfs_tools.py +++ b/drgn_tools/nfs_tools.py @@ -912,7 +912,7 @@ class NfsShow(CorelensModule): name = "nfsshow" # there's no point in running unless the nfs module is loaded - skip_unless_have_kmod = "nfs" + skip_unless_have_kmods = ["nfs"] # we need sunrpc, and all nfs related debuginfo loaded debuginfo_kmods = ["sunrpc", "nfs", "nfs*"] diff --git a/drgn_tools/rds.py b/drgn_tools/rds.py index 0c8f4c8..a6cf5ad 100644 --- a/drgn_tools/rds.py +++ b/drgn_tools/rds.py @@ -1540,7 +1540,7 @@ class Rds(CorelensModule): """Print info about RDS devices, sockets, connections, and stats""" name = "rds" - skip_unless_have_kmod = "rds" + skip_unless_have_kmods = ["rds"] # We access information from the following modules # debuginfo_kmods = ["mlx5_core", "mlx4_core", "mlx5_ib", "mlx4_ib"]