/* * * hv_ringbuffer_read() * * Read and advance the read index * */ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, u32 buflen, u32 offset, bool *signal) { u32 bytes_avail_towrite; u32 bytes_avail_toread; u32 next_read_location = 0; u64 prev_indices = 0; unsigned long flags; u32 old_read; if (buflen <= 0) return -EINVAL; spin_lock_irqsave(&inring_info->ring_lock, flags); hv_get_ringbuffer_availbytes(inring_info, &bytes_avail_toread, &bytes_avail_towrite); old_read = bytes_avail_toread; /* Make sure there is something to read */ if (bytes_avail_toread < buflen) { spin_unlock_irqrestore(&inring_info->ring_lock, flags); return -EAGAIN; } next_read_location = hv_get_next_readlocation_withoffset(inring_info, offset); next_read_location = hv_copyfrom_ringbuffer(inring_info, buffer, buflen, next_read_location); 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 */ mb(); /* Update the read index */ hv_set_next_read_location(inring_info, next_read_location); spin_unlock_irqrestore(&inring_info->ring_lock, flags); *signal = hv_need_to_signal_on_read(old_read, inring_info); return 0; }
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 = 0; u64 prev_indices = 0; struct vmpacket_descriptor desc; u32 offset; u32 packetlen; int ret = 0; struct hv_ring_buffer_info *inring_info = &channel->inbound; if (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)) { /* * No error is set when there is even no header, drivers are * supposed to analyze buffer_actual_len. */ return ret; } 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; *requestid = desc.trans_id; if (bytes_avail_toread < packetlen + offset) return -EAGAIN; if (packetlen > buflen) return -ENOBUFS; next_read_location = hv_get_next_readlocation_withoffset(inring_info, offset); next_read_location = hv_copyfrom_ringbuffer(inring_info, buffer, packetlen, next_read_location); 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); return ret; }
int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, u32 buflen, u32 *buffer_actual_len, u64 *requestid, bool *signal, bool raw) { u32 bytes_avail_toread; u32 next_read_location = 0; u64 prev_indices = 0; unsigned long flags; struct vmpacket_descriptor desc; u32 offset; u32 packetlen; int ret = 0; if (buflen <= 0) return -EINVAL; spin_lock_irqsave(&inring_info->ring_lock, flags); *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)) { /* * No error is set when there is even no header, drivers are * supposed to analyze buffer_actual_len. */ goto out_unlock; } 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; *requestid = desc.trans_id; if (bytes_avail_toread < packetlen + offset) { ret = -EAGAIN; goto out_unlock; } if (packetlen > buflen) { ret = -ENOBUFS; goto out_unlock; } next_read_location = hv_get_next_readlocation_withoffset(inring_info, offset); next_read_location = hv_copyfrom_ringbuffer(inring_info, buffer, packetlen, next_read_location); 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. */ mb(); /* Update the read index */ hv_set_next_read_location(inring_info, next_read_location); *signal = hv_need_to_signal_on_read(inring_info); out_unlock: spin_unlock_irqrestore(&inring_info->ring_lock, flags); return ret; }