--- /dev/null
+From 365e1ececb2905f94cc10a5817c5b644a32a3ae2 Mon Sep 17 00:00:00 2001
+From: Gaurav Kohli <gauravkohli@linux.microsoft.com>
+Date: Wed, 5 Oct 2022 22:52:59 -0700
+Subject: hv_netvsc: Fix race between VF offering and VF association message from host
+
+From: Gaurav Kohli <gauravkohli@linux.microsoft.com>
+
+commit 365e1ececb2905f94cc10a5817c5b644a32a3ae2 upstream.
+
+During vm boot, there might be possibility that vf registration
+call comes before the vf association from host to vm.
+
+And this might break netvsc vf path, To prevent the same block
+vf registration until vf bind message comes from host.
+
+Cc: stable@vger.kernel.org
+Fixes: 00d7ddba11436 ("hv_netvsc: pair VF based on serial number")
+Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
+Signed-off-by: Gaurav Kohli <gauravkohli@linux.microsoft.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/hyperv/hyperv_net.h | 3 +++
+ drivers/net/hyperv/netvsc.c | 4 ++++
+ drivers/net/hyperv/netvsc_drv.c | 20 ++++++++++++++++++++
+ 3 files changed, 27 insertions(+)
+
+--- a/drivers/net/hyperv/hyperv_net.h
++++ b/drivers/net/hyperv/hyperv_net.h
+@@ -954,6 +954,9 @@ struct net_device_context {
+ u32 vf_alloc;
+ /* Serial number of the VF to team with */
+ u32 vf_serial;
++
++ /* completion variable to confirm vf association */
++ struct completion vf_add;
+ };
+
+ /* Per channel data */
+--- a/drivers/net/hyperv/netvsc.c
++++ b/drivers/net/hyperv/netvsc.c
+@@ -1223,6 +1223,10 @@ static void netvsc_send_vf(struct net_de
+
+ net_device_ctx->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated;
+ net_device_ctx->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial;
++
++ if (net_device_ctx->vf_alloc)
++ complete(&net_device_ctx->vf_add);
++
+ netdev_info(ndev, "VF slot %u %s\n",
+ net_device_ctx->vf_serial,
+ net_device_ctx->vf_alloc ? "added" : "removed");
+--- a/drivers/net/hyperv/netvsc_drv.c
++++ b/drivers/net/hyperv/netvsc_drv.c
+@@ -2133,6 +2133,7 @@ static struct net_device *get_netvsc_bys
+ {
+ struct device *parent = vf_netdev->dev.parent;
+ struct net_device_context *ndev_ctx;
++ struct net_device *ndev;
+ struct pci_dev *pdev;
+ u32 serial;
+
+@@ -2159,6 +2160,18 @@ static struct net_device *get_netvsc_bys
+ return hv_get_drvdata(ndev_ctx->device_ctx);
+ }
+
++ /* Fallback path to check synthetic vf with
++ * help of mac addr
++ */
++ list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) {
++ ndev = hv_get_drvdata(ndev_ctx->device_ctx);
++ if (ether_addr_equal(vf_netdev->perm_addr, ndev->perm_addr)) {
++ netdev_notice(vf_netdev,
++ "falling back to mac addr based matching\n");
++ return ndev;
++ }
++ }
++
+ netdev_notice(vf_netdev,
+ "no netdev found for vf serial:%u\n", serial);
+ return NULL;
+@@ -2232,6 +2245,11 @@ static int netvsc_vf_changed(struct net_
+ if (!netvsc_dev)
+ return NOTIFY_DONE;
+
++ if (vf_is_up && !net_device_ctx->vf_alloc) {
++ netdev_info(ndev, "Waiting for the VF association from host\n");
++ wait_for_completion(&net_device_ctx->vf_add);
++ }
++
+ netvsc_switch_datapath(ndev, vf_is_up);
+ netdev_info(ndev, "Data path switched %s VF: %s\n",
+ vf_is_up ? "to" : "from", vf_netdev->name);
+@@ -2253,6 +2271,7 @@ static int netvsc_unregister_vf(struct n
+
+ netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
+
++ reinit_completion(&net_device_ctx->vf_add);
+ netdev_rx_handler_unregister(vf_netdev);
+ netdev_upper_dev_unlink(vf_netdev, ndev);
+ RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
+@@ -2290,6 +2309,7 @@ static int netvsc_probe(struct hv_device
+
+ INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
+
++ init_completion(&net_device_ctx->vf_add);
+ spin_lock_init(&net_device_ctx->lock);
+ INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
+ INIT_DELAYED_WORK(&net_device_ctx->vf_takeover, netvsc_vf_setup);