0);
 }
 
+void kcsan_save_irqtrace(struct task_struct *task)
+{
+#ifdef CONFIG_TRACE_IRQFLAGS
+       task->kcsan_save_irqtrace = task->irqtrace;
+#endif
+}
+
+void kcsan_restore_irqtrace(struct task_struct *task)
+{
+#ifdef CONFIG_TRACE_IRQFLAGS
+       task->irqtrace = task->kcsan_save_irqtrace;
+#endif
+}
+
 /*
  * Pull everything together: check_access() below contains the performance
  * critical operations; the fast-path (including check_access) functions should
        flags = user_access_save();
 
        if (consumed) {
+               kcsan_save_irqtrace(current);
                kcsan_report(ptr, size, type, KCSAN_VALUE_CHANGE_MAYBE,
                             KCSAN_REPORT_CONSUMED_WATCHPOINT,
                             watchpoint - watchpoints);
+               kcsan_restore_irqtrace(current);
        } else {
                /*
                 * The other thread may not print any diagnostics, as it has
                goto out;
        }
 
+       /*
+        * Save and restore the IRQ state trace touched by KCSAN, since KCSAN's
+        * runtime is entered for every memory access, and potentially useful
+        * information is lost if dirtied by KCSAN.
+        */
+       kcsan_save_irqtrace(current);
        if (!kcsan_interrupt_watcher)
                local_irq_save(irq_flags);
 
 out_unlock:
        if (!kcsan_interrupt_watcher)
                local_irq_restore(irq_flags);
+       kcsan_restore_irqtrace(current);
 out:
        user_access_restore(ua_flags);
 }
 
 #define _KERNEL_KCSAN_KCSAN_H
 
 #include <linux/kcsan.h>
+#include <linux/sched.h>
 
 /* The number of adjacent watchpoints to check. */
 #define KCSAN_CHECK_ADJACENT 1
  */
 extern bool kcsan_enabled;
 
+/*
+ * Save/restore IRQ flags state trace dirtied by KCSAN.
+ */
+void kcsan_save_irqtrace(struct task_struct *task);
+void kcsan_restore_irqtrace(struct task_struct *task);
+
 /*
  * Initialize debugfs file.
  */