From: Kan Liang Without PMU partitioning, a PMU with PERF_PMU_CAP_MEDIATED_VPMU blocks host event scheduling while the guest PMU context is loaded. When PMU partitioning is enabled, host-owned counters remain available. Skip exclude_guest events, but continue to allow other events to be scheduled on the remaining host-owned counters. Signed-off-by: Kan Liang Co-developed-by: Zide Chen Signed-off-by: Zide Chen --- kernel/events/core.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 9ce27cd83e04..23375f8d2261 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4105,6 +4105,32 @@ struct merge_sched_data { enum event_type_t event_type; }; +static bool +perf_mediated_pmu_skip_event(struct perf_event *event, enum event_type_t event_type) +{ + if (event->pmu_ctx->pmu->capabilities & PERF_PMU_CAP_PMU_PARTITION) { + /* + * EVENT_GUEST && !guest_ctx_loaded: perf_load_guest_context() + * reschedules !exclude_guest events. + * + * !EVENT_GUEST && guest_ctx_loaded: Guest context loaded. + */ + if (event->attr.exclude_guest && + !!(event_type & EVENT_GUEST) != is_guest_mediated_pmu_loaded()) + return true; + } else { + /* + * Don't schedule in any host events because no counters + * are available. + */ + if (!(event_type & EVENT_GUEST) && + is_guest_mediated_pmu_loaded()) + return true; + } + + return false; +} + static int merge_sched_in(struct perf_event *event, void *data) { struct perf_event_context *ctx = event->ctx; @@ -4116,13 +4142,8 @@ static int merge_sched_in(struct perf_event *event, void *data) if (!event_filter_match(event)) return 0; - /* - * Don't schedule in any host events from PMU with - * PERF_PMU_CAP_MEDIATED_VPMU, while a guest is running. - */ - if (is_guest_mediated_pmu_loaded() && - event->pmu_ctx->pmu->capabilities & PERF_PMU_CAP_MEDIATED_VPMU && - !(msd->event_type & EVENT_GUEST)) + if ((event->pmu_ctx->pmu->capabilities & PERF_PMU_CAP_MEDIATED_VPMU) && + perf_mediated_pmu_skip_event(event, msd->event_type)) return 0; if (group_can_go_on(event, msd->can_add_hw)) { -- 2.55.0