summaryrefslogtreecommitdiff
path: root/lib/igt_taints.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2021-01-07 10:37:03 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2021-01-08 13:59:02 +0000
commit532d6e84ab7fab9568dabc63a4620a257ea2fdff (patch)
tree46bb04a1c1fe58340f9c53c504d66fcb2c8014c7 /lib/igt_taints.c
parent39768c976b920dcf0f159284bce882088aa65c50 (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.c104
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);
+}