From 81b18bce48af3e222ca9eebb3b931f59141b7b49 Mon Sep 17 00:00:00 2001 From: Sunil Muthuswamy Date: Sun, 8 Jul 2018 02:56:51 +0000 Subject: Drivers: HV: Send one page worth of kmsg dump over Hyper-V during panic In the VM mode on Hyper-V, currently, when the kernel panics, an error code and few register values are populated in an MSR and the Hypervisor notified. This information is collected on the host. The amount of information currently collected is found to be limited and not very actionable. To gather more actionable data, such as stack trace, the proposal is to write one page worth of kmsg data on an allocated page and the Hypervisor notified of the page address through the MSR. - Sysctl option to control the behavior, with ON by default. Cc: K. Y. Srinivasan Cc: Stephen Hemminger Signed-off-by: Sunil Muthuswamy Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'drivers/hv/vmbus_drv.c') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index b10fe26c4891..05e37283d7c3 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -56,6 +56,8 @@ static struct completion probe_event; static int hyperv_cpuhp_online; +static void *hv_panic_page; + static int hyperv_panic_event(struct notifier_block *nb, unsigned long val, void *args) { @@ -1018,6 +1020,75 @@ static void vmbus_isr(void) 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 + * buffer and call into Hyper-V to transfer the data. + */ +static void hv_kmsg_dump(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason) +{ + size_t bytes_written; + phys_addr_t panic_pa; + + /* We are only interested in panics. */ + if ((reason != KMSG_DUMP_PANIC) || (!sysctl_record_panic_msg)) + return; + + panic_pa = virt_to_phys(hv_panic_page); + + /* + * Write dump contents to the page. No need to synchronize; panic should + * be single-threaded. + */ + if (!kmsg_dump_get_buffer(dumper, true, hv_panic_page, + PAGE_SIZE, &bytes_written)) { + pr_err("Hyper-V: Unable to get kmsg data for panic\n"); + return; + } + + hyperv_report_panic_msg(panic_pa, bytes_written); +} + +static struct kmsg_dumper hv_kmsg_dumper = { + .dump = hv_kmsg_dump, +}; + +static struct ctl_table_header *hv_ctl_table_hdr; +static int zero; +static int one = 1; + +/* + * sysctl option to allow the user to control whether kmsg data should be + * reported to Hyper-V on panic. + */ +static struct ctl_table hv_ctl_table[] = { + { + .procname = "hyperv_record_panic_msg", + .data = &sysctl_record_panic_msg, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one + }, + {} +}; + +static struct ctl_table hv_root_table[] = { + { + .procname = "kernel", + .mode = 0555, + .child = hv_ctl_table + }, + {} +}; /* * vmbus_bus_init -Main vmbus driver initialization routine. @@ -1065,6 +1136,32 @@ static int vmbus_bus_init(void) * Only register if the crash MSRs are available */ if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { + u64 hyperv_crash_ctl; + /* + * Sysctl registration is not fatal, since by default + * reporting is enabled. + */ + hv_ctl_table_hdr = register_sysctl_table(hv_root_table); + if (!hv_ctl_table_hdr) + pr_err("Hyper-V: sysctl table register error"); + + /* + * Register for panic kmsg callback only if the right + * capability is supported by the hypervisor. + */ + rdmsrl(HV_X64_MSR_CRASH_CTL, hyperv_crash_ctl); + if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) { + hv_panic_page = (void *)get_zeroed_page(GFP_KERNEL); + if (hv_panic_page) { + ret = kmsg_dump_register(&hv_kmsg_dumper); + if (ret) + pr_err("Hyper-V: kmsg dump register " + "error 0x%x\n", ret); + } else + pr_err("Hyper-V: panic message page memory " + "allocation failed"); + } + register_die_notifier(&hyperv_die_block); atomic_notifier_chain_register(&panic_notifier_list, &hyperv_panic_block); @@ -1081,6 +1178,11 @@ err_alloc: hv_remove_vmbus_irq(); bus_unregister(&hv_bus); + free_page((unsigned long)hv_panic_page); + if (!hv_ctl_table_hdr) { + unregister_sysctl_table(hv_ctl_table_hdr); + hv_ctl_table_hdr = NULL; + } return ret; } @@ -1785,10 +1887,18 @@ static void __exit vmbus_exit(void) vmbus_free_channels(); if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { + kmsg_dump_unregister(&hv_kmsg_dumper); unregister_die_notifier(&hyperv_die_block); atomic_notifier_chain_unregister(&panic_notifier_list, &hyperv_panic_block); } + + free_page((unsigned long)hv_panic_page); + if (!hv_ctl_table_hdr) { + unregister_sysctl_table(hv_ctl_table_hdr); + hv_ctl_table_hdr = NULL; + } + bus_unregister(&hv_bus); cpuhp_remove_state(hyperv_cpuhp_online); -- cgit v1.2.3 From ddcaf3ca4c3c87b955ad6f57952250030be77791 Mon Sep 17 00:00:00 2001 From: Sunil Muthuswamy Date: Sat, 28 Jul 2018 21:58:45 +0000 Subject: Drivers: hv: vmus: Fix the check for return value from kmsg get dump buffer The code to support panic control message was checking the return was checking the return value from kmsg_dump_get_buffer as error value, which is not what the routine returns. This fixes it. Fixes: 81b18bce48af ("Drivers: HV: Send one page worth of kmsg dump over Hyper-V during panic") Signed-off-by: Sunil Muthuswamy Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/hv/vmbus_drv.c') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 05e37283d7c3..a7f33c1f42c5 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1047,13 +1047,10 @@ static void hv_kmsg_dump(struct kmsg_dumper *dumper, * Write dump contents to the page. No need to synchronize; panic should * be single-threaded. */ - if (!kmsg_dump_get_buffer(dumper, true, hv_panic_page, - PAGE_SIZE, &bytes_written)) { - pr_err("Hyper-V: Unable to get kmsg data for panic\n"); - return; - } - - hyperv_report_panic_msg(panic_pa, bytes_written); + kmsg_dump_get_buffer(dumper, true, hv_panic_page, PAGE_SIZE, + &bytes_written); + if (bytes_written) + hyperv_report_panic_msg(panic_pa, bytes_written); } static struct kmsg_dumper hv_kmsg_dumper = { -- cgit v1.2.3 From 8afc06dd75c06b9d6e70e4a72fdafbd4cab8d1df Mon Sep 17 00:00:00 2001 From: Sunil Muthuswamy Date: Sat, 28 Jul 2018 21:58:46 +0000 Subject: Drivers: hv: vmbus: Fix the issue with freeing up hv_ctl_table_hdr The check to free the Hyper-V control table header was reversed. This fixes it. Fixes: 81b18bce48af ("Drivers: HV: Send one page worth of kmsg dump over Hyper-V during panic") Signed-off-by: Sunil Muthuswamy Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/hv/vmbus_drv.c') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index a7f33c1f42c5..5e946b1be54c 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1176,11 +1176,8 @@ err_alloc: bus_unregister(&hv_bus); free_page((unsigned long)hv_panic_page); - if (!hv_ctl_table_hdr) { - unregister_sysctl_table(hv_ctl_table_hdr); - hv_ctl_table_hdr = NULL; - } - + unregister_sysctl_table(hv_ctl_table_hdr); + hv_ctl_table_hdr = NULL; return ret; } @@ -1891,11 +1888,8 @@ static void __exit vmbus_exit(void) } free_page((unsigned long)hv_panic_page); - if (!hv_ctl_table_hdr) { - unregister_sysctl_table(hv_ctl_table_hdr); - hv_ctl_table_hdr = NULL; - } - + unregister_sysctl_table(hv_ctl_table_hdr); + hv_ctl_table_hdr = NULL; bus_unregister(&hv_bus); cpuhp_remove_state(hyperv_cpuhp_online); -- cgit v1.2.3 From 9d9c9656871cd9fc1d03a2b4f47a278d54c6d03d Mon Sep 17 00:00:00 2001 From: Sunil Muthuswamy Date: Sat, 28 Jul 2018 21:58:47 +0000 Subject: Drivers: hv: vmbus: Get rid of MSR access from vmbus_drv.c Get rid of ISA specific code from vmus_drv.c which is common code. Fixes: 81b18bce48af ("Drivers: HV: Send one page worth of kmsg dump over Hyper-V during panic") Signed-off-by: Sunil Muthuswamy Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/mshyperv.h | 3 +++ drivers/hv/vmbus_drv.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/hv/vmbus_drv.c') diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index 406da8d159e3..4d82ad347b75 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -97,6 +97,9 @@ static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) #define hv_set_synint_state(int_num, val) \ wrmsrl(HV_X64_MSR_SINT0 + int_num, val) +#define hv_get_crash_ctl(val) \ + rdmsrl(HV_X64_MSR_CRASH_CTL, val) + void hyperv_callback_vector(void); void hyperv_reenlightenment_vector(void); #ifdef CONFIG_TRACING diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 5e946b1be54c..db145e1a7049 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1146,7 +1146,7 @@ static int vmbus_bus_init(void) * Register for panic kmsg callback only if the right * capability is supported by the hypervisor. */ - rdmsrl(HV_X64_MSR_CRASH_CTL, hyperv_crash_ctl); + hv_get_crash_ctl(hyperv_crash_ctl); if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) { hv_panic_page = (void *)get_zeroed_page(GFP_KERNEL); if (hv_panic_page) { -- cgit v1.2.3 From 7ceb1c37533e2298797188087796dd44931d86af Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 28 Jul 2018 21:58:48 +0000 Subject: Drivers: hv: vmbus: add numa_node to sysfs Being able to find the numa_node for a device is useful for userspace drivers (DPDK) and also for diagnosing performance issues. This makes vmbus similar to pci. Signed-off-by: Stephen Hemminger Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/stable/sysfs-bus-vmbus | 7 +++++++ drivers/hv/vmbus_drv.c | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'drivers/hv/vmbus_drv.c') diff --git a/Documentation/ABI/stable/sysfs-bus-vmbus b/Documentation/ABI/stable/sysfs-bus-vmbus index 3eaffbb2d468..3fed8fdb873d 100644 --- a/Documentation/ABI/stable/sysfs-bus-vmbus +++ b/Documentation/ABI/stable/sysfs-bus-vmbus @@ -42,6 +42,13 @@ Contact: K. Y. Srinivasan Description: The 16 bit vendor ID of the device Users: tools/hv/lsvmbus and user level RDMA libraries +What: /sys/bus/vmbus/devices//numa_node +Date: Jul 2018 +KernelVersion: 4.19 +Contact: Stephen Hemminger +Description: This NUMA node to which the VMBUS device is + attached, or -1 if the node is unknown. + What: /sys/bus/vmbus/devices//channels/ Date: September. 2017 KernelVersion: 4.14 diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index db145e1a7049..b1b548a21f91 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -210,6 +210,20 @@ static ssize_t modalias_show(struct device *dev, } static DEVICE_ATTR_RO(modalias); +#ifdef CONFIG_NUMA +static ssize_t numa_node_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hv_device *hv_dev = device_to_hv_device(dev); + + if (!hv_dev->channel) + return -ENODEV; + + return sprintf(buf, "%d\n", hv_dev->channel->numa_node); +} +static DEVICE_ATTR_RO(numa_node); +#endif + static ssize_t server_monitor_pending_show(struct device *dev, struct device_attribute *dev_attr, char *buf) @@ -492,6 +506,9 @@ static struct attribute *vmbus_dev_attrs[] = { &dev_attr_class_id.attr, &dev_attr_device_id.attr, &dev_attr_modalias.attr, +#ifdef CONFIG_NUMA + &dev_attr_numa_node.attr, +#endif &dev_attr_server_monitor_pending.attr, &dev_attr_client_monitor_pending.attr, &dev_attr_server_monitor_latency.attr, -- cgit v1.2.3