Skip to content

Commit b6cae15

Browse files
kelleymhliuw
authored andcommitted
Drivers: hv: vmbus: Prevent load re-ordering when reading ring buffer
When reading a packet from a host-to-guest ring buffer, there is no memory barrier between reading the write index (to see if there is a packet to read) and reading the contents of the packet. The Hyper-V host uses store-release when updating the write index to ensure that writes of the packet data are completed first. On the guest side, the processor can reorder and read the packet data before the write index, and sometimes get stale packet data. Getting such stale packet data has been observed in a reproducible case in a VM on ARM64. Fix this by using virt_load_acquire() to read the write index, ensuring that reads of the packet data cannot be reordered before it. Preventing such reordering is logically correct, and with this change, getting stale data can no longer be reproduced. Signed-off-by: Michael Kelley <[email protected]> Reviewed-by: Andrea Parri (Microsoft) <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Wei Liu <[email protected]>
1 parent 8d21732 commit b6cae15

File tree

1 file changed

+10
-1
lines changed

1 file changed

+10
-1
lines changed

drivers/hv/ring_buffer.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,16 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
439439
static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
440440
{
441441
u32 priv_read_loc = rbi->priv_read_index;
442-
u32 write_loc = READ_ONCE(rbi->ring_buffer->write_index);
442+
u32 write_loc;
443+
444+
/*
445+
* The Hyper-V host writes the packet data, then uses
446+
* store_release() to update the write_index. Use load_acquire()
447+
* here to prevent loads of the packet data from being re-ordered
448+
* before the read of the write_index and potentially getting
449+
* stale data.
450+
*/
451+
write_loc = virt_load_acquire(&rbi->ring_buffer->write_index);
443452

444453
if (write_loc >= priv_read_loc)
445454
return write_loc - priv_read_loc;

0 commit comments

Comments
 (0)