@@ -467,12 +467,16 @@ static bool do_hot_add;
467467 * the specified number of seconds.
468468 */
469469static uint pressure_report_delay = 45 ;
470+ extern unsigned int page_reporting_order ;
471+ #define HV_MAX_FAILURES 2
470472
471473/*
472474 * The last time we posted a pressure report to host.
473475 */
474476static unsigned long last_post_time ;
475477
478+ static int hv_hypercall_multi_failure ;
479+
476480module_param (hot_add , bool , (S_IRUGO | S_IWUSR ));
477481MODULE_PARM_DESC (hot_add , "If set attempt memory hot_add" );
478482
@@ -572,6 +576,10 @@ static struct hv_dynmem_device dm_device;
572576
573577static void post_status (struct hv_dynmem_device * dm );
574578
579+ static void enable_page_reporting (void );
580+
581+ static void disable_page_reporting (void );
582+
575583#ifdef CONFIG_MEMORY_HOTPLUG
576584static inline bool has_pfn_is_backed (struct hv_hotadd_state * has ,
577585 unsigned long pfn )
@@ -1395,6 +1403,18 @@ static int dm_thread_func(void *dm_dev)
13951403 */
13961404 reinit_completion (& dm_device .config_event );
13971405 post_status (dm );
1406+ /*
1407+ * disable free page reporting if multiple hypercall
1408+ * failure flag set. It is not done in the page_reporting
1409+ * callback context as that causes a deadlock between
1410+ * page_reporting_process() and page_reporting_unregister()
1411+ */
1412+ if (hv_hypercall_multi_failure >= HV_MAX_FAILURES ) {
1413+ pr_err ("Multiple failures in cold memory discard hypercall, disabling page reporting\n" );
1414+ disable_page_reporting ();
1415+ /* Reset the flag after disabling reporting */
1416+ hv_hypercall_multi_failure = 0 ;
1417+ }
13981418 }
13991419
14001420 return 0 ;
@@ -1570,20 +1590,20 @@ static void balloon_onchannelcallback(void *context)
15701590
15711591}
15721592
1573- /* Hyper-V only supports reporting 2MB pages or higher */
1574- #define HV_MIN_PAGE_REPORTING_ORDER 9
1575- #define HV_MIN_PAGE_REPORTING_LEN (HV_HYP_PAGE_SIZE << HV_MIN_PAGE_REPORTING_ORDER )
1593+ #define HV_LARGE_REPORTING_ORDER 9
1594+ #define HV_LARGE_REPORTING_LEN (HV_HYP_PAGE_SIZE << \
1595+ HV_LARGE_REPORTING_ORDER )
15761596static int hv_free_page_report (struct page_reporting_dev_info * pr_dev_info ,
15771597 struct scatterlist * sgl , unsigned int nents )
15781598{
15791599 unsigned long flags ;
15801600 struct hv_memory_hint * hint ;
1581- int i ;
1601+ int i , order ;
15821602 u64 status ;
15831603 struct scatterlist * sg ;
15841604
15851605 WARN_ON_ONCE (nents > HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES );
1586- WARN_ON_ONCE (sgl -> length < HV_MIN_PAGE_REPORTING_LEN );
1606+ WARN_ON_ONCE (sgl -> length < ( HV_HYP_PAGE_SIZE << page_reporting_order ) );
15871607 local_irq_save (flags );
15881608 hint = * (struct hv_memory_hint * * )this_cpu_ptr (hyperv_pcpu_input_arg );
15891609 if (!hint ) {
@@ -1598,21 +1618,53 @@ static int hv_free_page_report(struct page_reporting_dev_info *pr_dev_info,
15981618
15991619 range = & hint -> ranges [i ];
16001620 range -> address_space = 0 ;
1601- /* page reporting only reports 2MB pages or higher */
1602- range -> page .largepage = 1 ;
1603- range -> page .additional_pages =
1604- (sg -> length / HV_MIN_PAGE_REPORTING_LEN ) - 1 ;
1605- range -> page_size = HV_GPA_PAGE_RANGE_PAGE_SIZE_2MB ;
1606- range -> base_large_pfn =
1607- page_to_hvpfn (sg_page (sg )) >> HV_MIN_PAGE_REPORTING_ORDER ;
1621+ order = get_order (sg -> length );
1622+ /*
1623+ * Hyper-V expects the additional_pages field in the units
1624+ * of one of these 3 sizes, 4Kbytes, 2Mbytes or 1Gbytes.
1625+ * This is dictated by the values of the fields page.largesize
1626+ * and page_size.
1627+ * This code however, only uses 4Kbytes and 2Mbytes units
1628+ * and not 1Gbytes unit.
1629+ */
1630+
1631+ /* page reporting for pages 2MB or higher */
1632+ if (order >= HV_LARGE_REPORTING_ORDER ) {
1633+ range -> page .largepage = 1 ;
1634+ range -> page_size = HV_GPA_PAGE_RANGE_PAGE_SIZE_2MB ;
1635+ range -> base_large_pfn = page_to_hvpfn (
1636+ sg_page (sg )) >> HV_LARGE_REPORTING_ORDER ;
1637+ range -> page .additional_pages =
1638+ (sg -> length / HV_LARGE_REPORTING_LEN ) - 1 ;
1639+ } else {
1640+ /* Page reporting for pages below 2MB */
1641+ range -> page .basepfn = page_to_hvpfn (sg_page (sg ));
1642+ range -> page .largepage = false;
1643+ range -> page .additional_pages =
1644+ (sg -> length / HV_HYP_PAGE_SIZE ) - 1 ;
1645+ }
1646+
16081647 }
16091648
16101649 status = hv_do_rep_hypercall (HV_EXT_CALL_MEMORY_HEAT_HINT , nents , 0 ,
16111650 hint , NULL );
16121651 local_irq_restore (flags );
1613- if ((status & HV_HYPERCALL_RESULT_MASK ) != HV_STATUS_SUCCESS ) {
1652+ if (!hv_result_success (status )) {
1653+
16141654 pr_err ("Cold memory discard hypercall failed with status %llx\n" ,
1615- status );
1655+ status );
1656+ if (hv_hypercall_multi_failure > 0 )
1657+ hv_hypercall_multi_failure ++ ;
1658+
1659+ if (hv_result (status ) == HV_STATUS_INVALID_PARAMETER ) {
1660+ pr_err ("Underlying Hyper-V does not support order less than 9. Hypercall failed\n" );
1661+ pr_err ("Defaulting to page_reporting_order %d\n" ,
1662+ pageblock_order );
1663+ page_reporting_order = pageblock_order ;
1664+ hv_hypercall_multi_failure ++ ;
1665+ return - EINVAL ;
1666+ }
1667+
16161668 return - EINVAL ;
16171669 }
16181670
@@ -1623,25 +1675,25 @@ static void enable_page_reporting(void)
16231675{
16241676 int ret ;
16251677
1626- /* Essentially, validating 'PAGE_REPORTING_MIN_ORDER' is big enough. */
1627- if (pageblock_order < HV_MIN_PAGE_REPORTING_ORDER ) {
1628- pr_debug ("Cold memory discard is only supported on 2MB pages and above\n" );
1629- return ;
1630- }
1631-
16321678 if (!hv_query_ext_cap (HV_EXT_CAPABILITY_MEMORY_COLD_DISCARD_HINT )) {
16331679 pr_debug ("Cold memory discard hint not supported by Hyper-V\n" );
16341680 return ;
16351681 }
16361682
16371683 BUILD_BUG_ON (PAGE_REPORTING_CAPACITY > HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES );
16381684 dm_device .pr_dev_info .report = hv_free_page_report ;
1685+ /*
1686+ * We let the page_reporting_order parameter decide the order
1687+ * in the page_reporting code
1688+ */
1689+ dm_device .pr_dev_info .order = 0 ;
16391690 ret = page_reporting_register (& dm_device .pr_dev_info );
16401691 if (ret < 0 ) {
16411692 dm_device .pr_dev_info .report = NULL ;
16421693 pr_err ("Failed to enable cold memory discard: %d\n" , ret );
16431694 } else {
1644- pr_info ("Cold memory discard hint enabled\n" );
1695+ pr_info ("Cold memory discard hint enabled with order %d\n" ,
1696+ page_reporting_order );
16451697 }
16461698}
16471699
0 commit comments