diff options
| author | Dexuan Cui <decui@microsoft.com> | 2017-01-28 11:46:02 -0700 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-01-31 10:59:48 +0100 | 
| commit | 433e19cf33d34bb6751c874a9c00980552fe508c (patch) | |
| tree | ce6547ef2987fbb289fa28f03536328a42781651 /include/linux/hyperv.h | |
| parent | 191e885a2e130e639bb0c8ee350d7047294f2ce6 (diff) | |
Drivers: hv: vmbus: finally fix hv_need_to_signal_on_read()
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>
Cc: <stable@vger.kernel.org>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include/linux/hyperv.h')
| -rw-r--r-- | include/linux/hyperv.h | 32 | 
1 files changed, 30 insertions, 2 deletions
| diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 42fe43fb0c80..183efde54269 100644 --- 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(struct hv_ring_buffer_info *rbi)  	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. @@ -1488,7 +1502,7 @@ hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)  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; @@ -1512,12 +1526,24 @@ static inline  void hv_signal_on_read(struct vmbus_channel *channel)  	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.   */ @@ -1569,6 +1595,8 @@ static inline void put_pkt_raw(struct vmbus_channel *channel,   * 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(); | 
