Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions net/vmw_vsock/hyperv_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,17 +694,38 @@ static ssize_t hvs_stream_enqueue(struct vsock_sock *vsk, struct msghdr *msg,
static s64 hvs_stream_has_data(struct vsock_sock *vsk)
{
struct hvsock *hvs = vsk->trans;
bool need_refill;
s64 ret;

if (hvs->recv_data_len > 0)
return hvs->recv_data_len;

switch (hvs_channel_readable_payload(hvs->chan)) {
case 1:
need_refill = !hvs->recv_desc;
if (!need_refill)
return -EIO;
if (hvs->recv_desc) {
/* Here hvs->recv_data_len is 0, so hvs->recv_desc must
* be NULL unless it points to the 0-byte-payload FIN
* packet or a malformed/short packet: see
* hvs_update_recv_data().
*
* If hvs->recv_desc points to the FIN packet, here all
* the payload has been dequeued and the peer_shutdown
* flag is set, but hvs_channel_readable_payload() still
* returns 1, because the VMBus ringbuffer's read_index
* is not updated for the FIN packet:
* hvs_stream_dequeue() -> hv_pkt_iter_next() updates
* the cached priv_read_index but has no opportunity to
* update the read_index in hv_pkt_iter_close() as
* hvs_stream_has_data() returns 0 for the FIN packet,
* so it won't get dequeued.
*
* In case hvs->recv_desc points to a malformed/short
* packet, return -EIO.
*/
if (!(vsk->peer_shutdown & SEND_SHUTDOWN))
return -EIO;

return 0;
}
Comment thread
dcui marked this conversation as resolved.

hvs->recv_desc = hv_pkt_iter_first(hvs->chan);
if (!hvs->recv_desc)
Expand Down
Loading