Merge tag 'hyperv-next-signed-20210216' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 21 Feb 2021 21:24:39 +0000 (13:24 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 21 Feb 2021 21:24:39 +0000 (13:24 -0800)
Pull Hyper-V updates from Wei Liu:

 - VMBus hardening patches from Andrea Parri and Andres Beltran.

 - Patches to make Linux boot as the root partition on Microsoft
   Hypervisor from Wei Liu.

 - One patch to add a new sysfs interface to support hibernation on
   Hyper-V from Dexuan Cui.

 - Two miscellaneous clean-up patches from Colin and Gustavo.

* tag 'hyperv-next-signed-20210216' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: (31 commits)
  Revert "Drivers: hv: vmbus: Copy packets sent by Hyper-V out of the ring buffer"
  iommu/hyperv: setup an IO-APIC IRQ remapping domain for root partition
  x86/hyperv: implement an MSI domain for root partition
  asm-generic/hyperv: import data structures for mapping device interrupts
  asm-generic/hyperv: introduce hv_device_id and auxiliary structures
  asm-generic/hyperv: update hv_interrupt_entry
  asm-generic/hyperv: update hv_msi_entry
  x86/hyperv: implement and use hv_smp_prepare_cpus
  x86/hyperv: provide a bunch of helper functions
  ACPI / NUMA: add a stub function for node_to_pxm()
  x86/hyperv: handling hypercall page setup for root
  x86/hyperv: extract partition ID from Microsoft Hypervisor if necessary
  x86/hyperv: allocate output arg pages if required
  clocksource/hyperv: use MSR-based access if running as root
  Drivers: hv: vmbus: skip VMBus initialization if Linux is root
  x86/hyperv: detect if Linux is the root partition
  asm-generic/hyperv: change HV_CPU_POWER_MANAGEMENT to HV_CPU_MANAGEMENT
  hv: hyperv.h: Replace one-element array with flexible-array in struct icmsg_negotiate
  hv_netvsc: Restrict configurations on isolated guests
  Drivers: hv: vmbus: Enforce 'VMBus version >= 5.2' on isolated guests
  ...

1  2 
drivers/net/hyperv/netvsc.c

@@@ -22,6 -22,7 +22,7 @@@
  #include <linux/prefetch.h>
  
  #include <asm/sync_bitops.h>
+ #include <asm/mshyperv.h>
  
  #include "hyperv_net.h"
  #include "netvsc_trace.h"
@@@ -37,10 -38,6 +38,10 @@@ void netvsc_switch_datapath(struct net_
        struct netvsc_device *nv_dev = rtnl_dereference(net_device_ctx->nvdev);
        struct nvsp_message *init_pkt = &nv_dev->channel_init_pkt;
  
 +      /* Block sending traffic to VF if it's about to be gone */
 +      if (!vf)
 +              net_device_ctx->data_path_is_vf = vf;
 +
        memset(init_pkt, 0, sizeof(struct nvsp_message));
        init_pkt->hdr.msg_type = NVSP_MSG4_TYPE_SWITCH_DATA_PATH;
        if (vf)
  
        vmbus_sendpacket(dev->channel, init_pkt,
                               sizeof(struct nvsp_message),
 -                             VMBUS_RQST_ID_NO_RESPONSE,
 -                             VM_PKT_DATA_INBAND, 0);
 +                             (unsigned long)init_pkt,
 +                             VM_PKT_DATA_INBAND,
 +                             VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
 +      wait_for_completion(&nv_dev->channel_init_wait);
 +      net_device_ctx->data_path_is_vf = vf;
  }
  
  /* Worker to setup sub channels on initial setup
@@@ -131,7 -125,6 +132,7 @@@ static void free_netvsc_device(struct r
  
        for (i = 0; i < VRSS_CHANNEL_MAX; i++) {
                xdp_rxq_info_unreg(&nvdev->chan_table[i].xdp_rxq);
 +              kfree(nvdev->chan_table[i].recv_buf);
                vfree(nvdev->chan_table[i].mrc.slots);
        }
  
@@@ -311,7 -304,7 +312,7 @@@ static int netvsc_init_buf(struct hv_de
        struct nvsp_message *init_packet;
        unsigned int buf_size;
        size_t map_words;
 -      int ret = 0;
 +      int i, ret = 0;
  
        /* Get receive buffer area. */
        buf_size = device_info->recv_sections * device_info->recv_section_size;
                goto cleanup;
        }
  
 +      for (i = 0; i < VRSS_CHANNEL_MAX; i++) {
 +              struct netvsc_channel *nvchan = &net_device->chan_table[i];
 +
 +              nvchan->recv_buf = kzalloc(net_device->recv_section_size, GFP_KERNEL);
 +              if (nvchan->recv_buf == NULL) {
 +                      ret = -ENOMEM;
 +                      goto cleanup;
 +              }
 +      }
 +
        /* Setup receive completion ring.
         * Add 1 to the recv_section_cnt because at least one entry in a
         * ring buffer has to be empty.
@@@ -562,7 -545,10 +563,10 @@@ static int negotiate_nvsp_ver(struct hv
        init_packet->msg.v2_msg.send_ndis_config.capability.ieee8021q = 1;
  
        if (nvsp_ver >= NVSP_PROTOCOL_VERSION_5) {
-               init_packet->msg.v2_msg.send_ndis_config.capability.sriov = 1;
+               if (hv_is_isolation_supported())
+                       netdev_info(ndev, "SR-IOV not advertised by guests on the host supporting isolation\n");
+               else
+                       init_packet->msg.v2_msg.send_ndis_config.capability.sriov = 1;
  
                /* Teaming bit is needed to receive link speed updates */
                init_packet->msg.v2_msg.send_ndis_config.capability.teaming = 1;
@@@ -609,6 -595,13 +613,13 @@@ static int netvsc_connect_vsp(struct hv
                goto cleanup;
        }
  
+       if (hv_is_isolation_supported() && net_device->nvsp_version < NVSP_PROTOCOL_VERSION_61) {
+               netdev_err(ndev, "Invalid NVSP version 0x%x (expected >= 0x%x) from the host supporting isolation\n",
+                          net_device->nvsp_version, NVSP_PROTOCOL_VERSION_61);
+               ret = -EPROTO;
+               goto cleanup;
+       }
        pr_debug("Negotiated NVSP version:%x\n", net_device->nvsp_version);
  
        /* Send the ndis version */
@@@ -772,31 -765,8 +783,31 @@@ static void netvsc_send_completion(stru
                                   const struct vmpacket_descriptor *desc,
                                   int budget)
  {
 -      const struct nvsp_message *nvsp_packet = hv_pkt_data(desc);
 +      const struct nvsp_message *nvsp_packet;
        u32 msglen = hv_pkt_datalen(desc);
 +      struct nvsp_message *pkt_rqst;
 +      u64 cmd_rqst;
 +
 +      /* First check if this is a VMBUS completion without data payload */
 +      if (!msglen) {
 +              cmd_rqst = vmbus_request_addr(&incoming_channel->requestor,
 +                                            (u64)desc->trans_id);
 +              if (cmd_rqst == VMBUS_RQST_ERROR) {
 +                      netdev_err(ndev, "Invalid transaction id\n");
 +                      return;
 +              }
 +
 +              pkt_rqst = (struct nvsp_message *)(uintptr_t)cmd_rqst;
 +              switch (pkt_rqst->hdr.msg_type) {
 +              case NVSP_MSG4_TYPE_SWITCH_DATA_PATH:
 +                      complete(&net_device->channel_init_wait);
 +                      break;
 +
 +              default:
 +                      netdev_err(ndev, "Unexpected VMBUS completion!!\n");
 +              }
 +              return;
 +      }
  
        /* Ensure packet is big enough to read header fields */
        if (msglen < sizeof(struct nvsp_message_header)) {
                return;
        }
  
 +      nvsp_packet = hv_pkt_data(desc);
        switch (nvsp_packet->hdr.msg_type) {
        case NVSP_MSG_TYPE_INIT_COMPLETE:
                if (msglen < sizeof(struct nvsp_message_header) +
@@@ -929,7 -898,6 +940,7 @@@ static inline int netvsc_send_pkt
        int ret;
        u32 ring_avail = hv_get_avail_to_write_percent(&out_channel->outbound);
  
 +      memset(&nvmsg, 0, sizeof(struct nvsp_message));
        nvmsg.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT;
        if (skb)
                rpkt->channel_type = 0;         /* 0 is RMC_DATA */
@@@ -1295,19 -1263,6 +1306,19 @@@ static int netvsc_receive(struct net_de
                        continue;
                }
  
 +              /* We're going to copy (sections of) the packet into nvchan->recv_buf;
 +               * make sure that nvchan->recv_buf is large enough to hold the packet.
 +               */
 +              if (unlikely(buflen > net_device->recv_section_size)) {
 +                      nvchan->rsc.cnt = 0;
 +                      status = NVSP_STAT_FAIL;
 +                      netif_err(net_device_ctx, rx_err, ndev,
 +                                "Packet too big: buflen=%u recv_section_size=%u\n",
 +                                buflen, net_device->recv_section_size);
 +
 +                      continue;
 +              }
 +
                data = recv_buf + offset;
  
                nvchan->rsc.is_last = (i == count - 1);
                ret = rndis_filter_receive(ndev, net_device,
                                           nvchan, data, buflen);
  
 -              if (unlikely(ret != NVSP_STAT_SUCCESS))
 +              if (unlikely(ret != NVSP_STAT_SUCCESS)) {
 +                      /* Drop incomplete packet */
 +                      nvchan->rsc.cnt = 0;
                        status = NVSP_STAT_FAIL;
 +              }
        }
  
        enq_receive_complete(ndev, net_device, q_idx,
@@@ -1365,7 -1317,7 +1376,7 @@@ static void netvsc_send_table(struct ne
                         sizeof(union nvsp_6_message_uber);
  
        /* Boundary check for all versions */
 -      if (offset > msglen - count * sizeof(u32)) {
 +      if (msglen < count * sizeof(u32) || offset > msglen - count * sizeof(u32)) {
                netdev_err(ndev, "Received send-table offset too big:%u\n",
                           offset);
                return;
@@@ -1416,7 -1368,10 +1427,10 @@@ static void netvsc_receive_inband(struc
                break;
  
        case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION:
-               netvsc_send_vf(ndev, nvmsg, msglen);
+               if (hv_is_isolation_supported())
+                       netdev_err(ndev, "Ignore VF_ASSOCIATION msg from the host supporting isolation\n");
+               else
+                       netvsc_send_vf(ndev, nvmsg, msglen);
                break;
        }
  }