diff options
author | Stephen Hemminger <stephen@networkplumber.org> | 2017-06-25 21:30:26 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-07-17 17:16:05 +0200 |
commit | 8dd45f2ab005a1f3301296059b23b03ec3dbf79b (patch) | |
tree | 12432e76b039c06a3b464ab42d9da7d8a8272f0a /drivers/hv/ring_buffer.c | |
parent | vmbus: drop unused ring_buffer_info elements (diff) | |
download | linux-8dd45f2ab005a1f3301296059b23b03ec3dbf79b.tar.xz linux-8dd45f2ab005a1f3301296059b23b03ec3dbf79b.zip |
vmbus: refactor hv_signal_on_read
The function hv_signal_on_read was defined in hyperv.h and
only used in one place in ring_buffer code. Clearer to just
move it inline there.
Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv/ring_buffer.c')
-rw-r--r-- | drivers/hv/ring_buffer.c | 32 |
1 files changed, 30 insertions, 2 deletions
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index f29981764653..a9021f13379f 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -29,6 +29,7 @@ #include <linux/uio.h> #include <linux/vmalloc.h> #include <linux/slab.h> +#include <linux/prefetch.h> #include "hyperv_vmbus.h" @@ -357,7 +358,7 @@ struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel) { struct hv_ring_buffer_info *rbi = &channel->inbound; - /* set state for later hv_signal_on_read() */ + /* set state for later hv_pkt_iter_close */ rbi->cached_read_index = rbi->ring_buffer->read_index; if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor)) @@ -400,6 +401,8 @@ EXPORT_SYMBOL_GPL(__hv_pkt_iter_next); void hv_pkt_iter_close(struct vmbus_channel *channel) { struct hv_ring_buffer_info *rbi = &channel->inbound; + u32 cur_write_sz, cached_write_sz; + u32 pending_sz; /* * Make sure all reads are done before we update the read index since @@ -409,6 +412,31 @@ void hv_pkt_iter_close(struct vmbus_channel *channel) virt_rmb(); rbi->ring_buffer->read_index = rbi->priv_read_index; - hv_signal_on_read(channel); + /* + * Issue a full memory barrier before making the signaling decision. + * Here is the reason for having this barrier: + * If the reading of the pend_sz (in this function) + * were to be reordered and read before we commit the new read + * index (in the calling function) we could + * have a problem. If the host were to set the pending_sz after we + * have sampled pending_sz and go to sleep before we commit the + * read index, we could miss sending the interrupt. Issue a full + * memory barrier to address this. + */ + virt_mb(); + + 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; + + cur_write_sz = hv_get_bytes_to_write(rbi); + + 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); } EXPORT_SYMBOL_GPL(hv_pkt_iter_close); |