@@ -468,12 +468,16 @@ static bool do_hot_add;
468468 * the specified number of seconds.
469469 */
470470static uint pressure_report_delay = 45 ;
471+ extern unsigned int page_reporting_order ;
472+ #define HV_MAX_FAILURES 2
471473
472474/*
473475 * The last time we posted a pressure report to host.
474476 */
475477static unsigned long last_post_time ;
476478
479+ static int hv_hypercall_multi_failure ;
480+
477481module_param (hot_add , bool , (S_IRUGO | S_IWUSR ));
478482MODULE_PARM_DESC (hot_add , "If set attempt memory hot_add" );
479483
@@ -573,6 +577,10 @@ static struct hv_dynmem_device dm_device;
573577
574578static void post_status (struct hv_dynmem_device * dm );
575579
580+ static void enable_page_reporting (void );
581+
582+ static void disable_page_reporting (void );
583+
576584#ifdef CONFIG_MEMORY_HOTPLUG
577585static inline bool has_pfn_is_backed (struct hv_hotadd_state * has ,
578586 unsigned long pfn )
@@ -1402,6 +1410,18 @@ static int dm_thread_func(void *dm_dev)
14021410 */
14031411 reinit_completion (& dm_device .config_event );
14041412 post_status (dm );
1413+ /*
1414+ * disable free page reporting if multiple hypercall
1415+ * failure flag set. It is not done in the page_reporting
1416+ * callback context as that causes a deadlock between
1417+ * page_reporting_process() and page_reporting_unregister()
1418+ */
1419+ if (hv_hypercall_multi_failure >= HV_MAX_FAILURES ) {
1420+ pr_err ("Multiple failures in cold memory discard hypercall, disabling page reporting\n" );
1421+ disable_page_reporting ();
1422+ /* Reset the flag after disabling reporting */
1423+ hv_hypercall_multi_failure = 0 ;
1424+ }
14051425 }
14061426
14071427 return 0 ;
@@ -1577,20 +1597,20 @@ static void balloon_onchannelcallback(void *context)
15771597
15781598}
15791599
1580- /* Hyper-V only supports reporting 2MB pages or higher */
1581- #define HV_MIN_PAGE_REPORTING_ORDER 9
1582- #define HV_MIN_PAGE_REPORTING_LEN (HV_HYP_PAGE_SIZE << HV_MIN_PAGE_REPORTING_ORDER )
1600+ #define HV_LARGE_REPORTING_ORDER 9
1601+ #define HV_LARGE_REPORTING_LEN (HV_HYP_PAGE_SIZE << \
1602+ HV_LARGE_REPORTING_ORDER )
15831603static int hv_free_page_report (struct page_reporting_dev_info * pr_dev_info ,
15841604 struct scatterlist * sgl , unsigned int nents )
15851605{
15861606 unsigned long flags ;
15871607 struct hv_memory_hint * hint ;
1588- int i ;
1608+ int i , order ;
15891609 u64 status ;
15901610 struct scatterlist * sg ;
15911611
15921612 WARN_ON_ONCE (nents > HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES );
1593- WARN_ON_ONCE (sgl -> length < HV_MIN_PAGE_REPORTING_LEN );
1613+ WARN_ON_ONCE (sgl -> length < ( HV_HYP_PAGE_SIZE << page_reporting_order ) );
15941614 local_irq_save (flags );
15951615 hint = * (struct hv_memory_hint * * )this_cpu_ptr (hyperv_pcpu_input_arg );
15961616 if (!hint ) {
@@ -1605,21 +1625,53 @@ static int hv_free_page_report(struct page_reporting_dev_info *pr_dev_info,
16051625
16061626 range = & hint -> ranges [i ];
16071627 range -> address_space = 0 ;
1608- /* page reporting only reports 2MB pages or higher */
1609- range -> page .largepage = 1 ;
1610- range -> page .additional_pages =
1611- (sg -> length / HV_MIN_PAGE_REPORTING_LEN ) - 1 ;
1612- range -> page_size = HV_GPA_PAGE_RANGE_PAGE_SIZE_2MB ;
1613- range -> base_large_pfn =
1614- page_to_hvpfn (sg_page (sg )) >> HV_MIN_PAGE_REPORTING_ORDER ;
1628+ order = get_order (sg -> length );
1629+ /*
1630+ * Hyper-V expects the additional_pages field in the units
1631+ * of one of these 3 sizes, 4Kbytes, 2Mbytes or 1Gbytes.
1632+ * This is dictated by the values of the fields page.largesize
1633+ * and page_size.
1634+ * This code however, only uses 4Kbytes and 2Mbytes units
1635+ * and not 1Gbytes unit.
1636+ */
1637+
1638+ /* page reporting for pages 2MB or higher */
1639+ if (order >= HV_LARGE_REPORTING_ORDER ) {
1640+ range -> page .largepage = 1 ;
1641+ range -> page_size = HV_GPA_PAGE_RANGE_PAGE_SIZE_2MB ;
1642+ range -> base_large_pfn = page_to_hvpfn (
1643+ sg_page (sg )) >> HV_LARGE_REPORTING_ORDER ;
1644+ range -> page .additional_pages =
1645+ (sg -> length / HV_LARGE_REPORTING_LEN ) - 1 ;
1646+ } else {
1647+ /* Page reporting for pages below 2MB */
1648+ range -> page .basepfn = page_to_hvpfn (sg_page (sg ));
1649+ range -> page .largepage = false;
1650+ range -> page .additional_pages =
1651+ (sg -> length / HV_HYP_PAGE_SIZE ) - 1 ;
1652+ }
1653+
16151654 }
16161655
16171656 status = hv_do_rep_hypercall (HV_EXT_CALL_MEMORY_HEAT_HINT , nents , 0 ,
16181657 hint , NULL );
16191658 local_irq_restore (flags );
1620- if ((status & HV_HYPERCALL_RESULT_MASK ) != HV_STATUS_SUCCESS ) {
1659+ if (!hv_result_success (status )) {
1660+
16211661 pr_err ("Cold memory discard hypercall failed with status %llx\n" ,
1622- status );
1662+ status );
1663+ if (hv_hypercall_multi_failure > 0 )
1664+ hv_hypercall_multi_failure ++ ;
1665+
1666+ if (hv_result (status ) == HV_STATUS_INVALID_PARAMETER ) {
1667+ pr_err ("Underlying Hyper-V does not support order less than 9. Hypercall failed\n" );
1668+ pr_err ("Defaulting to page_reporting_order %d\n" ,
1669+ pageblock_order );
1670+ page_reporting_order = pageblock_order ;
1671+ hv_hypercall_multi_failure ++ ;
1672+ return - EINVAL ;
1673+ }
1674+
16231675 return - EINVAL ;
16241676 }
16251677
@@ -1630,25 +1682,25 @@ static void enable_page_reporting(void)
16301682{
16311683 int ret ;
16321684
1633- /* Essentially, validating 'PAGE_REPORTING_MIN_ORDER' is big enough. */
1634- if (pageblock_order < HV_MIN_PAGE_REPORTING_ORDER ) {
1635- pr_debug ("Cold memory discard is only supported on 2MB pages and above\n" );
1636- return ;
1637- }
1638-
16391685 if (!hv_query_ext_cap (HV_EXT_CAPABILITY_MEMORY_COLD_DISCARD_HINT )) {
16401686 pr_debug ("Cold memory discard hint not supported by Hyper-V\n" );
16411687 return ;
16421688 }
16431689
16441690 BUILD_BUG_ON (PAGE_REPORTING_CAPACITY > HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES );
16451691 dm_device .pr_dev_info .report = hv_free_page_report ;
1692+ /*
1693+ * We let the page_reporting_order parameter decide the order
1694+ * in the page_reporting code
1695+ */
1696+ dm_device .pr_dev_info .order = 0 ;
16461697 ret = page_reporting_register (& dm_device .pr_dev_info );
16471698 if (ret < 0 ) {
16481699 dm_device .pr_dev_info .report = NULL ;
16491700 pr_err ("Failed to enable cold memory discard: %d\n" , ret );
16501701 } else {
1651- pr_info ("Cold memory discard hint enabled\n" );
1702+ pr_info ("Cold memory discard hint enabled with order %d\n" ,
1703+ page_reporting_order );
16521704 }
16531705}
16541706
0 commit comments