Commit d180e0a1 authored by Alexander Atanasov's avatar Alexander Atanasov Committed by Wei Liu

Drivers: hv: Create debugfs file with hyper-v balloon usage information

Allow the guest to know how much it is ballooned by the host.
It is useful when debugging out of memory conditions.

When host gets back memory from the guest it is accounted
as used memory in the guest but the guest have no way to know
how much it is actually ballooned.

Expose current state, flags and max possible memory to the guest.
While at it - fix a 10+ years old typo.
Signed-off-by: default avatarAlexander Atanasov <alexander.atanasov@virtuozzo.com>
Reviewed-by: default avatarMichael Kelley <mikelley@microsoft.com>
Link: https://lore.kernel.org/r/20220711181825.52318-1-alexander.atanasov@virtuozzo.comSigned-off-by: default avatarWei Liu <wei.liu@kernel.org>
parent bf28462e
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/debugfs.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -248,7 +249,7 @@ struct dm_capabilities_resp_msg { ...@@ -248,7 +249,7 @@ struct dm_capabilities_resp_msg {
* num_committed: Committed memory in pages. * num_committed: Committed memory in pages.
* page_file_size: The accumulated size of all page files * page_file_size: The accumulated size of all page files
* in the system in pages. * in the system in pages.
* zero_free: The nunber of zero and free pages. * zero_free: The number of zero and free pages.
* page_file_writes: The writes to the page file in pages. * page_file_writes: The writes to the page file in pages.
* io_diff: An indicator of file cache efficiency or page file activity, * io_diff: An indicator of file cache efficiency or page file activity,
* calculated as File Cache Page Fault Count - Page Read Count. * calculated as File Cache Page Fault Count - Page Read Count.
...@@ -567,6 +568,11 @@ struct hv_dynmem_device { ...@@ -567,6 +568,11 @@ struct hv_dynmem_device {
__u32 version; __u32 version;
struct page_reporting_dev_info pr_dev_info; struct page_reporting_dev_info pr_dev_info;
/*
* Maximum number of pages that can be hot_add-ed
*/
__u64 max_dynamic_page_count;
}; };
static struct hv_dynmem_device dm_device; static struct hv_dynmem_device dm_device;
...@@ -1078,6 +1084,7 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg) ...@@ -1078,6 +1084,7 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)
pr_info("Max. dynamic memory size: %llu MB\n", pr_info("Max. dynamic memory size: %llu MB\n",
(*max_page_count) >> (20 - HV_HYP_PAGE_SHIFT)); (*max_page_count) >> (20 - HV_HYP_PAGE_SHIFT));
dm->max_dynamic_page_count = *max_page_count;
} }
break; break;
...@@ -1116,6 +1123,19 @@ static unsigned long compute_balloon_floor(void) ...@@ -1116,6 +1123,19 @@ static unsigned long compute_balloon_floor(void)
return min_pages; return min_pages;
} }
/*
* Compute total committed memory pages
*/
static unsigned long get_pages_committed(struct hv_dynmem_device *dm)
{
return vm_memory_committed() +
dm->num_pages_ballooned +
(dm->num_pages_added > dm->num_pages_onlined ?
dm->num_pages_added - dm->num_pages_onlined : 0) +
compute_balloon_floor();
}
/* /*
* Post our status as it relates memory pressure to the * Post our status as it relates memory pressure to the
* host. Host expects the guests to post this status * host. Host expects the guests to post this status
...@@ -1157,11 +1177,7 @@ static void post_status(struct hv_dynmem_device *dm) ...@@ -1157,11 +1177,7 @@ static void post_status(struct hv_dynmem_device *dm)
* asking us to balloon them out. * asking us to balloon them out.
*/ */
num_pages_avail = si_mem_available(); num_pages_avail = si_mem_available();
num_pages_committed = vm_memory_committed() + num_pages_committed = get_pages_committed(dm);
dm->num_pages_ballooned +
(dm->num_pages_added > dm->num_pages_onlined ?
dm->num_pages_added - dm->num_pages_onlined : 0) +
compute_balloon_floor();
trace_balloon_status(num_pages_avail, num_pages_committed, trace_balloon_status(num_pages_avail, num_pages_committed,
vm_memory_committed(), dm->num_pages_ballooned, vm_memory_committed(), dm->num_pages_ballooned,
...@@ -1807,6 +1823,109 @@ static int balloon_connect_vsp(struct hv_device *dev) ...@@ -1807,6 +1823,109 @@ static int balloon_connect_vsp(struct hv_device *dev)
return ret; return ret;
} }
/*
* DEBUGFS Interface
*/
#ifdef CONFIG_DEBUG_FS
/**
* hv_balloon_debug_show - shows statistics of balloon operations.
* @f: pointer to the &struct seq_file.
* @offset: ignored.
*
* Provides the statistics that can be accessed in hv-balloon in the debugfs.
*
* Return: zero on success or an error code.
*/
static int hv_balloon_debug_show(struct seq_file *f, void *offset)
{
struct hv_dynmem_device *dm = f->private;
char *sname;
seq_printf(f, "%-22s: %u.%u\n", "host_version",
DYNMEM_MAJOR_VERSION(dm->version),
DYNMEM_MINOR_VERSION(dm->version));
seq_printf(f, "%-22s:", "capabilities");
if (ballooning_enabled())
seq_puts(f, " enabled");
if (hot_add_enabled())
seq_puts(f, " hot_add");
seq_puts(f, "\n");
seq_printf(f, "%-22s: %u", "state", dm->state);
switch (dm->state) {
case DM_INITIALIZING:
sname = "Initializing";
break;
case DM_INITIALIZED:
sname = "Initialized";
break;
case DM_BALLOON_UP:
sname = "Balloon Up";
break;
case DM_BALLOON_DOWN:
sname = "Balloon Down";
break;
case DM_HOT_ADD:
sname = "Hot Add";
break;
case DM_INIT_ERROR:
sname = "Error";
break;
default:
sname = "Unknown";
}
seq_printf(f, " (%s)\n", sname);
/* HV Page Size */
seq_printf(f, "%-22s: %ld\n", "page_size", HV_HYP_PAGE_SIZE);
/* Pages added with hot_add */
seq_printf(f, "%-22s: %u\n", "pages_added", dm->num_pages_added);
/* pages that are "onlined"/used from pages_added */
seq_printf(f, "%-22s: %u\n", "pages_onlined", dm->num_pages_onlined);
/* pages we have given back to host */
seq_printf(f, "%-22s: %u\n", "pages_ballooned", dm->num_pages_ballooned);
seq_printf(f, "%-22s: %lu\n", "total_pages_committed",
get_pages_committed(dm));
seq_printf(f, "%-22s: %llu\n", "max_dynamic_page_count",
dm->max_dynamic_page_count);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(hv_balloon_debug);
static void hv_balloon_debugfs_init(struct hv_dynmem_device *b)
{
debugfs_create_file("hv-balloon", 0444, NULL, b,
&hv_balloon_debug_fops);
}
static void hv_balloon_debugfs_exit(struct hv_dynmem_device *b)
{
debugfs_remove(debugfs_lookup("hv-balloon", NULL));
}
#else
static inline void hv_balloon_debugfs_init(struct hv_dynmem_device *b)
{
}
static inline void hv_balloon_debugfs_exit(struct hv_dynmem_device *b)
{
}
#endif /* CONFIG_DEBUG_FS */
static int balloon_probe(struct hv_device *dev, static int balloon_probe(struct hv_device *dev,
const struct hv_vmbus_device_id *dev_id) const struct hv_vmbus_device_id *dev_id)
{ {
...@@ -1854,6 +1973,8 @@ static int balloon_probe(struct hv_device *dev, ...@@ -1854,6 +1973,8 @@ static int balloon_probe(struct hv_device *dev,
goto probe_error; goto probe_error;
} }
hv_balloon_debugfs_init(&dm_device);
return 0; return 0;
probe_error: probe_error:
...@@ -1879,6 +2000,8 @@ static int balloon_remove(struct hv_device *dev) ...@@ -1879,6 +2000,8 @@ static int balloon_remove(struct hv_device *dev)
if (dm->num_pages_ballooned != 0) if (dm->num_pages_ballooned != 0)
pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned); pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned);
hv_balloon_debugfs_exit(dm);
cancel_work_sync(&dm->balloon_wrk.wrk); cancel_work_sync(&dm->balloon_wrk.wrk);
cancel_work_sync(&dm->ha_wrk.wrk); cancel_work_sync(&dm->ha_wrk.wrk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment