]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
x86/mce: Get rid of register_mce_write_callback()
authorBorislav Petkov <bp@suse.de>
Tue, 13 Jun 2017 16:28:31 +0000 (18:28 +0200)
committerIngo Molnar <mingo@kernel.org>
Wed, 14 Jun 2017 05:32:07 +0000 (07:32 +0200)
Make the mcelog call a notifier which lands in the injector module and
does the injection. This allows for mce-inject to be a normal kernel
module now.

Tested-by: Yazen Ghannam <yazen.ghannam@amd.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Acked-by: Yazen Ghannam <yazen.ghannam@amd.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Tony Luck <tony.luck@intel.com>
Link: http://lkml.kernel.org/r/20170613162835.30750-5-bp@alien8.de
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/include/asm/mce.h
arch/x86/kernel/cpu/mcheck/dev-mcelog.c
arch/x86/kernel/cpu/mcheck/mce-inject.c
arch/x86/kernel/cpu/mcheck/mce-internal.h

index 3f9a3d2a52095af1f100e72bc3c24b4fc8d1b397..181264989db572a8533c00bbe6392c880c0875e5 100644 (file)
@@ -285,10 +285,6 @@ int mce_notify_irq(void);
 
 DECLARE_PER_CPU(struct mce, injectm);
 
-extern void register_mce_write_callback(ssize_t (*)(struct file *filp,
-                                   const char __user *ubuf,
-                                   size_t usize, loff_t *off));
-
 /* Disable CMCI/polling for MCA bank claimed by firmware */
 extern void mce_disable_bank(int bank);
 
index 9c632cb88546cfc398bf3d96ffb407d8341e67b5..a80427c30c93958bf2d96b3e7e5d9d19b77e27b3 100644 (file)
@@ -17,6 +17,8 @@
 
 #include "mce-internal.h"
 
+static BLOCKING_NOTIFIER_HEAD(mce_injector_chain);
+
 static DEFINE_MUTEX(mce_chrdev_read_mutex);
 
 static char mce_helper[128];
@@ -345,24 +347,49 @@ static long mce_chrdev_ioctl(struct file *f, unsigned int cmd,
        }
 }
 
-static ssize_t (*mce_write)(struct file *filp, const char __user *ubuf,
-                           size_t usize, loff_t *off);
+void mce_register_injector_chain(struct notifier_block *nb)
+{
+       blocking_notifier_chain_register(&mce_injector_chain, nb);
+}
+EXPORT_SYMBOL_GPL(mce_register_injector_chain);
 
-void register_mce_write_callback(ssize_t (*fn)(struct file *filp,
-                            const char __user *ubuf,
-                            size_t usize, loff_t *off))
+void mce_unregister_injector_chain(struct notifier_block *nb)
 {
-       mce_write = fn;
+       blocking_notifier_chain_unregister(&mce_injector_chain, nb);
 }
-EXPORT_SYMBOL_GPL(register_mce_write_callback);
+EXPORT_SYMBOL_GPL(mce_unregister_injector_chain);
 
 static ssize_t mce_chrdev_write(struct file *filp, const char __user *ubuf,
                                size_t usize, loff_t *off)
 {
-       if (mce_write)
-               return mce_write(filp, ubuf, usize, off);
-       else
+       struct mce m;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       /*
+        * There are some cases where real MSR reads could slip
+        * through.
+        */
+       if (!boot_cpu_has(X86_FEATURE_MCE) || !boot_cpu_has(X86_FEATURE_MCA))
+               return -EIO;
+
+       if ((unsigned long)usize > sizeof(struct mce))
+               usize = sizeof(struct mce);
+       if (copy_from_user(&m, ubuf, usize))
+               return -EFAULT;
+
+       if (m.extcpu >= num_possible_cpus() || !cpu_online(m.extcpu))
                return -EINVAL;
+
+       /*
+        * Need to give user space some time to set everything up,
+        * so do it a jiffie or two later everywhere.
+        */
+       schedule_timeout(2);
+
+       blocking_notifier_call_chain(&mce_injector_chain, 0, &m);
+
+       return usize;
 }
 
 static const struct file_operations mce_chrdev_ops = {
index 7170186938e5186fcfd3c34a15971cff0df7fdce..c21c1a73712a7ba30a6374d9ebcf5313bfd3ff8a 100644 (file)
@@ -283,42 +283,24 @@ static void __maybe_unused raise_mce(struct mce *m)
        }
 }
 
