Commit 8632e9b5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hyperv-fixes-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux

Pull hyperv fixes from Wei Liu:

 - a series from Tianyu Lan to fix crash reporting on Hyper-V

 - three miscellaneous cleanup patches

* tag 'hyperv-fixes-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  x86/Hyper-V: Report crash data in die() when panic_on_oops is set
  x86/Hyper-V: Report crash register data when sysctl_record_panic_msg is not set
  x86/Hyper-V: Report crash register data or kmsg before running crash kernel
  x86/Hyper-V: Trigger crash enlightenment only once during system crash.
  x86/Hyper-V: Free hv_panic_page when fail to register kmsg dump
  x86/Hyper-V: Unload vmbus channel in hv panic callback
  x86: hyperv: report value of misc_features
  hv_debugfs: Make hv_debug_root static
  hv: hyperv_vmbus.h: Replace zero-length array with flexible-array member
parents 6cc9306b f3a99e76
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/hyperv.h> #include <linux/hyperv.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/cpuhotplug.h> #include <linux/cpuhotplug.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <clocksource/hyperv_timer.h> #include <clocksource/hyperv_timer.h>
...@@ -419,11 +420,14 @@ void hyperv_cleanup(void) ...@@ -419,11 +420,14 @@ void hyperv_cleanup(void)
} }
EXPORT_SYMBOL_GPL(hyperv_cleanup); EXPORT_SYMBOL_GPL(hyperv_cleanup);
void hyperv_report_panic(struct pt_regs *regs, long err) void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die)
{ {
static bool panic_reported; static bool panic_reported;
u64 guest_id; u64 guest_id;
if (in_die && !panic_on_oops)
return;
/* /*
* We prefer to report panic on 'die' chain as we have proper * We prefer to report panic on 'die' chain as we have proper
* registers to report, but if we miss it (e.g. on BUG()) we need * registers to report, but if we miss it (e.g. on BUG()) we need
......
...@@ -227,8 +227,8 @@ static void __init ms_hyperv_init_platform(void) ...@@ -227,8 +227,8 @@ static void __init ms_hyperv_init_platform(void)
ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES); ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES);
ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO); ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO);
pr_info("Hyper-V: features 0x%x, hints 0x%x\n", pr_info("Hyper-V: features 0x%x, hints 0x%x, misc 0x%x\n",
ms_hyperv.features, ms_hyperv.hints); ms_hyperv.features, ms_hyperv.hints, ms_hyperv.misc_features);
ms_hyperv.max_vp_index = cpuid_eax(HYPERV_CPUID_IMPLEMENT_LIMITS); ms_hyperv.max_vp_index = cpuid_eax(HYPERV_CPUID_IMPLEMENT_LIMITS);
ms_hyperv.max_lp_index = cpuid_ebx(HYPERV_CPUID_IMPLEMENT_LIMITS); ms_hyperv.max_lp_index = cpuid_ebx(HYPERV_CPUID_IMPLEMENT_LIMITS);
...@@ -263,6 +263,16 @@ static void __init ms_hyperv_init_platform(void) ...@@ -263,6 +263,16 @@ static void __init ms_hyperv_init_platform(void)
cpuid_eax(HYPERV_CPUID_NESTED_FEATURES); cpuid_eax(HYPERV_CPUID_NESTED_FEATURES);
} }
/*
* Hyper-V expects to get crash register data or kmsg when
* crash enlightment is available and system crashes. Set
* crash_kexec_post_notifiers to be true to make sure that
* calling crash enlightment interface before running kdump
* kernel.
*/
if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE)
crash_kexec_post_notifiers = true;
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS && if (ms_hyperv.features & HV_X64_ACCESS_FREQUENCY_MSRS &&
ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) { ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
......
...@@ -839,6 +839,9 @@ void vmbus_initiate_unload(bool crash) ...@@ -839,6 +839,9 @@ void vmbus_initiate_unload(bool crash)
{ {
struct vmbus_channel_message_header hdr; struct vmbus_channel_message_header hdr;
if (xchg(&vmbus_connection.conn_state, DISCONNECTED) == DISCONNECTED)
return;
/* Pre-Win2012R2 hosts don't support reconnect */ /* Pre-Win2012R2 hosts don't support reconnect */
if (vmbus_proto_version < VERSION_WIN8_1) if (vmbus_proto_version < VERSION_WIN8_1)
return; return;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include "hyperv_vmbus.h" #include "hyperv_vmbus.h"
struct dentry *hv_debug_root; static struct dentry *hv_debug_root;
static int hv_debugfs_delay_get(void *data, u64 *val) static int hv_debugfs_delay_get(void *data, u64 *val)
{ {
......
...@@ -292,7 +292,7 @@ struct vmbus_msginfo { ...@@ -292,7 +292,7 @@ struct vmbus_msginfo {
struct list_head msglist_entry; struct list_head msglist_entry;
/* The message itself */ /* The message itself */
unsigned char msg[0]; unsigned char msg[];
}; };
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/kernel.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <clocksource/hyperv_timer.h> #include <clocksource/hyperv_timer.h>
#include "hyperv_vmbus.h" #include "hyperv_vmbus.h"
...@@ -48,14 +49,35 @@ static int hyperv_cpuhp_online; ...@@ -48,14 +49,35 @@ static int hyperv_cpuhp_online;
static void *hv_panic_page; static void *hv_panic_page;
/*
* Boolean to control whether to report panic messages over Hyper-V.
*
* It can be set via /proc/sys/kernel/hyperv/record_panic_msg
*/
static int sysctl_record_panic_msg = 1;
static int hyperv_report_reg(void)
{
return !sysctl_record_panic_msg || !hv_panic_page;
}
static int hyperv_panic_event(struct notifier_block *nb, unsigned long val, static int hyperv_panic_event(struct notifier_block *nb, unsigned long val,
void *args) void *args)
{ {
struct pt_regs *regs; struct pt_regs *regs;
regs = current_pt_regs(); vmbus_initiate_unload(true);
hyperv_report_panic(regs, val); /*
* Hyper-V should be notified only once about a panic. If we will be
* doing hyperv_report_panic_msg() later with kmsg data, don't do
* the notification here.
*/
if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE
&& hyperv_report_reg()) {
regs = current_pt_regs();
hyperv_report_panic(regs, val, false);
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -65,7 +87,13 @@ static int hyperv_die_event(struct notifier_block *nb, unsigned long val, ...@@ -65,7 +87,13 @@ static int hyperv_die_event(struct notifier_block *nb, unsigned long val,
struct die_args *die = (struct die_args *)args; struct die_args *die = (struct die_args *)args;
struct pt_regs *regs = die->regs; struct pt_regs *regs = die->regs;
hyperv_report_panic(regs, val); /*
* Hyper-V should be notified only once about a panic. If we will be
* doing hyperv_report_panic_msg() later with kmsg data, don't do
* the notification here.
*/
if (hyperv_report_reg())
hyperv_report_panic(regs, val, true);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -1252,13 +1280,6 @@ static void vmbus_isr(void) ...@@ -1252,13 +1280,6 @@ static void vmbus_isr(void)
add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR, 0); add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR, 0);
} }
/*
* Boolean to control whether to report panic messages over Hyper-V.
*
* It can be set via /proc/sys/kernel/hyperv/record_panic_msg
*/
static int sysctl_record_panic_msg = 1;
/* /*
* Callback from kmsg_dump. Grab as much as possible from the end of the kmsg * Callback from kmsg_dump. Grab as much as possible from the end of the kmsg
* buffer and call into Hyper-V to transfer the data. * buffer and call into Hyper-V to transfer the data.
...@@ -1382,19 +1403,29 @@ static int vmbus_bus_init(void) ...@@ -1382,19 +1403,29 @@ static int vmbus_bus_init(void)
hv_panic_page = (void *)hv_alloc_hyperv_zeroed_page(); hv_panic_page = (void *)hv_alloc_hyperv_zeroed_page();
if (hv_panic_page) { if (hv_panic_page) {
ret = kmsg_dump_register(&hv_kmsg_dumper); ret = kmsg_dump_register(&hv_kmsg_dumper);
if (ret) if (ret) {
pr_err("Hyper-V: kmsg dump register " pr_err("Hyper-V: kmsg dump register "
"error 0x%x\n", ret); "error 0x%x\n", ret);
hv_free_hyperv_page(
(unsigned long)hv_panic_page);
hv_panic_page = NULL;
}
} else } else
pr_err("Hyper-V: panic message page memory " pr_err("Hyper-V: panic message page memory "
"allocation failed"); "allocation failed");
} }
register_die_notifier(&hyperv_die_block); register_die_notifier(&hyperv_die_block);
atomic_notifier_chain_register(&panic_notifier_list,
&hyperv_panic_block);
} }
/*
* Always register the panic notifier because we need to unload
* the VMbus channel connection to prevent any VMbus
* activity after the VM panics.
*/
atomic_notifier_chain_register(&panic_notifier_list,
&hyperv_panic_block);
vmbus_request_offers(); vmbus_request_offers();
return 0; return 0;
...@@ -1407,7 +1438,6 @@ static int vmbus_bus_init(void) ...@@ -1407,7 +1438,6 @@ static int vmbus_bus_init(void)
hv_remove_vmbus_irq(); hv_remove_vmbus_irq();
bus_unregister(&hv_bus); bus_unregister(&hv_bus);
hv_free_hyperv_page((unsigned long)hv_panic_page);
unregister_sysctl_table(hv_ctl_table_hdr); unregister_sysctl_table(hv_ctl_table_hdr);
hv_ctl_table_hdr = NULL; hv_ctl_table_hdr = NULL;
return ret; return ret;
...@@ -2204,8 +2234,6 @@ static int vmbus_bus_suspend(struct device *dev) ...@@ -2204,8 +2234,6 @@ static int vmbus_bus_suspend(struct device *dev)
vmbus_initiate_unload(false); vmbus_initiate_unload(false);
vmbus_connection.conn_state = DISCONNECTED;
/* Reset the event for the next resume. */ /* Reset the event for the next resume. */
reinit_completion(&vmbus_connection.ready_for_resume_event); reinit_completion(&vmbus_connection.ready_for_resume_event);
...@@ -2289,7 +2317,6 @@ static void hv_kexec_handler(void) ...@@ -2289,7 +2317,6 @@ static void hv_kexec_handler(void)
{ {
hv_stimer_global_cleanup(); hv_stimer_global_cleanup();
vmbus_initiate_unload(false); vmbus_initiate_unload(false);
vmbus_connection.conn_state = DISCONNECTED;
/* Make sure conn_state is set as hv_synic_cleanup checks for it */ /* Make sure conn_state is set as hv_synic_cleanup checks for it */
mb(); mb();
cpuhp_remove_state(hyperv_cpuhp_online); cpuhp_remove_state(hyperv_cpuhp_online);
...@@ -2306,7 +2333,6 @@ static void hv_crash_handler(struct pt_regs *regs) ...@@ -2306,7 +2333,6 @@ static void hv_crash_handler(struct pt_regs *regs)
* doing the cleanup for current CPU only. This should be sufficient * doing the cleanup for current CPU only. This should be sufficient
* for kdump. * for kdump.
*/ */
vmbus_connection.conn_state = DISCONNECTED;
cpu = smp_processor_id(); cpu = smp_processor_id();
hv_stimer_cleanup(cpu); hv_stimer_cleanup(cpu);
hv_synic_disable_regs(cpu); hv_synic_disable_regs(cpu);
......
...@@ -163,7 +163,7 @@ static inline int cpumask_to_vpset(struct hv_vpset *vpset, ...@@ -163,7 +163,7 @@ static inline int cpumask_to_vpset(struct hv_vpset *vpset,
return nr_bank; return nr_bank;
} }
void hyperv_report_panic(struct pt_regs *regs, long err); void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die);
void hyperv_report_panic_msg(phys_addr_t pa, size_t size); void hyperv_report_panic_msg(phys_addr_t pa, size_t size);
bool hv_is_hyperv_initialized(void); bool hv_is_hyperv_initialized(void);
bool hv_is_hibernation_supported(void); bool hv_is_hibernation_supported(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment