diff options
| author | Vitaly Kuznetsov <vkuznets@redhat.com> | 2015-02-27 14:25:55 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-03-01 22:29:05 -0500 |
| commit | e72e7ac583ee8adddbc668cdefde7d7d3021be79 (patch) | |
| tree | bd95e80877bcaf358b6902125d6fc7d132940143 /drivers/hv | |
| parent | 09a196288ec4617a920e051af6651ce03968c8b9 (diff) | |
drivers: hv: vmbus: Teardown synthetic interrupt controllers on module unload
SynIC has to be switched off when we unload the module, otherwise registered
memory pages can get corrupted after (as Hyper-V host still writes there) and
we see the following crashes for random processes:
[ 89.116774] BUG: Bad page map in process sh pte:4989c716 pmd:36f81067
[ 89.159454] addr:0000000000437000 vm_flags:00000875 anon_vma: (null) mapping:ffff88007bba55a0 index:37
[ 89.226146] vma->vm_ops->fault: filemap_fault+0x0/0x410
[ 89.257776] vma->vm_file->f_op->mmap: generic_file_mmap+0x0/0x60
[ 89.297570] CPU: 0 PID: 215 Comm: sh Tainted: G B 3.19.0-rc5_bug923184+ #488
[ 89.353738] Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS 090006 05/23/2012
[ 89.409138] 0000000000000000 000000004e083d7b ffff880036e9fa18 ffffffff81a68d31
[ 89.468724] 0000000000000000 0000000000437000 ffff880036e9fa68 ffffffff811a1e3a
[ 89.519233] 000000004989c716 0000000000000037 ffffea0001edc340 0000000000437000
[ 89.575751] Call Trace:
[ 89.591060] [<ffffffff81a68d31>] dump_stack+0x45/0x57
[ 89.625164] [<ffffffff811a1e3a>] print_bad_pte+0x1aa/0x250
[ 89.667234] [<ffffffff811a2c95>] vm_normal_page+0x55/0xa0
[ 89.703818] [<ffffffff811a3105>] unmap_page_range+0x425/0x8a0
[ 89.737982] [<ffffffff811a3601>] unmap_single_vma+0x81/0xf0
[ 89.780385] [<ffffffff81184320>] ? lru_deactivate_fn+0x190/0x190
[ 89.820130] [<ffffffff811a4131>] unmap_vmas+0x51/0xa0
[ 89.860168] [<ffffffff811ad12c>] exit_mmap+0xac/0x1a0
[ 89.890588] [<ffffffff810763c3>] mmput+0x63/0x100
[ 89.919205] [<ffffffff811eba48>] flush_old_exec+0x3f8/0x8b0
[ 89.962135] [<ffffffff8123b5bb>] load_elf_binary+0x32b/0x1260
[ 89.998581] [<ffffffff811a14f2>] ? get_user_pages+0x52/0x60
hv_synic_cleanup() function exists but noone calls it now. Do the following:
- call hv_synic_cleanup() on each cpu from vmbus_exit();
- write global disable bit through MSR;
- use hv_synic_free_cpu() to avoid memory leask and code duplication.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv')
| -rw-r--r-- | drivers/hv/hv.c | 9 | ||||
| -rw-r--r-- | drivers/hv/vmbus_drv.c | 4 |
2 files changed, 11 insertions, 2 deletions
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 50e51a51ff8b..39531dcf582f 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c | |||
| @@ -477,6 +477,7 @@ void hv_synic_cleanup(void *arg) | |||
| 477 | union hv_synic_sint shared_sint; | 477 | union hv_synic_sint shared_sint; |
| 478 | union hv_synic_simp simp; | 478 | union hv_synic_simp simp; |
| 479 | union hv_synic_siefp siefp; | 479 | union hv_synic_siefp siefp; |
| 480 | union hv_synic_scontrol sctrl; | ||
| 480 | int cpu = smp_processor_id(); | 481 | int cpu = smp_processor_id(); |
| 481 | 482 | ||
| 482 | if (!hv_context.synic_initialized) | 483 | if (!hv_context.synic_initialized) |
| @@ -502,6 +503,10 @@ void hv_synic_cleanup(void *arg) | |||
| 502 | 503 | ||
| 503 | wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); | 504 | wrmsrl(HV_X64_MSR_SIEFP, siefp.as_uint64); |
| 504 | 505 | ||
| 505 | free_page((unsigned long)hv_context.synic_message_page[cpu]); | 506 | /* Disable the global synic bit */ |
| 506 | free_page((unsigned long)hv_context.synic_event_page[cpu]); | 507 | rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64); |
| 508 | sctrl.enable = 0; | ||
| 509 | wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64); | ||
| 510 | |||
| 511 | hv_synic_free_cpu(cpu); | ||
| 507 | } | 512 | } |
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 76db97de09fd..d8233d4513a5 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c | |||
| @@ -1029,11 +1029,15 @@ cleanup: | |||
| 1029 | 1029 | ||
| 1030 | static void __exit vmbus_exit(void) | 1030 | static void __exit vmbus_exit(void) |
| 1031 | { | 1031 | { |
| 1032 | int cpu; | ||
| 1033 | |||
| 1032 | vmbus_connection.conn_state = DISCONNECTED; | 1034 | vmbus_connection.conn_state = DISCONNECTED; |
| 1033 | hv_remove_vmbus_irq(); | 1035 | hv_remove_vmbus_irq(); |
| 1034 | vmbus_free_channels(); | 1036 | vmbus_free_channels(); |
| 1035 | bus_unregister(&hv_bus); | 1037 | bus_unregister(&hv_bus); |
| 1036 | hv_cleanup(); | 1038 | hv_cleanup(); |
| 1039 | for_each_online_cpu(cpu) | ||
| 1040 | smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); | ||
| 1037 | acpi_bus_unregister_driver(&vmbus_acpi_driver); | 1041 | acpi_bus_unregister_driver(&vmbus_acpi_driver); |
| 1038 | hv_cpu_hotplug_quirk(false); | 1042 | hv_cpu_hotplug_quirk(false); |
| 1039 | vmbus_disconnect(); | 1043 | vmbus_disconnect(); |
