diff options
Diffstat (limited to 'drivers/hv/hv_balloon.c')
| -rw-r--r-- | drivers/hv/hv_balloon.c | 58 |
1 files changed, 43 insertions, 15 deletions
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 4c605c70ebf..5e90c5d771a 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -19,6 +19,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> +#include <linux/jiffies.h> #include <linux/mman.h> #include <linux/delay.h> #include <linux/init.h> @@ -459,6 +460,11 @@ static bool do_hot_add; */ static uint pressure_report_delay = 45; +/* + * The last time we posted a pressure report to host. + */ +static unsigned long last_post_time; + module_param(hot_add, bool, (S_IRUGO | S_IWUSR)); MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add"); @@ -542,6 +548,7 @@ struct hv_dynmem_device { static struct hv_dynmem_device dm_device; +static void post_status(struct hv_dynmem_device *dm); #ifdef CONFIG_MEMORY_HOTPLUG static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size) @@ -562,7 +569,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, struct hv_hotadd_state *has) { int ret = 0; - int i, nid, t; + int i, nid; unsigned long start_pfn; unsigned long processed_pfn; unsigned long total_pfn = pfn_count; @@ -607,15 +614,12 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, /* * Wait for the memory block to be onlined. + * Since the hot add has succeeded, it is ok to + * proceed even if the pages in the hot added region + * have not been "onlined" within the allowed time. */ - t = wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ); - if (t == 0) { - pr_info("hot_add memory timedout\n"); - has->ha_end_pfn -= HA_CHUNK; - has->covered_end_pfn -= processed_pfn; - break; - } - + wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ); + post_status(&dm_device); } return; @@ -828,7 +832,6 @@ static void hot_add_req(struct work_struct *dummy) memset(&resp, 0, sizeof(struct dm_hot_add_response)); resp.hdr.type = DM_MEM_HOT_ADD_RESPONSE; resp.hdr.size = sizeof(struct dm_hot_add_response); - resp.hdr.trans_id = atomic_inc_return(&trans_id); #ifdef CONFIG_MEMORY_HOTPLUG pg_start = dm->ha_wrk.ha_page_range.finfo.start_page; @@ -890,6 +893,7 @@ static void hot_add_req(struct work_struct *dummy) pr_info("Memory hot add failed\n"); dm->state = DM_INITIALIZED; + resp.hdr.trans_id = atomic_inc_return(&trans_id); vmbus_sendpacket(dm->dev->channel, &resp, sizeof(struct dm_hot_add_response), (unsigned long)NULL, @@ -954,11 +958,17 @@ static void post_status(struct hv_dynmem_device *dm) { struct dm_status status; struct sysinfo val; + unsigned long now = jiffies; + unsigned long last_post = last_post_time; if (pressure_report_delay > 0) { --pressure_report_delay; return; } + + if (!time_after(now, (last_post_time + HZ))) + return; + si_meminfo(&val); memset(&status, 0, sizeof(struct dm_status)); status.hdr.type = DM_STATUS_REPORT; @@ -978,6 +988,22 @@ static void post_status(struct hv_dynmem_device *dm) dm->num_pages_ballooned + compute_balloon_floor(); + /* + * If our transaction ID is no longer current, just don't + * send the status. This can happen if we were interrupted + * after we picked our transaction ID. + */ + if (status.hdr.trans_id != atomic_read(&trans_id)) + return; + + /* + * If the last post time that we sampled has changed, + * we have raced, don't post the status. + */ + if (last_post != last_post_time) + return; + + last_post_time = jiffies; vmbus_sendpacket(dm->dev->channel, &status, sizeof(struct dm_status), (unsigned long)NULL, @@ -1076,7 +1102,6 @@ static void balloon_up(struct work_struct *dummy) bl_resp = (struct dm_balloon_response *)send_buffer; memset(send_buffer, 0, PAGE_SIZE); bl_resp->hdr.type = DM_BALLOON_RESPONSE; - bl_resp->hdr.trans_id = atomic_inc_return(&trans_id); bl_resp->hdr.size = sizeof(struct dm_balloon_response); bl_resp->more_pages = 1; @@ -1104,6 +1129,7 @@ static void balloon_up(struct work_struct *dummy) */ do { + bl_resp->hdr.trans_id = atomic_inc_return(&trans_id); ret = vmbus_sendpacket(dm_device.dev->channel, bl_resp, bl_resp->hdr.size, @@ -1112,7 +1138,7 @@ static void balloon_up(struct work_struct *dummy) if (ret == -EAGAIN) msleep(20); - + post_status(&dm_device); } while (ret == -EAGAIN); if (ret) { @@ -1139,8 +1165,10 @@ static void balloon_down(struct hv_dynmem_device *dm, struct dm_unballoon_response resp; int i; - for (i = 0; i < range_count; i++) + for (i = 0; i < range_count; i++) { free_balloon_pages(dm, &range_array[i]); + post_status(&dm_device); + } if (req->more_pages == 1) return; @@ -1166,7 +1194,8 @@ static int dm_thread_func(void *dm_dev) int t; while (!kthread_should_stop()) { - t = wait_for_completion_timeout(&dm_device.config_event, 1*HZ); + t = wait_for_completion_interruptible_timeout( + &dm_device.config_event, 1*HZ); /* * The host expects us to post information on the memory * pressure every second. @@ -1521,5 +1550,4 @@ static int __init init_balloon_drv(void) module_init(init_balloon_drv); MODULE_DESCRIPTION("Hyper-V Balloon"); -MODULE_VERSION(HV_DRV_VERSION); MODULE_LICENSE("GPL"); |
