diff options
Diffstat (limited to 'drivers/hv')
| -rw-r--r-- | drivers/hv/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/hv/Makefile | 1 | ||||
| -rw-r--r-- | drivers/hv/channel_mgmt.c | 16 | ||||
| -rw-r--r-- | drivers/hv/hv_proc.c | 47 | ||||
| -rw-r--r-- | drivers/hv/hyperv_vmbus.h | 3 | ||||
| -rw-r--r-- | drivers/hv/mshv_eventfd.c | 14 | ||||
| -rw-r--r-- | drivers/hv/mshv_irq.c | 4 | ||||
| -rw-r--r-- | drivers/hv/mshv_root.h | 1 | ||||
| -rw-r--r-- | drivers/hv/mshv_root_hv_call.c | 22 | ||||
| -rw-r--r-- | drivers/hv/mshv_root_main.c | 84 | ||||
| -rw-r--r-- | drivers/hv/mshv_trace.c | 9 | ||||
| -rw-r--r-- | drivers/hv/mshv_trace.h | 544 | ||||
| -rw-r--r-- | drivers/hv/mshv_vtl_main.c | 12 | ||||
| -rw-r--r-- | drivers/hv/vmbus_drv.c | 29 |
14 files changed, 742 insertions, 46 deletions
diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 7937ac0cbd0f..2d0b3fcb0ff8 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -9,7 +9,6 @@ config HYPERV select PARAVIRT select X86_HV_CALLBACK_VECTOR if X86 select OF_EARLY_FLATTREE if OF - select SYSFB if EFI && !HYPERV_VTL_MODE select IRQ_MSI_LIB if X86 help Select this option to run Linux as a Hyper-V client operating @@ -62,6 +61,7 @@ config HYPERV_VMBUS tristate "Microsoft Hyper-V VMBus driver" depends on HYPERV default HYPERV + select SYSFB if EFI && !HYPERV_VTL_MODE help Select this option to enable Hyper-V Vmbus driver. diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile index 2593711c3628..888a748cc7cb 100644 --- a/drivers/hv/Makefile +++ b/drivers/hv/Makefile @@ -16,6 +16,7 @@ hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_utils_transport.o mshv_root-y := mshv_root_main.o mshv_synic.o mshv_eventfd.o mshv_irq.o \ mshv_root_hv_call.o mshv_portid_table.o mshv_regions.o mshv_root-$(CONFIG_DEBUG_FS) += mshv_debugfs.o +mshv_root-$(CONFIG_TRACEPOINTS) += mshv_trace.o mshv_vtl-y := mshv_vtl_main.o # Code that must be built-in diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 7c77ada12b2e..84eb0a6a0b54 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -384,8 +384,18 @@ static void free_channel(struct vmbus_channel *channel) void vmbus_channel_map_relid(struct vmbus_channel *channel) { - if (WARN_ON(channel->offermsg.child_relid >= MAX_CHANNEL_RELIDS)) + u32 new_relid = channel->offermsg.child_relid; + + if (WARN_ON(new_relid >= MAX_CHANNEL_RELIDS)) return; + + /* + * This function is always called in the tasklet for the connect CPU. + * So updating the relid hiwater mark does not need to be atomic. + */ + if (new_relid > READ_ONCE(vmbus_connection.relid_hiwater)) + WRITE_ONCE(vmbus_connection.relid_hiwater, new_relid); + /* * The mapping of the channel's relid is visible from the CPUs that * execute vmbus_chan_sched() by the time that vmbus_chan_sched() will @@ -411,9 +421,7 @@ void vmbus_channel_map_relid(struct vmbus_channel *channel) * of the VMBus driver and vmbus_chan_sched() can not run before * vmbus_bus_resume() has completed execution (cf. resume_noirq). */ - virt_store_mb( - vmbus_connection.channels[channel->offermsg.child_relid], - channel); + virt_store_mb(vmbus_connection.channels[new_relid], channel); } void vmbus_channel_unmap_relid(struct vmbus_channel *channel) diff --git a/drivers/hv/hv_proc.c b/drivers/hv/hv_proc.c index 3cb4b2a3035c..57b2c64197cb 100644 --- a/drivers/hv/hv_proc.c +++ b/drivers/hv/hv_proc.c @@ -239,3 +239,50 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags) return ret; } EXPORT_SYMBOL_GPL(hv_call_create_vp); + +int hv_call_notify_all_processors_started(void) +{ + struct hv_input_notify_partition_event *input; + u64 status; + unsigned long irq_flags; + int ret = 0; + + local_irq_save(irq_flags); + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + memset(input, 0, sizeof(*input)); + input->event = HV_PARTITION_ALL_LOGICAL_PROCESSORS_STARTED; + status = hv_do_hypercall(HVCALL_NOTIFY_PARTITION_EVENT, + input, NULL); + local_irq_restore(irq_flags); + + if (!hv_result_success(status)) { + hv_status_err(status, "\n"); + ret = hv_result_to_errno(status); + } + return ret; +} + +bool hv_lp_exists(u32 lp_index) +{ + struct hv_input_get_logical_processor_run_time *input; + struct hv_output_get_logical_processor_run_time *output; + unsigned long flags; + u64 status; + + local_irq_save(flags); + input = *this_cpu_ptr(hyperv_pcpu_input_arg); + output = *this_cpu_ptr(hyperv_pcpu_output_arg); + + input->lp_index = lp_index; + status = hv_do_hypercall(HVCALL_GET_LOGICAL_PROCESSOR_RUN_TIME, + input, output); + local_irq_restore(flags); + + if (!hv_result_success(status) && + hv_result(status) != HV_STATUS_INVALID_LP_INDEX) { + hv_status_err(status, "\n"); + BUG(); + } + + return hv_result_success(status); +} diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 31f576464f18..05a36854389a 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -276,8 +276,9 @@ struct vmbus_connection { struct list_head chn_list; struct mutex channel_mutex; - /* Array of channels */ + /* Array of channel pointers, indexed by relid */ struct vmbus_channel **channels; + u32 relid_hiwater; /* * An offer message is handled first on the work_queue, and then diff --git a/drivers/hv/mshv_eventfd.c b/drivers/hv/mshv_eventfd.c index d8471546e6a0..90959f639dc3 100644 --- a/drivers/hv/mshv_eventfd.c +++ b/drivers/hv/mshv_eventfd.c @@ -733,6 +733,14 @@ static int mshv_assign_ioeventfd(struct mshv_partition *pt, ret = mshv_register_doorbell(pt->pt_id, ioeventfd_mmio_write, (void *)pt, p->iovntfd_addr, p->iovntfd_datamatch, doorbell_flags); + + trace_mshv_assign_ioeventfd(pt->pt_id, p->iovntfd_addr, + p->iovntfd_length, + p->iovntfd_datamatch, + p->iovntfd_wildcard, + p->iovntfd_eventfd, + ret); + if (ret < 0) goto unlock_fail; @@ -780,6 +788,12 @@ static int mshv_deassign_ioeventfd(struct mshv_partition *pt, p->iovntfd_datamatch != args->datamatch) continue; + trace_mshv_deassign_ioeventfd(pt->pt_id, p->iovntfd_addr, + p->iovntfd_length, + p->iovntfd_datamatch, + p->iovntfd_wildcard, + p->iovntfd_eventfd); + hlist_del_rcu(&p->iovntfd_hnode); synchronize_rcu(); ioeventfd_release(p, pt->pt_id); diff --git a/drivers/hv/mshv_irq.c b/drivers/hv/mshv_irq.c index 02c56fc3a498..b3142c84dcbc 100644 --- a/drivers/hv/mshv_irq.c +++ b/drivers/hv/mshv_irq.c @@ -71,6 +71,10 @@ swap_routes: mutex_unlock(&partition->pt_irq_lock); synchronize_srcu_expedited(&partition->pt_irq_srcu); + + trace_mshv_update_routing_table(partition->pt_id, + old, new, numents); + new = old; out: diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h index 826798f1a8ec..1f086dcb7aa1 100644 --- a/drivers/hv/mshv_root.h +++ b/drivers/hv/mshv_root.h @@ -17,6 +17,7 @@ #include <linux/build_bug.h> #include <linux/mmu_notifier.h> #include <uapi/linux/mshv.h> +#include "mshv_trace.h" /* * Hypervisor must be between these version numbers (inclusive) diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c index 7f91096f95a8..cb55d4d4be2e 100644 --- a/drivers/hv/mshv_root_hv_call.c +++ b/drivers/hv/mshv_root_hv_call.c @@ -45,8 +45,7 @@ int hv_call_withdraw_memory(u64 count, int node, u64 partition_id) struct hv_output_withdraw_memory *output_page; struct page *page; u16 completed; - unsigned long remaining = count; - u64 status; + u64 status, withdrawn = 0; int i; unsigned long flags; @@ -55,7 +54,7 @@ int hv_call_withdraw_memory(u64 count, int node, u64 partition_id) return -ENOMEM; output_page = page_address(page); - while (remaining) { + while (withdrawn < count) { local_irq_save(flags); input_page = *this_cpu_ptr(hyperv_pcpu_input_arg); @@ -63,7 +62,7 @@ int hv_call_withdraw_memory(u64 count, int node, u64 partition_id) memset(input_page, 0, sizeof(*input_page)); input_page->partition_id = partition_id; status = hv_do_rep_hypercall(HVCALL_WITHDRAW_MEMORY, - min(remaining, HV_WITHDRAW_BATCH_SIZE), + min(count - withdrawn, HV_WITHDRAW_BATCH_SIZE), 0, input_page, output_page); local_irq_restore(flags); @@ -79,10 +78,12 @@ int hv_call_withdraw_memory(u64 count, int node, u64 partition_id) break; } - remaining -= completed; + withdrawn += completed; } free_page((unsigned long)output_page); + trace_mshv_hvcall_withdraw_memory(partition_id, withdrawn, status); + return hv_result_to_errno(status); } @@ -126,6 +127,8 @@ int hv_call_create_partition(u64 flags, ret = hv_deposit_memory(hv_current_partition_id, status); } while (!ret); + trace_mshv_hvcall_create_partition(flags, ret ? ret : *partition_id); + return ret; } @@ -153,6 +156,8 @@ int hv_call_initialize_partition(u64 partition_id) ret = hv_deposit_memory(partition_id, status); } while (!ret); + trace_mshv_hvcall_initialize_partition(partition_id, status); + return ret; } @@ -165,6 +170,8 @@ int hv_call_finalize_partition(u64 partition_id) status = hv_do_fast_hypercall8(HVCALL_FINALIZE_PARTITION, *(u64 *)&input); + trace_mshv_hvcall_finalize_partition(partition_id, status); + return hv_result_to_errno(status); } @@ -176,6 +183,8 @@ int hv_call_delete_partition(u64 partition_id) input.partition_id = partition_id; status = hv_do_fast_hypercall8(HVCALL_DELETE_PARTITION, *(u64 *)&input); + trace_mshv_hvcall_delete_partition(partition_id, status); + return hv_result_to_errno(status); } @@ -573,6 +582,9 @@ static int hv_call_map_vp_state_page(u64 partition_id, u32 vp_index, u32 type, ret = hv_deposit_memory(partition_id, status); } while (!ret); + trace_mshv_hvcall_map_vp_state_page(partition_id, vp_index, + type, status); + return ret; } diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index c8e5523a52b6..bd1359eb58dd 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -429,6 +429,17 @@ mshv_vp_dispatch(struct mshv_vp *vp, u32 flags, status = hv_do_hypercall(HVCALL_DISPATCH_VP, input, output); vp->run.flags.root_sched_dispatched = 0; + trace_mshv_hvcall_dispatch_vp(vp->vp_partition->pt_id, + vp->vp_index, flags, + output->dispatch_state, + output->dispatch_event, +#if defined(CONFIG_X86_64) + vp->vp_register_page->interrupt_vectors.as_uint64, +#else + 0, +#endif + status); + *res = *output; preempt_enable(); @@ -451,6 +462,9 @@ mshv_vp_clear_explicit_suspend(struct mshv_vp *vp) ret = mshv_set_vp_registers(vp->vp_index, vp->vp_partition->pt_id, 1, &explicit_suspend); + trace_mshv_vp_clear_explicit_suspend(vp->vp_partition->pt_id, + vp->vp_index, ret); + if (ret) vp_err(vp, "Failed to unsuspend\n"); @@ -493,6 +507,12 @@ mshv_vp_wait_for_hv_kick(struct mshv_vp *vp) if (ret) return -EINTR; + trace_mshv_vp_wait_for_hv_kick(vp->vp_partition->pt_id, + vp->vp_index, + vp->run.kicked_by_hv, + mshv_vp_dispatch_thread_blocked(vp), + mshv_vp_interrupt_pending(vp)); + vp->run.flags.root_sched_blocked = 0; vp->run.kicked_by_hv = 0; @@ -521,6 +541,12 @@ static long mshv_run_vp_with_root_scheduler(struct mshv_vp *vp) if (__xfer_to_guest_mode_work_pending()) { ret = xfer_to_guest_mode_handle_work(); + + trace_mshv_xfer_to_guest_mode_work(vp->vp_partition->pt_id, + vp->vp_index, + read_thread_flags(), + ret); + if (ret) break; } @@ -648,7 +674,7 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp) region = mshv_partition_region_by_gfn_get(p, gfn); if (!region) - return false; + goto out; if (access_type == HV_INTERCEPT_ACCESS_WRITE && !(region->hv_map_flags & HV_MAP_GPA_WRITABLE)) @@ -664,7 +690,9 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp) put_region: mshv_region_put(region); - +out: + trace_mshv_handle_gpa_intercept(p->pt_id, vp->vp_index, gfn, + access_type, ret); return ret; } @@ -681,6 +709,8 @@ static long mshv_vp_ioctl_run_vp(struct mshv_vp *vp, void __user *ret_msg) { long rc; + trace_mshv_run_vp_entry(vp->vp_partition->pt_id, vp->vp_index); + do { if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) rc = mshv_run_vp_with_root_scheduler(vp); @@ -688,6 +718,10 @@ static long mshv_vp_ioctl_run_vp(struct mshv_vp *vp, void __user *ret_msg) rc = mshv_run_vp_with_hyp_scheduler(vp); } while (rc == 0 && mshv_vp_handle_intercept(vp)); + trace_mshv_run_vp_exit(vp->vp_partition->pt_id, vp->vp_index, + vp->vp_intercept_msg_page->header.message_type, + rc); + if (rc) return rc; @@ -949,6 +983,8 @@ mshv_vp_release(struct inode *inode, struct file *filp) { struct mshv_vp *vp = filp->private_data; + trace_mshv_vp_release(vp->vp_partition->pt_id, vp->vp_index); + /* Rest of VP cleanup happens in destroy_partition() */ mshv_partition_put(vp->vp_partition); return 0; @@ -1121,7 +1157,7 @@ mshv_partition_ioctl_create_vp(struct mshv_partition *partition, partition->pt_vp_count++; partition->pt_vp_array[args.vp_index] = vp; - return ret; + goto out; remove_debugfs_vp: mshv_debugfs_vp_remove(vp); @@ -1147,6 +1183,8 @@ unmap_intercept_message_page: intercept_msg_page, input_vtl_zero); destroy_vp: hv_call_delete_vp(partition->pt_id, args.vp_index); +out: + trace_mshv_create_vp(partition->pt_id, args.vp_index, ret); return ret; } @@ -1346,6 +1384,10 @@ mshv_map_user_memory(struct mshv_partition *partition, break; } + trace_mshv_map_user_memory(partition->pt_id, region->start_uaddr, + region->start_gfn, region->nr_pages, + region->hv_map_flags, ret); + if (ret) goto errout; @@ -1641,6 +1683,9 @@ disable_vp_dispatch(struct mshv_vp *vp) if (ret) vp_err(vp, "failed to suspend\n"); + trace_mshv_disable_vp_dispatch(vp->vp_partition->pt_id, + vp->vp_index, ret); + return ret; } @@ -1689,6 +1734,8 @@ drain_vp_signals(struct mshv_vp *vp) vp->run.kicked_by_hv = 0; vp_signal_count = atomic64_read(&vp->run.vp_signaled_count); } + + trace_mshv_drain_vp_signals(vp->vp_partition->pt_id, vp->vp_index); } static void drain_all_vps(const struct mshv_partition *partition) @@ -1742,6 +1789,8 @@ static void destroy_partition(struct mshv_partition *partition) return; } + trace_mshv_destroy_partition(partition->pt_id); + if (partition->pt_initialized) { /* * We only need to drain signals for root scheduler. This should be @@ -1848,6 +1897,8 @@ mshv_partition_release(struct inode *inode, struct file *filp) { struct mshv_partition *partition = filp->private_data; + trace_mshv_partition_release(partition->pt_id); + mshv_eventfd_release(partition); cleanup_srcu_struct(&partition->pt_irq_srcu); @@ -1977,6 +2028,7 @@ mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev) struct hv_partition_creation_properties creation_properties; union hv_partition_isolation_properties isolation_properties; struct mshv_partition *partition; + u64 pt_id = -1; long ret; ret = mshv_ioctl_process_pt_flags(user_arg, &creation_flags, @@ -2016,22 +2068,29 @@ mshv_ioctl_create_partition(void __user *user_arg, struct device *module_dev) ret = hv_call_create_partition(creation_flags, creation_properties, isolation_properties, - &partition->pt_id); + &pt_id); if (ret) goto cleanup_irq_srcu; + partition->pt_id = pt_id; + ret = add_partition(partition); if (ret) goto delete_partition; ret = mshv_init_async_handler(partition); - if (!ret) { - ret = FD_ADD(O_CLOEXEC, anon_inode_getfile("mshv_partition", - &mshv_partition_fops, - partition, O_RDWR)); - if (ret >= 0) - return ret; - } + if (ret) + goto remove_partition; + + ret = FD_ADD(O_CLOEXEC, anon_inode_getfile("mshv_partition", + &mshv_partition_fops, + partition, O_RDWR)); + if (ret < 0) + goto remove_partition; + + goto out; + +remove_partition: remove_partition(partition); delete_partition: hv_call_delete_partition(partition->pt_id); @@ -2039,7 +2098,8 @@ cleanup_irq_srcu: cleanup_srcu_struct(&partition->pt_irq_srcu); free_partition: kfree(partition); - +out: + trace_mshv_create_partition(pt_id, ret); return ret; } diff --git a/drivers/hv/mshv_trace.c b/drivers/hv/mshv_trace.c new file mode 100644 index 000000000000..0936b2f95edd --- /dev/null +++ b/drivers/hv/mshv_trace.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2026, Microsoft Corporation. + * + * Tracepoint definitions for mshv driver. + */ + +#define CREATE_TRACE_POINTS +#include "mshv_trace.h" diff --git a/drivers/hv/mshv_trace.h b/drivers/hv/mshv_trace.h new file mode 100644 index 000000000000..e7280c47e579 --- /dev/null +++ b/drivers/hv/mshv_trace.h @@ -0,0 +1,544 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2026, Microsoft Corporation. + * + * Tracepoint declarations for mshv driver. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mshv + +#if !defined(__MSHV_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _MSHV_TRACE_H_ + +#include <linux/tracepoint.h> +#include <hyperv/hvhdk.h> + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/hv + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE mshv_trace + +TRACE_EVENT(mshv_create_partition, + TP_PROTO(u64 partition_id, int vm_fd), + TP_ARGS(partition_id, vm_fd), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(int, vm_fd) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vm_fd = vm_fd; + ), + TP_printk("partition_id=%llu vm_fd=%d", + __entry->partition_id, + __entry->vm_fd + ) +); + +TRACE_EVENT(mshv_hvcall_create_partition, + TP_PROTO(u64 flags, s64 partition_id), + TP_ARGS(flags, partition_id), + TP_STRUCT__entry( + __field(u64, flags) + __field(s64, partition_id) + ), + TP_fast_assign( + __entry->flags = flags; + __entry->partition_id = partition_id; + ), + TP_printk("flags=%#llx partition_id=%lld", + __entry->flags, + __entry->partition_id + ) +); + +TRACE_EVENT(mshv_hvcall_initialize_partition, + TP_PROTO(u64 partition_id, u64 status), + TP_ARGS(partition_id, status), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u64, status) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->status = status; + ), + TP_printk("partition_id=%llu status=%#llx", + __entry->partition_id, + __entry->status + ) +); + +TRACE_EVENT(mshv_partition_release, + TP_PROTO(u64 partition_id), + TP_ARGS(partition_id), + TP_STRUCT__entry( + __field(u64, partition_id) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + ), + TP_printk("partition_id=%llu", + __entry->partition_id + ) +); + +TRACE_EVENT(mshv_destroy_partition, + TP_PROTO(u64 partition_id), + TP_ARGS(partition_id), + TP_STRUCT__entry( + __field(u64, partition_id) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + ), + TP_printk("partition_id=%llu", + __entry->partition_id + ) +); + +TRACE_EVENT(mshv_hvcall_finalize_partition, + TP_PROTO(u64 partition_id, u64 status), + TP_ARGS(partition_id, status), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u64, status) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->status = status; + ), + TP_printk("partition_id=%llu status=%#llx ", + __entry->partition_id, + __entry->status + ) +); + +TRACE_EVENT(mshv_hvcall_withdraw_memory, + TP_PROTO(u64 partition_id, u64 withdrawn, u64 status), + TP_ARGS(partition_id, withdrawn, status), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u64, withdrawn) + __field(u64, status) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->withdrawn = withdrawn; + __entry->status = status; + ), + TP_printk("partition_id=%llu withdrawn=%llu status=%#llx", + __entry->partition_id, + __entry->withdrawn, + __entry->status + ) +); + +TRACE_EVENT(mshv_hvcall_delete_partition, + TP_PROTO(u64 partition_id, u64 status), + TP_ARGS(partition_id, status), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u64, status) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->status = status; + ), + TP_printk("partition_id=%llu status=%#llx", + __entry->partition_id, + __entry->status + ) +); + +TRACE_EVENT(mshv_create_vp, + TP_PROTO(u64 partition_id, u32 vp_index, long vp_fd), + TP_ARGS(partition_id, vp_index, vp_fd), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + __field(long, vp_fd) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + __entry->vp_fd = vp_fd; + ), + TP_printk("partition_id=%llu vp_index=%u vp_fd=%ld", + __entry->partition_id, + __entry->vp_index, + __entry->vp_fd + ) +); + +TRACE_EVENT(mshv_hvcall_map_vp_state_page, + TP_PROTO(u64 partition_id, u32 vp_index, u32 page_type, u64 status), + TP_ARGS(partition_id, vp_index, page_type, status), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + __field(u32, page_type) + __field(u64, status) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + __entry->page_type = page_type; + __entry->status = status; + ), + TP_printk("partition_id=%llu vp_index=%u page_type=%u status=%#llx", + __entry->partition_id, + __entry->vp_index, + __entry->page_type, + __entry->status + ) +); + +TRACE_EVENT(mshv_drain_vp_signals, + TP_PROTO(u64 partition_id, u32 vp_index), + TP_ARGS(partition_id, vp_index), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + ), + TP_printk("partition_id=%llu vp_index=%u", + __entry->partition_id, + __entry->vp_index + ) +); + +TRACE_EVENT(mshv_disable_vp_dispatch, + TP_PROTO(u64 partition_id, u32 vp_index, int ret), + TP_ARGS(partition_id, vp_index, ret), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + __field(int, ret) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + __entry->ret = ret; + ), + TP_printk("partition_id=%llu vp_index=%u ret=%d", + __entry->partition_id, + __entry->vp_index, + __entry->ret + ) +); + +TRACE_EVENT(mshv_vp_release, + TP_PROTO(u64 partition_id, u32 vp_index), + TP_ARGS(partition_id, vp_index), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + ), + TP_printk("partition_id=%llu vp_index=%u", + __entry->partition_id, + __entry->vp_index + ) +); + +TRACE_EVENT(mshv_run_vp_entry, + TP_PROTO(u64 partition_id, u32 vp_index), + TP_ARGS(partition_id, vp_index), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + ), + TP_printk("partition_id=%llu vp_index=%u", + __entry->partition_id, + __entry->vp_index + ) +); + +TRACE_EVENT(mshv_run_vp_exit, + TP_PROTO(u64 partition_id, u32 vp_index, u64 hv_message_type, long ret), + TP_ARGS(partition_id, vp_index, hv_message_type, ret), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + __field(u64, hv_message_type) + __field(long, ret) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + __entry->hv_message_type = hv_message_type; + __entry->ret = ret; + ), + TP_printk("partition_id=%llu vp_index=%u hv_message_type=%#llx ret=%ld", + __entry->partition_id, + __entry->vp_index, + __entry->hv_message_type, + __entry->ret + ) +); + +TRACE_EVENT(mshv_vp_clear_explicit_suspend, + TP_PROTO(u64 partition_id, u32 vp_index, int ret), + TP_ARGS(partition_id, vp_index, ret), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + __field(int, ret) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + __entry->ret = ret; + ), + TP_printk("partition_id=%llu vp_index=%u ret=%d", + __entry->partition_id, + __entry->vp_index, + __entry->ret + ) +); + +TRACE_EVENT(mshv_xfer_to_guest_mode_work, + TP_PROTO(u64 partition_id, u32 vp_index, unsigned long thread_info_flag, long ret), + TP_ARGS(partition_id, vp_index, thread_info_flag, ret), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + __field(unsigned long, thread_info_flag) + __field(long, ret) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + __entry->thread_info_flag = thread_info_flag; + __entry->ret = ret; + ), + TP_printk("partition_id=%llu vp_index=%u thread_info_flag=%#lx ret=%ld", + __entry->partition_id, + __entry->vp_index, + __entry->thread_info_flag, + __entry->ret + ) +); + +TRACE_EVENT(mshv_hvcall_dispatch_vp, + TP_PROTO(u64 partition_id, u32 vp_index, u32 flags, + u32 dispatch_state, u32 dispatch_event, u64 irq_vectors, u64 status), + TP_ARGS(partition_id, vp_index, flags, dispatch_state, dispatch_event, irq_vectors, + status), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + __field(u32, flags) + __field(u32, dispatch_state) + __field(u32, dispatch_event) + __field(u64, irq_vectors) + __field(u64, status) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + __entry->flags = flags; + __entry->dispatch_state = dispatch_state; + __entry->dispatch_event = dispatch_event; + __entry->irq_vectors = irq_vectors; + __entry->status = status; + ), + TP_printk("partition_id=%llu vp_index=%u flags=%#x dispatch_state=%#x dispatch_event=%#x irq_vectors=%#016llx status=%#llx", + __entry->partition_id, + __entry->vp_index, + __entry->flags, + __entry->dispatch_state, + __entry->dispatch_event, + __entry->irq_vectors, + __entry->status + ) +); + +TRACE_EVENT(mshv_update_routing_table, + TP_PROTO(u64 partition_id, void *old, void *new, u32 numents), + TP_ARGS(partition_id, old, new, numents), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(struct mshv_girq_routing_table *, old) + __field(struct mshv_girq_routing_table *, new) + __field(u32, numents) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->old = old; + __entry->new = new; + __entry->numents = numents; + ), + TP_printk("partition_id=%llu old=%p new=%p numents=%u", + __entry->partition_id, + __entry->old, + __entry->new, + __entry->numents + ) +); + +TRACE_EVENT(mshv_map_user_memory, + TP_PROTO(u64 partition_id, u64 start_uaddr, u64 start_gfn, u64 nr_pages, u32 map_flags, + long ret), + TP_ARGS(partition_id, start_uaddr, start_gfn, nr_pages, map_flags, ret), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u64, start_uaddr) + __field(u64, start_gfn) + __field(u64, nr_pages) + __field(u32, map_flags) + __field(long, ret) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->start_uaddr = start_uaddr; + __entry->start_gfn = start_gfn; + __entry->nr_pages = nr_pages; + __entry->map_flags = map_flags; + __entry->ret = ret; + ), + TP_printk("partition_id=%llu start_uaddr=%#llx start_gfn=%#llx nr_pages=%llu map_flags=%#x ret=%ld", + __entry->partition_id, + __entry->start_uaddr, + __entry->start_gfn, + __entry->nr_pages, + __entry->map_flags, + __entry->ret + ) +); + +TRACE_EVENT(mshv_assign_ioeventfd, + TP_PROTO(u64 partition_id, u64 addr, u64 length, u64 datamatch, bool wildcard, + void *eventfd, int ret), + TP_ARGS(partition_id, addr, length, datamatch, wildcard, eventfd, ret), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u64, addr) + __field(u64, length) + __field(u64, datamatch) + __field(bool, wildcard) + __field(struct eventfd_ctx *, eventfd) + __field(int, ret) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->addr = addr; + __entry->length = length; + __entry->datamatch = datamatch; + __entry->wildcard = wildcard; + __entry->eventfd = eventfd; + __entry->ret = ret; + ), + TP_printk("partition_id=%llu addr=%#016llx length=%#llx datamatch=%#llx wildcard=%d eventfd=%p ret=%d", + __entry->partition_id, + __entry->addr, + __entry->length, + __entry->datamatch, + __entry->wildcard, + __entry->eventfd, + __entry->ret + ) +); + +TRACE_EVENT(mshv_deassign_ioeventfd, + TP_PROTO(u64 partition_id, u64 addr, u64 length, u64 datamatch, bool wildcard, + void *eventfd), + TP_ARGS(partition_id, addr, length, datamatch, wildcard, eventfd), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u64, addr) + __field(u64, length) + __field(u64, datamatch) + __field(bool, wildcard) + __field(struct eventfd_ctx *, eventfd) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->addr = addr; + __entry->length = length; + __entry->datamatch = datamatch; + __entry->wildcard = wildcard; + __entry->eventfd = eventfd; + ), + TP_printk("partition_id=%llu addr=%#016llx length=%#llx datamatch=%#llx wildcard=%d eventfd=%p", + __entry->partition_id, + __entry->addr, + __entry->length, + __entry->datamatch, + __entry->wildcard, + __entry->eventfd + ) +); + +TRACE_EVENT(mshv_vp_wait_for_hv_kick, + TP_PROTO(u64 partition_id, u32 vp_index, bool kicked_by_hv, bool blocked, + bool irq_pending), + TP_ARGS(partition_id, vp_index, kicked_by_hv, blocked, irq_pending), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + __field(bool, kicked_by_hv) + __field(bool, blocked) + __field(bool, irq_pending) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + __entry->kicked_by_hv = kicked_by_hv; + __entry->blocked = blocked; + __entry->irq_pending = irq_pending; + ), + TP_printk("partition_id=%llu vp_index=%u kicked_by_hv=%d blocked=%d irq_pending=%d", + __entry->partition_id, + __entry->vp_index, + __entry->kicked_by_hv, + __entry->blocked, + __entry->irq_pending + ) +); + +TRACE_EVENT(mshv_handle_gpa_intercept, + TP_PROTO(u64 partition_id, u32 vp_index, u64 gfn, u8 access_type, bool handled), + TP_ARGS(partition_id, vp_index, gfn, access_type, handled), + TP_STRUCT__entry( + __field(u64, partition_id) + __field(u32, vp_index) + __field(u64, gfn) + __field(u8, access_type) + __field(bool, handled) + ), + TP_fast_assign( + __entry->partition_id = partition_id; + __entry->vp_index = vp_index; + __entry->gfn = gfn; + __entry->access_type = access_type == HV_INTERCEPT_ACCESS_READ ? 'R' : + (access_type == HV_INTERCEPT_ACCESS_WRITE ? 'W' : + (access_type == HV_INTERCEPT_ACCESS_EXECUTE ? 'X' : '?')); + __entry->handled = handled; + ), + TP_printk("partition_id=%llu vp_index=%u gfn=0x%llx access_type=%c handled=%d", + __entry->partition_id, + __entry->vp_index, + __entry->gfn, + __entry->access_type, + __entry->handled + ) +); + +#endif /* _MSHV_TRACE_H_ */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/drivers/hv/mshv_vtl_main.c b/drivers/hv/mshv_vtl_main.c index 5856975f32e1..c19400701467 100644 --- a/drivers/hv/mshv_vtl_main.c +++ b/drivers/hv/mshv_vtl_main.c @@ -386,7 +386,6 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg) if (copy_from_user(&vtl0_mem, arg, sizeof(vtl0_mem))) return -EFAULT; - /* vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design */ if (vtl0_mem.last_pfn <= vtl0_mem.start_pfn) { dev_err(vtl->module_dev, "range start pfn (%llx) > end pfn (%llx)\n", vtl0_mem.start_pfn, vtl0_mem.last_pfn); @@ -397,6 +396,10 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg) if (!pgmap) return -ENOMEM; + /* + * vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design. + * last_pfn is not reserved or wasted, and reflects 'start_pfn + size' of pagemap range. + */ pgmap->ranges[0].start = PFN_PHYS(vtl0_mem.start_pfn); pgmap->ranges[0].end = PFN_PHYS(vtl0_mem.last_pfn) - 1; pgmap->nr_range = 1; @@ -405,8 +408,11 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg) /* * Determine the highest page order that can be used for the given memory range. * This works best when the range is aligned; i.e. both the start and the length. + * Clamp to MAX_FOLIO_ORDER to avoid a WARN in memremap_pages() when the range + * alignment exceeds the maximum supported folio order for this kernel config. */ - pgmap->vmemmap_shift = count_trailing_zeros(vtl0_mem.start_pfn | vtl0_mem.last_pfn); + pgmap->vmemmap_shift = min(count_trailing_zeros(vtl0_mem.start_pfn | vtl0_mem.last_pfn), + MAX_FOLIO_ORDER); dev_dbg(vtl->module_dev, "Add VTL0 memory: start: 0x%llx, end_pfn: 0x%llx, page order: %lu\n", vtl0_mem.start_pfn, vtl0_mem.last_pfn, pgmap->vmemmap_shift); @@ -415,7 +421,7 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg) if (IS_ERR(addr)) { dev_err(vtl->module_dev, "devm_memremap_pages error: %ld\n", PTR_ERR(addr)); kfree(pgmap); - return -EFAULT; + return PTR_ERR(addr); } /* Don't free pgmap, since it has to stick around until the memory diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index f0d0803d1e16..d28ff45d4cfd 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -100,13 +100,11 @@ struct device *hv_get_vmbus_root_device(void) } EXPORT_SYMBOL_GPL(hv_get_vmbus_root_device); -static int vmbus_exists(void) +bool hv_vmbus_exists(void) { - if (vmbus_root_device == NULL) - return -ENODEV; - - return 0; + return vmbus_root_device != NULL; } +EXPORT_SYMBOL_GPL(hv_vmbus_exists); static u8 channel_monitor_group(const struct vmbus_channel *channel) { @@ -1257,17 +1255,12 @@ static void vmbus_chan_sched(void *event_page_addr) return; event = (union hv_synic_event_flags *)event_page_addr + VMBUS_MESSAGE_SINT; - maxbits = HV_EVENT_FLAGS_COUNT; + maxbits = READ_ONCE(vmbus_connection.relid_hiwater) + 1; recv_int_page = event->flags; if (unlikely(!recv_int_page)) return; - /* - * Suggested-by: Michael Kelley <mhklinux@outlook.com> - * One possible optimization would be to keep track of the largest relID that's in use, - * and only scan up to that relID. - */ for_each_set_bit(relid, recv_int_page, maxbits) { void (*callback_fn)(void *context); struct vmbus_channel *channel; @@ -1427,7 +1420,6 @@ static int vmbus_alloc_synic_and_connect(void) { int ret, cpu; struct work_struct __percpu *works; - int hyperv_cpuhp_online; ret = hv_synic_alloc(); if (ret < 0) @@ -1579,11 +1571,10 @@ int __vmbus_driver_register(struct hv_driver *hv_driver, struct module *owner, c { int ret; - pr_info("registering driver %s\n", hv_driver->name); + if (!hv_vmbus_exists()) + return -ENODEV; - ret = vmbus_exists(); - if (ret < 0) - return ret; + pr_info("registering driver %s\n", hv_driver->name); hv_driver->driver.name = hv_driver->name; hv_driver->driver.owner = owner; @@ -1609,9 +1600,8 @@ EXPORT_SYMBOL_GPL(__vmbus_driver_register); */ void vmbus_driver_unregister(struct hv_driver *hv_driver) { - pr_info("unregistering driver %s\n", hv_driver->name); - - if (!vmbus_exists()) { + if (hv_vmbus_exists()) { + pr_info("unregistering driver %s\n", hv_driver->name); driver_unregister(&hv_driver->driver); vmbus_free_dynids(hv_driver); } @@ -2897,7 +2887,6 @@ static struct platform_driver vmbus_platform_driver = { static void hv_kexec_handler(void) { - hv_stimer_global_cleanup(); vmbus_initiate_unload(false); /* Make sure conn_state is set as hv_synic_cleanup checks for it */ mb(); |
