[RFC PATCH 8/12] x86/Hyper-V: Initialize bounce buffer page cache and list

From: Tianyu Lan
Date: Sun Feb 28 2021 - 10:08:48 EST


From: Tianyu Lan <Tianyu.Lan@xxxxxxxxxxxxx>

Initialize/free bounce buffer resource when add/delete
vmbus channel in Isolation VM.

Signed-off-by: Sunil Muthuswamy <sunilmut@xxxxxxxxxxxxx>
Co-Developed-by: Sunil Muthuswamy <sunilmut@xxxxxxxxxxxxx>
Signed-off-by: Tianyu Lan <Tianyu.Lan@xxxxxxxxxxxxx>
---
drivers/hv/Makefile | 2 +-
drivers/hv/channel_mgmt.c | 29 +++++++++++++++++----------
drivers/hv/hv_bounce.c | 42 +++++++++++++++++++++++++++++++++++++++
drivers/hv/hyperv_vmbus.h | 14 +++++++++++++
include/linux/hyperv.h | 22 ++++++++++++++++++++
5 files changed, 97 insertions(+), 12 deletions(-)
create mode 100644 drivers/hv/hv_bounce.c

diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile
index 94daf8240c95..b0c20fed9153 100644
--- a/drivers/hv/Makefile
+++ b/drivers/hv/Makefile
@@ -8,6 +8,6 @@ CFLAGS_hv_balloon.o = -I$(src)

hv_vmbus-y := vmbus_drv.o \
hv.o connection.o channel.o \
- channel_mgmt.o ring_buffer.o hv_trace.o
+ channel_mgmt.o ring_buffer.o hv_trace.o hv_bounce.o
hv_vmbus-$(CONFIG_HYPERV_TESTING) += hv_debugfs.o
hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o hv_utils_transport.o
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index f0ed730e2e4e..e2846cacfd70 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -336,6 +336,18 @@ bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, u8 *buf,

EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);

+/*
+ * free_channel - Release the resources used by the vmbus channel object
+ */
+static void free_channel(struct vmbus_channel *channel)
+{
+ tasklet_kill(&channel->callback_event);
+ vmbus_remove_channel_attr_group(channel);
+
+ kobject_put(&channel->kobj);
+ hv_free_channel_ivm(channel);
+}
+
/*
* alloc_channel - Allocate and initialize a vmbus channel object
*/
@@ -360,17 +372,6 @@ static struct vmbus_channel *alloc_channel(void)
return channel;
}

-/*
- * free_channel - Release the resources used by the vmbus channel object
- */
-static void free_channel(struct vmbus_channel *channel)
-{
- tasklet_kill(&channel->callback_event);
- vmbus_remove_channel_attr_group(channel);
-
- kobject_put(&channel->kobj);
-}
-
void vmbus_channel_map_relid(struct vmbus_channel *channel)
{
if (WARN_ON(channel->offermsg.child_relid >= MAX_CHANNEL_RELIDS))
@@ -510,6 +511,8 @@ static void vmbus_add_channel_work(struct work_struct *work)
if (vmbus_add_channel_kobj(dev, newchannel))
goto err_deq_chan;

+ hv_init_channel_ivm(newchannel);
+
if (primary_channel->sc_creation_callback != NULL)
primary_channel->sc_creation_callback(newchannel);

@@ -543,6 +546,10 @@ static void vmbus_add_channel_work(struct work_struct *work)
}

newchannel->probe_done = true;
+
+ if (hv_init_channel_ivm(newchannel))
+ goto err_deq_chan;
+
return;

