Commit df7a456e authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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);

+129 −6
Original line number Diff line number Diff line
@@ -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;
@@ -1116,6 +1123,19 @@ static unsigned long compute_balloon_floor(void)
	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
 * host. Host expects the guests to post this status
@@ -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 @@ static int balloon_connect_vsp(struct hv_device *dev)
	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);

+7 −0
Original line number Diff line number Diff line
@@ -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
+19 −8
Original line number Diff line number Diff line
@@ -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 @@ static int vmbus_acpi_add(struct acpi_device *device)
#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.