Skip to content

Commit e0e7ed2

Browse files
committed
Hyper-V: support for free page reporting
Linux has support for free page reporting now (36e66c5) for virtualized environment. On Hyper-V when virtually backed VMs are configured, Hyper-V will advertise cold memory discard capability, when supported. This patch adds the support to hook into the free page reporting infrastructure and leverage the Hyper-V cold memory discard hint hypercall to report/free these pages back to the host. Signed-off-by: Sunil Muthuswamy <[email protected]> TAG_MSFT: wsl
1 parent a68a2c7 commit e0e7ed2

File tree

3 files changed

+120
-1
lines changed

3 files changed

+120
-1
lines changed

drivers/hv/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ config HYPERV_UTILS
2424
config HYPERV_BALLOON
2525
tristate "Microsoft Hyper-V Balloon driver"
2626
depends on HYPERV
27+
select PAGE_REPORTING
2728
help
2829
Select this option to enable Hyper-V Balloon driver.
2930

drivers/hv/hv_balloon.c

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include <linux/memory.h>
2222
#include <linux/notifier.h>
2323
#include <linux/percpu_counter.h>
24-
24+
#include <linux/page_reporting.h>
2525
#include <linux/hyperv.h>
2626
#include <asm/hyperv-tlfs.h>
2727

@@ -563,6 +563,9 @@ struct hv_dynmem_device {
563563
* The negotiated version agreed by host.
564564
*/
565565
__u32 version;
566+
#ifdef CONFIG_PAGE_REPORTING
567+
struct page_reporting_dev_info ph_dev_info;
568+
#endif
566569
};
567570

568571
static struct hv_dynmem_device dm_device;
@@ -1565,6 +1568,88 @@ static void balloon_onchannelcallback(void *context)
15651568

15661569
}
15671570

