Commit df7a456e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hyperv-next-signed-20220807' of...

Merge tag 'hyperv-next-signed-20220807' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux

Pull hyperv updates from Wei Liu:
 "A few miscellaneous patches. There is no large patch series for this
  merge window"

* tag 'hyperv-next-signed-20220807' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  Drivers: hv: Create debugfs file with hyper-v balloon usage information
  drm/hyperv : Removing the restruction of VRAM allocation with PCI bar size
  PCI: hv: Take a const cpumask in hv_compose_msi_req_get_cpu()
  Drivers: hv: vm_bus: Handle vmbus rescind calls after vmbus is suspended
parents cab9de71 d180e0a1
...@@ -171,6 +171,14 @@ int vmbus_connect(void) ...@@ -171,6 +171,14 @@ int vmbus_connect(void)
goto cleanup; goto cleanup;
} }
vmbus_connection.rescind_work_queue =
create_workqueue("hv_vmbus_rescind");
if (!vmbus_connection.rescind_work_queue) {
ret = -ENOMEM;
goto cleanup;
}
vmbus_connection.ignore_any_offer_msg = false;
vmbus_connection.handle_primary_chan_wq = vmbus_connection.handle_primary_chan_wq =
create_workqueue("hv_pri_chan"); create_workqueue("hv_pri_chan");
if (!vmbus_connection.handle_primary_chan_wq) { if (!vmbus_connection.handle_primary_chan_wq) {
...@@ -357,6 +365,9 @@ void vmbus_disconnect(void) ...@@ -357,6 +365,9 @@ void vmbus_disconnect(void)
if (vmbus_connection.handle_primary_chan_wq) if (vmbus_connection.handle_primary_chan_wq)
destroy_workqueue(vmbus_connection.handle_primary_chan_wq); destroy_workqueue(vmbus_connection.handle_primary_chan_wq);
if (vmbus_connection.rescind_work_queue)
destroy_workqueue(vmbus_connection.rescind_work_queue);
if (vmbus_connection.work_queue) if (vmbus_connection.work_queue)
destroy_workqueue(vmbus_connection.work_queue); destroy_workqueue(vmbus_connection.work_queue);
......
...@@ -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);
......
...@@ -261,6 +261,13 @@ struct vmbus_connection { ...@@ -261,6 +261,13 @@ struct vmbus_connection {
struct workqueue_struct *work_queue; struct workqueue_struct *work_queue;
struct workqueue_struct *handle_primary_chan_wq; struct workqueue_struct *handle_primary_chan_wq;
struct workqueue_struct *handle_sub_chan_wq; struct workqueue_struct *handle_sub_chan_wq;
struct workqueue_struct *rescind_work_queue;
/*
* On suspension of the vmbus, the accumulated offer messages
* must be dropped.
*/
bool ignore_any_offer_msg;
/* /*
* The number of sub-channels and hv_sock channels that should be * The number of sub-channels and hv_sock channels that should be
......
...@@ -1160,7 +1160,9 @@ void vmbus_on_msg_dpc(unsigned long data) ...@@ -1160,7 +1160,9 @@ void vmbus_on_msg_dpc(unsigned long data)
* work queue: the RESCIND handler can not start to * work queue: the RESCIND handler can not start to
* run before the OFFER handler finishes. * run before the OFFER handler finishes.
*/ */
schedule_work(&ctx->work); if (vmbus_connection.ignore_any_offer_msg)
break;
queue_work(vmbus_connection.rescind_work_queue, &ctx->work);
break; break;
case CHANNELMSG_OFFERCHANNEL: case CHANNELMSG_OFFERCHANNEL:
...@@ -1186,6 +1188,8 @@ void vmbus_on_msg_dpc(unsigned long data) ...@@ -1186,6 +1188,8 @@ void vmbus_on_msg_dpc(unsigned long data)
* to the CPUs which will execute the offer & rescind * to the CPUs which will execute the offer & rescind
* works by the time these works will start execution. * works by the time these works will start execution.
*/ */
if (vmbus_connection.ignore_any_offer_msg)
break;
atomic_inc(&vmbus_connection.offer_in_progress); atomic_inc(&vmbus_connection.offer_in_progress);
fallthrough; fallthrough;
...@@ -2446,15 +2450,20 @@ static int vmbus_acpi_add(struct acpi_device *device) ...@@ -2446,15 +2450,20 @@ static int vmbus_acpi_add(struct acpi_device *device)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int vmbus_bus_suspend(struct device *dev) static int vmbus_bus_suspend(struct device *dev)
{ {
struct hv_per_cpu_context *hv_cpu = per_cpu_ptr(
hv_context.cpu_context, VMBUS_CONNECT_CPU);
struct vmbus_channel *channel, *sc; struct vmbus_channel *channel, *sc;
while (atomic_read(&vmbus_connection.offer_in_progress) != 0) { tasklet_disable(&hv_cpu->msg_dpc);
/* vmbus_connection.ignore_any_offer_msg = true;
* We wait here until the completion of any channel /* The tasklet_enable() takes care of providing a memory barrier */
* offers that are currently in progress. tasklet_enable(&hv_cpu->msg_dpc);
*/
usleep_range(1000, 2000); /* Drain all the workqueues as we are in suspend */
} drain_workqueue(vmbus_connection.rescind_work_queue);
drain_workqueue(vmbus_connection.work_queue);
drain_workqueue(vmbus_connection.handle_primary_chan_wq);
drain_workqueue(vmbus_connection.handle_sub_chan_wq);
mutex_lock(&vmbus_connection.channel_mutex); mutex_lock(&vmbus_connection.channel_mutex);
list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
...@@ -2531,6 +2540,8 @@ static int vmbus_bus_resume(struct device *dev) ...@@ -2531,6 +2540,8 @@ static int vmbus_bus_resume(struct device *dev)
size_t msgsize; size_t msgsize;
int ret; int ret;
vmbus_connection.ignore_any_offer_msg = false;
/* /*
* We only use the 'vmbus_proto_version', which was in use before * We only use the 'vmbus_proto_version', which was in use before
* hibernation, to re-negotiate with the host. * hibernation, to re-negotiate with the host.
......
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