[PATCH V4 04/13] hyperv: Mark vmbus ring buffer visible to host in Isolation VM

From: Tianyu Lan
Date: Fri Aug 27 2021 - 13:22:06 EST


From: Tianyu Lan <Tianyu.Lan@xxxxxxxxxxxxx>

Mark vmbus ring buffer visible with set_memory_decrypted() when
establish gpadl handle.

Signed-off-by: Tianyu Lan <Tianyu.Lan@xxxxxxxxxxxxx>
---
Change since v3:
* Change vmbus_teardown_gpadl() parameter and put gpadl handle,
buffer and buffer size in the struct vmbus_gpadl.
---
drivers/hv/channel.c | 36 ++++++++++++++++++++++++++++-----
drivers/net/hyperv/hyperv_net.h | 1 +
drivers/net/hyperv/netvsc.c | 16 +++++++++++----
drivers/uio/uio_hv_generic.c | 14 +++++++++++--
include/linux/hyperv.h | 8 +++++++-
5 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index f3761c73b074..82650beb3af0 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -17,6 +17,7 @@
#include <linux/hyperv.h>
#include <linux/uio.h>
#include <linux/interrupt.h>
+#include <linux/set_memory.h>
#include <asm/page.h>
#include <asm/mshyperv.h>

@@ -474,6 +475,13 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
if (ret)
return ret;

+ ret = set_memory_decrypted((unsigned long)kbuffer,
+ HVPFN_UP(size));
+ if (ret) {
+ pr_warn("Failed to set host visibility for new GPADL %d.\n", ret);
+ return ret;
+ }
+
init_completion(&msginfo->waitevent);
msginfo->waiting_channel = channel;

@@ -549,6 +557,11 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
}

kfree(msginfo);
+
+ if (ret)
+ set_memory_encrypted((unsigned long)kbuffer,
+ HVPFN_UP(size));
+
return ret;
}

