x86/mce: Do not enter deferred errors into the generic pool twice
authorTony Luck <tony.luck@intel.com>
Tue, 24 Nov 2015 07:41:17 +0000 (08:41 +0100)
committerIngo Molnar <mingo@kernel.org>
Tue, 24 Nov 2015 08:12:35 +0000 (09:12 +0100)
We used to have a special ring buffer for deferred errors that
was used to mark problem pages. We replaced that with a generic
pool. Then later converted mce_log() to also use the same pool.
As a result, we end up adding all deferred errors to the pool
twice.

Rearrange this code. Make sure to set the m.severity and
m.usable_addr fields for deferred errors. Then if flags and
mca_cfg.dont_log_ce mean we call mce_log() we are done, because
that will add this entry to the generic pool.

If we skipped mce_log(), then we still want to take action for
the deferred error, so add to the pool.

Change the name of the boolean "error_logged" to "error_seen",
we should set it whether of not we logged an error because the
return value from machine_check_poll() is used to decide whether
storms have subsided or not.

Reported-by: Gong Chen <gong.chen@linux.intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-edac <linux-edac@vger.kernel.org>
Link: http://lkml.kernel.org/r/1448350880-5573-2-git-send-email-bp@alien8.de
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/kernel/cpu/mcheck/mce.c

index c5b0d562dbf55064685c78b5d0fa6280748086d1..6531cb46803c6c571e8d31f6d092bc44011ff385 100644 (file)
@@ -567,7 +567,7 @@ DEFINE_PER_CPU(unsigned, mce_poll_count);
  */
 bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
 {
-       bool error_logged = false;
+       bool error_seen = false;
        struct mce m;
        int severity;
        int i;
@@ -601,6 +601,8 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
                    (m.status & (mca_cfg.ser ? MCI_STATUS_S : MCI_STATUS_UC)))
                        continue;
 
+               error_seen = true;
+
                mce_read_aux(&m, i);
 
                if (!(flags & MCP_TIMESTAMP))
@@ -608,17 +610,10 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
 
                severity = mce_severity(&m, mca_cfg.tolerant, NULL, false);
 
-               /*
-                * In the cases where we don't have a valid address after all,
-                * do not add it into the ring buffer.
-                */
                if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m)) {
                        if (m.status & MCI_STATUS_ADDRV) {
                                m.severity = severity;
                                m.usable_addr = mce_usable_address(&m);
-
-                               if (!mce_gen_pool_add(&m))
-                                       mce_schedule_work();
                        }
                }
 
@@ -626,9 +621,16 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
                 * Don't get the IP here because it's unlikely to
                 * have anything to do with the actual error location.
                 */
-               if (!(flags & MCP_DONTLOG) && !mca_cfg.dont_log_ce) {
-                       error_logged = true;
+               if (!(flags & MCP_DONTLOG) && !mca_cfg.dont_log_ce)
                        mce_log(&m);
+               else if (m.usable_addr) {
+                       /*
+                        * Although we skipped logging this, we still want
+                        * to take action. Add to the pool so the registered
+                        * notifiers will see it.
+                        */
+                       if (!mce_gen_pool_add(&m))
+                               mce_schedule_work();
                }
 
                /*
@@ -644,7 +646,7 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
 
        sync_core();
 
-       return error_logged;
+       return error_seen;
 }
 EXPORT_SYMBOL_GPL(machine_check_poll);