]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 11 Feb 2017 07:14:45 +0000 (08:14 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 11 Feb 2017 07:14:45 +0000 (08:14 +0100)
added patches:
drivers-hv-vmbus-base-host-signaling-strictly-on-the-ring-state.patch
drivers-hv-vmbus-finally-fix-hv_need_to_signal_on_read.patch
drivers-hv-vmbus-on-the-read-path-cleanup-the-logic-to-interrupt-the-host.patch
drivers-hv-vmbus-on-write-cleanup-the-logic-to-interrupt-the-host.patch

queue-4.9/drivers-hv-vmbus-base-host-signaling-strictly-on-the-ring-state.patch [new file with mode: 0644]
queue-4.9/drivers-hv-vmbus-finally-fix-hv_need_to_signal_on_read.patch [new file with mode: 0644]
queue-4.9/drivers-hv-vmbus-on-the-read-path-cleanup-the-logic-to-interrupt-the-host.patch [new file with mode: 0644]
queue-4.9/drivers-hv-vmbus-on-write-cleanup-the-logic-to-interrupt-the-host.patch [new file with mode: 0644]
queue-4.9/series

diff --git a/queue-4.9/drivers-hv-vmbus-base-host-signaling-strictly-on-the-ring-state.patch b/queue-4.9/drivers-hv-vmbus-base-host-signaling-strictly-on-the-ring-state.patch
new file mode 100644 (file)
index 0000000..5d7d99b
--- /dev/null
@@ -0,0 +1,98 @@
+From 74198eb4a42c4a3c4fbef08fa01a291a282f7c2e Mon Sep 17 00:00:00 2001
+From: "K. Y. Srinivasan" <kys@microsoft.com>
+Date: Sun, 6 Nov 2016 13:14:16 -0800
+Subject: Drivers: hv: vmbus: Base host signaling strictly on the ring state
+
+From: K. Y. Srinivasan <kys@microsoft.com>
+
+commit 74198eb4a42c4a3c4fbef08fa01a291a282f7c2e upstream.
+
+One of the factors that can result in the host concluding that a given
+guest in mounting a DOS attack is if the guest generates interrupts
+to the host when the host is not expecting it. If these "spurious"
+interrupts reach a certain rate, the host can throttle the guest to
+minimize the impact. The host computation of the "expected number
+of interrupts" is strictly based on the ring transitions. Until
+the host logic is fixed, base the guest logic to interrupt solely
+on the ring state.
+
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Cc: Rolf Neugebauer <rolf.neugebauer@docker.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hv/channel.c      |   23 ++++++++++++++++++++---
+ drivers/hv/channel_mgmt.c |    2 --
+ drivers/hv/ring_buffer.c  |    7 -------
+ 3 files changed, 20 insertions(+), 12 deletions(-)
+
+--- a/drivers/hv/channel.c
++++ b/drivers/hv/channel.c
+@@ -676,10 +676,18 @@ int vmbus_sendpacket_ctl(struct vmbus_ch
+        * NOTE: in this case, the hvsock channel is an exception, because
+        * it looks the host side's hvsock implementation has a throttling
+        * mechanism which can hurt the performance otherwise.
++       *
++       * KYS: Oct. 30, 2016:
++       * It looks like Windows hosts have logic to deal with DOS attacks that
++       * can be triggered if it receives interrupts when it is not expecting
++       * the interrupt. The host expects interrupts only when the ring
++       * transitions from empty to non-empty (or full to non full on the guest
++       * to host ring).
++       * So, base the signaling decision solely on the ring state until the
++       * host logic is fixed.
+        */
+-      if (((ret == 0) && kick_q && signal) ||
+-          (ret && !is_hvsock_channel(channel)))
++      if (((ret == 0) && signal))
+               vmbus_setevent(channel);
+       return ret;
+@@ -786,9 +794,18 @@ int vmbus_sendpacket_pagebuffer_ctl(stru
+        * If we cannot write to the ring-buffer; signal the host
+        * even if we may not have written anything. This is a rare
+        * enough condition that it should not matter.
++       *
++       * KYS: Oct. 30, 2016:
++       * It looks like Windows hosts have logic to deal with DOS attacks that
++       * can be triggered if it receives interrupts when it is not expecting
++       * the interrupt. The host expects interrupts only when the ring
++       * transitions from empty to non-empty (or full to non full on the guest
++       * to host ring).
++       * So, base the signaling decision solely on the ring state until the
++       * host logic is fixed.
+        */
+-      if (((ret == 0) && kick_q && signal) || (ret))
++      if (((ret == 0) && signal))
+               vmbus_setevent(channel);
+       return ret;
+--- a/drivers/hv/channel_mgmt.c
++++ b/drivers/hv/channel_mgmt.c
+@@ -449,8 +449,6 @@ static void vmbus_process_offer(struct v
+       }
+       dev_type = hv_get_dev_type(newchannel);
+-      if (dev_type == HV_NIC)
+-              set_channel_signal_state(newchannel, HV_SIGNAL_POLICY_EXPLICIT);
+       init_vp_index(newchannel, dev_type);
+--- a/drivers/hv/ring_buffer.c
++++ b/drivers/hv/ring_buffer.c
+@@ -75,13 +75,6 @@ static bool hv_need_to_signal(u32 old_wr
+       if (READ_ONCE(rbi->ring_buffer->interrupt_mask))
+               return false;
+-      /*
+-       * When the client wants to control signaling,
+-       * we only honour the host interrupt mask.
+-       */
+-      if (policy == HV_SIGNAL_POLICY_EXPLICIT)
+-              return true;
+-
+       /* check interrupt_mask before read_index */
+       virt_rmb();
+       /*
diff --git a/queue-4.9/drivers-hv-vmbus-finally-fix-hv_need_to_signal_on_read.patch b/queue-4.9/drivers-hv-vmbus-finally-fix-hv_need_to_signal_on_read.patch
new file mode 100644 (file)
index 0000000..5a81228
--- /dev/null
@@ -0,0 +1,149 @@
+From 433e19cf33d34bb6751c874a9c00980552fe508c Mon Sep 17 00:00:00 2001
+From: Dexuan Cui <decui@microsoft.com>
+Date: Sat, 28 Jan 2017 11:46:02 -0700
+Subject: Drivers: hv: vmbus: finally fix hv_need_to_signal_on_read()
+
+From: Dexuan Cui <decui@microsoft.com>
+
+commit 433e19cf33d34bb6751c874a9c00980552fe508c upstream.
+
+Commit a389fcfd2cb5 ("Drivers: hv: vmbus: Fix signaling logic in
+hv_need_to_signal_on_read()")
+added the proper mb(), but removed the test "prev_write_sz < pending_sz"
+when making the signal decision.
+
+As a result, the guest can signal the host unnecessarily,
+and then the host can throttle the guest because the host
+thinks the guest is buggy or malicious; finally the user
+running stress test can perceive intermittent freeze of
+the guest.
+
+This patch brings back the test, and properly handles the
+in-place consumption APIs used by NetVSC (see get_next_pkt_raw(),
+put_pkt_raw() and commit_rd_index()).
+
+Fixes: a389fcfd2cb5 ("Drivers: hv: vmbus: Fix signaling logic in
+hv_need_to_signal_on_read()")
+
+Signed-off-by: Dexuan Cui <decui@microsoft.com>
+Reported-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
+Tested-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
+Cc: "K. Y. Srinivasan" <kys@microsoft.com>
+Cc: Haiyang Zhang <haiyangz@microsoft.com>
+Cc: Stephen Hemminger <sthemmin@microsoft.com>
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Cc: Rolf Neugebauer <rolf.neugebauer@docker.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hv/ring_buffer.c    |    1 +
+ drivers/net/hyperv/netvsc.c |    6 ++++++
+ include/linux/hyperv.h      |   32 ++++++++++++++++++++++++++++++--
+ 3 files changed, 37 insertions(+), 2 deletions(-)
+
+--- a/drivers/hv/ring_buffer.c
++++ b/drivers/hv/ring_buffer.c
+@@ -383,6 +383,7 @@ int hv_ringbuffer_read(struct vmbus_chan
+               return ret;
+       }
++      init_cached_read_index(channel);
+       next_read_location = hv_get_next_read_location(inring_info);
+       next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
+                                                   sizeof(desc),
+--- a/drivers/net/hyperv/netvsc.c
++++ b/drivers/net/hyperv/netvsc.c
+@@ -1288,6 +1288,9 @@ void netvsc_channel_cb(void *context)
+       ndev = hv_get_drvdata(device);
+       buffer = get_per_channel_state(channel);
++      /* commit_rd_index() -> hv_signal_on_read() needs this. */
++      init_cached_read_index(channel);
++
+       do {
+               desc = get_next_pkt_raw(channel);
+               if (desc != NULL) {
+@@ -1340,6 +1343,9 @@ void netvsc_channel_cb(void *context)
+                       bufferlen = bytes_recvd;
+               }
++
++              init_cached_read_index(channel);
++
+       } while (1);
+       if (bufferlen > NETVSC_PACKET_SIZE)
+--- a/include/linux/hyperv.h
++++ b/include/linux/hyperv.h
+@@ -128,6 +128,7 @@ struct hv_ring_buffer_info {
+       u32 ring_data_startoffset;
+       u32 priv_write_index;
+       u32 priv_read_index;
++      u32 cached_read_index;
+ };
+ /*
+@@ -180,6 +181,19 @@ static inline u32 hv_get_bytes_to_write(
+       return write;
+ }
++static inline u32 hv_get_cached_bytes_to_write(
++      const struct hv_ring_buffer_info *rbi)
++{
++      u32 read_loc, write_loc, dsize, write;
++
++      dsize = rbi->ring_datasize;
++      read_loc = rbi->cached_read_index;
++      write_loc = rbi->ring_buffer->write_index;
++
++      write = write_loc >= read_loc ? dsize - (write_loc - read_loc) :
++              read_loc - write_loc;
++      return write;
++}
+ /*
+  * VMBUS version is 32 bit entity broken up into
+  * two 16 bit quantities: major_number. minor_number.
+@@ -1482,7 +1496,7 @@ hv_get_ring_buffer(struct hv_ring_buffer
+ static inline  void hv_signal_on_read(struct vmbus_channel *channel)
+ {
+-      u32 cur_write_sz;
++      u32 cur_write_sz, cached_write_sz;
+       u32 pending_sz;
+       struct hv_ring_buffer_info *rbi = &channel->inbound;
+@@ -1506,12 +1520,24 @@ static inline  void hv_signal_on_read(st
+       cur_write_sz = hv_get_bytes_to_write(rbi);
+-      if (cur_write_sz >= pending_sz)
++      if (cur_write_sz < pending_sz)
++              return;
++
++      cached_write_sz = hv_get_cached_bytes_to_write(rbi);
++      if (cached_write_sz < pending_sz)
+               vmbus_setevent(channel);
+       return;
+ }
++static inline void
++init_cached_read_index(struct vmbus_channel *channel)
++{
++      struct hv_ring_buffer_info *rbi = &channel->inbound;
++
++      rbi->cached_read_index = rbi->ring_buffer->read_index;
++}
++
+ /*
+  * An API to support in-place processing of incoming VMBUS packets.
+  */
+@@ -1573,6 +1599,8 @@ static inline void put_pkt_raw(struct vm
+  * This call commits the read index and potentially signals the host.
+  * Here is the pattern for using the "in-place" consumption APIs:
+  *
++ * init_cached_read_index();
++ *
+  * while (get_next_pkt_raw() {
+  *    process the packet "in-place";
+  *    put_pkt_raw();
diff --git a/queue-4.9/drivers-hv-vmbus-on-the-read-path-cleanup-the-logic-to-interrupt-the-host.patch b/queue-4.9/drivers-hv-vmbus-on-the-read-path-cleanup-the-logic-to-interrupt-the-host.patch
new file mode 100644 (file)
index 0000000..feaf66a
--- /dev/null
@@ -0,0 +1,135 @@
+From 3372592a140db69fd63837e81f048ab4abf8111e Mon Sep 17 00:00:00 2001
+From: "K. Y. Srinivasan" <kys@microsoft.com>
+Date: Sun, 6 Nov 2016 13:14:18 -0800
+Subject: Drivers: hv: vmbus: On the read path cleanup the logic to interrupt the host
+
+From: K. Y. Srinivasan <kys@microsoft.com>
+
+commit 3372592a140db69fd63837e81f048ab4abf8111e upstream.
+
+Signal the host when we determine the host is to be signaled -
+on th read path. The currrent code determines the need to signal in the
+ringbuffer code and actually issues the signal elsewhere. This can result
+in the host viewing this interrupt as spurious since the host may also
+poll the channel. Make the necessary adjustments.
+
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Cc: Rolf Neugebauer <rolf.neugebauer@docker.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hv/channel.c      |   11 ++---------
+ drivers/hv/hyperv_vmbus.h |    4 ++--
+ drivers/hv/ring_buffer.c  |    7 ++++---
+ include/linux/hyperv.h    |   12 ++++++------
+ 4 files changed, 14 insertions(+), 20 deletions(-)
+
+--- a/drivers/hv/channel.c
++++ b/drivers/hv/channel.c
+@@ -879,16 +879,9 @@ __vmbus_recvpacket(struct vmbus_channel
+                  u32 bufferlen, u32 *buffer_actual_len, u64 *requestid,
+                  bool raw)
+ {
+-      int ret;
+-      bool signal = false;
++      return hv_ringbuffer_read(channel, buffer, bufferlen,
++                                buffer_actual_len, requestid, raw);
+-      ret = hv_ringbuffer_read(&channel->inbound, buffer, bufferlen,
+-                               buffer_actual_len, requestid, &signal, raw);
+-
+-      if (signal)
+-              vmbus_setevent(channel);
+-
+-      return ret;
+ }
+ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
+--- a/drivers/hv/hyperv_vmbus.h
++++ b/drivers/hv/hyperv_vmbus.h
+@@ -532,9 +532,9 @@ int hv_ringbuffer_write(struct vmbus_cha
+                   u32 kv_count, bool lock,
+                   bool kick_q);
+-int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
++int hv_ringbuffer_read(struct vmbus_channel *channel,
+                      void *buffer, u32 buflen, u32 *buffer_actual_len,
+-                     u64 *requestid, bool *signal, bool raw);
++                     u64 *requestid, bool raw);
+ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
+                           struct hv_ring_buffer_debug_info *debug_info);
+--- a/drivers/hv/ring_buffer.c
++++ b/drivers/hv/ring_buffer.c
+@@ -353,9 +353,9 @@ int hv_ringbuffer_write(struct vmbus_cha
+       return 0;
+ }
+-int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
++int hv_ringbuffer_read(struct vmbus_channel *channel,
+                      void *buffer, u32 buflen, u32 *buffer_actual_len,
+-                     u64 *requestid, bool *signal, bool raw)
++                     u64 *requestid, bool raw)
+ {
+       u32 bytes_avail_toread;
+       u32 next_read_location = 0;
+@@ -364,6 +364,7 @@ int hv_ringbuffer_read(struct hv_ring_bu
+       u32 offset;
+       u32 packetlen;
+       int ret = 0;
++      struct hv_ring_buffer_info *inring_info = &channel->inbound;
+       if (buflen <= 0)
+               return -EINVAL;
+@@ -421,7 +422,7 @@ int hv_ringbuffer_read(struct hv_ring_bu
+       /* Update the read index */
+       hv_set_next_read_location(inring_info, next_read_location);
+-      *signal = hv_need_to_signal_on_read(inring_info);
++      hv_signal_on_read(channel);
+       return ret;
+ }
+--- a/include/linux/hyperv.h
++++ b/include/linux/hyperv.h
+@@ -1480,10 +1480,11 @@ hv_get_ring_buffer(struct hv_ring_buffer
+  *    there is room for the producer to send the pending packet.
+  */
+-static inline  bool hv_need_to_signal_on_read(struct hv_ring_buffer_info *rbi)
++static inline  void hv_signal_on_read(struct vmbus_channel *channel)
+ {
+       u32 cur_write_sz;
+       u32 pending_sz;
++      struct hv_ring_buffer_info *rbi = &channel->inbound;
+       /*
+        * Issue a full memory barrier before making the signaling decision.
+@@ -1501,14 +1502,14 @@ static inline  bool hv_need_to_signal_on
+       pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz);
+       /* If the other end is not blocked on write don't bother. */
+       if (pending_sz == 0)
+-              return false;
++              return;
+       cur_write_sz = hv_get_bytes_to_write(rbi);
+       if (cur_write_sz >= pending_sz)
+-              return true;
++              vmbus_setevent(channel);
+-      return false;
++      return;
+ }
+ /*
+@@ -1590,8 +1591,7 @@ static inline void commit_rd_index(struc
+       virt_rmb();
+       ring_info->ring_buffer->read_index = ring_info->priv_read_index;
+-      if (hv_need_to_signal_on_read(ring_info))
+-              vmbus_set_event(channel);
++      hv_signal_on_read(channel);
+ }
diff --git a/queue-4.9/drivers-hv-vmbus-on-write-cleanup-the-logic-to-interrupt-the-host.patch b/queue-4.9/drivers-hv-vmbus-on-write-cleanup-the-logic-to-interrupt-the-host.patch
new file mode 100644 (file)
index 0000000..5578478
--- /dev/null
@@ -0,0 +1,314 @@
+From 1f6ee4e7d83586c8b10bd4f2f4346353d04ce884 Mon Sep 17 00:00:00 2001
+From: "K. Y. Srinivasan" <kys@microsoft.com>
+Date: Sun, 6 Nov 2016 13:14:17 -0800
+Subject: Drivers: hv: vmbus: On write cleanup the logic to interrupt the host
+
+From: K. Y. Srinivasan <kys@microsoft.com>
+
+commit 1f6ee4e7d83586c8b10bd4f2f4346353d04ce884 upstream.
+
+Signal the host when we determine the host is to be signaled.
+The currrent code determines the need to signal in the ringbuffer
+code and actually issues the signal elsewhere. This can result
+in the host viewing this interrupt as spurious since the host may also
+poll the channel. Make the necessary adjustments.
+
+Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
+Cc: Rolf Neugebauer <rolf.neugebauer@docker.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hv/channel.c      |   99 ++++------------------------------------------
+ drivers/hv/hyperv_vmbus.h |    6 +-
+ drivers/hv/ring_buffer.c  |   30 +++++++++----
+ include/linux/hyperv.h    |    1 
+ 4 files changed, 35 insertions(+), 101 deletions(-)
+
+--- a/drivers/hv/channel.c
++++ b/drivers/hv/channel.c
+@@ -39,7 +39,7 @@
+  * vmbus_setevent- Trigger an event notification on the specified
+  * channel.
+  */
+-static void vmbus_setevent(struct vmbus_channel *channel)
++void vmbus_setevent(struct vmbus_channel *channel)
+ {
+       struct hv_monitor_page *monitorpage;
+@@ -65,6 +65,7 @@ static void vmbus_setevent(struct vmbus_
+               vmbus_set_event(channel);
+       }
+ }
++EXPORT_SYMBOL_GPL(vmbus_setevent);
+ /*
+  * vmbus_open - Open the specified channel.
+@@ -635,8 +636,6 @@ int vmbus_sendpacket_ctl(struct vmbus_ch
+       u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
+       struct kvec bufferlist[3];
+       u64 aligned_data = 0;
+-      int ret;
+-      bool signal = false;
+       bool lock = channel->acquire_ring_lock;
+       int num_vecs = ((bufferlen != 0) ? 3 : 1);
+@@ -656,41 +655,9 @@ int vmbus_sendpacket_ctl(struct vmbus_ch
+       bufferlist[2].iov_base = &aligned_data;
+       bufferlist[2].iov_len = (packetlen_aligned - packetlen);
+-      ret = hv_ringbuffer_write(&channel->outbound, bufferlist, num_vecs,
+-                                &signal, lock, channel->signal_policy);
+-
+-      /*
+-       * Signalling the host is conditional on many factors:
+-       * 1. The ring state changed from being empty to non-empty.
+-       *    This is tracked by the variable "signal".
+-       * 2. The variable kick_q tracks if more data will be placed
+-       *    on the ring. We will not signal if more data is
+-       *    to be placed.
+-       *
+-       * Based on the channel signal state, we will decide
+-       * which signaling policy will be applied.
+-       *
+-       * If we cannot write to the ring-buffer; signal the host
+-       * even if we may not have written anything. This is a rare
+-       * enough condition that it should not matter.
+-       * NOTE: in this case, the hvsock channel is an exception, because
+-       * it looks the host side's hvsock implementation has a throttling
+-       * mechanism which can hurt the performance otherwise.
+-       *
+-       * KYS: Oct. 30, 2016:
+-       * It looks like Windows hosts have logic to deal with DOS attacks that
+-       * can be triggered if it receives interrupts when it is not expecting
+-       * the interrupt. The host expects interrupts only when the ring
+-       * transitions from empty to non-empty (or full to non full on the guest
+-       * to host ring).
+-       * So, base the signaling decision solely on the ring state until the
+-       * host logic is fixed.
+-       */
+-
+-      if (((ret == 0) && signal))
+-              vmbus_setevent(channel);
++      return hv_ringbuffer_write(channel, bufferlist, num_vecs,
++                                 lock, kick_q);
+-      return ret;
+ }
+ EXPORT_SYMBOL(vmbus_sendpacket_ctl);
+@@ -731,7 +698,6 @@ int vmbus_sendpacket_pagebuffer_ctl(stru
+                                    u32 flags,
+                                    bool kick_q)
+ {
+-      int ret;
+       int i;
+       struct vmbus_channel_packet_page_buffer desc;
+       u32 descsize;
+@@ -739,7 +705,6 @@ int vmbus_sendpacket_pagebuffer_ctl(stru
+       u32 packetlen_aligned;
+       struct kvec bufferlist[3];
+       u64 aligned_data = 0;
+-      bool signal = false;
+       bool lock = channel->acquire_ring_lock;
+       if (pagecount > MAX_PAGE_BUFFER_COUNT)
+@@ -777,38 +742,8 @@ int vmbus_sendpacket_pagebuffer_ctl(stru
+       bufferlist[2].iov_base = &aligned_data;
+       bufferlist[2].iov_len = (packetlen_aligned - packetlen);
+-      ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
+-                                &signal, lock, channel->signal_policy);
+-
+-      /*
+-       * Signalling the host is conditional on many factors:
+-       * 1. The ring state changed from being empty to non-empty.
+-       *    This is tracked by the variable "signal".
+-       * 2. The variable kick_q tracks if more data will be placed
+-       *    on the ring. We will not signal if more data is
+-       *    to be placed.
+-       *
+-       * Based on the channel signal state, we will decide
+-       * which signaling policy will be applied.
+-       *
+-       * If we cannot write to the ring-buffer; signal the host
+-       * even if we may not have written anything. This is a rare
+-       * enough condition that it should not matter.
+-       *
+-       * KYS: Oct. 30, 2016:
+-       * It looks like Windows hosts have logic to deal with DOS attacks that
+-       * can be triggered if it receives interrupts when it is not expecting
+-       * the interrupt. The host expects interrupts only when the ring
+-       * transitions from empty to non-empty (or full to non full on the guest
+-       * to host ring).
+-       * So, base the signaling decision solely on the ring state until the
+-       * host logic is fixed.
+-       */
+-
+-      if (((ret == 0) && signal))
+-              vmbus_setevent(channel);
+-
+-      return ret;
++      return hv_ringbuffer_write(channel, bufferlist, 3,
++                                 lock, kick_q);
+ }
+ EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer_ctl);
+@@ -839,12 +774,10 @@ int vmbus_sendpacket_mpb_desc(struct vmb
+                             u32 desc_size,
+                             void *buffer, u32 bufferlen, u64 requestid)
+ {
+-      int ret;
+       u32 packetlen;
+       u32 packetlen_aligned;
+       struct kvec bufferlist[3];
+       u64 aligned_data = 0;
+-      bool signal = false;
+       bool lock = channel->acquire_ring_lock;
+       packetlen = desc_size + bufferlen;
+@@ -865,13 +798,8 @@ int vmbus_sendpacket_mpb_desc(struct vmb
+       bufferlist[2].iov_base = &aligned_data;
+       bufferlist[2].iov_len = (packetlen_aligned - packetlen);
+-      ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
+-                                &signal, lock, channel->signal_policy);
+-
+-      if (ret == 0 && signal)
+-              vmbus_setevent(channel);
+-
+-      return ret;
++      return hv_ringbuffer_write(channel, bufferlist, 3,
++                                 lock, true);
+ }
+ EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc);
+@@ -883,14 +811,12 @@ int vmbus_sendpacket_multipagebuffer(str
+                               struct hv_multipage_buffer *multi_pagebuffer,
+                               void *buffer, u32 bufferlen, u64 requestid)
+ {
+-      int ret;
+       struct vmbus_channel_packet_multipage_buffer desc;
+       u32 descsize;
+       u32 packetlen;
+       u32 packetlen_aligned;
+       struct kvec bufferlist[3];
+       u64 aligned_data = 0;
+-      bool signal = false;
+       bool lock = channel->acquire_ring_lock;
+       u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
+                                        multi_pagebuffer->len);
+@@ -930,13 +856,8 @@ int vmbus_sendpacket_multipagebuffer(str
+       bufferlist[2].iov_base = &aligned_data;
+       bufferlist[2].iov_len = (packetlen_aligned - packetlen);
+-      ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
+-                                &signal, lock, channel->signal_policy);
+-
+-      if (ret == 0 && signal)
+-              vmbus_setevent(channel);
+-
+-      return ret;
++      return hv_ringbuffer_write(channel, bufferlist, 3,
++                                 lock, true);
+ }
+ EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
+--- a/drivers/hv/hyperv_vmbus.h
++++ b/drivers/hv/hyperv_vmbus.h
+@@ -527,10 +527,10 @@ int hv_ringbuffer_init(struct hv_ring_bu
+ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
+-int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
++int hv_ringbuffer_write(struct vmbus_channel *channel,
+                   struct kvec *kv_list,
+-                  u32 kv_count, bool *signal, bool lock,
+-                  enum hv_signal_policy policy);
++                  u32 kv_count, bool lock,
++                  bool kick_q);
+ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
+                      void *buffer, u32 buflen, u32 *buffer_actual_len,
+--- a/drivers/hv/ring_buffer.c
++++ b/drivers/hv/ring_buffer.c
+@@ -66,14 +66,25 @@ u32 hv_end_read(struct hv_ring_buffer_in
+  *       once the ring buffer is empty, it will clear the
+  *       interrupt_mask and re-check to see if new data has
+  *       arrived.
++ *
++ * KYS: Oct. 30, 2016:
++ * It looks like Windows hosts have logic to deal with DOS attacks that
++ * can be triggered if it receives interrupts when it is not expecting
++ * the interrupt. The host expects interrupts only when the ring
++ * transitions from empty to non-empty (or full to non full on the guest
++ * to host ring).
++ * So, base the signaling decision solely on the ring state until the
++ * host logic is fixed.
+  */
+-static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi,
+-                            enum hv_signal_policy policy)
++static void hv_signal_on_write(u32 old_write, struct vmbus_channel *channel,
++                             bool kick_q)
+ {
++      struct hv_ring_buffer_info *rbi = &channel->outbound;
++
+       virt_mb();
+       if (READ_ONCE(rbi->ring_buffer->interrupt_mask))
+-              return false;
++              return;
+       /* check interrupt_mask before read_index */
+       virt_rmb();
+@@ -82,9 +93,9 @@ static bool hv_need_to_signal(u32 old_wr
+        * ring transitions from being empty to non-empty.
+        */
+       if (old_write == READ_ONCE(rbi->ring_buffer->read_index))
+-              return true;
++              vmbus_setevent(channel);
+-      return false;
++      return;
+ }
+ /* Get the next write location for the specified ring buffer. */
+@@ -273,9 +284,9 @@ void hv_ringbuffer_cleanup(struct hv_rin
+ }
+ /* Write to the ring buffer. */
+-int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
+-                  struct kvec *kv_list, u32 kv_count, bool *signal, bool lock,
+-                  enum hv_signal_policy policy)
++int hv_ringbuffer_write(struct vmbus_channel *channel,
++                  struct kvec *kv_list, u32 kv_count, bool lock,
++                  bool kick_q)
+ {
+       int i = 0;
+       u32 bytes_avail_towrite;
+@@ -285,6 +296,7 @@ int hv_ringbuffer_write(struct hv_ring_b
+       u32 old_write;
+       u64 prev_indices = 0;
+       unsigned long flags = 0;
++      struct hv_ring_buffer_info *outring_info = &channel->outbound;
+       for (i = 0; i < kv_count; i++)
+               totalbytes_towrite += kv_list[i].iov_len;
+@@ -337,7 +349,7 @@ int hv_ringbuffer_write(struct hv_ring_b
+       if (lock)
+               spin_unlock_irqrestore(&outring_info->ring_lock, flags);
+-      *signal = hv_need_to_signal(old_write, outring_info, policy);
++      hv_signal_on_write(old_write, channel, kick_q);
+       return 0;
+ }
+--- a/include/linux/hyperv.h
++++ b/include/linux/hyperv.h
+@@ -1447,6 +1447,7 @@ void hv_event_tasklet_enable(struct vmbu
+ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid);
++void vmbus_setevent(struct vmbus_channel *channel);
+ /*
+  * Negotiated version with the Host.
+  */
index 4ae1383a1d309d9672a245f91bd2fc10ea4d890d..66232400bc074b65af688fd42903fe7148490192 100644 (file)
@@ -33,3 +33,7 @@ drm-i915-always-convert-incoming-exec-offsets-to-non-canonical.patch
 nl80211-fix-mesh-ht-operation-check.patch
 mac80211-fix-adding-of-mesh-vendor-ies.patch
 net-mlx5e-modify-tirs-hash-only-when-it-s-needed.patch
+drivers-hv-vmbus-base-host-signaling-strictly-on-the-ring-state.patch
+drivers-hv-vmbus-on-write-cleanup-the-logic-to-interrupt-the-host.patch
+drivers-hv-vmbus-on-the-read-path-cleanup-the-logic-to-interrupt-the-host.patch
+drivers-hv-vmbus-finally-fix-hv_need_to_signal_on_read.patch