vmbus: simplify hv_ringbuffer_read
authorStephen Hemminger <stephen@networkplumber.org>
Sun, 25 Jun 2017 19:30:24 +0000 (12:30 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Jul 2017 15:15:10 +0000 (17:15 +0200)
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>
drivers/hv/ring_buffer.c

index 1f450c39a9b0830f68611c0a11ee90c9f77ab2a3..f2998176465359aa17b5d011eba11cda7952e56d 100644 (file)
@@ -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;
 }
 
-/* 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. */
 static inline void
 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;
 }
 
-/*
- * 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.
  * 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;
 }
 
-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,
                       void *buffer, u32 buflen, u32 *buffer_actual_len,
                       u64 *requestid, bool raw)
 {
-       u32 bytes_avail_toread;
-       u32 next_read_location;
-       u64 prev_indices = 0;
-       struct vmpacket_descriptor desc;
-       u32 offset;
-       u32 packetlen;
-       struct hv_ring_buffer_info *inring_info = &channel->inbound;
-
-       if (buflen <= 0)
+       struct vmpacket_descriptor *desc;
+       u32 packetlen, offset;
+
+       if (unlikely(buflen == 0))
                return -EINVAL;
 
        *buffer_actual_len = 0;
        *requestid = 0;
 
-       bytes_avail_toread = hv_get_bytes_to_read(inring_info);
        /* 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
                 * supposed to analyze buffer_actual_len.
@@ -368,48 +310,22 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
                return 0;
        }
 
-       init_cached_read_index(inring_info);
-
-       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;
+       offset = raw ? 0 : (desc->offset8 << 3);
+       packetlen = (desc->len8 << 3) - offset;
        *buffer_actual_len = packetlen;
-       *requestid = desc.trans_id;
-
-       if (bytes_avail_toread < packetlen + offset)
-               return -EAGAIN;
+       *requestid = desc->trans_id;
 
-       if (packetlen > buflen)
+       if (unlikely(packetlen > buflen))
                return -ENOBUFS;
 
-       next_read_location =
-               hv_get_next_readlocation_withoffset(inring_info, offset);
+       /* since ring is double mapped, only one copy is necessary */
+       memcpy(buffer, (const char *)desc + offset, packetlen);
 
-       next_read_location = hv_copyfrom_ringbuffer(inring_info,
-                                               buffer,
-                                               packetlen,
-                                               next_read_location);
+       /* Advance ring index to next packet descriptor */
+       __hv_pkt_iter_next(channel, desc);
 
-       next_read_location = hv_copyfrom_ringbuffer(inring_info,
-                                               &prev_indices,
-                                               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);
+       /* Notify host of update */
+       hv_pkt_iter_close(channel);
 
        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;
 
        /* 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))
                return NULL;