vmbus: simplify hv_ringbuffer_read

With new iterator functions (and the double mapping) the ring buffer
read function can be greatly simplified.

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>
This commit is contained in:
Stephen Hemminger 2017-06-25 12:30:24 -07:00 коммит произвёл Greg Kroah-Hartman
Родитель 133d55cdb2
Коммит 4226ff69a3
1 изменённых файлов: 16 добавлений и 100 удалений

Просмотреть файл

@ -94,30 +94,6 @@ hv_set_next_write_location(struct hv_ring_buffer_info *ring_info,
ring_info->ring_buffer->write_index = next_write_location; ring_info->ring_buffer->write_index = next_write_location;
} }
/* Get the next read location for the specified ring buffer. */
static inline u32
hv_get_next_read_location(const struct hv_ring_buffer_info *ring_info)
{
return ring_info->ring_buffer->read_index;
}
/*
* Get the next read location + offset for the specified ring buffer.
* This allows the caller to skip.
*/
static inline u32
hv_get_next_readlocation_withoffset(const struct hv_ring_buffer_info *ring_info,
u32 offset)
{
u32 next = ring_info->ring_buffer->read_index;
next += offset;
if (next >= ring_info->ring_datasize)
next -= ring_info->ring_datasize;
return next;
}
/* Set the next read location for the specified ring buffer. */ /* Set the next read location for the specified ring buffer. */
static inline void static inline void
hv_set_next_read_location(struct hv_ring_buffer_info *ring_info, hv_set_next_read_location(struct hv_ring_buffer_info *ring_info,
@ -141,29 +117,6 @@ hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info)
return (u64)ring_info->ring_buffer->write_index << 32; return (u64)ring_info->ring_buffer->write_index << 32;
} }
/*
* Helper routine to copy to source from ring buffer.
* Assume there is enough room. Handles wrap-around in src case only!!
*/
static u32 hv_copyfrom_ringbuffer(
const struct hv_ring_buffer_info *ring_info,
void *dest,
u32 destlen,
u32 start_read_offset)
{
void *ring_buffer = hv_get_ring_buffer(ring_info);
u32 ring_buffer_size = hv_get_ring_buffersize(ring_info);
memcpy(dest, ring_buffer + start_read_offset, destlen);
start_read_offset += destlen;
if (start_read_offset >= ring_buffer_size)
start_read_offset -= ring_buffer_size;
return start_read_offset;
}
/* /*
* Helper routine to copy from source to ring buffer. * Helper routine to copy from source to ring buffer.
* Assume there is enough room. Handles wrap-around in dest case only!! * Assume there is enough room. Handles wrap-around in dest case only!!
@ -334,33 +287,22 @@ int hv_ringbuffer_write(struct vmbus_channel *channel,
return 0; return 0;
} }
static inline void
init_cached_read_index(struct hv_ring_buffer_info *rbi)
{
rbi->cached_read_index = rbi->ring_buffer->read_index;
}
int hv_ringbuffer_read(struct vmbus_channel *channel, int hv_ringbuffer_read(struct vmbus_channel *channel,
void *buffer, u32 buflen, u32 *buffer_actual_len, void *buffer, u32 buflen, u32 *buffer_actual_len,
u64 *requestid, bool raw) u64 *requestid, bool raw)
{ {
u32 bytes_avail_toread; struct vmpacket_descriptor *desc;
u32 next_read_location; u32 packetlen, offset;
u64 prev_indices = 0;
struct vmpacket_descriptor desc;
u32 offset;
u32 packetlen;
struct hv_ring_buffer_info *inring_info = &channel->inbound;
if (buflen <= 0) if (unlikely(buflen == 0))
return -EINVAL; return -EINVAL;
*buffer_actual_len = 0; *buffer_actual_len = 0;
*requestid = 0; *requestid = 0;
bytes_avail_toread = hv_get_bytes_to_read(inring_info);
/* Make sure there is something to read */ /* Make sure there is something to read */
if (bytes_avail_toread < sizeof(desc)) { desc = hv_pkt_iter_first(channel);
if (desc == NULL) {
/* /*
* No error is set when there is even no header, drivers are * No error is set when there is even no header, drivers are
* supposed to analyze buffer_actual_len. * supposed to analyze buffer_actual_len.
@ -368,48 +310,22 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
return 0; return 0;
} }
init_cached_read_index(inring_info); offset = raw ? 0 : (desc->offset8 << 3);
packetlen = (desc->len8 << 3) - offset;
next_read_location = hv_get_next_read_location(inring_info);
next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
sizeof(desc),
next_read_location);
offset = raw ? 0 : (desc.offset8 << 3);
packetlen = (desc.len8 << 3) - offset;
*buffer_actual_len = packetlen; *buffer_actual_len = packetlen;
*requestid = desc.trans_id; *requestid = desc->trans_id;
if (bytes_avail_toread < packetlen + offset) if (unlikely(packetlen > buflen))
return -EAGAIN;
if (packetlen > buflen)
return -ENOBUFS; return -ENOBUFS;
next_read_location = /* since ring is double mapped, only one copy is necessary */
hv_get_next_readlocation_withoffset(inring_info, offset); memcpy(buffer, (const char *)desc + offset, packetlen);
next_read_location = hv_copyfrom_ringbuffer(inring_info, /* Advance ring index to next packet descriptor */
buffer, __hv_pkt_iter_next(channel, desc);
packetlen,
next_read_location);
next_read_location = hv_copyfrom_ringbuffer(inring_info, /* Notify host of update */
&prev_indices, hv_pkt_iter_close(channel);
sizeof(u64),
next_read_location);
/*
* Make sure all reads are done before we update the read index since
* the writer may start writing to the read area once the read index
* is updated.
*/
virt_mb();
/* Update the read index */
hv_set_next_read_location(inring_info, next_read_location);
hv_signal_on_read(channel);
return 0; return 0;
} }
@ -442,7 +358,7 @@ struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
struct hv_ring_buffer_info *rbi = &channel->inbound; struct hv_ring_buffer_info *rbi = &channel->inbound;
/* set state for later hv_signal_on_read() */ /* set state for later hv_signal_on_read() */
init_cached_read_index(rbi); rbi->cached_read_index = rbi->ring_buffer->read_index;
if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor)) if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
return NULL; return NULL;