1571+
#ifdef CONFIG_PAGE_REPORTING
1572+
static int hyperv_discard_pages(struct scatterlist **sgs, int nents)
1573+
{
1574+
unsigned long flags;
1575+
struct hv_memory_hint *hint;
1576+
int i;
1577+
struct scatterlist *sg;
1578+
u64 status;
1579+
1580+
WARN_ON(nents > HV_MAX_GPA_PAGE_RANGES);
1581+
local_irq_save(flags);
1582+
hint = *(struct hv_memory_hint **)this_cpu_ptr(hyperv_pcpu_input_arg);
1583+
if (!hint) {
1584+
local_irq_restore(flags);
1585+
return -EINVAL;
1586+
}
1587+
1588+
hint->type = HV_MEMORY_HINT_TYPE_COLD_DISCARD;
1589+
hint->reserved = 0;
1590+
for (i = 0, sg = sgs[0]; sg; sg = sg_next(sg), i++) {
1591+
int order;
1592+
union hv_gpa_page_range *range;
1593+
1594+
order = get_order(sg->length);
1595+
range = &hint->ranges[i];
1596+
range->address_space = 0;
1597+
range->page.largepage = 1;
1598+
range->page.additional_pages = (1ull << (order - 9)) - 1;
1599+
range->base_large_pfn = page_to_pfn(sg_page(sg)) >> 9;
1600+
}
1601+
1602+
WARN_ON(i != nents);
1603+
1604+
status = hv_do_rep_hypercall(HVCALL_MEMORY_HEAT_HINT, nents, 0,
1605+
hint, NULL);
1606+
local_irq_restore(flags);
1607+
status &= HV_HYPERCALL_RESULT_MASK;
1608+
if (status != HV_STATUS_SUCCESS) {
1609+
WARN_ONCE(1,
1610+
"Cold memory discard hypercall failed with status 0x%llx\n",
1611+
status);
1612+
return -EINVAL;
1613+
} else {
1614+
return 0;
1615+
}
1616+
}
1617+
1618+
static int hv_page_hinting(struct page_reporting_dev_info *ph_dev_info,
1619+
struct scatterlist *sg, unsigned int nents)
1620+
{
1621+
return hyperv_discard_pages(&sg, nents);
1622+
}
1623+
1624+
static void enable_page_reporting(void)
1625+
{
1626+
int ret;
1627+
1628+
if (!hyperv_query_ext_cap(HV_CAPABILITY_MEMORY_COLD_DISCARD_HINT)) {
1629+
pr_info("Cold memory discard hint not supported.\n");
1630+
return;
1631+
}
1632+
1633+
BUILD_BUG_ON(PAGE_REPORTING_CAPACITY > HV_MAX_GPA_PAGE_RANGES);
1634+
dm_device.ph_dev_info.report = hv_page_hinting;
1635+
ret = page_reporting_register(&dm_device.ph_dev_info);
1636+
if (ret < 0) {
1637+
pr_err("Failed to enable cold memory discard: %d\n", ret);
1638+
dm_device.ph_dev_info.report = NULL;
1639+
} else {
1640+
pr_info("Cold memory discard hint enabled\n");
1641+
}
1642+
}
1643+
1644+
static void disable_hinting(void)
1645+
{
1646+
if (dm_device.ph_dev_info.report) {
1647+
page_reporting_unregister(&dm_device.ph_dev_info);
1648+
dm_device.ph_dev_info.report = NULL;
1649+
}
1650+
}
1651+
#endif //CONFIG_PAGE_REPORTING
1652+
15681653
static int balloon_connect_vsp(struct hv_device *dev)
15691654
{
15701655
struct dm_version_request version_req;
@@ -1710,6 +1795,10 @@ static int balloon_probe(struct hv_device *dev,
17101795
if (ret != 0)
17111796
return ret;
17121797

1798+
#ifdef CONFIG_PAGE_REPORTING
1799+
enable_page_reporting();
1800+
#endif
1801+
17131802
dm_device.state = DM_INITIALIZED;
17141803

17151804
dm_device.thread =
@@ -1725,6 +1814,9 @@ static int balloon_probe(struct hv_device *dev,
17251814
dm_device.state = DM_INIT_ERROR;
17261815
dm_device.thread = NULL;
17271816
vmbus_close(dev->channel);
1817+
#ifdef CONFIG_PAGE_REPORTING
1818+
disable_hinting();
1819+
#endif
17281820
#ifdef CONFIG_MEMORY_HOTPLUG
17291821
unregister_memory_notifier(&hv_memory_nb);
17301822
restore_online_page_callback(&hv_online_page);
@@ -1747,6 +1839,9 @@ static int balloon_remove(struct hv_device *dev)
17471839

17481840
kthread_stop(dm->thread);
17491841
vmbus_close(dev->channel);
1842+
#ifdef CONFIG_PAGE_REPORTING
1843+
disable_hinting();
1844+
#endif
17501845
#ifdef CONFIG_MEMORY_HOTPLUG
17511846
unregister_memory_notifier(&hv_memory_nb);
17521847
restore_online_page_callback(&hv_online_page);

include/asm-generic/hyperv-tlfs.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ struct ms_hyperv_tsc_page {
153153
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af
154154
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0
155155
#define HVCALL_QUERY_CAPABILITIES 0x8001
156+
#define HVCALL_MEMORY_HEAT_HINT 0x8003
156157

157158
#define HV_FLUSH_ALL_PROCESSORS BIT(0)
158159
#define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES BIT(1)
@@ -377,6 +378,12 @@ union hv_gpa_page_range {
377378
u64 largepage:1;
378379
u64 basepfn:52;
379380
} page;
381+
struct {
382+
u64:12;
383+
u64 page_size:1;
384+
u64 reserved:8;
385+
u64 base_large_pfn:43;
386+
};
380387
};
381388

382389
/*
@@ -496,4 +503,20 @@ struct hv_set_vp_registers_input {
496503
} element[];
497504
} __packed;
498505

506+
#ifdef CONFIG_PAGE_REPORTING
507+
#define HV_CAPABILITY_MEMORY_COLD_DISCARD_HINT BIT(8)
508+
509+
// The whole argument should fit in a page to be able to pass to the hypervisor
510+
// in one hypercall.
511+
#define HV_MAX_GPA_PAGE_RANGES ((PAGE_SIZE - 8)/sizeof(union hv_gpa_page_range))
512+
513+
/* HvExtMemoryHeatHint hypercall */
514+
#define HV_MEMORY_HINT_TYPE_COLD_DISCARD BIT(1)
515+
struct hv_memory_hint {
516+
u64 type:2;
517+
u64 reserved:62;
518+
union hv_gpa_page_range ranges[1];
519+
};
520+
521+
#endif //CONFIG_PAGE_REPORTING
499522
#endif

0 commit comments

Comments
 (0)