From: Greg Kroah-Hartman Date: Sat, 11 Feb 2017 07:14:45 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v4.9.10~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6479f8a4f598a17f6effe18e80e659932293fdd4;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches 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 --- 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 index 00000000000..5d7d99b820e --- /dev/null +++ b/queue-4.9/drivers-hv-vmbus-base-host-signaling-strictly-on-the-ring-state.patch @@ -0,0 +1,98 @@ +From 74198eb4a42c4a3c4fbef08fa01a291a282f7c2e Mon Sep 17 00:00:00 2001 +From: "K. Y. Srinivasan" +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 + +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 +Cc: Rolf Neugebauer +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..5a81228cd68 --- /dev/null +++ b/queue-4.9/drivers-hv-vmbus-finally-fix-hv_need_to_signal_on_read.patch @@ -0,0 +1,149 @@ +From 433e19cf33d34bb6751c874a9c00980552fe508c Mon Sep 17 00:00:00 2001 +From: Dexuan Cui +Date: Sat, 28 Jan 2017 11:46:02 -0700 +Subject: Drivers: hv: vmbus: finally fix hv_need_to_signal_on_read() + +From: Dexuan Cui + +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 +Reported-by: Rolf Neugebauer +Tested-by: Rolf Neugebauer +Cc: "K. Y. Srinivasan" +Cc: Haiyang Zhang +Cc: Stephen Hemminger +Signed-off-by: K. Y. Srinivasan +Cc: Rolf Neugebauer +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..feaf66a3b44 --- /dev/null +++ b/queue-4.9/drivers-hv-vmbus-on-the-read-path-cleanup-the-logic-to-interrupt-the-host.patch @@ -0,0 +1,135 @@ +From 3372592a140db69fd63837e81f048ab4abf8111e Mon Sep 17 00:00:00 2001 +From: "K. Y. Srinivasan" +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 + +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 +Cc: Rolf Neugebauer +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..5578478c412 --- /dev/null +++ b/queue-4.9/drivers-hv-vmbus-on-write-cleanup-the-logic-to-interrupt-the-host.patch @@ -0,0 +1,314 @@ +From 1f6ee4e7d83586c8b10bd4f2f4346353d04ce884 Mon Sep 17 00:00:00 2001 +From: "K. Y. Srinivasan" +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 + +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 +Cc: Rolf Neugebauer +Signed-off-by: Greg Kroah-Hartman + +--- + 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. + */ diff --git a/queue-4.9/series b/queue-4.9/series index 4ae1383a1d3..66232400bc0 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -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