* RE: [PATCH v2 1/1] x86/hyperv: Initialize clockevents earlier in CPU onlining
From: Michael Kelley @ 2019-11-18 1:23 UTC (permalink / raw)
To: Dexuan Cui, linux-kernel@vger.kernel.org, tglx@linutronix.de,
daniel.lezcano@linaro.org, vkuznets, KY Srinivasan,
Stephen Hemminger, sashal@kernel.org, mingo@redhat.com,
bp@alien8.de, hpa@zytor.com, x86@kernel.org, will@kernel.org,
Ganapatrao.Kulkarni@cavium.com, james.morse@arm.com,
steven.price@arm.com, josephl@nvidia.com,
m.szyprowski@samsung.com, linux-hyperv@vger.kernel.org
In-Reply-To: <PU1P153MB0169807BF9CE60FC3CA51B31BF700@PU1P153MB0169.APCP153.PROD.OUTLOOK.COM>
From: Dexuan Cui <decui@microsoft.com> Sent: Thursday, November 14, 2019 10:49 PM
> > From: Michael Kelley <mikelley@microsoft.com>
> > Sent: Tuesday, November 12, 2019 5:12 PM
> > ...
> > @@ -190,14 +278,20 @@ void hv_stimer_free(void)
> > void hv_stimer_global_cleanup(void)
> > {
> > int cpu;
> > ...
> > + /*
> > + * hv_stime_legacy_cleanup() will stop the stimer if Direct
> > + * Mode is not enabled, and fallback to the LAPIC timer.
> > + */
> > + for_each_present_cpu(cpu) {
> > + hv_stimer_legacy_cleanup(cpu);
> > }
> > +
> > + /*
> > + * If Direct Mode is enabled, the cpuhp teardown callback
> > + * (hv_stimer_cleanup) will be run on all CPUs to stop the
> > + * stimers.
> > + */
> > hv_stimer_free();
> > }
>
> In the case of direct_mode_enabled == true: When hv_vmbus unloads,
> vmbus_exit() -> hv_stimer_global_cleanup() -> hv_stimer_free() ->
> cpuhp_remove_state() disables the direct mode timers.
>
> This does not look symmetric since hv_stimer_alloc() is called before
> hv_vmbus loads, but I suppose this is not a real issue because hv_vmbus
> should never unload in practice. :-)
Thanks for the review. Looking at this a bit more, ideally
hv_stimer_global_cleanup() should go away entirely. vmbus_exit() should
let the call to cpuhp_remove_state() clean up the stimer on each CPU via
hv_synic_cleanup(). But vmbus_exit() shuts down the VMbus first, which
is really the wrong order.
As you say, vmbus_exit() never gets called in practice, so it's not a
current issue. But I'll look at fixing this in a future patch so that it
makes logical sense.
Michael
>
> Tested-by: Dexuan Cui <decui@microsoft.com>
> Reviewed-by: Dexuan Cui <decui@microsoft.com>
^ permalink raw reply
* [PATCH net, 0/2] Fix send indirection table offset
From: Haiyang Zhang @ 2019-11-18 16:33 UTC (permalink / raw)
To: sashal@kernel.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org
Cc: Haiyang Zhang, KY Srinivasan, Stephen Hemminger, olaf@aepfle.de,
vkuznets, davem@davemloft.net, linux-kernel@vger.kernel.org
Fix send indirection table offset issues related to guest and
host bugs.
Haiyang Zhang (2):
hv_netvsc: Fix offset usage in netvsc_send_table()
hv_netvsc: Fix send_table offset in case of a host bug
drivers/net/hyperv/hyperv_net.h | 3 ++-
drivers/net/hyperv/netvsc.c | 35 +++++++++++++++++++++++++++--------
2 files changed, 29 insertions(+), 9 deletions(-)
--
1.8.3.1
^ permalink raw reply
* [PATCH net, 1/2] hv_netvsc: Fix offset usage in netvsc_send_table()
From: Haiyang Zhang @ 2019-11-18 16:34 UTC (permalink / raw)
To: sashal@kernel.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org
Cc: Haiyang Zhang, KY Srinivasan, Stephen Hemminger, olaf@aepfle.de,
vkuznets, davem@davemloft.net, linux-kernel@vger.kernel.org
In-Reply-To: <1574094751-98966-1-git-send-email-haiyangz@microsoft.com>
To reach the data region, the existing code adds offset in struct
nvsp_5_send_indirect_table on the beginning of this struct. But the
offset should be based on the beginning of its container,
struct nvsp_message. This bug causes the first table entry missing,
and adds an extra zero from the zero pad after the data region.
This can put extra burden on the channel 0.
So, correct the offset usage. Also add a boundary check to ensure
not reading beyond data region.
Fixes: 5b54dac856cb ("hyperv: Add support for virtual Receive Side Scaling (vRSS)")
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/net/hyperv/hyperv_net.h | 3 ++-
drivers/net/hyperv/netvsc.c | 26 ++++++++++++++++++--------
2 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 670ef68..fb547f3 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -609,7 +609,8 @@ struct nvsp_5_send_indirect_table {
/* The number of entries in the send indirection table */
u32 count;
- /* The offset of the send indirection table from top of this struct.
+ /* The offset of the send indirection table from the beginning of
+ * struct nvsp_message.
* The send indirection table tells which channel to put the send
* traffic on. Each entry is a channel number.
*/
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index d22a36f..efd30e2 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -1178,20 +1178,28 @@ static int netvsc_receive(struct net_device *ndev,
}
static void netvsc_send_table(struct net_device *ndev,
- const struct nvsp_message *nvmsg)
+ const struct nvsp_message *nvmsg,
+ u32 msglen)
{
struct net_device_context *net_device_ctx = netdev_priv(ndev);
- u32 count, *tab;
+ u32 count, offset, *tab;
int i;
count = nvmsg->msg.v5_msg.send_table.count;
+ offset = nvmsg->msg.v5_msg.send_table.offset;
+
if (count != VRSS_SEND_TAB_SIZE) {
netdev_err(ndev, "Received wrong send-table size:%u\n", count);
return;
}
- tab = (u32 *)((unsigned long)&nvmsg->msg.v5_msg.send_table +
- nvmsg->msg.v5_msg.send_table.offset);
+ if (offset + count * sizeof(u32) > msglen) {
+ netdev_err(ndev, "Received send-table offset too big:%u\n",
+ offset);
+ return;
+ }
+
+ tab = (void *)nvmsg + offset;
for (i = 0; i < count; i++)
net_device_ctx->tx_table[i] = tab[i];
@@ -1209,12 +1217,13 @@ static void netvsc_send_vf(struct net_device *ndev,
net_device_ctx->vf_alloc ? "added" : "removed");
}
-static void netvsc_receive_inband(struct net_device *ndev,
- const struct nvsp_message *nvmsg)
+static void netvsc_receive_inband(struct net_device *ndev,
+ const struct nvsp_message *nvmsg,
+ u32 msglen)
{
switch (nvmsg->hdr.msg_type) {
case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE:
- netvsc_send_table(ndev, nvmsg);
+ netvsc_send_table(ndev, nvmsg, msglen);
break;
case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION:
@@ -1232,6 +1241,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
{
struct vmbus_channel *channel = nvchan->channel;
const struct nvsp_message *nvmsg = hv_pkt_data(desc);
+ u32 msglen = hv_pkt_datalen(desc);
trace_nvsp_recv(ndev, channel, nvmsg);
@@ -1247,7 +1257,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
break;
case VM_PKT_DATA_INBAND:
- netvsc_receive_inband(ndev, nvmsg);
+ netvsc_receive_inband(ndev, nvmsg, msglen);
break;
default:
--
1.8.3.1
^ permalink raw reply related
* [PATCH net, 2/2] hv_netvsc: Fix send_table offset in case of a host bug
From: Haiyang Zhang @ 2019-11-18 16:34 UTC (permalink / raw)
To: sashal@kernel.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org
Cc: Haiyang Zhang, KY Srinivasan, Stephen Hemminger, olaf@aepfle.de,
vkuznets, davem@davemloft.net, linux-kernel@vger.kernel.org
In-Reply-To: <1574094751-98966-1-git-send-email-haiyangz@microsoft.com>
If negotiated NVSP version <= NVSP_PROTOCOL_VERSION_6, the offset may
be wrong (too small) due to a host bug. This can cause missing the
end of the send indirection table, and add multiple zero entries from
leading zeros before the data region. This bug adds extra burden on
channel 0.
So fix the offset by computing it from the end of the table. This
will ensure netvsc driver runs normally on unfixed hosts, and future
fixed hosts.
Fixes: 5b54dac856cb ("hyperv: Add support for virtual Receive Side Scaling (vRSS)")
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
drivers/net/hyperv/netvsc.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index efd30e2..7c5481a 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -1178,6 +1178,7 @@ static int netvsc_receive(struct net_device *ndev,
}
static void netvsc_send_table(struct net_device *ndev,
+ struct netvsc_device *nvscdev,
const struct nvsp_message *nvmsg,
u32 msglen)
{
@@ -1193,6 +1194,13 @@ static void netvsc_send_table(struct net_device *ndev,
return;
}
+ /* If negotiated version <= NVSP_PROTOCOL_VERSION_6, the offset may be
+ * wrong due to a host bug. So fix the offset here.
+ */
+ if (nvscdev->nvsp_version <= NVSP_PROTOCOL_VERSION_6)
+ offset = msglen - count * sizeof(u32);
+
+ /* Boundary check for all versions */
if (offset + count * sizeof(u32) > msglen) {
netdev_err(ndev, "Received send-table offset too big:%u\n",
offset);
@@ -1218,12 +1226,13 @@ static void netvsc_send_vf(struct net_device *ndev,
}
static void netvsc_receive_inband(struct net_device *ndev,
+ struct netvsc_device *nvscdev,
const struct nvsp_message *nvmsg,
u32 msglen)
{
switch (nvmsg->hdr.msg_type) {
case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE:
- netvsc_send_table(ndev, nvmsg, msglen);
+ netvsc_send_table(ndev, nvscdev, nvmsg, msglen);
break;
case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION:
@@ -1257,7 +1266,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
break;
case VM_PKT_DATA_INBAND:
- netvsc_receive_inband(ndev, nvmsg, msglen);
+ netvsc_receive_inband(ndev, net_device, nvmsg, msglen);
break;
default:
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH net, 1/2] hv_netvsc: Fix offset usage in netvsc_send_table()
From: Vitaly Kuznetsov @ 2019-11-18 17:28 UTC (permalink / raw)
To: Haiyang Zhang
Cc: KY Srinivasan, Stephen Hemminger, olaf@aepfle.de,
davem@davemloft.net, linux-kernel@vger.kernel.org,
sashal@kernel.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org
In-Reply-To: <1574094751-98966-2-git-send-email-haiyangz@microsoft.com>
Haiyang Zhang <haiyangz@microsoft.com> writes:
> To reach the data region, the existing code adds offset in struct
> nvsp_5_send_indirect_table on the beginning of this struct. But the
> offset should be based on the beginning of its container,
> struct nvsp_message. This bug causes the first table entry missing,
> and adds an extra zero from the zero pad after the data region.
> This can put extra burden on the channel 0.
>
> So, correct the offset usage. Also add a boundary check to ensure
> not reading beyond data region.
>
> Fixes: 5b54dac856cb ("hyperv: Add support for virtual Receive Side Scaling (vRSS)")
> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> ---
> drivers/net/hyperv/hyperv_net.h | 3 ++-
> drivers/net/hyperv/netvsc.c | 26 ++++++++++++++++++--------
> 2 files changed, 20 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
> index 670ef68..fb547f3 100644
> --- a/drivers/net/hyperv/hyperv_net.h
> +++ b/drivers/net/hyperv/hyperv_net.h
> @@ -609,7 +609,8 @@ struct nvsp_5_send_indirect_table {
> /* The number of entries in the send indirection table */
> u32 count;
>
> - /* The offset of the send indirection table from top of this struct.
> + /* The offset of the send indirection table from the beginning of
> + * struct nvsp_message.
> * The send indirection table tells which channel to put the send
> * traffic on. Each entry is a channel number.
> */
> diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
> index d22a36f..efd30e2 100644
> --- a/drivers/net/hyperv/netvsc.c
> +++ b/drivers/net/hyperv/netvsc.c
> @@ -1178,20 +1178,28 @@ static int netvsc_receive(struct net_device *ndev,
> }
>
> static void netvsc_send_table(struct net_device *ndev,
> - const struct nvsp_message *nvmsg)
> + const struct nvsp_message *nvmsg,
> + u32 msglen)
> {
> struct net_device_context *net_device_ctx = netdev_priv(ndev);
> - u32 count, *tab;
> + u32 count, offset, *tab;
> int i;
>
> count = nvmsg->msg.v5_msg.send_table.count;
> + offset = nvmsg->msg.v5_msg.send_table.offset;
> +
> if (count != VRSS_SEND_TAB_SIZE) {
> netdev_err(ndev, "Received wrong send-table size:%u\n", count);
> return;
> }
>
> - tab = (u32 *)((unsigned long)&nvmsg->msg.v5_msg.send_table +
> - nvmsg->msg.v5_msg.send_table.offset);
> + if (offset + count * sizeof(u32) > msglen) {
Nit: I think this can overflow.
> + netdev_err(ndev, "Received send-table offset too big:%u\n",
> + offset);
> + return;
> + }
> +
> + tab = (void *)nvmsg + offset;
But tab is 'u32 *', doesn't compiler complain?
>
> for (i = 0; i < count; i++)
> net_device_ctx->tx_table[i] = tab[i];
> @@ -1209,12 +1217,13 @@ static void netvsc_send_vf(struct net_device *ndev,
> net_device_ctx->vf_alloc ? "added" : "removed");
> }
>
> -static void netvsc_receive_inband(struct net_device *ndev,
> - const struct nvsp_message *nvmsg)
> +static void netvsc_receive_inband(struct net_device *ndev,
> + const struct nvsp_message *nvmsg,
> + u32 msglen)
> {
> switch (nvmsg->hdr.msg_type) {
> case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE:
> - netvsc_send_table(ndev, nvmsg);
> + netvsc_send_table(ndev, nvmsg, msglen);
> break;
>
> case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION:
> @@ -1232,6 +1241,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
> {
> struct vmbus_channel *channel = nvchan->channel;
> const struct nvsp_message *nvmsg = hv_pkt_data(desc);
> + u32 msglen = hv_pkt_datalen(desc);
>
> trace_nvsp_recv(ndev, channel, nvmsg);
>
> @@ -1247,7 +1257,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
> break;
>
> case VM_PKT_DATA_INBAND:
> - netvsc_receive_inband(ndev, nvmsg);
> + netvsc_receive_inband(ndev, nvmsg, msglen);
> break;
>
> default:
--
Vitaly
^ permalink raw reply
* Re: [PATCH net, 1/2] hv_netvsc: Fix offset usage in netvsc_send_table()
From: Stephen Hemminger @ 2019-11-18 17:59 UTC (permalink / raw)
To: Vitaly Kuznetsov
Cc: Haiyang Zhang, KY Srinivasan, Stephen Hemminger, olaf@aepfle.de,
davem@davemloft.net, linux-kernel@vger.kernel.org,
sashal@kernel.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org
In-Reply-To: <87wobxgkkv.fsf@vitty.brq.redhat.com>
On Mon, 18 Nov 2019 18:28:48 +0100
Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
> > + netdev_err(ndev, "Received send-table offset too big:%u\n",
> > + offset);
> > + return;
> > + }
> > +
> > + tab = (void *)nvmsg + offset;
>
> But tab is 'u32 *', doesn't compiler complain?
nvmsg + offset is still of type void *.
assigning void * to another pointer type is allowed with C.
^ permalink raw reply
* RE: [PATCH net, 1/2] hv_netvsc: Fix offset usage in netvsc_send_table()
From: Haiyang Zhang @ 2019-11-18 18:39 UTC (permalink / raw)
To: vkuznets
Cc: KY Srinivasan, Stephen Hemminger, olaf@aepfle.de,
davem@davemloft.net, linux-kernel@vger.kernel.org,
sashal@kernel.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org
In-Reply-To: <87wobxgkkv.fsf@vitty.brq.redhat.com>
> -----Original Message-----
> From: Vitaly Kuznetsov <vkuznets@redhat.com>
> Sent: Monday, November 18, 2019 12:29 PM
> To: Haiyang Zhang <haiyangz@microsoft.com>
> Cc: KY Srinivasan <kys@microsoft.com>; Stephen Hemminger
> <sthemmin@microsoft.com>; olaf@aepfle.de; davem@davemloft.net; linux-
> kernel@vger.kernel.org; sashal@kernel.org; linux-hyperv@vger.kernel.org;
> netdev@vger.kernel.org
> Subject: Re: [PATCH net, 1/2] hv_netvsc: Fix offset usage in netvsc_send_table()
>
> Haiyang Zhang <haiyangz@microsoft.com> writes:
>
> > To reach the data region, the existing code adds offset in struct
> > nvsp_5_send_indirect_table on the beginning of this struct. But the
> > offset should be based on the beginning of its container,
> > struct nvsp_message. This bug causes the first table entry missing,
> > and adds an extra zero from the zero pad after the data region.
> > This can put extra burden on the channel 0.
> >
> > So, correct the offset usage. Also add a boundary check to ensure
> > not reading beyond data region.
> >
> > Fixes: 5b54dac856cb ("hyperv: Add support for virtual Receive Side Scaling
> (vRSS)")
> > Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> > ---
> > drivers/net/hyperv/hyperv_net.h | 3 ++-
> > drivers/net/hyperv/netvsc.c | 26 ++++++++++++++++++--------
> > 2 files changed, 20 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/net/hyperv/hyperv_net.h
> b/drivers/net/hyperv/hyperv_net.h
> > index 670ef68..fb547f3 100644
> > --- a/drivers/net/hyperv/hyperv_net.h
> > +++ b/drivers/net/hyperv/hyperv_net.h
> > @@ -609,7 +609,8 @@ struct nvsp_5_send_indirect_table {
> > /* The number of entries in the send indirection table */
> > u32 count;
> >
> > - /* The offset of the send indirection table from top of this struct.
> > + /* The offset of the send indirection table from the beginning of
> > + * struct nvsp_message.
> > * The send indirection table tells which channel to put the send
> > * traffic on. Each entry is a channel number.
> > */
> > diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
> > index d22a36f..efd30e2 100644
> > --- a/drivers/net/hyperv/netvsc.c
> > +++ b/drivers/net/hyperv/netvsc.c
> > @@ -1178,20 +1178,28 @@ static int netvsc_receive(struct net_device *ndev,
> > }
> >
> > static void netvsc_send_table(struct net_device *ndev,
> > - const struct nvsp_message *nvmsg)
> > + const struct nvsp_message *nvmsg,
> > + u32 msglen)
> > {
> > struct net_device_context *net_device_ctx = netdev_priv(ndev);
> > - u32 count, *tab;
> > + u32 count, offset, *tab;
> > int i;
> >
> > count = nvmsg->msg.v5_msg.send_table.count;
> > + offset = nvmsg->msg.v5_msg.send_table.offset;
> > +
> > if (count != VRSS_SEND_TAB_SIZE) {
> > netdev_err(ndev, "Received wrong send-table size:%u\n",
> count);
> > return;
> > }
> >
> > - tab = (u32 *)((unsigned long)&nvmsg->msg.v5_msg.send_table +
> > - nvmsg->msg.v5_msg.send_table.offset);
> > + if (offset + count * sizeof(u32) > msglen) {
>
> Nit: I think this can overflow.
To prevent overflow, I will change it to:
if (offset > msglen || offset + count * sizeof(u32) > msglen) {
Thanks,
- Haiyang
^ permalink raw reply
* RE: [PATCH net, 1/2] hv_netvsc: Fix offset usage in netvsc_send_table()
From: Michael Kelley @ 2019-11-18 20:47 UTC (permalink / raw)
To: Haiyang Zhang, vkuznets
Cc: KY Srinivasan, Stephen Hemminger, olaf@aepfle.de,
davem@davemloft.net, linux-kernel@vger.kernel.org,
sashal@kernel.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org
In-Reply-To: <MN2PR21MB13758E83B89BD524B41B71C2CA4D0@MN2PR21MB1375.namprd21.prod.outlook.com>
From: Haiyang Zhang <haiyangz@microsoft.com> Sent: Monday, November 18, 2019 10:40 AM
> > -----Original Message-----
> > From: Vitaly Kuznetsov <vkuznets@redhat.com>
> > Sent: Monday, November 18, 2019 12:29 PM
> >
> > Haiyang Zhang <haiyangz@microsoft.com> writes:
> >
> > > To reach the data region, the existing code adds offset in struct
> > > nvsp_5_send_indirect_table on the beginning of this struct. But the
> > > offset should be based on the beginning of its container,
> > > struct nvsp_message. This bug causes the first table entry missing,
> > > and adds an extra zero from the zero pad after the data region.
> > > This can put extra burden on the channel 0.
> > >
> > > So, correct the offset usage. Also add a boundary check to ensure
> > > not reading beyond data region.
> > >
> > > Fixes: 5b54dac856cb ("hyperv: Add support for virtual Receive Side Scaling
> > (vRSS)")
> > > Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> > > ---
> > > drivers/net/hyperv/hyperv_net.h | 3 ++-
> > > drivers/net/hyperv/netvsc.c | 26 ++++++++++++++++++--------
> > > 2 files changed, 20 insertions(+), 9 deletions(-)
> > >
> > > diff --git a/drivers/net/hyperv/hyperv_net.h
> > b/drivers/net/hyperv/hyperv_net.h
> > > index 670ef68..fb547f3 100644
> > > --- a/drivers/net/hyperv/hyperv_net.h
> > > +++ b/drivers/net/hyperv/hyperv_net.h
> > > @@ -609,7 +609,8 @@ struct nvsp_5_send_indirect_table {
> > > /* The number of entries in the send indirection table */
> > > u32 count;
> > >
> > > - /* The offset of the send indirection table from top of this struct.
> > > + /* The offset of the send indirection table from the beginning of
> > > + * struct nvsp_message.
> > > * The send indirection table tells which channel to put the send
> > > * traffic on. Each entry is a channel number.
> > > */
> > > diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
> > > index d22a36f..efd30e2 100644
> > > --- a/drivers/net/hyperv/netvsc.c
> > > +++ b/drivers/net/hyperv/netvsc.c
> > > @@ -1178,20 +1178,28 @@ static int netvsc_receive(struct net_device *ndev,
> > > }
> > >
> > > static void netvsc_send_table(struct net_device *ndev,
> > > - const struct nvsp_message *nvmsg)
> > > + const struct nvsp_message *nvmsg,
> > > + u32 msglen)
> > > {
> > > struct net_device_context *net_device_ctx = netdev_priv(ndev);
> > > - u32 count, *tab;
> > > + u32 count, offset, *tab;
> > > int i;
> > >
> > > count = nvmsg->msg.v5_msg.send_table.count;
> > > + offset = nvmsg->msg.v5_msg.send_table.offset;
> > > +
> > > if (count != VRSS_SEND_TAB_SIZE) {
> > > netdev_err(ndev, "Received wrong send-table size:%u\n",
> > count);
> > > return;
> > > }
> > >
> > > - tab = (u32 *)((unsigned long)&nvmsg->msg.v5_msg.send_table +
> > > - nvmsg->msg.v5_msg.send_table.offset);
> > > + if (offset + count * sizeof(u32) > msglen) {
> >
> > Nit: I think this can overflow.
>
> To prevent overflow, I will change it to:
> if (offset > msglen || offset + count * sizeof(u32) > msglen) {
> Thanks,
> - Haiyang
Actually, this would be simpler since we already trust msglen and count
to have good values:
if (offset > msglen - count * sizeof(u32)) {
Michael
^ permalink raw reply
* RE: [PATCH net, 1/2] hv_netvsc: Fix offset usage in netvsc_send_table()
From: Haiyang Zhang @ 2019-11-18 21:01 UTC (permalink / raw)
To: Michael Kelley, vkuznets
Cc: KY Srinivasan, Stephen Hemminger, olaf@aepfle.de,
davem@davemloft.net, linux-kernel@vger.kernel.org,
sashal@kernel.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org
In-Reply-To: <DM5PR21MB0634CF7997BD9F9B6326D1CED74D0@DM5PR21MB0634.namprd21.prod.outlook.com>
> -----Original Message-----
> From: Michael Kelley <mikelley@microsoft.com>
> Sent: Monday, November 18, 2019 3:47 PM
> To: Haiyang Zhang <haiyangz@microsoft.com>; vkuznets
> <vkuznets@redhat.com>
> Cc: KY Srinivasan <kys@microsoft.com>; Stephen Hemminger
> <sthemmin@microsoft.com>; olaf@aepfle.de; davem@davemloft.net; linux-
> kernel@vger.kernel.org; sashal@kernel.org; linux-hyperv@vger.kernel.org;
> netdev@vger.kernel.org
> Subject: RE: [PATCH net, 1/2] hv_netvsc: Fix offset usage in netvsc_send_table()
>
> From: Haiyang Zhang <haiyangz@microsoft.com> Sent: Monday, November 18,
> 2019 10:40 AM
> > > -----Original Message-----
> > > From: Vitaly Kuznetsov <vkuznets@redhat.com>
> > > Sent: Monday, November 18, 2019 12:29 PM
> > >
> > > Haiyang Zhang <haiyangz@microsoft.com> writes:
> > >
> > > > To reach the data region, the existing code adds offset in struct
> > > > nvsp_5_send_indirect_table on the beginning of this struct. But the
> > > > offset should be based on the beginning of its container,
> > > > struct nvsp_message. This bug causes the first table entry missing,
> > > > and adds an extra zero from the zero pad after the data region.
> > > > This can put extra burden on the channel 0.
> > > >
> > > > So, correct the offset usage. Also add a boundary check to ensure
> > > > not reading beyond data region.
> > > >
> > > > Fixes: 5b54dac856cb ("hyperv: Add support for virtual Receive Side
> Scaling
> > > (vRSS)")
> > > > Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> > > > ---
> > > > drivers/net/hyperv/hyperv_net.h | 3 ++-
> > > > drivers/net/hyperv/netvsc.c | 26 ++++++++++++++++++--------
> > > > 2 files changed, 20 insertions(+), 9 deletions(-)
> > > >
> > > > diff --git a/drivers/net/hyperv/hyperv_net.h
> > > b/drivers/net/hyperv/hyperv_net.h
> > > > index 670ef68..fb547f3 100644
> > > > --- a/drivers/net/hyperv/hyperv_net.h
> > > > +++ b/drivers/net/hyperv/hyperv_net.h
> > > > @@ -609,7 +609,8 @@ struct nvsp_5_send_indirect_table {
> > > > /* The number of entries in the send indirection table */
> > > > u32 count;
> > > >
> > > > - /* The offset of the send indirection table from top of this struct.
> > > > + /* The offset of the send indirection table from the beginning of
> > > > + * struct nvsp_message.
> > > > * The send indirection table tells which channel to put the send
> > > > * traffic on. Each entry is a channel number.
> > > > */
> > > > diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
> > > > index d22a36f..efd30e2 100644
> > > > --- a/drivers/net/hyperv/netvsc.c
> > > > +++ b/drivers/net/hyperv/netvsc.c
> > > > @@ -1178,20 +1178,28 @@ static int netvsc_receive(struct net_device
> *ndev,
> > > > }
> > > >
> > > > static void netvsc_send_table(struct net_device *ndev,
> > > > - const struct nvsp_message *nvmsg)
> > > > + const struct nvsp_message *nvmsg,
> > > > + u32 msglen)
> > > > {
> > > > struct net_device_context *net_device_ctx = netdev_priv(ndev);
> > > > - u32 count, *tab;
> > > > + u32 count, offset, *tab;
> > > > int i;
> > > >
> > > > count = nvmsg->msg.v5_msg.send_table.count;
> > > > + offset = nvmsg->msg.v5_msg.send_table.offset;
> > > > +
> > > > if (count != VRSS_SEND_TAB_SIZE) {
> > > > netdev_err(ndev, "Received wrong send-table size:%u\n",
> > > count);
> > > > return;
> > > > }
> > > >
> > > > - tab = (u32 *)((unsigned long)&nvmsg->msg.v5_msg.send_table +
> > > > - nvmsg->msg.v5_msg.send_table.offset);
> > > > + if (offset + count * sizeof(u32) > msglen) {
> > >
> > > Nit: I think this can overflow.
> >
> > To prevent overflow, I will change it to:
> > if (offset > msglen || offset + count * sizeof(u32) > msglen) {
> > Thanks,
> > - Haiyang
>
> Actually, this would be simpler since we already trust msglen and count
> to have good values:
>
> if (offset > msglen - count * sizeof(u32)) {
Great idea. Thanks!
^ permalink raw reply
* Re: [PATCH v8 0/5] Add a unified parameter "nopvspin"
From: Zhenzhong Duan @ 2019-11-19 2:01 UTC (permalink / raw)
To: linux-kernel, tglx, pbonzini
Cc: mingo, bp, x86, rkrcmar, sean.j.christopherson, vkuznets,
wanpengli, jmattson, joro, boris.ostrovsky, jgross, peterz, will,
linux-hyperv, kvm, mikelley, kys, haiyangz, sthemmin, sashal
In-Reply-To: <86263ee3-f94f-8a6b-3842-f15fb0316798@oracle.com>
Hi Maintainers,
May I get a final update on this patchset?
There is only a few days remaining before my layoff at Oracle. I can't
login the mail address after that.
No matter if you prefer to reject it, please let me know. I'd like to
get an end to this patchset.
Thanks
Zhenzhong
On 2019/10/29 9:33, Zhenzhong Duan wrote:
> Hi Baolo, Thomas
>
> This patchset is reviewed pass and keep silent for a while, will
> anyone of you
>
> consider to pick it up? Thanks
>
> Zhenzhong
>
> On 2019/10/23 19:16, Zhenzhong Duan wrote:
>> There are cases folks want to disable spinlock optimization for
>> debug/test purpose. Xen and hyperv already have parameters
>> "xen_nopvspin"
>> and "hv_nopvspin" to support that, but kvm doesn't.
>>
>> The first patch adds that feature to KVM guest with "nopvspin".
>>
>> For compatibility reason original parameters "xen_nopvspin" and
>> "hv_nopvspin" are retained and marked obsolete.
>>
>> v8:
>> PATCH2: use 'kvm-guest' instead of 'kvm_guest' [Sean
>> Christopherson]
>> PATCH3: add a comment to explain missed 'return' [Sean
>> Christopherson]
>>
>> v7:
>> PATCH3: update comment and use goto, add RB [Vitaly
>> Kuznetsov]
>>
>> v6:
>> PATCH1: add Reviewed-by [Vitaly
>> Kuznetsov]
>> PATCH2: change 'pv' to 'PV', add Reviewed-by [Vitaly
>> Kuznetsov]
>> PATCH3: refactor 'if' branch in kvm_spinlock_init() [Vitaly
>> Kuznetsov]
>>
>> v5:
>> PATCH1: new patch to revert a currently unnecessory commit,
>> code is simpler a bit after that change. [Boris
>> Ostrovsky]
>> PATCH3: fold 'if' statement,add comments on virt_spin_lock_key,
>> reorder with PATCH2 to better reflect dependency
>> PATCH4: fold 'if' statement, add Reviewed-by [Boris
>> Ostrovsky]
>> PATCH5: add Reviewed-by [Michael Kelley]
>>
>> v4:
>> PATCH1: use variable name nopvspin instead of pvspin and
>> defined it as __initdata, changed print message,
>> updated patch description [Sean
>> Christopherson]
>> PATCH2: remove Suggested-by, use "kvm-guest:" prefix [Sean
>> Christopherson]
>> PATCH3: make variable nopvsin and xen_pvspin coexist
>> remove Reviewed-by due to code change [Sean
>> Christopherson]
>> PATCH4: make variable nopvsin and hv_pvspin coexist [Sean
>> Christopherson]
>>
>> v3:
>> PATCH2: Fix indentation
>>
>> v2:
>> PATCH1: pick the print code change into separate PATCH2,
>> updated patch description [Vitaly Kuznetsov]
>> PATCH2: new patch with print code change [Vitaly Kuznetsov]
>> PATCH3: add Reviewed-by [Juergen Gross]
>>
>> Zhenzhong Duan (5):
>> Revert "KVM: X86: Fix setup the virt_spin_lock_key before static key
>> get initialized"
>> x86/kvm: Change print code to use pr_*() format
>> x86/kvm: Add "nopvspin" parameter to disable PV spinlocks
>> xen: Mark "xen_nopvspin" parameter obsolete
>> x86/hyperv: Mark "hv_nopvspin" parameter obsolete
>>
>> Documentation/admin-guide/kernel-parameters.txt | 14 ++++-
>> arch/x86/hyperv/hv_spinlock.c | 4 ++
>> arch/x86/include/asm/qspinlock.h | 1 +
>> arch/x86/kernel/kvm.c | 79
>> ++++++++++++++++---------
>> arch/x86/xen/spinlock.c | 4 +-
>> kernel/locking/qspinlock.c | 7 +++
>> 6 files changed, 76 insertions(+), 33 deletions(-)
>>
^ permalink raw reply
* Re: [PATCH v8 1/5] Revert "KVM: X86: Fix setup the virt_spin_lock_key before static key get initialized"
From: Wanpeng Li @ 2019-11-19 7:00 UTC (permalink / raw)
To: Zhenzhong Duan
Cc: LKML, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
the arch/x86 maintainers, Paolo Bonzini, Radim Krcmar,
Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
Joerg Roedel, Boris Ostrovsky, Juergen Gross, Peter Zijlstra,
will, linux-hyperv, kvm, mikelley, K. Y. Srinivasan,
Haiyang Zhang, Stephen Hemminger, Sasha Levin, H. Peter Anvin
In-Reply-To: <1571829384-5309-2-git-send-email-zhenzhong.duan@oracle.com>
On Wed, 23 Oct 2019 at 19:20, Zhenzhong Duan <zhenzhong.duan@oracle.com> wrote:
>
> This reverts commit 34226b6b70980a8f81fff3c09a2c889f77edeeff.
>
> Commit 8990cac6e5ea ("x86/jump_label: Initialize static branching
> early") adds jump_label_init() call in setup_arch() to make static
> keys initialized early, so we could use the original simpler code
> again.
>
> The similar change for XEN is in commit 090d54bcbc54 ("Revert
> "x86/paravirt: Set up the virt_spin_lock_key after static keys get
> initialized"")
>
> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@oracle.com>
> Reviewed-by: Vitaly Kuznetsov <vkuznets@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Radim Krcmar <rkrcmar@redhat.com>
> Cc: Sean Christopherson <sean.j.christopherson@intel.com>
> Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
> Cc: Wanpeng Li <wanpengli@tencent.com>
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Joerg Roedel <joro@8bytes.org>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
Reviewed-by: Wanpeng Li <wanpengli@tencent.com>
> ---
> arch/x86/kernel/kvm.c | 12 +++---------
> 1 file changed, 3 insertions(+), 9 deletions(-)
>
> diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
> index e820568..3bc6a266 100644
> --- a/arch/x86/kernel/kvm.c
> +++ b/arch/x86/kernel/kvm.c
> @@ -527,13 +527,6 @@ static void kvm_smp_send_call_func_ipi(const struct cpumask *mask)
> }
> }
>
> -static void __init kvm_smp_prepare_cpus(unsigned int max_cpus)
> -{
> - native_smp_prepare_cpus(max_cpus);
> - if (kvm_para_has_hint(KVM_HINTS_REALTIME))
> - static_branch_disable(&virt_spin_lock_key);
> -}
> -
> static void __init kvm_smp_prepare_boot_cpu(void)
> {
> /*
> @@ -633,7 +626,6 @@ static void __init kvm_guest_init(void)
> apic_set_eoi_write(kvm_guest_apic_eoi_write);
>
> #ifdef CONFIG_SMP
> - smp_ops.smp_prepare_cpus = kvm_smp_prepare_cpus;
> smp_ops.smp_prepare_boot_cpu = kvm_smp_prepare_boot_cpu;
> if (kvm_para_has_feature(KVM_FEATURE_PV_SCHED_YIELD) &&
> !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
> @@ -835,8 +827,10 @@ void __init kvm_spinlock_init(void)
> if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT))
> return;
>
> - if (kvm_para_has_hint(KVM_HINTS_REALTIME))
> + if (kvm_para_has_hint(KVM_HINTS_REALTIME)) {
> + static_branch_disable(&virt_spin_lock_key);
> return;
> + }
>
> /* Don't use the pvqspinlock code if there is only 1 vCPU. */
> if (num_possible_cpus() == 1)
> --
> 1.8.3.1
>
^ permalink raw reply
* Re: [PATCH v8 2/5] x86/kvm: Change print code to use pr_*() format
From: Wanpeng Li @ 2019-11-19 7:01 UTC (permalink / raw)
To: Zhenzhong Duan
Cc: LKML, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
the arch/x86 maintainers, Paolo Bonzini, Radim Krcmar,
Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
Joerg Roedel, Boris Ostrovsky, Juergen Gross, Peter Zijlstra,
will, linux-hyperv, kvm, mikelley, K. Y. Srinivasan,
Haiyang Zhang, Stephen Hemminger, Sasha Levin, H. Peter Anvin
In-Reply-To: <1571829384-5309-3-git-send-email-zhenzhong.duan@oracle.com>
On Wed, 23 Oct 2019 at 19:23, Zhenzhong Duan <zhenzhong.duan@oracle.com> wrote:
>
> pr_*() is preferred than printk(KERN_* ...), after change all the print
> in arch/x86/kernel/kvm.c will have "kvm-guest: xxx" style.
>
> No functional change.
>
> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@oracle.com>
> Reviewed-by: Vitaly Kuznetsov <vkuznets@redhat.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Radim Krcmar <rkrcmar@redhat.com>
> Cc: Sean Christopherson <sean.j.christopherson@intel.com>
> Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
> Cc: Wanpeng Li <wanpengli@tencent.com>
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Joerg Roedel <joro@8bytes.org>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
Reviewed-by: Wanpeng Li <wanpengli@tencent.com>
> ---
> arch/x86/kernel/kvm.c | 30 ++++++++++++++++--------------
> 1 file changed, 16 insertions(+), 14 deletions(-)
>
> diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
> index 3bc6a266..6562886 100644
> --- a/arch/x86/kernel/kvm.c
> +++ b/arch/x86/kernel/kvm.c
> @@ -7,6 +7,8 @@
> * Authors: Anthony Liguori <aliguori@us.ibm.com>
> */
>
> +#define pr_fmt(fmt) "kvm-guest: " fmt
> +
> #include <linux/context_tracking.h>
> #include <linux/init.h>
> #include <linux/kernel.h>
> @@ -286,8 +288,8 @@ static void kvm_register_steal_time(void)
> return;
>
> wrmsrl(MSR_KVM_STEAL_TIME, (slow_virt_to_phys(st) | KVM_MSR_ENABLED));
> - pr_info("kvm-stealtime: cpu %d, msr %llx\n",
> - cpu, (unsigned long long) slow_virt_to_phys(st));
> + pr_info("stealtime: cpu %d, msr %llx\n", cpu,
> + (unsigned long long) slow_virt_to_phys(st));
> }
>
> static DEFINE_PER_CPU_DECRYPTED(unsigned long, kvm_apic_eoi) = KVM_PV_EOI_DISABLED;
> @@ -321,8 +323,7 @@ static void kvm_guest_cpu_init(void)
>
> wrmsrl(MSR_KVM_ASYNC_PF_EN, pa);
> __this_cpu_write(apf_reason.enabled, 1);
> - printk(KERN_INFO"KVM setup async PF for cpu %d\n",
> - smp_processor_id());
> + pr_info("setup async PF for cpu %d\n", smp_processor_id());
> }
>
> if (kvm_para_has_feature(KVM_FEATURE_PV_EOI)) {
> @@ -347,8 +348,7 @@ static void kvm_pv_disable_apf(void)
> wrmsrl(MSR_KVM_ASYNC_PF_EN, 0);
> __this_cpu_write(apf_reason.enabled, 0);
>
> - printk(KERN_INFO"Unregister pv shared memory for cpu %d\n",
> - smp_processor_id());
> + pr_info("unregister PV shared memory for cpu %d\n", smp_processor_id());
> }
>
> static void kvm_pv_guest_cpu_reboot(void *unused)
> @@ -469,7 +469,8 @@ static void __send_ipi_mask(const struct cpumask *mask, int vector)
> } else {
> ret = kvm_hypercall4(KVM_HC_SEND_IPI, (unsigned long)ipi_bitmap,
> (unsigned long)(ipi_bitmap >> BITS_PER_LONG), min, icr);
> - WARN_ONCE(ret < 0, "KVM: failed to send PV IPI: %ld", ret);
> + WARN_ONCE(ret < 0, "kvm-guest: failed to send PV IPI: %ld",
> + ret);
> min = max = apic_id;
> ipi_bitmap = 0;
> }
> @@ -479,7 +480,8 @@ static void __send_ipi_mask(const struct cpumask *mask, int vector)
> if (ipi_bitmap) {
> ret = kvm_hypercall4(KVM_HC_SEND_IPI, (unsigned long)ipi_bitmap,
> (unsigned long)(ipi_bitmap >> BITS_PER_LONG), min, icr);
> - WARN_ONCE(ret < 0, "KVM: failed to send PV IPI: %ld", ret);
> + WARN_ONCE(ret < 0, "kvm-guest: failed to send PV IPI: %ld",
> + ret);
> }
>
> local_irq_restore(flags);
> @@ -509,7 +511,7 @@ static void kvm_setup_pv_ipi(void)
> {
> apic->send_IPI_mask = kvm_send_ipi_mask;
> apic->send_IPI_mask_allbutself = kvm_send_ipi_mask_allbutself;
> - pr_info("KVM setup pv IPIs\n");
> + pr_info("setup PV IPIs\n");
> }
>
> static void kvm_smp_send_call_func_ipi(const struct cpumask *mask)
> @@ -631,11 +633,11 @@ static void __init kvm_guest_init(void)
> !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
> kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) {
> smp_ops.send_call_func_ipi = kvm_smp_send_call_func_ipi;
> - pr_info("KVM setup pv sched yield\n");
> + pr_info("setup PV sched yield\n");
> }
> if (cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "x86/kvm:online",
> kvm_cpu_online, kvm_cpu_down_prepare) < 0)
> - pr_err("kvm_guest: Failed to install cpu hotplug callbacks\n");
> + pr_err("failed to install cpu hotplug callbacks\n");
> #else
> sev_map_percpu_data();
> kvm_guest_cpu_init();
> @@ -738,7 +740,7 @@ static __init int kvm_setup_pv_tlb_flush(void)
> zalloc_cpumask_var_node(per_cpu_ptr(&__pv_tlb_mask, cpu),
> GFP_KERNEL, cpu_to_node(cpu));
> }
> - pr_info("KVM setup pv remote TLB flush\n");
> + pr_info("setup PV remote TLB flush\n");
> }
>
> return 0;
> @@ -866,8 +868,8 @@ static void kvm_enable_host_haltpoll(void *i)
> void arch_haltpoll_enable(unsigned int cpu)
> {
> if (!kvm_para_has_feature(KVM_FEATURE_POLL_CONTROL)) {
> - pr_err_once("kvm: host does not support poll control\n");
> - pr_err_once("kvm: host upgrade recommended\n");
> + pr_err_once("host does not support poll control\n");
> + pr_err_once("host upgrade recommended\n");
> return;
> }
>
> --
> 1.8.3.1
>
^ permalink raw reply
* Re: [PATCH v8 3/5] x86/kvm: Add "nopvspin" parameter to disable PV spinlocks
From: Wanpeng Li @ 2019-11-19 7:01 UTC (permalink / raw)
To: Zhenzhong Duan
Cc: LKML, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
the arch/x86 maintainers, Paolo Bonzini, Radim Krcmar,
Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson,
Joerg Roedel, Boris Ostrovsky, Juergen Gross, Peter Zijlstra,
will, linux-hyperv, kvm, mikelley, K. Y. Srinivasan,
Haiyang Zhang, Stephen Hemminger, Sasha Levin, Jonathan Corbet,
H. Peter Anvin
In-Reply-To: <1571829384-5309-4-git-send-email-zhenzhong.duan@oracle.com>
On Wed, 23 Oct 2019 at 19:21, Zhenzhong Duan <zhenzhong.duan@oracle.com> wrote:
>
> There are cases where a guest tries to switch spinlocks to bare metal
> behavior (e.g. by setting "xen_nopvspin" on XEN platform and
> "hv_nopvspin" on HYPER_V).
>
> That feature is missed on KVM, add a new parameter "nopvspin" to disable
> PV spinlocks for KVM guest.
>
> The new 'nopvspin' parameter will also replace Xen and Hyper-V specific
> parameters in future patches.
>
> Define variable nopvsin as global because it will be used in future
> patches as above.
>
> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@oracle.com>
> Reviewed-by: Vitaly Kuznetsov <vkuznets@redhat.com>
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Radim Krcmar <rkrcmar@redhat.com>
> Cc: Sean Christopherson <sean.j.christopherson@intel.com>
> Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
> Cc: Wanpeng Li <wanpengli@tencent.com>
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Joerg Roedel <joro@8bytes.org>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Will Deacon <will@kernel.org>
Reviewed-by: Wanpeng Li <wanpengli@tencent.com>
> ---
> Documentation/admin-guide/kernel-parameters.txt | 5 ++++
> arch/x86/include/asm/qspinlock.h | 1 +
> arch/x86/kernel/kvm.c | 39 ++++++++++++++++++++-----
> kernel/locking/qspinlock.c | 7 +++++
> 4 files changed, 45 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index a84a83f..bd49ed2 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -5334,6 +5334,11 @@
> as generic guest with no PV drivers. Currently support
> XEN HVM, KVM, HYPER_V and VMWARE guest.
>
> + nopvspin [X86,KVM]
> + Disables the qspinlock slow path using PV optimizations
> + which allow the hypervisor to 'idle' the guest on lock
> + contention.
> +
> xirc2ps_cs= [NET,PCMCIA]
> Format:
> <irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]]
> diff --git a/arch/x86/include/asm/qspinlock.h b/arch/x86/include/asm/qspinlock.h
> index 444d6fd..d86ab94 100644
> --- a/arch/x86/include/asm/qspinlock.h
> +++ b/arch/x86/include/asm/qspinlock.h
> @@ -32,6 +32,7 @@ static __always_inline u32 queued_fetch_set_pending_acquire(struct qspinlock *lo
> extern void __pv_init_lock_hash(void);
> extern void __pv_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
> extern void __raw_callee_save___pv_queued_spin_unlock(struct qspinlock *lock);
> +extern bool nopvspin;
>
> #define queued_spin_unlock queued_spin_unlock
> /**
> diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
> index 6562886..9834737 100644
> --- a/arch/x86/kernel/kvm.c
> +++ b/arch/x86/kernel/kvm.c
> @@ -825,18 +825,36 @@ __visible bool __kvm_vcpu_is_preempted(long cpu)
> */
> void __init kvm_spinlock_init(void)
> {
> - /* Does host kernel support KVM_FEATURE_PV_UNHALT? */
> - if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT))
> + /*
> + * In case host doesn't support KVM_FEATURE_PV_UNHALT there is still an
> + * advantage of keeping virt_spin_lock_key enabled: virt_spin_lock() is
> + * preferred over native qspinlock when vCPU is preempted.
> + */
> + if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT)) {
> + pr_info("PV spinlocks disabled, no host support\n");
> return;
> + }
>
> + /*
> + * Disable PV spinlocks and use native qspinlock when dedicated pCPUs
> + * are available.
> + */
> if (kvm_para_has_hint(KVM_HINTS_REALTIME)) {
> - static_branch_disable(&virt_spin_lock_key);
> - return;
> + pr_info("PV spinlocks disabled with KVM_HINTS_REALTIME hints\n");
> + goto out;
> }
>
> - /* Don't use the pvqspinlock code if there is only 1 vCPU. */
> - if (num_possible_cpus() == 1)
> - return;
> + if (num_possible_cpus() == 1) {
> + pr_info("PV spinlocks disabled, single CPU\n");
> + goto out;
> + }
> +
> + if (nopvspin) {
> + pr_info("PV spinlocks disabled, forced by \"nopvspin\" parameter\n");
> + goto out;
> + }
> +
> + pr_info("PV spinlocks enabled\n");
>
> __pv_init_lock_hash();
> pv_ops.lock.queued_spin_lock_slowpath = __pv_queued_spin_lock_slowpath;
> @@ -849,6 +867,13 @@ void __init kvm_spinlock_init(void)
> pv_ops.lock.vcpu_is_preempted =
> PV_CALLEE_SAVE(__kvm_vcpu_is_preempted);
> }
> + /*
> + * When PV spinlock is enabled which is preferred over
> + * virt_spin_lock(), virt_spin_lock_key's value is meaningless.
> + * Just disable it anyway.
> + */
> +out:
> + static_branch_disable(&virt_spin_lock_key);
> }
>
> #endif /* CONFIG_PARAVIRT_SPINLOCKS */
> diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
> index 2473f10..75193d6 100644
> --- a/kernel/locking/qspinlock.c
> +++ b/kernel/locking/qspinlock.c
> @@ -580,4 +580,11 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
> #include "qspinlock_paravirt.h"
> #include "qspinlock.c"
>
> +bool nopvspin __initdata;
> +static __init int parse_nopvspin(char *arg)
> +{
> + nopvspin = true;
> + return 0;
> +}
> +early_param("nopvspin", parse_nopvspin);
> #endif
> --
> 1.8.3.1
>
^ permalink raw reply
* Re: [PATCH] drivers/hv: Replace binary semaphore with mutex
From: Sasha Levin @ 2019-11-19 13:20 UTC (permalink / raw)
To: Davidlohr Bueso
Cc: kys, haiyangz, sthemmin, linux-kernel, linux-hyperv,
Davidlohr Bueso
In-Reply-To: <20191101200004.20318-1-dave@stgolabs.net>
On Fri, Nov 01, 2019 at 01:00:04PM -0700, Davidlohr Bueso wrote:
>At a slight footprint cost (24 vs 32 bytes), mutexes are more optimal
>than semaphores; it's also a nicer interface for mutual exclusion,
>which is why they are encouraged over binary semaphores, when possible.
>
>Replace the hyperv_mmio_lock, its semantics implies traditional lock
>ownership; that is, the lock owner is the same for both lock/unlock
>operations. Therefore it is safe to convert.
>
>Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Queued up for hyperv-next, thank you.
--
Thanks,
Sasha
^ permalink raw reply
* Re: [PATCH 1/1] Drivers: hv: vmbus: Fix crash handler reset of Hyper-V synic
From: Sasha Levin @ 2019-11-19 13:23 UTC (permalink / raw)
To: Michael Kelley
Cc: linux-kernel@vger.kernel.org, vkuznets, KY Srinivasan,
Stephen Hemminger, Dexuan Cui, linux-hyperv@vger.kernel.org
In-Reply-To: <1573713076-8446-1-git-send-email-mikelley@microsoft.com>
On Thu, Nov 14, 2019 at 06:32:01AM +0000, Michael Kelley wrote:
>The crash handler calls hv_synic_cleanup() to shutdown the
>Hyper-V synthetic interrupt controller. But if the CPU
>that calls hv_synic_cleanup() has a VMbus channel interrupt
>assigned to it (which is likely the case in smaller VM sizes),
>hv_synic_cleanup() returns an error and the synthetic
>interrupt controller isn't shutdown. While the lack of
>being shutdown hasn't caused a known problem, it still
>should be fixed for highest reliability.
>
>So directly call hv_synic_disable_regs() instead of
>hv_synic_cleanup(), which ensures that the synic is always
>shutdown.
>
>Signed-off-by: Michael Kelley <mikelley@microsoft.com>
Queued up, thank you.
--
Thanks,
Sasha
^ permalink raw reply
* RE: [PATCH] VFIO/VMBUS: Add VFIO VMBUS driver support
From: Michael Kelley @ 2019-11-19 23:37 UTC (permalink / raw)
To: lantianyu1986@gmail.com, alex.williamson@redhat.com,
cohuck@redhat.com, KY Srinivasan, Haiyang Zhang,
Stephen Hemminger, sashal@kernel.org, mchehab+samsung@kernel.org,
davem@davemloft.net, gregkh@linuxfoundation.org, robh@kernel.org,
Jonathan.Cameron@huawei.com, paulmck@linux.ibm.com
Cc: Tianyu Lan, linux-kernel@vger.kernel.org, kvm@vger.kernel.org,
linux-hyperv@vger.kernel.org, vkuznets
In-Reply-To: <20191111084507.9286-1-Tianyu.Lan@microsoft.com>
From: lantianyu1986@gmail.com <lantianyu1986@gmail.com> Sent: Monday, November 11, 2019 12:45 AM
>
> This patch is to add VFIO VMBUS driver support in order to expose
> VMBUS devices to user space drivers(Reference Hyper-V UIO driver).
> DPDK now has netvsc PMD driver support and it may get VMBUS resources
> via VFIO interface with new driver support.
>
> So far, Hyper-V doesn't provide virtual IOMMU support and so this
> driver needs to be used with VFIO noiommu mode.
>
> Current netvsc PMD driver in DPDK doesn't have IRQ mode support.
> This driver version skips IRQ control part and adds later when
> there is a real request.
Let me suggest some cleaned up wording for the commit message:
Add a VFIO VMBus driver to expose VMBus devices to user-space
drivers in a manner similar to the Hyper-V UIO driver. For example,
DPDK has a netvsc Poll-Mode Driver (PMD) and it can get VMBus
resources via the VFIO interface with this new driver.
Hyper-V doesn't provide a virtual IOMMU in guest VMs, so this
driver must be used in VFIO noiommu mode.
The current netvsc PMD driver in DPDK doesn't use IRQ mode so this
driver does not implement IRQ control. IRQ control can be added
later when there is a PMD driver that needs it.
>
> Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
> ---
> MAINTAINERS | 1 +
> drivers/vfio/Kconfig | 1 +
> drivers/vfio/Makefile | 1 +
> drivers/vfio/vmbus/Kconfig | 9 +
> drivers/vfio/vmbus/vfio_vmbus.c | 407
> ++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/vfio.h | 12 ++
> 6 files changed, 431 insertions(+)
> create mode 100644 drivers/vfio/vmbus/Kconfig
> create mode 100644 drivers/vfio/vmbus/vfio_vmbus.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 55199ef7fa74..6f61fb351a5d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7574,6 +7574,7 @@ F: drivers/scsi/storvsc_drv.c
> F: drivers/uio/uio_hv_generic.c
> F: drivers/video/fbdev/hyperv_fb.c
> F: drivers/iommu/hyperv-iommu.c
> +F: drivers/vfio/vmbus/
> F: net/vmw_vsock/hyperv_transport.c
> F: include/clocksource/hyperv_timer.h
> F: include/linux/hyperv.h
> diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
> index fd17db9b432f..f4e075fcedbe 100644
> --- a/drivers/vfio/Kconfig
> +++ b/drivers/vfio/Kconfig
> @@ -47,4 +47,5 @@ menuconfig VFIO_NOIOMMU
> source "drivers/vfio/pci/Kconfig"
> source "drivers/vfio/platform/Kconfig"
> source "drivers/vfio/mdev/Kconfig"
> +source "drivers/vfio/vmbus/Kconfig"
> source "virt/lib/Kconfig"
> diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
> index de67c4725cce..acef916cba7f 100644
> --- a/drivers/vfio/Makefile
> +++ b/drivers/vfio/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spapr_eeh.o
> obj-$(CONFIG_VFIO_PCI) += pci/
> obj-$(CONFIG_VFIO_PLATFORM) += platform/
> obj-$(CONFIG_VFIO_MDEV) += mdev/
> +obj-$(CONFIG_VFIO_VMBUS) += vmbus/
> diff --git a/drivers/vfio/vmbus/Kconfig b/drivers/vfio/vmbus/Kconfig
> new file mode 100644
> index 000000000000..27a85daae55a
> --- /dev/null
> +++ b/drivers/vfio/vmbus/Kconfig
> @@ -0,0 +1,9 @@
> +config VFIO_VMBUS
> + tristate "VFIO support for vmbus devices"
> + depends on VFIO && HYPERV
> + help
> + Support for the VMBUS VFIO bus driver. Expose VMBUS
> + resources to user space drivers(e.g, DPDK and SPDK).
> +
> + If you don't know what to do here, say N.
> +
Let's use consistent capitalization of "VMBus". So:
config VFIO_VMBUS
tristate "VFIO support for Hyper-V VMBus devices"
depends on VFIO && HYPERV
help
Support for the VMBus VFIO driver, which exposes VMBus
resources to user space drivers (e.g., DPDK and SPDK).
If you don't know what to do here, say N.
> diff --git a/drivers/vfio/vmbus/vfio_vmbus.c b/drivers/vfio/vmbus/vfio_vmbus.c
> new file mode 100644
> index 000000000000..25d9cafa2c0a
> --- /dev/null
> +++ b/drivers/vfio/vmbus/vfio_vmbus.c
> @@ -0,0 +1,407 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * VFIO VMBUS driver.
> + *
> + * Copyright (C) 2019, Microsoft, Inc.
> + *
> + * Author : Lan Tianyu <Tianyu.Lan@microsoft.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/vfio.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/hyperv.h>
> +
> +#include "../../hv/hyperv_vmbus.h"
> +
> +
> +#define DRIVER_VERSION "0.0.1"
> +#define DRIVER_AUTHOR "Tianyu Lan <Tianyu.Lan@microsoft.com>"
> +#define DRIVER_DESC "VFIO driver for VMBus devices"
> +
> +#define HV_RING_SIZE (512 * HV_HYP_PAGE_SIZE) /* 2M Ring size */
> +#define SEND_BUFFER_SIZE (16 * 1024 * 1024)
> +#define RECV_BUFFER_SIZE (31 * 1024 * 1024)
> +
> +struct vmbus_mem {
> + phys_addr_t addr;
> + resource_size_t size;
> +};
> +
> +struct vfio_vmbus_device {
> + struct hv_device *hdev;
> + atomic_t refcnt;
> + struct vmbus_mem mem[VFIO_VMBUS_MAX_MAP_NUM];
> +
> + void *recv_buf;
> + void *send_buf;
> +};
> +
> +static void vfio_vmbus_channel_cb(void *context)
> +{
> + struct vmbus_channel *chan = context;
> +
> + /* Disable interrupts on channel */
> + chan->inbound.ring_buffer->interrupt_mask = 1;
> +
> + /* Issue a full memory barrier after masking interrupt */
> + virt_mb();
> +}
> +
> +static int vfio_vmbus_ring_mmap(struct file *filp, struct kobject *kobj,
> + struct bin_attribute *attr,
> + struct vm_area_struct *vma)
> +{
> + struct vmbus_channel *channel
> + = container_of(kobj, struct vmbus_channel, kobj);
> + void *ring_buffer = page_address(channel->ringbuffer_page);
> +
> + if (channel->state != CHANNEL_OPENED_STATE)
> + return -ENODEV;
> +
> + return vm_iomap_memory(vma, virt_to_phys(ring_buffer),
> + channel->ringbuffer_pagecount << PAGE_SHIFT);
Use HV_HYP_PAGE_SHIFT since ringbuffer_pagecount is in units of the
Hyper-V page size, which may be different from the guest PAGE_SIZE.
> +}
> +
> +static const struct bin_attribute ring_buffer_bin_attr = {
> + .attr = {
> + .name = "ring",
> + .mode = 0600,
> + },
> + .size = 2 * HV_RING_SIZE,
> + .mmap = vfio_vmbus_ring_mmap,
> +};
> +
[snip]
> +static int vfio_vmbus_probe(struct hv_device *dev,
> + const struct hv_vmbus_device_id *dev_id)
> +{
> + struct vmbus_channel *channel = dev->channel;
> + struct vfio_vmbus_device *vdev;
> + struct iommu_group *group;
> + u32 gpadl;
> + void *ring_buffer;
> + int ret;
> +
> + group = vfio_iommu_group_get(&dev->device);
> + if (!group)
> + return -EINVAL;
> +
> + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
> + if (!vdev) {
> + vfio_iommu_group_put(group, &dev->device);
> + return -ENOMEM;
> + }
> +
> + ret = vfio_add_group_dev(&dev->device, &vfio_vmbus_ops, vdev);
> + if (ret)
> + goto free_vdev;
> +
> + vdev->hdev = dev;
> + ret = vmbus_alloc_ring(channel, HV_RING_SIZE, HV_RING_SIZE);
> + if (ret)
> + goto del_group_dev;
> +
> + set_channel_read_mode(channel, HV_CALL_ISR);
> +
> + ring_buffer = page_address(channel->ringbuffer_page);
> + vdev->mem[VFIO_VMBUS_TXRX_RING_MAP].addr
> + = virt_to_phys(ring_buffer);
> + vdev->mem[VFIO_VMBUS_TXRX_RING_MAP].size
> + = channel->ringbuffer_pagecount << PAGE_SHIFT;
Use HV_HYP_PAGE_SHIFT per my earlier comment.
> +
> + vdev->mem[VFIO_VMBUS_INT_PAGE_MAP].addr
> + = (phys_addr_t)vmbus_connection.int_page;
> + vdev->mem[VFIO_VMBUS_INT_PAGE_MAP].size = PAGE_SIZE;
Use HV_HYP_PAGE_SIZE since the interrupt page is sized to the
Hyper-V page size, not the guest page size.
> +
> + vdev->mem[VFIO_VMBUS_MON_PAGE_MAP].addr
> + = (phys_addr_t)vmbus_connection.monitor_pages[1];
> + vdev->mem[VFIO_VMBUS_MON_PAGE_MAP].size = PAGE_SIZE;
Same here for the monitor page.
> +
> + vdev->recv_buf = vzalloc(RECV_BUFFER_SIZE);
> + if (vdev->recv_buf == NULL) {
> + ret = -ENOMEM;
> + goto free_ring;
> + }
> +
> + ret = vmbus_establish_gpadl(channel, vdev->recv_buf,
> + RECV_BUFFER_SIZE, &gpadl);
> + if (ret)
> + goto free_recv_buf;
> +
> + vdev->mem[VFIO_VMBUS_RECV_BUF_MAP].addr
> + = (phys_addr_t)vdev->recv_buf;
> + vdev->mem[VFIO_VMBUS_RECV_BUF_MAP].size = RECV_BUFFER_SIZE;
> +
> + /* Expose Recv GPADL via region info. */
> + vdev->mem[VFIO_VMBUS_RECV_GPADL].addr = gpadl;
> +
> + vdev->send_buf = vzalloc(SEND_BUFFER_SIZE);
> + if (vdev->send_buf == NULL) {
> + ret = -ENOMEM;
> + goto free_recv_gpadl;
> + }
> +
> + ret = vmbus_establish_gpadl(channel, vdev->send_buf,
> + SEND_BUFFER_SIZE, &gpadl);
> + if (ret)
> + goto free_send_buf;
> +
> + vdev->mem[VFIO_VMBUS_SEND_BUF_MAP].addr
> + = (phys_addr_t)vdev->send_buf;
> + vdev->mem[VFIO_VMBUS_SEND_BUF_MAP].size = SEND_BUFFER_SIZE;
> +
> + /* Expose Send GPADL via region info. */
> + vdev->mem[VFIO_VMBUS_SEND_GPADL].addr = gpadl;
> +
> + ret = sysfs_create_bin_file(&channel->kobj, &ring_buffer_bin_attr);
> + if (ret)
> + dev_notice(&dev->device,
> + "sysfs create ring bin file failed; %d\n", ret);
> +
> + return 0;
> +
> + free_send_buf:
> + vfree(vdev->send_buf);
> + free_recv_gpadl:
> + vmbus_teardown_gpadl(channel, vdev->mem[VFIO_VMBUS_RECV_GPADL].addr);
> + free_recv_buf:
> + vfree(vdev->recv_buf);
> + free_ring:
> + vmbus_free_ring(channel);
> + del_group_dev:
> + vfio_del_group_dev(&dev->device);
> + free_vdev:
> + vfio_iommu_group_put(group, &dev->device);
> + kfree(vdev);
> + return -EINVAL;
> +}
> +
[snip]
> diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
> index 9e843a147ead..611baf7a30e4 100644
> --- a/include/uapi/linux/vfio.h
> +++ b/include/uapi/linux/vfio.h
> @@ -201,6 +201,7 @@ struct vfio_device_info {
> #define VFIO_DEVICE_FLAGS_AMBA (1 << 3) /* vfio-amba device */
> #define VFIO_DEVICE_FLAGS_CCW (1 << 4) /* vfio-ccw device */
> #define VFIO_DEVICE_FLAGS_AP (1 << 5) /* vfio-ap device */
> +#define VFIO_DEVICE_FLAGS_VMBUS (1 << 6) /* vfio-vmbus device */
> __u32 num_regions; /* Max region index + 1 */
> __u32 num_irqs; /* Max IRQ index + 1 */
> };
> @@ -564,6 +565,17 @@ enum {
> VFIO_PCI_NUM_IRQS
> };
>
> +enum {
> + VFIO_VMBUS_TXRX_RING_MAP = 0,
> + VFIO_VMBUS_INT_PAGE_MAP,
> + VFIO_VMBUS_MON_PAGE_MAP,
> + VFIO_VMBUS_RECV_BUF_MAP,
> + VFIO_VMBUS_SEND_BUF_MAP,
> + VFIO_VMBUS_RECV_GPADL,
> + VFIO_VMBUS_SEND_GPADL,
> + VFIO_VMBUS_MAX_MAP_NUM,
While the code that uses VFIO_VMBUS_MAX_MAP_NUM appears
correct, the "MAX_MAP_NUM" in the symbol name tends to
imply that this is an index value. But it's not the max index
value -- it's actually a "count" or "size". I think it would be
clearer as VFIO_VMBUS_MAP_COUNT or
VFIO_VMBUS_MAP_SIZE.
> +};
> +
> /*
> * The vfio-ccw bus driver makes use of the following fixed region and
> * IRQ index mapping. Unimplemented regions return a size of zero.
> --
> 2.14.5
^ permalink raw reply
* Re: [PATCH] VFIO/VMBUS: Add VFIO VMBUS driver support
From: Alex Williamson @ 2019-11-19 23:56 UTC (permalink / raw)
To: lantianyu1986
Cc: cohuck, kys, haiyangz, sthemmin, sashal, mchehab+samsung, davem,
gregkh, robh, Jonathan.Cameron, paulmck, michael.h.kelley,
Tianyu Lan, linux-kernel, kvm, linux-hyperv, vkuznets
In-Reply-To: <20191111084507.9286-1-Tianyu.Lan@microsoft.com>
On Mon, 11 Nov 2019 16:45:07 +0800
lantianyu1986@gmail.com wrote:
> From: Tianyu Lan <Tianyu.Lan@microsoft.com>
>
> This patch is to add VFIO VMBUS driver support in order to expose
> VMBUS devices to user space drivers(Reference Hyper-V UIO driver).
> DPDK now has netvsc PMD driver support and it may get VMBUS resources
> via VFIO interface with new driver support.
>
> So far, Hyper-V doesn't provide virtual IOMMU support and so this
> driver needs to be used with VFIO noiommu mode.
Let's be clear here, vfio no-iommu mode taints the kernel and was a
compromise that we can re-use vfio-pci in its entirety, so it had a
high code reuse value for minimal code and maintenance investment. It
was certainly not intended to provoke new drivers that rely on this mode
of operation. In fact, no-iommu should be discouraged as it provides
absolutely no isolation. I'd therefore ask, why should this be in the
kernel versus any other unsupportable out of tree driver? It appears
almost entirely self contained. Thanks,
Alex
> Current netvsc PMD driver in DPDK doesn't have IRQ mode support.
> This driver version skips IRQ control part and adds later when
> there is a real request.
>
> Signed-off-by: Tianyu Lan <Tianyu.Lan@microsoft.com>
> ---
> MAINTAINERS | 1 +
> drivers/vfio/Kconfig | 1 +
> drivers/vfio/Makefile | 1 +
> drivers/vfio/vmbus/Kconfig | 9 +
> drivers/vfio/vmbus/vfio_vmbus.c | 407 ++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/vfio.h | 12 ++
> 6 files changed, 431 insertions(+)
> create mode 100644 drivers/vfio/vmbus/Kconfig
> create mode 100644 drivers/vfio/vmbus/vfio_vmbus.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 55199ef7fa74..6f61fb351a5d 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7574,6 +7574,7 @@ F: drivers/scsi/storvsc_drv.c
> F: drivers/uio/uio_hv_generic.c
> F: drivers/video/fbdev/hyperv_fb.c
> F: drivers/iommu/hyperv-iommu.c
> +F: drivers/vfio/vmbus/
> F: net/vmw_vsock/hyperv_transport.c
> F: include/clocksource/hyperv_timer.h
> F: include/linux/hyperv.h
> diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
> index fd17db9b432f..f4e075fcedbe 100644
> --- a/drivers/vfio/Kconfig
> +++ b/drivers/vfio/Kconfig
> @@ -47,4 +47,5 @@ menuconfig VFIO_NOIOMMU
> source "drivers/vfio/pci/Kconfig"
> source "drivers/vfio/platform/Kconfig"
> source "drivers/vfio/mdev/Kconfig"
> +source "drivers/vfio/vmbus/Kconfig"
> source "virt/lib/Kconfig"
> diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
> index de67c4725cce..acef916cba7f 100644
> --- a/drivers/vfio/Makefile
> +++ b/drivers/vfio/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spapr_eeh.o
> obj-$(CONFIG_VFIO_PCI) += pci/
> obj-$(CONFIG_VFIO_PLATFORM) += platform/
> obj-$(CONFIG_VFIO_MDEV) += mdev/
> +obj-$(CONFIG_VFIO_VMBUS) += vmbus/
> diff --git a/drivers/vfio/vmbus/Kconfig b/drivers/vfio/vmbus/Kconfig
> new file mode 100644
> index 000000000000..27a85daae55a
> --- /dev/null
> +++ b/drivers/vfio/vmbus/Kconfig
> @@ -0,0 +1,9 @@
> +config VFIO_VMBUS
> + tristate "VFIO support for vmbus devices"
> + depends on VFIO && HYPERV
> + help
> + Support for the VMBUS VFIO bus driver. Expose VMBUS
> + resources to user space drivers(e.g, DPDK and SPDK).
> +
> + If you don't know what to do here, say N.
> +
> diff --git a/drivers/vfio/vmbus/vfio_vmbus.c b/drivers/vfio/vmbus/vfio_vmbus.c
> new file mode 100644
> index 000000000000..25d9cafa2c0a
> --- /dev/null
> +++ b/drivers/vfio/vmbus/vfio_vmbus.c
> @@ -0,0 +1,407 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * VFIO VMBUS driver.
> + *
> + * Copyright (C) 2019, Microsoft, Inc.
> + *
> + * Author : Lan Tianyu <Tianyu.Lan@microsoft.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/vfio.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/hyperv.h>
> +
> +#include "../../hv/hyperv_vmbus.h"
> +
> +
> +#define DRIVER_VERSION "0.0.1"
> +#define DRIVER_AUTHOR "Tianyu Lan <Tianyu.Lan@microsoft.com>"
> +#define DRIVER_DESC "VFIO driver for VMBus devices"
> +
> +#define HV_RING_SIZE (512 * HV_HYP_PAGE_SIZE) /* 2M Ring size */
> +#define SEND_BUFFER_SIZE (16 * 1024 * 1024)
> +#define RECV_BUFFER_SIZE (31 * 1024 * 1024)
> +
> +struct vmbus_mem {
> + phys_addr_t addr;
> + resource_size_t size;
> +};
> +
> +struct vfio_vmbus_device {
> + struct hv_device *hdev;
> + atomic_t refcnt;
> + struct vmbus_mem mem[VFIO_VMBUS_MAX_MAP_NUM];
> +
> + void *recv_buf;
> + void *send_buf;
> +};
> +
> +static void vfio_vmbus_channel_cb(void *context)
> +{
> + struct vmbus_channel *chan = context;
> +
> + /* Disable interrupts on channel */
> + chan->inbound.ring_buffer->interrupt_mask = 1;
> +
> + /* Issue a full memory barrier after masking interrupt */
> + virt_mb();
> +}
> +
> +static int vfio_vmbus_ring_mmap(struct file *filp, struct kobject *kobj,
> + struct bin_attribute *attr,
> + struct vm_area_struct *vma)
> +{
> + struct vmbus_channel *channel
> + = container_of(kobj, struct vmbus_channel, kobj);
> + void *ring_buffer = page_address(channel->ringbuffer_page);
> +
> + if (channel->state != CHANNEL_OPENED_STATE)
> + return -ENODEV;
> +
> + return vm_iomap_memory(vma, virt_to_phys(ring_buffer),
> + channel->ringbuffer_pagecount << PAGE_SHIFT);
> +}
> +
> +static const struct bin_attribute ring_buffer_bin_attr = {
> + .attr = {
> + .name = "ring",
> + .mode = 0600,
> + },
> + .size = 2 * HV_RING_SIZE,
> + .mmap = vfio_vmbus_ring_mmap,
> +};
> +
> +static void
> +vfio_vmbus_new_channel(struct vmbus_channel *new_sc)
> +{
> + struct hv_device *hv_dev = new_sc->primary_channel->device_obj;
> + struct device *device = &hv_dev->device;
> + int ret;
> +
> + /* Create host communication ring */
> + ret = vmbus_open(new_sc, HV_RING_SIZE, HV_RING_SIZE, NULL, 0,
> + vfio_vmbus_channel_cb, new_sc);
> + if (ret) {
> + dev_err(device, "vmbus_open subchannel failed: %d\n", ret);
> + return;
> + }
> +
> + /* Disable interrupts on sub channel */
> + new_sc->inbound.ring_buffer->interrupt_mask = 1;
> + set_channel_read_mode(new_sc, HV_CALL_ISR);
> +
> + ret = sysfs_create_bin_file(&new_sc->kobj, &ring_buffer_bin_attr);
> + if (ret)
> + dev_notice(&hv_dev->device,
> + "sysfs create ring bin file failed; %d\n", ret);
> +}
> +
> +static int vfio_vmbus_open(void *device_data)
> +{
> + struct vfio_vmbus_device *vdev = device_data;
> + struct hv_device *dev = vdev->hdev;
> + int ret;
> +
> + vmbus_set_sc_create_callback(dev->channel, vfio_vmbus_new_channel);
> +
> + ret = vmbus_connect_ring(dev->channel,
> + vfio_vmbus_channel_cb, dev->channel);
> + if (ret == 0)
> + dev->channel->inbound.ring_buffer->interrupt_mask = 1;
> +
> + return 0;
> +}
> +
> +static long vfio_vmbus_ioctl(void *device_data, unsigned int cmd,
> + unsigned long arg)
> +{
> + struct vfio_vmbus_device *vdev = device_data;
> + unsigned long minsz;
> +
> + if (cmd == VFIO_DEVICE_GET_INFO) {
> + struct vfio_device_info info;
> +
> + minsz = offsetofend(struct vfio_device_info, num_irqs);
> +
> + if (copy_from_user(&info, (void __user *)arg, minsz))
> + return -EFAULT;
> +
> + if (info.argsz < minsz)
> + return -EINVAL;
> +
> + info.flags = VFIO_DEVICE_FLAGS_VMBUS;
> + info.num_regions = VFIO_VMBUS_MAX_MAP_NUM;
> +
> + return copy_to_user((void __user *)arg, &info, minsz) ?
> + -EFAULT : 0;
> + } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
> + struct vfio_region_info info;
> +
> + minsz = offsetofend(struct vfio_region_info, offset);
> +
> + if (copy_from_user(&info, (void __user *)arg, minsz))
> + return -EFAULT;
> +
> + if (info.argsz < minsz)
> + return -EINVAL;
> +
> + if (info.index >= VFIO_VMBUS_MAX_MAP_NUM)
> + return -EINVAL;
> +
> + info.offset = vdev->mem[info.index].addr;
> + info.size = vdev->mem[info.index].size;
> + info.flags = VFIO_REGION_INFO_FLAG_READ
> + | VFIO_REGION_INFO_FLAG_WRITE
> + | VFIO_REGION_INFO_FLAG_MMAP;
> +
> + return copy_to_user((void __user *)arg, &info, minsz) ?
> + -EFAULT : 0;
> + }
> +
> + return -ENOTTY;
> +}
> +
> +static void vfio_vmbus_release(void *device_data)
> +{
> + struct vfio_vmbus_device *vdev = device_data;
> +
> + vmbus_disconnect_ring(vdev->hdev->channel);
> +}
> +
> +static vm_fault_t vfio_vma_fault(struct vm_fault *vmf)
> +{
> + struct vfio_vmbus_device *vdev = vmf->vma->vm_private_data;
> + struct vm_area_struct *vma = vmf->vma;
> + struct page *page;
> + unsigned long offset;
> + void *addr;
> + int index;
> +
> + index = vma->vm_pgoff;
> +
> + /*
> + * Page fault should only happen on mmap regiones
> + * and bypass GPADL indexes here.
> + */
> + if (index >= VFIO_VMBUS_MAX_MAP_NUM - 2)
> + return VM_FAULT_SIGBUS;
> +
> + offset = (vmf->pgoff - index) << PAGE_SHIFT;
> + addr = (void *)(vdev->mem[index].addr + offset);
> +
> + if (index == VFIO_VMBUS_SEND_BUF_MAP ||
> + index == VFIO_VMBUS_RECV_BUF_MAP)
> + page = vmalloc_to_page(addr);
> + else
> + page = virt_to_page(addr);
> +
> + get_page(page);
> + vmf->page = page;
> +
> + return 0;
> +}
> +
> +static const struct vm_operations_struct vfio_logical_vm_ops = {
> + .fault = vfio_vma_fault,
> +};
> +
> +static const struct vm_operations_struct vfio_physical_vm_ops = {
> +#ifdef CONFIG_HAVE_IOREMAP_PROT
> + .access = generic_access_phys,
> +#endif
> +};
> +
> +static int vfio_vmbus_mmap(void *device_data, struct vm_area_struct *vma)
> +{
> + struct vfio_vmbus_device *vdev = device_data;
> + int index;
> +
> + if (vma->vm_end < vma->vm_start)
> + return -EINVAL;
> +
> + /*
> + * Mmap should only happen on map regions
> + * and bypass GPADL index here.
> + */
> + if (vma->vm_pgoff >= VFIO_VMBUS_MAX_MAP_NUM - 2)
> + return -EINVAL;
> +
> + index = vma->vm_pgoff;
> + vma->vm_private_data = vdev;
> +
> + if (index == VFIO_VMBUS_TXRX_RING_MAP) {
> + u64 addr;
> +
> + addr = vdev->mem[VFIO_VMBUS_TXRX_RING_MAP].addr;
> + vma->vm_ops = &vfio_physical_vm_ops;
> + return remap_pfn_range(vma,
> + vma->vm_start,
> + addr >> PAGE_SHIFT,
> + vma->vm_end - vma->vm_start,
> + vma->vm_page_prot);
> + } else {
> + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
> + vma->vm_ops = &vfio_logical_vm_ops;
> + return 0;
> + }
> +}
> +
> +static const struct vfio_device_ops vfio_vmbus_ops = {
> + .name = "vfio-vmbus",
> + .open = vfio_vmbus_open,
> + .release = vfio_vmbus_release,
> + .mmap = vfio_vmbus_mmap,
> + .ioctl = vfio_vmbus_ioctl,
> +};
> +
> +static int vfio_vmbus_probe(struct hv_device *dev,
> + const struct hv_vmbus_device_id *dev_id)
> +{
> + struct vmbus_channel *channel = dev->channel;
> + struct vfio_vmbus_device *vdev;
> + struct iommu_group *group;
> + u32 gpadl;
> + void *ring_buffer;
> + int ret;
> +
> + group = vfio_iommu_group_get(&dev->device);
> + if (!group)
> + return -EINVAL;
> +
> + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
> + if (!vdev) {
> + vfio_iommu_group_put(group, &dev->device);
> + return -ENOMEM;
> + }
> +
> + ret = vfio_add_group_dev(&dev->device, &vfio_vmbus_ops, vdev);
> + if (ret)
> + goto free_vdev;
> +
> + vdev->hdev = dev;
> + ret = vmbus_alloc_ring(channel, HV_RING_SIZE, HV_RING_SIZE);
> + if (ret)
> + goto del_group_dev;
> +
> + set_channel_read_mode(channel, HV_CALL_ISR);
> +
> + ring_buffer = page_address(channel->ringbuffer_page);
> + vdev->mem[VFIO_VMBUS_TXRX_RING_MAP].addr
> + = virt_to_phys(ring_buffer);
> + vdev->mem[VFIO_VMBUS_TXRX_RING_MAP].size
> + = channel->ringbuffer_pagecount << PAGE_SHIFT;
> +
> + vdev->mem[VFIO_VMBUS_INT_PAGE_MAP].addr
> + = (phys_addr_t)vmbus_connection.int_page;
> + vdev->mem[VFIO_VMBUS_INT_PAGE_MAP].size = PAGE_SIZE;
> +
> + vdev->mem[VFIO_VMBUS_MON_PAGE_MAP].addr
> + = (phys_addr_t)vmbus_connection.monitor_pages[1];
> + vdev->mem[VFIO_VMBUS_MON_PAGE_MAP].size = PAGE_SIZE;
> +
> + vdev->recv_buf = vzalloc(RECV_BUFFER_SIZE);
> + if (vdev->recv_buf == NULL) {
> + ret = -ENOMEM;
> + goto free_ring;
> + }
> +
> + ret = vmbus_establish_gpadl(channel, vdev->recv_buf,
> + RECV_BUFFER_SIZE, &gpadl);
> + if (ret)
> + goto free_recv_buf;
> +
> + vdev->mem[VFIO_VMBUS_RECV_BUF_MAP].addr
> + = (phys_addr_t)vdev->recv_buf;
> + vdev->mem[VFIO_VMBUS_RECV_BUF_MAP].size = RECV_BUFFER_SIZE;
> +
> + /* Expose Recv GPADL via region info. */
> + vdev->mem[VFIO_VMBUS_RECV_GPADL].addr = gpadl;
> +
> + vdev->send_buf = vzalloc(SEND_BUFFER_SIZE);
> + if (vdev->send_buf == NULL) {
> + ret = -ENOMEM;
> + goto free_recv_gpadl;
> + }
> +
> + ret = vmbus_establish_gpadl(channel, vdev->send_buf,
> + SEND_BUFFER_SIZE, &gpadl);
> + if (ret)
> + goto free_send_buf;
> +
> + vdev->mem[VFIO_VMBUS_SEND_BUF_MAP].addr
> + = (phys_addr_t)vdev->send_buf;
> + vdev->mem[VFIO_VMBUS_SEND_BUF_MAP].size = SEND_BUFFER_SIZE;
> +
> + /* Expose Send GPADL via region info. */
> + vdev->mem[VFIO_VMBUS_SEND_GPADL].addr = gpadl;
> +
> + ret = sysfs_create_bin_file(&channel->kobj, &ring_buffer_bin_attr);
> + if (ret)
> + dev_notice(&dev->device,
> + "sysfs create ring bin file failed; %d\n", ret);
> +
> + return 0;
> +
> + free_send_buf:
> + vfree(vdev->send_buf);
> + free_recv_gpadl:
> + vmbus_teardown_gpadl(channel, vdev->mem[VFIO_VMBUS_RECV_GPADL].addr);
> + free_recv_buf:
> + vfree(vdev->recv_buf);
> + free_ring:
> + vmbus_free_ring(channel);
> + del_group_dev:
> + vfio_del_group_dev(&dev->device);
> + free_vdev:
> + vfio_iommu_group_put(group, &dev->device);
> + kfree(vdev);
> + return -EINVAL;
> +}
> +
> +static int vfio_vmbus_remove(struct hv_device *hdev)
> +{
> + struct vfio_vmbus_device *vdev = vfio_del_group_dev(&hdev->device);
> + struct vmbus_channel *channel = hdev->channel;
> +
> + if (!vdev)
> + return 0;
> +
> + sysfs_remove_bin_file(&channel->kobj, &ring_buffer_bin_attr);
> +
> + vmbus_teardown_gpadl(channel, vdev->mem[VFIO_VMBUS_SEND_GPADL].addr);
> + vmbus_teardown_gpadl(channel, vdev->mem[VFIO_VMBUS_RECV_GPADL].addr);
> + vfree(vdev->recv_buf);
> + vfree(vdev->send_buf);
> + vmbus_free_ring(channel);
> + vfio_iommu_group_put(hdev->device.iommu_group, &hdev->device);
> + kfree(vdev);
> +
> + return 0;
> +}
> +
> +static struct hv_driver hv_vfio_drv = {
> + .name = "hv_vfio",
> + .id_table = NULL,
> + .probe = vfio_vmbus_probe,
> + .remove = vfio_vmbus_remove,
> +};
> +
> +static int __init vfio_vmbus_init(void)
> +{
> + return vmbus_driver_register(&hv_vfio_drv);
> +}
> +
> +static void __exit vfio_vmbus_exit(void)
> +{
> + vmbus_driver_unregister(&hv_vfio_drv);
> +}
> +
> +module_init(vfio_vmbus_init);
> +module_exit(vfio_vmbus_exit);
> +
> +MODULE_VERSION(DRIVER_VERSION);
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
> index 9e843a147ead..611baf7a30e4 100644
> --- a/include/uapi/linux/vfio.h
> +++ b/include/uapi/linux/vfio.h
> @@ -201,6 +201,7 @@ struct vfio_device_info {
> #define VFIO_DEVICE_FLAGS_AMBA (1 << 3) /* vfio-amba device */
> #define VFIO_DEVICE_FLAGS_CCW (1 << 4) /* vfio-ccw device */
> #define VFIO_DEVICE_FLAGS_AP (1 << 5) /* vfio-ap device */
> +#define VFIO_DEVICE_FLAGS_VMBUS (1 << 6) /* vfio-vmbus device */
> __u32 num_regions; /* Max region index + 1 */
> __u32 num_irqs; /* Max IRQ index + 1 */
> };
> @@ -564,6 +565,17 @@ enum {
> VFIO_PCI_NUM_IRQS
> };
>
> +enum {
> + VFIO_VMBUS_TXRX_RING_MAP = 0,
> + VFIO_VMBUS_INT_PAGE_MAP,
> + VFIO_VMBUS_MON_PAGE_MAP,
> + VFIO_VMBUS_RECV_BUF_MAP,
> + VFIO_VMBUS_SEND_BUF_MAP,
> + VFIO_VMBUS_RECV_GPADL,
> + VFIO_VMBUS_SEND_GPADL,
> + VFIO_VMBUS_MAX_MAP_NUM,
> +};
> +
> /*
> * The vfio-ccw bus driver makes use of the following fixed region and
> * IRQ index mapping. Unimplemented regions return a size of zero.
^ permalink raw reply
* [PATCH v6] x86/hyperv: Suspend/resume the hypercall page for hibernation
From: Dexuan Cui @ 2019-11-20 7:09 UTC (permalink / raw)
To: arnd, bp, daniel.lezcano, haiyangz, hpa, kys, linux-hyperv,
linux-kernel, mingo, sashal, sthemmin, tglx, x86, mikelley,
Alexander.Levin, vkuznets
Cc: linux-arch, Dexuan Cui
This is needed for hibernation, e.g. when we resume the old kernel, we need
to disable the "current" kernel's hypercall page and then resume the old
kernel's.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
---
This patch is part of the v5 patchset:
https://lkml.org/lkml/2019/9/5/1158
https://lkml.org/lkml/2019/9/5/1159
The change is: I set 'hv_hypercall_pg' to NULL in hv_suspend(), and
restore it in hv_resume(). This is suggested by Vitaly Kuznetsov.
There is no other change, compared to v1 (v2~v5 were posted with the other
patches).
Please pick up this patch onto the tip.git tree's branch x86/hyperv.
arch/x86/hyperv/hv_init.c | 48 +++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
index 426dc8b78193..c170653da589 100644
--- a/arch/x86/hyperv/hv_init.c
+++ b/arch/x86/hyperv/hv_init.c
@@ -20,11 +20,15 @@
#include <linux/hyperv.h>
#include <linux/slab.h>
#include <linux/cpuhotplug.h>
+#include <linux/syscore_ops.h>
#include <clocksource/hyperv_timer.h>
void *hv_hypercall_pg;
EXPORT_SYMBOL_GPL(hv_hypercall_pg);
+/* Save the hypercall page temporarily for hibernation */
+static void *hv_hypercall_pg_saved;
+
u32 *hv_vp_index;
EXPORT_SYMBOL_GPL(hv_vp_index);
@@ -245,6 +249,46 @@ static int __init hv_pci_init(void)
return 1;
}
+static int hv_suspend(void)
+{
+ union hv_x64_msr_hypercall_contents hypercall_msr;
+
+ /*
+ * Reset hypercall page reference before reset the page,
+ * let hypercall operations fail safely rather than
+ * panic the kernel for using invalid hypercall page
+ */
+ hv_hypercall_pg_saved = hv_hypercall_pg;
+ hv_hypercall_pg = NULL;
+
+ /* Reset the hypercall page */
+ rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+ hypercall_msr.enable = 0;
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+
+ return 0;
+}
+
+static void hv_resume(void)
+{
+ union hv_x64_msr_hypercall_contents hypercall_msr;
+
+ /* Re-enable the hypercall page */
+ rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+ hypercall_msr.enable = 1;
+ hypercall_msr.guest_physical_address =
+ vmalloc_to_pfn(hv_hypercall_pg_saved);
+ wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
+
+ hv_hypercall_pg = hv_hypercall_pg_saved;
+ hv_hypercall_pg_saved = NULL;
+}
+
+static struct syscore_ops hv_syscore_ops = {
+ .suspend = hv_suspend,
+ .resume = hv_resume,
+};
+
/*
* This function is to be invoked early in the boot sequence after the
* hypervisor has been detected.
@@ -329,6 +373,8 @@ void __init hyperv_init(void)
x86_init.pci.arch_init = hv_pci_init;
+ register_syscore_ops(&hv_syscore_ops);
+
return;
remove_cpuhp_state:
@@ -348,6 +394,8 @@ void hyperv_cleanup(void)
{
union hv_x64_msr_hypercall_contents hypercall_msr;
+ unregister_syscore_ops(&hv_syscore_ops);
+
/* Reset our OS id */
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
--
2.19.1
^ permalink raw reply related
* [PATCH v6] clocksource/drivers: Suspend/resume Hyper-V clocksource for hibernation
From: Dexuan Cui @ 2019-11-20 7:12 UTC (permalink / raw)
To: arnd, bp, daniel.lezcano, haiyangz, hpa, kys, linux-hyperv,
linux-kernel, mingo, sashal, sthemmin, tglx, x86, mikelley,
Alexander.Levin, vkuznets
Cc: linux-arch, Dexuan Cui
This is needed for hibernation, e.g. when we resume the old kernel, we need
to disable the "current" kernel's TSC page and then resume the old kernel's.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
---
This patch is part of the v5 patchset:
https://lkml.org/lkml/2019/9/5/1158
https://lkml.org/lkml/2019/9/5/1161
Actually v6 is the same as v1 (v2~v5 were posted with the other patches).
Please pick up this patch into the tip.git tree, probably onto the branch
timers/core.
drivers/clocksource/hyperv_timer.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c
index 287d8d58c21a..1aec08e82b7a 100644
--- a/drivers/clocksource/hyperv_timer.c
+++ b/drivers/clocksource/hyperv_timer.c
@@ -330,12 +330,37 @@ static u64 read_hv_sched_clock_tsc(void)
return read_hv_clock_tsc(NULL) - hv_sched_clock_offset;
}
+static void suspend_hv_clock_tsc(struct clocksource *arg)
+{
+ u64 tsc_msr;
+
+ /* Disable the TSC page */
+ hv_get_reference_tsc(tsc_msr);
+ tsc_msr &= ~BIT_ULL(0);
+ hv_set_reference_tsc(tsc_msr);
+}
+
+
+static void resume_hv_clock_tsc(struct clocksource *arg)
+{
+ phys_addr_t phys_addr = virt_to_phys(&tsc_pg);
+ u64 tsc_msr;
+
+ /* Re-enable the TSC page */
+ hv_get_reference_tsc(tsc_msr);
+ tsc_msr &= GENMASK_ULL(11, 0);
+ tsc_msr |= BIT_ULL(0) | (u64)phys_addr;
+ hv_set_reference_tsc(tsc_msr);
+}
+
static struct clocksource hyperv_cs_tsc = {
.name = "hyperv_clocksource_tsc_page",
.rating = 400,
.read = read_hv_clock_tsc,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .suspend= suspend_hv_clock_tsc,
+ .resume = resume_hv_clock_tsc,
};
static u64 notrace read_hv_clock_msr(struct clocksource *arg)
--
2.19.1
^ permalink raw reply related
* [PATCH] video: hyperv_fb: Fix hibernation for the deferred IO feature
From: Dexuan Cui @ 2019-11-20 7:13 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, sashal, b.zolnierkie, linux-hyperv,
dri-devel, linux-fbdev, linux-kernel, mikelley, Alexander.Levin
Cc: weh, Dexuan Cui
fb_deferred_io_work() can access the vmbus ringbuffer by calling
fbdefio->deferred_io() -> synthvid_deferred_io() -> synthvid_update().
Because the vmbus ringbuffer is inaccessible between hvfb_suspend()
and hvfb_resume(), we must cancel info->deferred_work before calling
vmbus_close() and then reschedule it after we reopen the channel
in hvfb_resume().
Fixes: a4ddb11d297e ("video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver")
Fixes: 824946a8b6fb ("video: hyperv_fb: Add the support of hibernation")
Signed-off-by: Dexuan Cui <decui@microsoft.com>
---
This patch fixes the 2 aforementioned patches on Sasha Levin's Hyper-V tree's
hyperv-next branch:
https://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git/log/?h=hyperv-next
The 2 aforementioned patches have not appeared in the mainline yet, so
please pick up this patch onto he same hyperv-next branch.
drivers/video/fbdev/hyperv_fb.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 4cd27e5172a1..08bc0dfb5ce7 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -1194,6 +1194,7 @@ static int hvfb_suspend(struct hv_device *hdev)
fb_set_suspend(info, 1);
cancel_delayed_work_sync(&par->dwork);
+ cancel_delayed_work_sync(&info->deferred_work);
par->update_saved = par->update;
par->update = false;
@@ -1227,6 +1228,7 @@ static int hvfb_resume(struct hv_device *hdev)
par->fb_ready = true;
par->update = par->update_saved;
+ schedule_delayed_work(&info->deferred_work, info->fbdefio->delay);
schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
/* 0 means do resume */
--
2.19.1
^ permalink raw reply related
* [PATCH v2] Input: hyperv-keyboard: Add the support of hibernation
From: Dexuan Cui @ 2019-11-20 7:14 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, sashal, dmitry.torokhov, linux-hyperv,
linux-input, linux-kernel, mikelley, Alexander.Levin
Cc: Dexuan Cui
During the suspend process and resume process, if there is any keyboard
event, there is a small chance the suspend and the resume process can be
aborted because of hv_kbd_on_receive() -> pm_wakeup_hard_event().
This behavior can be avoided by disabling the Hyper-V keyboard device as
a wakeup source:
echo disabled > /sys/bus/vmbus/drivers/hyperv_keyboard/XXX/power/wakeup
(XXX is the device's GUID).
Signed-off-by: Dexuan Cui <decui@microsoft.com>
---
This patch is basically a pure Hyper-V specific change. I suggest it should
go through the Hyper-V tree:
https://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git/log/?h=hyperv-next
Changes in v2:
Removed the "struct notifier_block pm_nb;" after the discussion
with Dmitry Torokhov:
https://lore.kernel.org/lkml/PU1P153MB016914A7C827CA35D7FEB66ABF8B0@PU1P153MB0169.APCP153.PROD.OUTLOOK.COM/T/#m8948c711301220a36a1a413eead74cd2fb6dcac1
drivers/input/serio/hyperv-keyboard.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c
index e486a8a74c40..df4e9f6f4529 100644
--- a/drivers/input/serio/hyperv-keyboard.c
+++ b/drivers/input/serio/hyperv-keyboard.c
@@ -259,6 +259,8 @@ static int hv_kbd_connect_to_vsp(struct hv_device *hv_dev)
u32 proto_status;
int error;
+ reinit_completion(&kbd_dev->wait_event);
+
request = &kbd_dev->protocol_req;
memset(request, 0, sizeof(struct synth_kbd_protocol_request));
request->header.type = __cpu_to_le32(SYNTH_KBD_PROTOCOL_REQUEST);
@@ -380,6 +382,29 @@ static int hv_kbd_remove(struct hv_device *hv_dev)
return 0;
}
+static int hv_kbd_suspend(struct hv_device *hv_dev)
+{
+ vmbus_close(hv_dev->channel);
+
+ return 0;
+}
+
+static int hv_kbd_resume(struct hv_device *hv_dev)
+{
+ int ret;
+
+ ret = vmbus_open(hv_dev->channel,
+ KBD_VSC_SEND_RING_BUFFER_SIZE,
+ KBD_VSC_RECV_RING_BUFFER_SIZE,
+ NULL, 0,
+ hv_kbd_on_channel_callback,
+ hv_dev);
+ if (ret == 0)
+ ret = hv_kbd_connect_to_vsp(hv_dev);
+
+ return ret;
+}
+
static const struct hv_vmbus_device_id id_table[] = {
/* Keyboard guid */
{ HV_KBD_GUID, },
@@ -393,6 +418,8 @@ static struct hv_driver hv_kbd_drv = {
.id_table = id_table,
.probe = hv_kbd_probe,
.remove = hv_kbd_remove,
+ .suspend = hv_kbd_suspend,
+ .resume = hv_kbd_resume,
.driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
--
2.19.1
^ permalink raw reply related
* [PATCH v2] HID: hyperv: Add the support of hibernation
From: Dexuan Cui @ 2019-11-20 7:14 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, sashal, jikos, benjamin.tissoires,
linux-hyperv, linux-input, linux-kernel, mikelley,
Alexander.Levin
Cc: Dexuan Cui
During the suspend process and resume process, if there is any mouse
event, there is a small chance the suspend and the resume process can be
aborted because of mousevsc_on_receive() -> pm_wakeup_hard_event().
This behavior can be avoided by disabling the Hyper-V mouse device as
a wakeup source:
echo disabled > /sys/bus/vmbus/drivers/hid_hyperv/XXX/power/wakeup
(XXX is the device's GUID).
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Acked-by: Jiri Kosina <jkosina@suse.cz>
---
Changes in v2:
Removed the "struct notifier_block pm_nb;" after the discussion
with Dmitry Torokhov:
https://lore.kernel.org/lkml/PU1P153MB016914A7C827CA35D7FEB66ABF8B0@PU1P153MB0169.APCP153.PROD.OUTLOOK.COM/T/#m8948c711301220a36a1a413eead74cd2fb6dcac1
drivers/hid/hid-hyperv.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 79a28fc91521..dddfca555df9 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -192,6 +192,9 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
if (desc->bLength == 0)
goto cleanup;
+ /* The pointer is not NULL when we resume from hibernation */
+ if (input_device->hid_desc != NULL)
+ kfree(input_device->hid_desc);
input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
if (!input_device->hid_desc)
@@ -203,6 +206,9 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
goto cleanup;
}
+ /* The pointer is not NULL when we resume from hibernation */
+ if (input_device->report_desc != NULL)
+ kfree(input_device->report_desc);
input_device->report_desc = kzalloc(input_device->report_desc_size,
GFP_ATOMIC);
@@ -342,6 +348,8 @@ static int mousevsc_connect_to_vsp(struct hv_device *device)
struct mousevsc_prt_msg *request;
struct mousevsc_prt_msg *response;
+ reinit_completion(&input_dev->wait_event);
+
request = &input_dev->protocol_req;
memset(request, 0, sizeof(struct mousevsc_prt_msg));
@@ -541,6 +549,30 @@ static int mousevsc_remove(struct hv_device *dev)
return 0;
}
+static int mousevsc_suspend(struct hv_device *dev)
+{
+ vmbus_close(dev->channel);
+
+ return 0;
+}
+
+static int mousevsc_resume(struct hv_device *dev)
+{
+ int ret;
+
+ ret = vmbus_open(dev->channel,
+ INPUTVSC_SEND_RING_BUFFER_SIZE,
+ INPUTVSC_RECV_RING_BUFFER_SIZE,
+ NULL, 0,
+ mousevsc_on_channel_callback,
+ dev);
+ if (ret)
+ return ret;
+
+ ret = mousevsc_connect_to_vsp(dev);
+ return ret;
+}
+
static const struct hv_vmbus_device_id id_table[] = {
/* Mouse guid */
{ HV_MOUSE_GUID, },
@@ -554,6 +586,8 @@ static struct hv_driver mousevsc_drv = {
.id_table = id_table,
.probe = mousevsc_probe,
.remove = mousevsc_remove,
+ .suspend = mousevsc_suspend,
+ .resume = mousevsc_resume,
.driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
--
2.19.1
^ permalink raw reply related
* [PATCH v2 0/2] Implement hv_is_hibernation_supported() and enhance hv_balloon for hibernation
From: Dexuan Cui @ 2019-11-20 7:16 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, sashal, linux-hyperv, linux-kernel,
mikelley, david, arnd, bp, daniel.lezcano, hpa, mingo, tglx, x86,
Alexander.Levin, vkuznets
Cc: linux-arch, Dexuan Cui
v2 is actually the same as v1. This is just a resend.
I suggest both the patches should go through the Hyper-V tree:
https://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git/log/?h=hyperv-next
because the first patch is needed by the second one.
This first patch doesn't conflict with any patch in the tip.git tree.
Dexuan Cui (2):
x86/hyperv: Implement hv_is_hibernation_supported()
hv_balloon: Add the support of hibernation
arch/x86/hyperv/hv_init.c | 7 +++
drivers/hv/hv_balloon.c | 87 +++++++++++++++++++++++++++++++++-
include/asm-generic/mshyperv.h | 2 +
3 files changed, 94 insertions(+), 2 deletions(-)
--
2.19.1
^ permalink raw reply
* [PATCH v2 2/2] hv_balloon: Add the support of hibernation
From: Dexuan Cui @ 2019-11-20 7:16 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, sashal, linux-hyperv, linux-kernel,
mikelley, david, arnd, bp, daniel.lezcano, hpa, mingo, tglx, x86,
Alexander.Levin, vkuznets
Cc: linux-arch, Dexuan Cui
In-Reply-To: <1574234165-49066-1-git-send-email-decui@microsoft.com>
When hibernation is enabled, we must ignore the balloon up/down and
hot-add requests from the host, if any.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Acked-by: David Hildenbrand <david@redhat.com>
---
v2 is actually the same as v1. This is just a resend.
I suggest this patch should go through the Hyper-V tree:
https://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git/log/?h=hyperv-next
together with
[PATCH v2 1/2] x86/hyperv: Implement hv_is_hibernation_supported()
drivers/hv/hv_balloon.c | 87 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 85 insertions(+), 2 deletions(-)
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 935904830d42..7f4cf4fc805e 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -25,6 +25,8 @@
#include <linux/hyperv.h>
#include <asm/hyperv-tlfs.h>
+#include <asm/mshyperv.h>
+
#define CREATE_TRACE_POINTS
#include "hv_trace_balloon.h"
@@ -456,6 +458,7 @@ struct hot_add_wrk {
struct work_struct wrk;
};
+static bool allow_hibernation;
static bool hot_add = true;
static bool do_hot_add;
/*
@@ -1052,8 +1055,12 @@ static void hot_add_req(struct work_struct *dummy)
else
resp.result = 0;
- if (!do_hot_add || (resp.page_count == 0))
- pr_err("Memory hot add failed\n");
+ if (!do_hot_add || resp.page_count == 0) {
+ if (!allow_hibernation)
+ pr_err("Memory hot add failed\n");
+ else
+ pr_info("Ignore hot-add request!\n");
+ }
dm->state = DM_INITIALIZED;
resp.hdr.trans_id = atomic_inc_return(&trans_id);
@@ -1508,6 +1515,11 @@ static void balloon_onchannelcallback(void *context)
break;
case DM_BALLOON_REQUEST:
+ if (allow_hibernation) {
+ pr_info("Ignore balloon-up request!\n");
+ break;
+ }
+
if (dm->state == DM_BALLOON_UP)
pr_warn("Currently ballooning\n");
bal_msg = (struct dm_balloon *)recv_buffer;
@@ -1517,6 +1529,11 @@ static void balloon_onchannelcallback(void *context)
break;
case DM_UNBALLOON_REQUEST:
+ if (allow_hibernation) {
+ pr_info("Ignore balloon-down request!\n");
+ break;
+ }
+
dm->state = DM_BALLOON_DOWN;
balloon_down(dm,
(struct dm_unballoon_request *)recv_buffer);
@@ -1622,6 +1639,11 @@ static int balloon_connect_vsp(struct hv_device *dev)
cap_msg.hdr.size = sizeof(struct dm_capabilities);
cap_msg.hdr.trans_id = atomic_inc_return(&trans_id);
+ /*
+ * When hibernation (i.e. virtual ACPI S4 state) is enabled, the host
+ * currently still requires the bits to be set, so we have to add code
+ * to fail the host's hot-add and balloon up/down requests, if any.
+ */
cap_msg.caps.cap_bits.balloon = 1;
cap_msg.caps.cap_bits.hot_add = 1;
@@ -1671,6 +1693,10 @@ static int balloon_probe(struct hv_device *dev,
{
int ret;
+ allow_hibernation = hv_is_hibernation_supported();
+ if (allow_hibernation)
+ hot_add = false;
+
#ifdef CONFIG_MEMORY_HOTPLUG
do_hot_add = hot_add;
#else
@@ -1710,6 +1736,8 @@ static int balloon_probe(struct hv_device *dev,
return 0;
probe_error:
+ dm_device.state = DM_INIT_ERROR;
+ dm_device.thread = NULL;
vmbus_close(dev->channel);
#ifdef CONFIG_MEMORY_HOTPLUG
unregister_memory_notifier(&hv_memory_nb);
@@ -1751,6 +1779,59 @@ static int balloon_remove(struct hv_device *dev)
return 0;
}
+static int balloon_suspend(struct hv_device *hv_dev)
+{
+ struct hv_dynmem_device *dm = hv_get_drvdata(hv_dev);
+
+ tasklet_disable(&hv_dev->channel->callback_event);
+
+ cancel_work_sync(&dm->balloon_wrk.wrk);
+ cancel_work_sync(&dm->ha_wrk.wrk);
+
+ if (dm->thread) {
+ kthread_stop(dm->thread);
+ dm->thread = NULL;
+ vmbus_close(hv_dev->channel);
+ }
+
+ tasklet_enable(&hv_dev->channel->callback_event);
+
+ return 0;
+
+}
+
+static int balloon_resume(struct hv_device *dev)
+{
+ int ret;
+
+ dm_device.state = DM_INITIALIZING;
+
+ ret = balloon_connect_vsp(dev);
+
+ if (ret != 0)
+ goto out;
+
+ dm_device.thread =
+ kthread_run(dm_thread_func, &dm_device, "hv_balloon");
+ if (IS_ERR(dm_device.thread)) {
+ ret = PTR_ERR(dm_device.thread);
+ dm_device.thread = NULL;
+ goto close_channel;
+ }
+
+ dm_device.state = DM_INITIALIZED;
+ return 0;
+close_channel:
+ vmbus_close(dev->channel);
+out:
+ dm_device.state = DM_INIT_ERROR;
+#ifdef CONFIG_MEMORY_HOTPLUG
+ unregister_memory_notifier(&hv_memory_nb);
+ restore_online_page_callback(&hv_online_page);
+#endif
+ return ret;
+}
+
static const struct hv_vmbus_device_id id_table[] = {
/* Dynamic Memory Class ID */
/* 525074DC-8985-46e2-8057-A307DC18A502 */
@@ -1765,6 +1846,8 @@ static struct hv_driver balloon_drv = {
.id_table = id_table,
.probe = balloon_probe,
.remove = balloon_remove,
+ .suspend = balloon_suspend,
+ .resume = balloon_resume,
.driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
--
2.19.1
^ permalink raw reply related
* [PATCH v2 1/2] x86/hyperv: Implement hv_is_hibernation_supported()
From: Dexuan Cui @ 2019-11-20 7:16 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, sashal, linux-hyperv, linux-kernel,
mikelley, david, arnd, bp, daniel.lezcano, hpa, mingo, tglx, x86,
Alexander.Levin, vkuznets
Cc: linux-arch, Dexuan Cui
In-Reply-To: <1574234165-49066-1-git-send-email-decui@microsoft.com>
The API will be used by the hv_balloon and hv_vmbus drivers.
Balloon up/down and hot-add of memory must not be active if the user
wants the Linux VM to support hibernation, because they are incompatible
with hibernation according to Hyper-V team, e.g. upon suspend the
balloon VSP doesn't save any info about the ballooned-out pages (if any);
so, after Linux resumes, Linux balloon VSC expects that the VSP will
return the pages if Linux is under memory pressure, but the VSP will
never do that, since the VSP thinks it never stole the pages from the VM.
So, if the user wants Linux VM to support hibernation, Linux must forbid
balloon up/down and hot-add, and the only functionality of the balloon VSC
driver is reporting the VM's memory pressure to the host.
Ideally, when Linux detects that the user wants it to support hibernation,
the balloon VSC should tell the VSP that it does not support ballooning
and hot-add. However, the current version of the VSP requires the VSC
should support these capabilities, otherwise the capability negotiation
fails and the VSC can not load at all, so with the later changes to the
VSC driver, Linux VM still reports to the VSP that the VSC supports these
capabilities, but the VSC ignores the VSP's requests of balloon up/down
and hot add, and reports an error to the VSP, when applicable. BTW, in
the future the balloon VSP driver will allow the VSC to not support the
capabilities of balloon up/down and hot add.
The ACPI S4 state is not a must for hibernation to work, because Linux is
able to hibernate as long as the system can shut down. However in practice
we decide to artificially use the presence of the virtual ACPI S4 state as
an indicator of the user's intent of using hibernation, because Linux VM
must find a way to know if the user wants to use the hibernation feature
or not.
By default, Hyper-V does not enable the virtual ACPI S4 state; on recent
Hyper-V hosts (e.g. RS5, 19H1), the administrator is able to enable the
state for a VM by WMI commands.
Once all the vmbus and VSC patches for the hibernation feature are
accepted, an extra patch will be submitted to forbid hibernation if the
virtual ACPI S4 state is absent, i.e. hv_is_hibernation_supported() is
false.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
---
v2 is actually the same as v1. This is just a resend.
I suggest this patch should go through the Hyper-V tree:
https://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git/log/?h=hyperv-next
because it's needed by
[PATCH v2 2/2] hv_balloon: Add the support of hibernation
and some upcoming patches.
This patch doesn't conflict with any patch in the tip.git tree.
arch/x86/hyperv/hv_init.c | 7 +++++++
include/asm-generic/mshyperv.h | 2 ++
2 files changed, 9 insertions(+)
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
index c170653da589..24a62d33067c 100644
--- a/arch/x86/hyperv/hv_init.c
+++ b/arch/x86/hyperv/hv_init.c
@@ -7,6 +7,7 @@
* Author : K. Y. Srinivasan <kys@microsoft.com>
*/
+#include <linux/acpi.h>
#include <linux/efi.h>
#include <linux/types.h>
#include <asm/apic.h>
@@ -493,3 +494,9 @@ bool hv_is_hyperv_initialized(void)
return hypercall_msr.enable;
}
EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized);
+
+bool hv_is_hibernation_supported(void)
+{
+ return acpi_sleep_state_supported(ACPI_STATE_S4);
+}
+EXPORT_SYMBOL_GPL(hv_is_hibernation_supported);
diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h
index 18d8e2d8210f..b3f1082cc435 100644
--- a/include/asm-generic/mshyperv.h
+++ b/include/asm-generic/mshyperv.h
@@ -166,10 +166,12 @@ static inline int cpumask_to_vpset(struct hv_vpset *vpset,
void hyperv_report_panic(struct pt_regs *regs, long err);
void hyperv_report_panic_msg(phys_addr_t pa, size_t size);
bool hv_is_hyperv_initialized(void);
+bool hv_is_hibernation_supported(void);
void hyperv_cleanup(void);
void hv_setup_sched_clock(void *sched_clock);
#else /* CONFIG_HYPERV */
static inline bool hv_is_hyperv_initialized(void) { return false; }
+static inline bool hv_is_hibernation_supported(void) { return false; }
static inline void hyperv_cleanup(void) {}
#endif /* CONFIG_HYPERV */
--
2.19.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox