Merge tag 'hyperv-next-signed-20220807' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 8 Aug 2022 17:05:19 +0000 (10:05 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 8 Aug 2022 17:05:19 +0000 (10:05 -0700)
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

drivers/hv/connection.c
drivers/hv/hv_balloon.c
drivers/hv/hyperv_vmbus.h
drivers/hv/vmbus_drv.c

index 6218bbf..eca7afd 100644 (file)
@@ -171,6 +171,14 @@ int vmbus_connect(void)
                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 =
                create_workqueue("hv_pri_chan");
        if (!vmbus_connection.handle_primary_chan_wq) {
@@ -357,6 +365,9 @@ void vmbus_disconnect(void)
        if (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)
                destroy_workqueue(vmbus_connection.work_queue);
 
index 91e8a72..fdf6dec 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/jiffies.h>
 #include <linux/mman.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -248,7 +249,7 @@ struct dm_capabilities_resp_msg {
  * num_committed: Committed memory in pages.
  * page_file_size: The accumulated size of all page files
  *                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.
  * io_diff: An indicator of file cache efficiency or page file activity,
  *         calculated as File Cache Page Fault Count - Page Read Count.
@@ -567,6 +568,11 @@ struct hv_dynmem_device {
        __u32 version;
 
        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;
@@ -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",
                                (*max_page_count) >> (20 - HV_HYP_PAGE_SHIFT));
+                       dm->max_dynamic_page_count = *max_page_count;
                }
 
                break;
@@ -1117,6 +1124,19 @@ static unsigned long compute_balloon_floor(void)
 }
 
 /*
+ * 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
  * host. Host expects the guests to post this status
  * periodically at 1 second intervals.
@@ -1157,11 +1177,7 @@ static void post_status(struct hv_dynmem_device *dm)
         * asking us to balloon them out.
         */
        num_pages_avail = si_mem_available();
-       num_pages_committed = 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();
+       num_pages_committed = get_pages_committed(dm);
 
        trace_balloon_status(num_pages_avail, num_pages_committed,
                             vm_memory_committed(), dm->num_pages_ballooned,
@@ -1807,6 +1823,109 @@ out:
        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,
                         const struct hv_vmbus_device_id *dev_id)
 {
@@ -1854,6 +1973,8 @@ static int balloon_probe(struct hv_device *dev,
                goto probe_error;
        }
 
+       hv_balloon_debugfs_init(&dm_device);
+
        return 0;
 
 probe_error:
@@ -1879,6 +2000,8 @@ static int balloon_remove(struct hv_device *dev)
        if (dm->num_pages_ballooned != 0)
                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->ha_wrk.wrk);
 
index 4f5b824..dc673ed 100644 (file)
@@ -261,6 +261,13 @@ struct vmbus_connection {
        struct workqueue_struct *work_queue;
        struct workqueue_struct *handle_primary_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
index 547ae33..23c680d 100644 (file)
@@ -1160,7 +1160,9 @@ void vmbus_on_msg_dpc(unsigned long data)
                         * work queue: the RESCIND handler can not start to
                         * 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;
 
                case CHANNELMSG_OFFERCHANNEL:
@@ -1186,6 +1188,8 @@ void vmbus_on_msg_dpc(unsigned long data)
                         * to the CPUs which will execute the offer & rescind
                         * works by the time these works will start execution.
                         */
+                       if (vmbus_connection.ignore_any_offer_msg)
+                               break;
                        atomic_inc(&vmbus_connection.offer_in_progress);
                        fallthrough;
 
@@ -2446,15 +2450,20 @@ acpi_walk_err:
 #ifdef CONFIG_PM_SLEEP
 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;
 
-       while (atomic_read(&vmbus_connection.offer_in_progress) != 0) {
-               /*
-                * We wait here until the completion of any channel
-                * offers that are currently in progress.
-                */
-               usleep_range(1000, 2000);
-       }
+       tasklet_disable(&hv_cpu->msg_dpc);
+       vmbus_connection.ignore_any_offer_msg = true;
+       /* The tasklet_enable() takes care of providing a memory barrier */
+       tasklet_enable(&hv_cpu->msg_dpc);
+
+       /* 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);
        list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
@@ -2531,6 +2540,8 @@ static int vmbus_bus_resume(struct device *dev)
        size_t msgsize;
        int ret;
 
+       vmbus_connection.ignore_any_offer_msg = false;
+
        /*
         * We only use the 'vmbus_proto_version', which was in use before
         * hibernation, to re-negotiate with the host.