Browse Source

Merge branch 'ras-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull RAS fixes from Thomas Gleixner:
 "Two small fixes for RAS/MCE:

   - Serialize sysfs changes to avoid concurrent modificaiton of
     underlying data

   - Add microcode revision to Machine Check records. This should have
     been there forever, but now with the broken microcode versions in
     the wild it has become important"

* 'ras-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/MCE: Serialize sysfs changes
  x86/MCE: Save microcode revision in machine check records
Linus Torvalds 7 years ago
parent
commit
ebb3762e88
2 changed files with 25 additions and 2 deletions
  1. 1 0
      arch/x86/include/uapi/asm/mce.h
  2. 24 2
      arch/x86/kernel/cpu/mcheck/mce.c

+ 1 - 0
arch/x86/include/uapi/asm/mce.h

@@ -30,6 +30,7 @@ struct mce {
 	__u64 synd;	/* MCA_SYND MSR: only valid on SMCA systems */
 	__u64 synd;	/* MCA_SYND MSR: only valid on SMCA systems */
 	__u64 ipid;	/* MCA_IPID MSR: only valid on SMCA systems */
 	__u64 ipid;	/* MCA_IPID MSR: only valid on SMCA systems */
 	__u64 ppin;	/* Protected Processor Inventory Number */
 	__u64 ppin;	/* Protected Processor Inventory Number */
+	__u32 microcode;/* Microcode revision */
 };
 };
 
 
 #define MCE_GET_RECORD_LEN   _IOR('M', 1, int)
 #define MCE_GET_RECORD_LEN   _IOR('M', 1, int)

+ 24 - 2
arch/x86/kernel/cpu/mcheck/mce.c

@@ -56,6 +56,9 @@
 
 
 static DEFINE_MUTEX(mce_log_mutex);
 static DEFINE_MUTEX(mce_log_mutex);
 
 
+/* sysfs synchronization */
+static DEFINE_MUTEX(mce_sysfs_mutex);
+
 #define CREATE_TRACE_POINTS
 #define CREATE_TRACE_POINTS
 #include <trace/events/mce.h>
 #include <trace/events/mce.h>
 
 
@@ -130,6 +133,8 @@ void mce_setup(struct mce *m)
 
 
 	if (this_cpu_has(X86_FEATURE_INTEL_PPIN))
 	if (this_cpu_has(X86_FEATURE_INTEL_PPIN))
 		rdmsrl(MSR_PPIN, m->ppin);
 		rdmsrl(MSR_PPIN, m->ppin);
+
+	m->microcode = boot_cpu_data.microcode;
 }
 }
 
 
 DEFINE_PER_CPU(struct mce, injectm);
 DEFINE_PER_CPU(struct mce, injectm);
@@ -262,7 +267,7 @@ static void __print_mce(struct mce *m)
 	 */
 	 */
 	pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n",
 	pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n",
 		m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
 		m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
-		cpu_data(m->extcpu).microcode);
+		m->microcode);
 }
 }
 
 
 static void print_mce(struct mce *m)
 static void print_mce(struct mce *m)
@@ -2086,6 +2091,7 @@ static ssize_t set_ignore_ce(struct device *s,
 	if (kstrtou64(buf, 0, &new) < 0)
 	if (kstrtou64(buf, 0, &new) < 0)
 		return -EINVAL;
 		return -EINVAL;
 
 
+	mutex_lock(&mce_sysfs_mutex);
 	if (mca_cfg.ignore_ce ^ !!new) {
 	if (mca_cfg.ignore_ce ^ !!new) {
 		if (new) {
 		if (new) {
 			/* disable ce features */
 			/* disable ce features */
@@ -2098,6 +2104,8 @@ static ssize_t set_ignore_ce(struct device *s,
 			on_each_cpu(mce_enable_ce, (void *)1, 1);
 			on_each_cpu(mce_enable_ce, (void *)1, 1);
 		}
 		}
 	}
 	}
+	mutex_unlock(&mce_sysfs_mutex);
+
 	return size;
 	return size;
 }
 }
 
 
@@ -2110,6 +2118,7 @@ static ssize_t set_cmci_disabled(struct device *s,
 	if (kstrtou64(buf, 0, &new) < 0)
 	if (kstrtou64(buf, 0, &new) < 0)
 		return -EINVAL;
 		return -EINVAL;
 
 
+	mutex_lock(&mce_sysfs_mutex);
 	if (mca_cfg.cmci_disabled ^ !!new) {
 	if (mca_cfg.cmci_disabled ^ !!new) {
 		if (new) {
 		if (new) {
 			/* disable cmci */
 			/* disable cmci */
@@ -2121,6 +2130,8 @@ static ssize_t set_cmci_disabled(struct device *s,
 			on_each_cpu(mce_enable_ce, NULL, 1);
 			on_each_cpu(mce_enable_ce, NULL, 1);
 		}
 		}
 	}
 	}
+	mutex_unlock(&mce_sysfs_mutex);
+
 	return size;
 	return size;
 }
 }
 
 
@@ -2128,8 +2139,19 @@ static ssize_t store_int_with_restart(struct device *s,
 				      struct device_attribute *attr,
 				      struct device_attribute *attr,
 				      const char *buf, size_t size)
 				      const char *buf, size_t size)
 {
 {
-	ssize_t ret = device_store_int(s, attr, buf, size);
+	unsigned long old_check_interval = check_interval;
+	ssize_t ret = device_store_ulong(s, attr, buf, size);
+
+	if (check_interval == old_check_interval)
+		return ret;
+
+	if (check_interval < 1)
+		check_interval = 1;
+
+	mutex_lock(&mce_sysfs_mutex);
 	mce_restart();
 	mce_restart();
+	mutex_unlock(&mce_sysfs_mutex);
+
 	return ret;
 	return ret;
 }
 }