diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2021-01-07 10:37:03 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2021-01-08 13:59:02 +0000 |
commit | 532d6e84ab7fab9568dabc63a4620a257ea2fdff (patch) | |
tree | 46bb04a1c1fe58340f9c53c504d66fcb2c8014c7 /lib/igt_taints.c | |
parent | 39768c976b920dcf0f159284bce882088aa65c50 (diff) |
lib: Process kernel taints
A small library routine to read '/proc/sys/kernel/taints' and check for
a fatal condition. This is currently used by the runner, but is also
useful for some tests.
v2,3: function docs
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Petri Latvala <petri.latvala@intel.com>
Reviewed-by: Petri Latvala <petri.latvala@intel.com>
Diffstat (limited to 'lib/igt_taints.c')
-rw-r--r-- | lib/igt_taints.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/lib/igt_taints.c b/lib/igt_taints.c new file mode 100644 index 00000000..6f5b827c --- /dev/null +++ b/lib/igt_taints.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2021 Intel Corporation + */ + +#include <stdio.h> + +#include "igt_taints.h" + +/* see Linux's include/linux/kernel.h */ +static const struct { + int bit; + int bad; + const char *explanation; +} abort_taints[] = { + { 5, 1, "TAINT_BAD_PAGE: Bad page reference or an unexpected page flags." }, + { 7, 1, "TAINT_DIE: Kernel has died - BUG/OOPS." }, + { 9, 1, "TAINT_WARN: WARN_ON has happened." }, + { -1 } +}; + +/** + * igt_explain_taints: + * @taints: mask of taints requiring an explanation [inout] + * + * Inspects the mask and looks up the first reason corresponding to a set + * bit in the mask. It returns the reason as a string constant, and removes + * the bit from the mask. If the mask is empty, or we have no known reason + * matching the mask, NULL is returned. + * + * This may be used in a loop to extract all known reasons for why the + * kernel is tainted: + * + * while (reason = igt_explain_taints(&taints)) + * igt_info("%s", reason); + * + * Returns the first reason corresponding to a taint bit. + */ +const char *igt_explain_taints(unsigned long *taints) +{ + for (typeof(*abort_taints) *taint = abort_taints; + taint->bit >= 0; + taint++) { + if (*taints & (1ul << taint->bit)) { + *taints &= ~(1ul << taint->bit); + return taint->explanation; + } + } + + return NULL; +} + +/** + * igt_bad_taints: + * + * Returns the mask of kernel taints that IGT considers fatal. + * Such as TAINT_WARN set when the kernel oopses. + */ +unsigned long igt_bad_taints(void) +{ + static unsigned long bad_taints; + + if (!bad_taints) { + for (typeof(*abort_taints) *taint = abort_taints; + taint->bit >= 0; + taint++) { + if (taint->bad) + bad_taints |= 1ul << taint->bit; + } + } + + return bad_taints; +} + +/** + * igt_kernel_tainted: + * @taints: bitmask of kernel taints [out] + * + * Reads the bitmask of kernel taints from "/proc/sys/kernel/tainted", + * see linux/kernel.h for the full set of flags. These are set whenever + * the kernel encounters an exceptional condition that may impair functionality. + * The kernel only sets the taint once, and so once a "fatal" condition has + * been encountered, it is generally not advisable to continue testing, as at + * least all future taint reporting will be lost. + * + * igt_kernel_tainted() returns the set of _all_ taints reported via @taints, + * and also the set of _fatal_ taints as its return value. + * + * Returns a mask of fatal taints; 0 if untainted. + */ +unsigned long igt_kernel_tainted(unsigned long *taints) +{ + FILE *f; + + *taints = 0; + + f = fopen("/proc/sys/kernel/tainted", "r"); + if (f) { + fscanf(f, "%lu", taints); + fclose(f); + } + + return is_tainted(*taints); +} |