Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mshv: Introduce new hypercall to map stats page for L1VH partitions

Introduce HVCALL_MAP_STATS_PAGE2 which provides a map location (GPFN)
to map the stats to. This hypercall is required for L1VH partitions,
depending on the hypervisor version. This uses the same check as the
state page map location; mshv_use_overlay_gpfn().

Add mshv_map_vp_state_page() helpers to use this new hypercall or the
old one depending on availability.

For unmapping, the original HVCALL_UNMAP_STATS_PAGE works for both
cases.

Signed-off-by: Jinank Jain <jinankjain@linux.microsoft.com>
Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Easwar Hariharan <easwar.hariharan@linux.microsoft.com>
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Jinank Jain and committed by
Wei Liu
d62313bd 19c515c2

+115 -20
+5 -5
drivers/hv/mshv_root.h
··· 297 297 int hv_call_disconnect_port(u64 connection_partition_id, 298 298 union hv_connection_id connection_id); 299 299 int hv_call_notify_port_ring_empty(u32 sint_index); 300 - int hv_call_map_stat_page(enum hv_stats_object_type type, 301 - const union hv_stats_object_identity *identity, 302 - void **addr); 303 - int hv_call_unmap_stat_page(enum hv_stats_object_type type, 304 - const union hv_stats_object_identity *identity); 300 + int hv_map_stats_page(enum hv_stats_object_type type, 301 + const union hv_stats_object_identity *identity, 302 + void **addr); 303 + int hv_unmap_stats_page(enum hv_stats_object_type type, void *page_addr, 304 + const union hv_stats_object_identity *identity); 305 305 int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages, 306 306 u64 page_struct_count, u32 host_access, 307 307 u32 flags, u8 acquire);
+90 -5
drivers/hv/mshv_root_hv_call.c
··· 807 807 return hv_result_to_errno(status); 808 808 } 809 809 810 - int hv_call_map_stat_page(enum hv_stats_object_type type, 811 - const union hv_stats_object_identity *identity, 812 - void **addr) 810 + static int hv_call_map_stats_page2(enum hv_stats_object_type type, 811 + const union hv_stats_object_identity *identity, 812 + u64 map_location) 813 + { 814 + unsigned long flags; 815 + struct hv_input_map_stats_page2 *input; 816 + u64 status; 817 + int ret; 818 + 819 + if (!map_location || !mshv_use_overlay_gpfn()) 820 + return -EINVAL; 821 + 822 + do { 823 + local_irq_save(flags); 824 + input = *this_cpu_ptr(hyperv_pcpu_input_arg); 825 + 826 + memset(input, 0, sizeof(*input)); 827 + input->type = type; 828 + input->identity = *identity; 829 + input->map_location = map_location; 830 + 831 + status = hv_do_hypercall(HVCALL_MAP_STATS_PAGE2, input, NULL); 832 + 833 + local_irq_restore(flags); 834 + 835 + ret = hv_result_to_errno(status); 836 + 837 + if (!ret) 838 + break; 839 + 840 + if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { 841 + hv_status_debug(status, "\n"); 842 + break; 843 + } 844 + 845 + ret = hv_call_deposit_pages(NUMA_NO_NODE, 846 + hv_current_partition_id, 1); 847 + } while (!ret); 848 + 849 + return ret; 850 + } 851 + 852 + static int hv_call_map_stats_page(enum hv_stats_object_type type, 853 + const union hv_stats_object_identity *identity, 854 + void **addr) 813 855 { 814 856 unsigned long flags; 815 857 struct hv_input_map_stats_page *input; ··· 890 848 return ret; 891 849 } 892 850 893 - int hv_call_unmap_stat_page(enum hv_stats_object_type type, 894 - const union hv_stats_object_identity *identity) 851 + int hv_map_stats_page(enum hv_stats_object_type type, 852 + const union hv_stats_object_identity *identity, 853 + void **addr) 854 + { 855 + int ret; 856 + struct page *allocated_page = NULL; 857 + 858 + if (!addr) 859 + return -EINVAL; 860 + 861 + if (mshv_use_overlay_gpfn()) { 862 + allocated_page = alloc_page(GFP_KERNEL); 863 + if (!allocated_page) 864 + return -ENOMEM; 865 + 866 + ret = hv_call_map_stats_page2(type, identity, 867 + page_to_pfn(allocated_page)); 868 + *addr = page_address(allocated_page); 869 + } else { 870 + ret = hv_call_map_stats_page(type, identity, addr); 871 + } 872 + 873 + if (ret && allocated_page) { 874 + __free_page(allocated_page); 875 + *addr = NULL; 876 + } 877 + 878 + return ret; 879 + } 880 + 881 + static int hv_call_unmap_stats_page(enum hv_stats_object_type type, 882 + const union hv_stats_object_identity *identity) 895 883 { 896 884 unsigned long flags; 897 885 struct hv_input_unmap_stats_page *input; ··· 938 866 local_irq_restore(flags); 939 867 940 868 return hv_result_to_errno(status); 869 + } 870 + 871 + int hv_unmap_stats_page(enum hv_stats_object_type type, void *page_addr, 872 + const union hv_stats_object_identity *identity) 873 + { 874 + int ret; 875 + 876 + ret = hv_call_unmap_stats_page(type, identity); 877 + 878 + if (mshv_use_overlay_gpfn() && page_addr) 879 + __free_page(virt_to_page(page_addr)); 880 + 881 + return ret; 941 882 } 942 883 943 884 int hv_call_modify_spa_host_access(u64 partition_id, struct page **pages,
+12 -10
drivers/hv/mshv_root_main.c
··· 843 843 return 0; 844 844 } 845 845 846 - static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index) 846 + static void mshv_vp_stats_unmap(u64 partition_id, u32 vp_index, 847 + void *stats_pages[]) 847 848 { 848 849 union hv_stats_object_identity identity = { 849 850 .vp.partition_id = partition_id, ··· 852 851 }; 853 852 854 853 identity.vp.stats_area_type = HV_STATS_AREA_SELF; 855 - hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); 854 + hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); 856 855 857 856 identity.vp.stats_area_type = HV_STATS_AREA_PARENT; 858 - hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); 857 + hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); 859 858 } 860 859 861 860 static int mshv_vp_stats_map(u64 partition_id, u32 vp_index, ··· 868 867 int err; 869 868 870 869 identity.vp.stats_area_type = HV_STATS_AREA_SELF; 871 - err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity, 872 - &stats_pages[HV_STATS_AREA_SELF]); 870 + err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity, 871 + &stats_pages[HV_STATS_AREA_SELF]); 873 872 if (err) 874 873 return err; 875 874 876 875 identity.vp.stats_area_type = HV_STATS_AREA_PARENT; 877 - err = hv_call_map_stat_page(HV_STATS_OBJECT_VP, &identity, 878 - &stats_pages[HV_STATS_AREA_PARENT]); 876 + err = hv_map_stats_page(HV_STATS_OBJECT_VP, &identity, 877 + &stats_pages[HV_STATS_AREA_PARENT]); 879 878 if (err) 880 879 goto unmap_self; 881 880 ··· 883 882 884 883 unmap_self: 885 884 identity.vp.stats_area_type = HV_STATS_AREA_SELF; 886 - hv_call_unmap_stat_page(HV_STATS_OBJECT_VP, &identity); 885 + hv_unmap_stats_page(HV_STATS_OBJECT_VP, NULL, &identity); 887 886 return err; 888 887 } 889 888 ··· 991 990 kfree(vp); 992 991 unmap_stats_pages: 993 992 if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) 994 - mshv_vp_stats_unmap(partition->pt_id, args.vp_index); 993 + mshv_vp_stats_unmap(partition->pt_id, args.vp_index, stats_pages); 995 994 unmap_ghcb_page: 996 995 if (mshv_partition_encrypted(partition) && is_ghcb_mapping_available()) 997 996 hv_unmap_vp_state_page(partition->pt_id, args.vp_index, ··· 1743 1742 continue; 1744 1743 1745 1744 if (hv_scheduler_type == HV_SCHEDULER_TYPE_ROOT) 1746 - mshv_vp_stats_unmap(partition->pt_id, vp->vp_index); 1745 + mshv_vp_stats_unmap(partition->pt_id, vp->vp_index, 1746 + (void **)vp->vp_stats_pages); 1747 1747 1748 1748 if (vp->vp_register_page) { 1749 1749 (void)hv_unmap_vp_state_page(partition->pt_id,
+1
include/hyperv/hvgdk_mini.h
··· 494 494 #define HVCALL_GET_PARTITION_PROPERTY_EX 0x0101 495 495 #define HVCALL_MMIO_READ 0x0106 496 496 #define HVCALL_MMIO_WRITE 0x0107 497 + #define HVCALL_MAP_STATS_PAGE2 0x0131 497 498 498 499 /* HV_HYPERCALL_INPUT */ 499 500 #define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0)
+7
include/hyperv/hvhdk_mini.h
··· 177 177 union hv_stats_object_identity identity; 178 178 } __packed; 179 179 180 + struct hv_input_map_stats_page2 { 181 + u32 type; /* enum hv_stats_object_type */ 182 + u32 padding; 183 + union hv_stats_object_identity identity; 184 + u64 map_location; 185 + } __packed; 186 + 180 187 struct hv_output_map_stats_page { 181 188 u64 map_location; 182 189 } __packed;