[igt-dev] [PATCH i-g-t] lib: Process kernel taints
Chris Wilson
chris at chris-wilson.co.uk
Fri Jan 8 13:01:57 UTC 2021
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: function docs
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Petri Latvala <petri.latvala at intel.com>
---
lib/Makefile.sources | 2 +
lib/igt_taints.c | 98 ++++++++++++++++++++++++++++++++++++++++++++
lib/igt_taints.h | 19 +++++++++
lib/meson.build | 1 +
runner/executor.c | 73 +++++++--------------------------
5 files changed, 134 insertions(+), 59 deletions(-)
create mode 100644 lib/igt_taints.c
create mode 100644 lib/igt_taints.h
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index 67b386457..7102f95e7 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -64,6 +64,8 @@ lib_source_list = \
igt_sysfs.h \
igt_sysrq.c \
igt_sysrq.h \
+ igt_taints.c \
+ igt_taints.h \
igt_thread.c \
igt_thread.h \
igt_x86.h \
diff --git a/lib/igt_taints.c b/lib/igt_taints.c
new file mode 100644
index 000000000..a5a7e6cae
--- /dev/null
+++ b/lib/igt_taints.c
@@ -0,0 +1,98 @@
+// 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 correspoding to a set
+ * bit in the mast. 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 match, NULL is returned.
+ *
+ * This may be used in a loop to extract all known reasons for why the
+ * kernel tained:
+ *
+ * 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 "/prco/sys/kernel/tainted" and returns both the set of all
+ * taints reported via @taints, and the set of fatal taints as the
+ * return parameters.
+ *
+ * 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);
+}
diff --git a/lib/igt_taints.h b/lib/igt_taints.h
new file mode 100644
index 000000000..be4195c5a
--- /dev/null
+++ b/lib/igt_taints.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2021 Intel Corporation
+ */
+
+#ifndef __IGT_TAINTS_H__
+#define __IGT_TAINTS_H__
+
+unsigned long igt_kernel_tainted(unsigned long *taints);
+const char *igt_explain_taints(unsigned long *taints);
+
+unsigned long igt_bad_taints(void);
+
+static inline unsigned long is_tainted(unsigned long taints)
+{
+ return taints & igt_bad_taints();
+}
+
+#endif /* __IGT_TAINTS_H__ */
diff --git a/lib/meson.build b/lib/meson.build
index 540facb24..3abc42cb3 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -27,6 +27,7 @@ lib_sources = [
'igt_syncobj.c',
'igt_sysfs.c',
'igt_sysrq.c',
+ 'igt_taints.c',
'igt_thread.c',
'igt_vec.c',
'igt_vgem.c',
diff --git a/runner/executor.c b/runner/executor.c
index faf272d85..93db8bb36 100644
--- a/runner/executor.c
+++ b/runner/executor.c
@@ -24,6 +24,7 @@
#include "igt_aux.h"
#include "igt_core.h"
+#include "igt_taints.h"
#include "executor.h"
#include "output_strings.h"
@@ -307,70 +308,23 @@ static char *handle_lockdep(void)
return NULL;
}
-/* see Linux's include/linux/kernel.h */
-static const struct {
- unsigned long bit;
- const char *explanation;
-} abort_taints[] = {
- {(1 << 5), "TAINT_BAD_PAGE: Bad page reference or an unexpected page flags."},
- {(1 << 7), "TAINT_DIE: Kernel has died - BUG/OOPS."},
- {(1 << 9), "TAINT_WARN: WARN_ON has happened."},
- {0, 0}};
-
-static unsigned long bad_taints(void)
-{
- static unsigned long __bad_taints;
-
- if (!__bad_taints) {
- for (typeof(*abort_taints) *taint = abort_taints;
- taint->bit;
- taint++)
- __bad_taints |= taint->bit;
- }
-
- return __bad_taints;
-}
-
-static unsigned long is_tainted(unsigned long taints)
-{
- return taints & bad_taints();
-}
-
-static unsigned long 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);
-}
-
static char *handle_taint(void)
{
- unsigned long taints;
+ unsigned long taints, bad;
+ char *explain;
char *reason;
- if (!tainted(&taints))
+ bad = igt_kernel_tainted(&taints);
+ if (!bad)
return NULL;
- asprintf(&reason, "Kernel badly tainted (%#lx) (check dmesg for details):\n",
- taints);
-
- for (typeof(*abort_taints) *taint = abort_taints; taint->bit; taint++) {
- if (taint->bit & taints) {
- char *old_reason = reason;
- asprintf(&reason, "%s\t(%#lx) %s\n",
- old_reason,
- taint->bit,
- taint->explanation);
- free(old_reason);
- }
+ asprintf(&reason, "Kernel badly tainted (%#lx, %#lx) (check dmesg for details):\n",
+ taints, bad);
+
+ while ((explain = igt_explain_taints(&bad))) {
+ char *old_reason = reason;
+ asprintf(&reason, "%s\t%s\n", old_reason, explain);
+ free(old_reason);
}
return reason;
@@ -1142,7 +1096,8 @@ static int monitor_output(pid_t child,
sigfd = -1; /* we are dying, no signal handling for now */
}
- timeout_reason = need_to_timeout(settings, killed, tainted(&taints),
+ timeout_reason = need_to_timeout(settings, killed,
+ igt_kernel_tainted(&taints),
igt_time_elapsed(&time_last_activity, &time_now),
igt_time_elapsed(&time_last_subtest, &time_now),
igt_time_elapsed(&time_killed, &time_now),
--
2.30.0
More information about the igt-dev
mailing list