Skip to content

Commit 25bd2b2

Browse files
dcuiSasha Levin
authored andcommitted
hv_balloon: Add the support of hibernation
When hibernation is enabled, we must ignore the balloon up/down and hot-add requests from the host, if any. Signed-off-by: Dexuan Cui <[email protected]> Acked-by: David Hildenbrand <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent b96f865 commit 25bd2b2

File tree

1 file changed

+85
-2
lines changed

1 file changed

+85
-2
lines changed

drivers/hv/hv_balloon.c

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <linux/hyperv.h>
2626
#include <asm/hyperv-tlfs.h>
2727

28+
#include <asm/mshyperv.h>
29+
2830
#define CREATE_TRACE_POINTS
2931
#include "hv_trace_balloon.h"
3032

@@ -456,6 +458,7 @@ struct hot_add_wrk {
456458
struct work_struct wrk;
457459
};
458460

461+
static bool allow_hibernation;
459462
static bool hot_add = true;
460463
static bool do_hot_add;
461464
/*
@@ -1052,8 +1055,12 @@ static void hot_add_req(struct work_struct *dummy)
10521055
else
10531056
resp.result = 0;
10541057

1055-
if (!do_hot_add || (resp.page_count == 0))
1056-
pr_err("Memory hot add failed\n");
1058+
if (!do_hot_add || resp.page_count == 0) {
1059+
if (!allow_hibernation)
1060+
pr_err("Memory hot add failed\n");
1061+
else
1062+
pr_info("Ignore hot-add request!\n");
1063+
}
10571064

10581065
dm->state = DM_INITIALIZED;
10591066
resp.hdr.trans_id = atomic_inc_return(&trans_id);
@@ -1508,6 +1515,11 @@ static void balloon_onchannelcallback(void *context)
15081515
break;
15091516

15101517
case DM_BALLOON_REQUEST:
1518+
if (allow_hibernation) {
1519+
pr_info("Ignore balloon-up request!\n");
1520+
break;
1521+
}
1522+
15111523
if (dm->state == DM_BALLOON_UP)
15121524
pr_warn("Currently ballooning\n");
15131525
bal_msg = (struct dm_balloon *)recv_buffer;
@@ -1517,6 +1529,11 @@ static void balloon_onchannelcallback(void *context)
15171529
break;
15181530

15191531
case DM_UNBALLOON_REQUEST:
1532+
if (allow_hibernation) {
1533+
pr_info("Ignore balloon-down request!\n");
1534+
break;
1535+
}
1536+
15201537
dm->state = DM_BALLOON_DOWN;
15211538
balloon_down(dm,
15221539
(struct dm_unballoon_request *)recv_buffer);
@@ -1622,6 +1639,11 @@ static int balloon_connect_vsp(struct hv_device *dev)
16221639
cap_msg.hdr.size = sizeof(struct dm_capabilities);
16231640
cap_msg.hdr.trans_id = atomic_inc_return(&trans_id);
16241641

1642+
/*
1643+
* When hibernation (i.e. virtual ACPI S4 state) is enabled, the host
1644+
* currently still requires the bits to be set, so we have to add code
1645+
* to fail the host's hot-add and balloon up/down requests, if any.
1646+
*/
16251647
cap_msg.caps.cap_bits.balloon = 1;
16261648
cap_msg.caps.cap_bits.hot_add = 1;
16271649

@@ -1671,6 +1693,10 @@ static int balloon_probe(struct hv_device *dev,
16711693
{
16721694
int ret;
16731695

1696+
allow_hibernation = hv_is_hibernation_supported();
1697+
if (allow_hibernation)
1698+
hot_add = false;
1699+
16741700
#ifdef CONFIG_MEMORY_HOTPLUG
16751701
do_hot_add = hot_add;
16761702
#else
@@ -1710,6 +1736,8 @@ static int balloon_probe(struct hv_device *dev,
17101736
return 0;
17111737

17121738
probe_error:
1739+
dm_device.state = DM_INIT_ERROR;
1740+
dm_device.thread = NULL;
17131741
vmbus_close(dev->channel);
17141742
#ifdef CONFIG_MEMORY_HOTPLUG
17151743
unregister_memory_notifier(&hv_memory_nb);
@@ -1751,6 +1779,59 @@ static int balloon_remove(struct hv_device *dev)
17511779
return 0;
17521780
}
17531781

1782+
static int balloon_suspend(struct hv_device *hv_dev)
1783+
{
1784+
struct hv_dynmem_device *dm = hv_get_drvdata(hv_dev);
1785+
1786+
tasklet_disable(&hv_dev->channel->callback_event);
1787+
1788+
cancel_work_sync(&dm->balloon_wrk.wrk);
1789+
cancel_work_sync(&dm->ha_wrk.wrk);
1790+
1791+
if (dm->thread) {
1792+
kthread_stop(dm->thread);
1793+
dm->thread = NULL;
1794+
vmbus_close(hv_dev->channel);
1795+
}
1796+
1797+
tasklet_enable(&hv_dev->channel->callback_event);
1798+
1799+
return 0;
1800+
1801+
}
1802+
1803+
static int balloon_resume(struct hv_device *dev)
1804+
{
1805+
int ret;
1806+
1807+
dm_device.state = DM_INITIALIZING;
1808+
1809+
ret = balloon_connect_vsp(dev);
1810+
1811+
if (ret != 0)
1812+
goto out;
1813+
1814+
dm_device.thread =
1815+
kthread_run(dm_thread_func, &dm_device, "hv_balloon");
1816+
if (IS_ERR(dm_device.thread)) {
1817+
ret = PTR_ERR(dm_device.thread);
1818+
dm_device.thread = NULL;
1819+
goto close_channel;
1820+
}
1821+
1822+
dm_device.state = DM_INITIALIZED;
1823+
return 0;
1824+
close_channel:
1825+
vmbus_close(dev->channel);
1826+
out:
1827+
dm_device.state = DM_INIT_ERROR;
1828+
#ifdef CONFIG_MEMORY_HOTPLUG
1829+
unregister_memory_notifier(&hv_memory_nb);
1830+
restore_online_page_callback(&hv_online_page);
1831+
#endif
1832+
return ret;
1833+
}
1834+
17541835
static const struct hv_vmbus_device_id id_table[] = {
17551836
/* Dynamic Memory Class ID */
17561837
/* 525074DC-8985-46e2-8057-A307DC18A502 */
@@ -1765,6 +1846,8 @@ static struct hv_driver balloon_drv = {
17651846
.id_table = id_table,
17661847
.probe = balloon_probe,
17671848
.remove = balloon_remove,
1849+
.suspend = balloon_suspend,
1850+
.resume = balloon_resume,
17681851
.driver = {
17691852
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
17701853
},

0 commit comments

Comments
 (0)