@@ -639,6 +652,7 @@ static int __vmbus_open(struct vmbus_channel *newchannel,
struct vmbus_channel_open_channel *open_msg;
struct vmbus_channel_msginfo *open_info = NULL;
struct page *page = newchannel->ringbuffer_page;
+ struct vmbus_gpadl gpadl;
u32 send_pages, recv_pages;
unsigned long flags;
int err;
@@ -759,7 +773,10 @@ static int __vmbus_open(struct vmbus_channel *newchannel,
error_free_info:
kfree(open_info);
error_free_gpadl:
- vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle);
+ gpadl.gpadl_handle = newchannel->ringbuffer_gpadlhandle;
+ gpadl.buffer = page_address(newchannel->ringbuffer_page);
+ gpadl.size = (send_pages + recv_pages) << PAGE_SHIFT;
+ vmbus_teardown_gpadl(newchannel, &gpadl);
newchannel->ringbuffer_gpadlhandle = 0;
error_clean_ring:
hv_ringbuffer_cleanup(&newchannel->outbound);
@@ -806,7 +823,7 @@ EXPORT_SYMBOL_GPL(vmbus_open);
/*
* vmbus_teardown_gpadl -Teardown the specified GPADL handle
*/
-int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
+int vmbus_teardown_gpadl(struct vmbus_channel *channel, struct vmbus_gpadl *gpadl)
{
struct vmbus_channel_gpadl_teardown *msg;
struct vmbus_channel_msginfo *info;
@@ -825,7 +842,7 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)

msg->header.msgtype = CHANNELMSG_GPADL_TEARDOWN;
msg->child_relid = channel->offermsg.child_relid;
- msg->gpadl = gpadl_handle;
+ msg->gpadl = gpadl->gpadl_handle;

spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_add_tail(&info->msglistentry,
@@ -859,6 +876,12 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);

kfree(info);
+
+ ret = set_memory_encrypted((unsigned long)gpadl->buffer,
+ HVPFN_UP(gpadl->size));
+ if (ret)
+ pr_warn("Fail to set mem host visibility in GPADL teardown %d.\n", ret);
+
return ret;
}
EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
@@ -896,6 +919,7 @@ void vmbus_reset_channel_cb(struct vmbus_channel *channel)
static int vmbus_close_internal(struct vmbus_channel *channel)
{
struct vmbus_channel_close_channel *msg;
+ struct vmbus_gpadl gpadl;
int ret;

vmbus_reset_channel_cb(channel);
@@ -934,8 +958,10 @@ static int vmbus_close_internal(struct vmbus_channel *channel)

/* Tear down the gpadl for the channel's ring buffer */
else if (channel->ringbuffer_gpadlhandle) {
- ret = vmbus_teardown_gpadl(channel,
- channel->ringbuffer_gpadlhandle);
+ gpadl.gpadl_handle = channel->ringbuffer_gpadlhandle;
+ gpadl.buffer = page_address(channel->ringbuffer_page);
+ gpadl.size = channel->ringbuffer_pagecount;
+ ret = vmbus_teardown_gpadl(channel, &gpadl);
if (ret) {
pr_err("Close failed: teardown gpadl return %d\n", ret);
/*
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index bc48855dff10..aa7c9962dbd8 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -1082,6 +1082,7 @@ struct netvsc_device {

/* Send buffer allocated by us */
void *send_buf;
+ u32 send_buf_size;
u32 send_buf_gpadl_handle;
u32 send_section_cnt;
u32 send_section_size;
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 7bd935412853..f19bffff6a63 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -276,11 +276,14 @@ static void netvsc_teardown_recv_gpadl(struct hv_device *device,
struct netvsc_device *net_device,
struct net_device *ndev)
{
+ struct vmbus_gpadl gpadl;
int ret;

if (net_device->recv_buf_gpadl_handle) {
- ret = vmbus_teardown_gpadl(device->channel,
- net_device->recv_buf_gpadl_handle);
+ gpadl.gpadl_handle = net_device->recv_buf_gpadl_handle;
+ gpadl.buffer = net_device->recv_buf;
+ gpadl.size = net_device->recv_buf_size;
+ ret = vmbus_teardown_gpadl(device->channel, &gpadl);

/* If we failed here, we might as well return and have a leak
* rather than continue and a bugchk
@@ -298,11 +301,15 @@ static void netvsc_teardown_send_gpadl(struct hv_device *device,
struct netvsc_device *net_device,
struct net_device *ndev)
{
+ struct vmbus_gpadl gpadl;
int ret;

if (net_device->send_buf_gpadl_handle) {
- ret = vmbus_teardown_gpadl(device->channel,
- net_device->send_buf_gpadl_handle);
+ gpadl.gpadl_handle = net_device->send_buf_gpadl_handle;
+ gpadl.buffer = net_device->send_buf;
+ gpadl.size = net_device->send_buf_size;
+
+ ret = vmbus_teardown_gpadl(device->channel, &gpadl);

/* If we failed here, we might as well return and have a leak
* rather than continue and a bugchk
@@ -463,6 +470,7 @@ static int netvsc_init_buf(struct hv_device *device,
ret = -ENOMEM;
goto cleanup;
}
+ net_device->send_buf_size = buf_size;

/* Establish the gpadl handle for this buffer on this
* channel. Note: This call uses the vmbus connection rather
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index 652fe2547587..13c5df8dd11d 100644
--- a/drivers/uio/uio_hv_generic.c
+++ b/drivers/uio/uio_hv_generic.c
@@ -179,14 +179,24 @@ hv_uio_new_channel(struct vmbus_channel *new_sc)
static void
hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata)
{
+ struct vmbus_gpadl gpadl;
+
if (pdata->send_gpadl) {
- vmbus_teardown_gpadl(dev->channel, pdata->send_gpadl);
+ gpadl.gpadl_handle = pdata->send_gpadl;
+ gpadl.buffer = pdata->send_buf;
+ gpadl.size = SEND_BUFFER_SIZE;
+
+ vmbus_teardown_gpadl(dev->channel, &gpadl);
pdata->send_gpadl = 0;
vfree(pdata->send_buf);
}

if (pdata->recv_gpadl) {
- vmbus_teardown_gpadl(dev->channel, pdata->recv_gpadl);
+ gpadl.gpadl_handle = pdata->recv_gpadl;
+ gpadl.buffer = pdata->recv_buf;
+ gpadl.size = RECV_BUFFER_SIZE;
+
+ vmbus_teardown_gpadl(dev->channel, &gpadl);
pdata->recv_gpadl = 0;
vfree(pdata->recv_buf);
}
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index ddc8713ce57b..757e09606fd3 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -803,6 +803,12 @@ struct vmbus_device {

#define VMBUS_DEFAULT_MAX_PKT_SIZE 4096

+struct vmbus_gpadl {
+ u32 gpadl_handle;
+ u32 size;
+ void *buffer;
+};
+
struct vmbus_channel {
struct list_head listentry;

@@ -1195,7 +1201,7 @@ extern int vmbus_establish_gpadl(struct vmbus_channel *channel,
u32 *gpadl_handle);

extern int vmbus_teardown_gpadl(struct vmbus_channel *channel,
- u32 gpadl_handle);
+ struct vmbus_gpadl *gpadl);

void vmbus_reset_channel_cb(struct vmbus_channel *channel);

--
2.25.1