diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h index 05ba1f716f9e..e4912b0618fa 100644 --- a/drivers/hv/mshv_root.h +++ b/drivers/hv/mshv_root.h @@ -254,6 +254,16 @@ struct mshv_partition *mshv_partition_get(struct mshv_partition *partition); void mshv_partition_put(struct mshv_partition *partition); struct mshv_partition *mshv_partition_find(u64 partition_id) __must_hold(RCU); +static inline bool is_l1vh_parent(u64 partition_id) +{ + return hv_l1vh_partition() && (partition_id == HV_PARTITION_ID_SELF); +} + +int mshv_vp_stats_map(u64 partition_id, u32 vp_index, + struct hv_stats_page **stats_pages); +void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index, + struct hv_stats_page **stats_pages); + /* hypercalls */ int hv_call_withdraw_memory(u64 count, int node, u64 partition_id); diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index f2cd48101d2b..781e49721539 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -957,23 +957,36 @@ mshv_vp_release(struct inode *inode, struct file *filp) return 0; } -static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index, - struct hv_stats_page *stats_pages[]) +void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index, + struct hv_stats_page *stats_pages[]) { union hv_stats_object_identity identity = { .vp.partition_id = partition_id, .vp.vp_index = vp_index, }; + int err; identity.vp.stats_area_type = HV_STATS_AREA_SELF; - hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); + err = hv_unmap_stats_page(HV_STATS_OBJECT_VP, + stats_pages[HV_STATS_AREA_SELF], + &identity); + if (err) + pr_err("%s: failed to unmap partition %llu vp %u self stats, err: %d\n", + __func__, partition_id, vp_index, err); - identity.vp.stats_area_type = HV_STATS_AREA_PARENT; - hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); + if (stats_pages[HV_STATS_AREA_PARENT] != stats_pages[HV_STATS_AREA_SELF]) { + identity.vp.stats_area_type = HV_STATS_AREA_PARENT; + err = hv_unmap_stats_page(HV_STATS_OBJECT_VP, + stats_pages[HV_STATS_AREA_PARENT], + &identity); + if (err) + pr_err("%s: failed to unmap partition %llu vp %u parent stats, err: %d\n", + __func__, partition_id, vp_index, err); + } } -static int mshv_vp_stats_map(u64 partition_id, u32 vp_index, - struct hv_stats_page *stats_pages[]) +int mshv_vp_stats_map(u64 partition_id, u32 vp_index, + struct hv_stats_page *stats_pages[]) { union hv_stats_object_identity identity = { .vp.partition_id = partition_id, @@ -984,23 +997,37 @@ static int mshv_vp_stats_map(u64 partition_id, u32 vp_index, identity.vp.stats_area_type = HV_STATS_AREA_SELF; err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity, &stats_pages[HV_STATS_AREA_SELF]); - if (err) + if (err) { + pr_err("%s: failed to map partition %llu vp %u self stats, err: %d\n", + __func__, partition_id, vp_index, err); return err; + } - identity.vp.stats_area_type = HV_STATS_AREA_PARENT; - err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity, - &stats_pages[HV_STATS_AREA_PARENT]); - if (err) - goto unmap_self; - - if (!stats_pages[HV_STATS_AREA_PARENT]) + /* + * L1VH partition cannot access its vp stats in parent area. + */ + if (is_l1vh_parent(partition_id)) { stats_pages[HV_STATS_AREA_PARENT] = stats_pages[HV_STATS_AREA_SELF]; + } else { + identity.vp.stats_area_type = HV_STATS_AREA_PARENT; + err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity, + &stats_pages[HV_STATS_AREA_PARENT]); + if (err) { + pr_err("%s: failed to map partition %llu vp %u parent stats, err: %d\n", + __func__, partition_id, vp_index, err); + goto unmap_self; + } + if (!stats_pages[HV_STATS_AREA_PARENT]) + stats_pages[HV_STATS_AREA_PARENT] = stats_pages[HV_STATS_AREA_SELF]; + } return 0; unmap_self: identity.vp.stats_area_type = HV_STATS_AREA_SELF; - hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); + hv_unmap_stats_page(HV_STATS_OBJECT_VP, + stats_pages[HV_STATS_AREA_SELF], + &identity); return err; }