diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 18:33:03 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-03 18:33:03 -0700 |
commit | 4422d80ed7d4bdb2d6e9fb890c66c3d9250ba694 (patch) | |
tree | 667e352576878a62f5e49c34e6eed5f164252415 /arch/x86/kernel/cpu/mcheck/dev-mcelog.c | |
parent | 9a9594efe54324e9124add7e7b1e7bdb6d0b08a3 (diff) | |
parent | 32288daf3f2439f57167c03cd679c2eba28923b7 (diff) | |
download | kernel_replicant_linux-4422d80ed7d4bdb2d6e9fb890c66c3d9250ba694.tar.gz kernel_replicant_linux-4422d80ed7d4bdb2d6e9fb890c66c3d9250ba694.tar.bz2 kernel_replicant_linux-4422d80ed7d4bdb2d6e9fb890c66c3d9250ba694.zip |
Merge branch 'ras-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull RAS updates from Thomas Gleixner:
"The RAS updates for the 4.13 merge window:
- Cleanup of the MCE injection facility (Borsilav Petkov)
- Rework of the AMD/SMCA handling (Yazen Ghannam)
- Enhancements for ACPI/APEI to handle new notitication types (Shiju
Jose)
- atomic_t to refcount_t conversion (Elena Reshetova)
- A few fixes and enhancements all over the place"
* 'ras-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
RAS/CEC: Check the correct variable in the debugfs error handling
x86/mce: Always save severity in machine_check_poll()
x86/MCE, xen/mcelog: Make /dev/mcelog registration messages more precise
x86/mce: Update bootlog description to reflect behavior on AMD
x86/mce: Don't disable MCA banks when offlining a CPU on AMD
x86/mce/mce-inject: Preset the MCE injection struct
x86/mce: Clean up include files
x86/mce: Get rid of register_mce_write_callback()
x86/mce: Merge mce_amd_inj into mce-inject
x86/mce/AMD: Use saved threshold block info in interrupt handler
x86/mce/AMD: Use msr_stat when clearing MCA_STATUS
x86/mce/AMD: Carve out SMCA bank configuration
x86/mce/AMD: Redo error logging from APIC LVT interrupt handlers
x86/mce: Convert threshold_bank.cpus from atomic_t to refcount_t
RAS: Make local function parse_ras_param() static
ACPI/APEI: Handle GSIV and GPIO notification types
Diffstat (limited to 'arch/x86/kernel/cpu/mcheck/dev-mcelog.c')
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/dev-mcelog.c | 55 |
1 files changed, 44 insertions, 11 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/dev-mcelog.c b/arch/x86/kernel/cpu/mcheck/dev-mcelog.c index 9c632cb88546..10cec43aac38 100644 --- a/arch/x86/kernel/cpu/mcheck/dev-mcelog.c +++ b/arch/x86/kernel/cpu/mcheck/dev-mcelog.c @@ -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 = { @@ -388,9 +415,15 @@ static __init int dev_mcelog_init_device(void) /* register character device /dev/mcelog */ err = misc_register(&mce_chrdev_device); if (err) { - pr_err("Unable to init device /dev/mcelog (rc: %d)\n", err); + if (err == -EBUSY) + /* Xen dom0 might have registered the device already. */ + pr_info("Unable to init device /dev/mcelog, already registered"); + else + pr_err("Unable to init device /dev/mcelog (rc: %d)\n", err); + return err; } + mce_register_decode_chain(&dev_mcelog_nb); return 0; } |