Skip to content

Commit ad42723

Browse files
Shradha Guptakelsey-steele
authored andcommitted
hv_balloon: Add support for configurable order free page reporting
Newer versions of Hyper-V allow reporting unused guest pages in chunks smaller than 2 Mbytes. Using smaller chunks allows reporting more unused guest pages, but with increased overhead in the finding the small chunks. To make this tradeoff configurable, use the existing page_reporting_order module parameter to control the reporting order. Drop and refine checks that restricted the minimun page reporting order to 2Mbytes size pages. Add appropriate checks to make sure the underlying Hyper-V versions support cold discard hints of any order (and not just starting from 9) Signed-off-by: Shradha Gupta <shradhagupta@linux.microsoft.com> Reviewed-by: Michael Kelley <mikelley@microsoft.com> Link: https://lore.kernel.org/r/1664517699-1085-3-git-send-email-shradhagupta@linux.microsoft.com Signed-off-by: Wei Liu <wei.liu@kernel.org> (cherry picked from commit 047eabc hyperv-next) Link: https://microsoft.visualstudio.com/OS/_workitems/edit/42270731/ Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
1 parent 0f8c1c4 commit ad42723

1 file changed

Lines changed: 73 additions & 21 deletions

File tree

drivers/hv/hv_balloon.c

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -467,12 +467,16 @@ static bool do_hot_add;
467467
* the specified number of seconds.
468468
*/
469469
static 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
*/
474476
static unsigned long last_post_time;
475477

478+
static int hv_hypercall_multi_failure;
479+
476480
module_param(hot_add, bool, (S_IRUGO | S_IWUSR));
477481
MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add");
478482

@@ -572,6 +576,10 @@ static struct hv_dynmem_device dm_device;
572576

573577
static 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
576584
static 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)
15761596
static 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

Comments
 (0)