err_deq_chan:
diff --git a/drivers/hv/hv_bounce.c b/drivers/hv/hv_bounce.c
new file mode 100644
index 000000000000..c5898325b238
--- /dev/null
+++ b/drivers/hv/hv_bounce.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Bounce buffer code for Hyper-V Isolation VM support.
+ *
+ * Authors:
+ * Sunil Muthuswamy <sunilmut@xxxxxxxxxxxxx>
+ * Tianyu Lan <Tianyu.Lan@xxxxxxxxxxxxx>
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "hyperv_vmbus.h"
+
+int hv_init_channel_ivm(struct vmbus_channel *channel)
+{
+ if (!hv_is_isolation_supported())
+ return 0;
+
+ INIT_LIST_HEAD(&channel->bounce_page_free_head);
+ INIT_LIST_HEAD(&channel->bounce_pkt_free_list_head);
+
+ channel->bounce_pkt_cache = KMEM_CACHE(hv_bounce_pkt, 0);
+ if (unlikely(!channel->bounce_pkt_cache))
+ return -ENOMEM;
+ channel->bounce_page_cache = KMEM_CACHE(hv_bounce_page_list, 0);
+ if (unlikely(!channel->bounce_page_cache))
+ return -ENOMEM;
+
+ return 0;
+}
+
+void hv_free_channel_ivm(struct vmbus_channel *channel)
+{
+ if (!hv_is_isolation_supported())
+ return;
+
+
+ cancel_delayed_work_sync(&channel->bounce_page_list_maintain);
+ hv_bounce_pkt_list_free(channel, &channel->bounce_pkt_free_list_head);
+ hv_bounce_page_list_free(channel, &channel->bounce_page_free_head);
+ kmem_cache_destroy(channel->bounce_pkt_cache);
+ kmem_cache_destroy(channel->bounce_page_cache);
+}
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index d78a04ad5490..7edf2be60d2c 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -19,6 +19,7 @@
#include <linux/hyperv.h>
#include <linux/interrupt.h>

+#include <asm/mshyperv.h>
#include "hv_trace.h"

/*
@@ -56,6 +57,19 @@ union hv_monitor_trigger_state {
};
};

+/*
+ * All vmbus channels initially start with zero bounce pages and are required
+ * to set any non-zero size, if needed.
+ */
+#define HV_DEFAULT_BOUNCE_BUFFER_PAGES 0
+
+/* MIN should be a power of 2 */
+#define HV_MIN_BOUNCE_BUFFER_PAGES 64
+
+extern int hv_init_channel_ivm(struct vmbus_channel *channel);
+
+extern void hv_free_channel_ivm(struct vmbus_channel *channel);
+
/* struct hv_monitor_page Layout */
/* ------------------------------------------------------ */
/* | 0 | TriggerState (4 bytes) | Rsvd1 (4 bytes) | */
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 41cbaa2db567..d518aba17565 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -25,6 +25,9 @@
#include <linux/interrupt.h>
#include <linux/reciprocal_div.h>
#include <asm/hyperv-tlfs.h>
+#include <linux/slab.h>
+#include <linux/mempool.h>
+#include <linux/mempool.h>

#define MAX_PAGE_BUFFER_COUNT 32
#define MAX_MULTIPAGE_BUFFER_COUNT 32 /* 128K */
@@ -1007,9 +1010,28 @@ struct vmbus_channel {
u32 fuzz_testing_interrupt_delay;
u32 fuzz_testing_message_delay;

+
/* request/transaction ids for VMBus */
struct vmbus_requestor requestor;
u32 rqstor_size;
+ /*
+ * Minimum number of bounce resources (i.e bounce packets & pages) that
+ * should be allocated and reserved for this channel. Allocation is
+ * permitted to go beyond this limit, and the maintenance task takes
+ * care of releasing the extra allocated resources.
+ */
+ u32 min_bounce_resource_count;
+
+ /* The free list of bounce pages is LRU sorted based on last used */
+ struct list_head bounce_page_free_head;
+ u32 bounce_page_alloc_count;
+ struct delayed_work bounce_page_list_maintain;
+
+ struct kmem_cache *bounce_page_cache;
+ struct kmem_cache *bounce_pkt_cache;
+ struct list_head bounce_pkt_free_list_head;
+ u32 bounce_pkt_free_count;
+ spinlock_t bp_lock;
};

u64 vmbus_next_request_id(struct vmbus_requestor *rqstor, u64 rqst_addr);
--
2.25.1