-#ifdef CONFIG_X86_MCELOG_LEGACY
-/* Error injection interface */
-static ssize_t mce_write(struct file *filp, const char __user *ubuf,
-                        size_t usize, loff_t *off)
+static int mce_inject_raise(struct notifier_block *nb, unsigned long val,
+                           void *data)
 {
-       struct mce m;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       /*
-        * There are some cases where real MSR reads could slip
-        * through.
-        */
-       if (!boot_cpu_has(X86_FEATURE_MCE) || !boot_cpu_has(X86_FEATURE_MCA))
-               return -EIO;
-
-       if ((unsigned long)usize > sizeof(struct mce))
-               usize = sizeof(struct mce);
-       if (copy_from_user(&m, ubuf, usize))
-               return -EFAULT;
-
-       if (m.extcpu >= num_possible_cpus() || !cpu_online(m.extcpu))
-               return -EINVAL;
+       struct mce *m = (struct mce *)data;
 
-       /*
-        * Need to give user space some time to set everything up,
-        * so do it a jiffie or two later everywhere.
-        */
-       schedule_timeout(2);
+       if (!m)
+               return NOTIFY_DONE;
 
        mutex_lock(&mce_inject_mutex);
-       raise_mce(&m);
+       raise_mce(m);
        mutex_unlock(&mce_inject_mutex);
-       return usize;
+
+       return NOTIFY_DONE;
 }
-#endif /* CONFIG_X86_MCELOG_LEGACY */
+
+static struct notifier_block inject_nb = {
+       .notifier_call  = mce_inject_raise,
+};
 
 /*
  * Caller needs to be make sure this cpu doesn't disappear
@@ -719,44 +701,34 @@ static int __init inject_init(void)
        if (!alloc_cpumask_var(&mce_inject_cpumask, GFP_KERNEL))
                return -ENOMEM;
 
-#ifdef CONFIG_X86_MCELOG_LEGACY
-               register_mce_write_callback(mce_write);
-#endif
-
-       register_nmi_handler(NMI_LOCAL, mce_raise_notify, 0, "mce_notify");
-
        err = debugfs_init();
        if (err) {
                free_cpumask_var(mce_inject_cpumask);
                return err;
        }
 
+       register_nmi_handler(NMI_LOCAL, mce_raise_notify, 0, "mce_notify");
+       mce_register_injector_chain(&inject_nb);
+
        pr_info("Machine check injector initialized\n");
 
        return 0;
 }
 
-module_init(inject_init);
-
-/*
- * Cannot tolerate unloading currently because we cannot
- * guarantee all openers of mce_chrdev will get a reference to us.
- */
-#ifndef CONFIG_X86_MCELOG_LEGACY
 static void __exit inject_exit(void)
 {
 
+       mce_unregister_injector_chain(&inject_nb);
+       unregister_nmi_handler(NMI_LOCAL, "mce_notify");
+
        debugfs_remove_recursive(dfs_inj);
        dfs_inj = NULL;
 
        memset(&dfs_fls, 0, sizeof(dfs_fls));
 
-       unregister_nmi_handler(NMI_LOCAL, "mce_notify");
-
        free_cpumask_var(mce_inject_cpumask);
 }
 
+module_init(inject_init);
 module_exit(inject_exit);
-#endif
-
 MODULE_LICENSE("GPL");
index 654ad0668d7222df719b50bcc66ca80e2640f1de..098530a93bb7cc4e451687ae29a0b86447105861 100644 (file)
@@ -100,7 +100,11 @@ static inline bool mce_cmp(struct mce *m1, struct mce *m2)
 extern struct device_attribute dev_attr_trigger;
 
 #ifdef CONFIG_X86_MCELOG_LEGACY
-extern void mce_work_trigger(void);
+void mce_work_trigger(void);
+void mce_register_injector_chain(struct notifier_block *nb);
+void mce_unregister_injector_chain(struct notifier_block *nb);
 #else
 static inline void mce_work_trigger(void)      { }
+static inline void mce_register_injector_chain(struct notifier_block *nb)      { }
+static inline void mce_unregister_injector_chain(struct notifier_block *nb)    { }
 #endif