diff options
Diffstat (limited to 'net/vmw_vsock/virtio_transport_common.c')
| -rw-r--r-- | net/vmw_vsock/virtio_transport_common.c | 104 | 
1 files changed, 79 insertions, 25 deletions
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index b769fc258931..352d042b130b 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -348,37 +348,34 @@ virtio_transport_stream_do_peek(struct vsock_sock *vsk,  				size_t len)  {  	struct virtio_vsock_sock *vvs = vsk->trans; -	size_t bytes, total = 0, off; -	struct sk_buff *skb, *tmp; -	int err = -EFAULT; +	struct sk_buff *skb; +	size_t total = 0; +	int err;  	spin_lock_bh(&vvs->rx_lock); -	skb_queue_walk_safe(&vvs->rx_queue, skb,  tmp) { -		off = 0; +	skb_queue_walk(&vvs->rx_queue, skb) { +		size_t bytes; -		if (total == len) -			break; +		bytes = len - total; +		if (bytes > skb->len) +			bytes = skb->len; -		while (total < len && off < skb->len) { -			bytes = len - total; -			if (bytes > skb->len - off) -				bytes = skb->len - off; +		spin_unlock_bh(&vvs->rx_lock); -			/* sk_lock is held by caller so no one else can dequeue. -			 * Unlock rx_lock since memcpy_to_msg() may sleep. -			 */ -			spin_unlock_bh(&vvs->rx_lock); +		/* sk_lock is held by caller so no one else can dequeue. +		 * Unlock rx_lock since memcpy_to_msg() may sleep. +		 */ +		err = memcpy_to_msg(msg, skb->data, bytes); +		if (err) +			goto out; -			err = memcpy_to_msg(msg, skb->data + off, bytes); -			if (err) -				goto out; +		total += bytes; -			spin_lock_bh(&vvs->rx_lock); +		spin_lock_bh(&vvs->rx_lock); -			total += bytes; -			off += bytes; -		} +		if (total == len) +			break;  	}  	spin_unlock_bh(&vvs->rx_lock); @@ -463,6 +460,63 @@ out:  	return err;  } +static ssize_t +virtio_transport_seqpacket_do_peek(struct vsock_sock *vsk, +				   struct msghdr *msg) +{ +	struct virtio_vsock_sock *vvs = vsk->trans; +	struct sk_buff *skb; +	size_t total, len; + +	spin_lock_bh(&vvs->rx_lock); + +	if (!vvs->msg_count) { +		spin_unlock_bh(&vvs->rx_lock); +		return 0; +	} + +	total = 0; +	len = msg_data_left(msg); + +	skb_queue_walk(&vvs->rx_queue, skb) { +		struct virtio_vsock_hdr *hdr; + +		if (total < len) { +			size_t bytes; +			int err; + +			bytes = len - total; +			if (bytes > skb->len) +				bytes = skb->len; + +			spin_unlock_bh(&vvs->rx_lock); + +			/* sk_lock is held by caller so no one else can dequeue. +			 * Unlock rx_lock since memcpy_to_msg() may sleep. +			 */ +			err = memcpy_to_msg(msg, skb->data, bytes); +			if (err) +				return err; + +			spin_lock_bh(&vvs->rx_lock); +		} + +		total += skb->len; +		hdr = virtio_vsock_hdr(skb); + +		if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM) { +			if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOR) +				msg->msg_flags |= MSG_EOR; + +			break; +		} +	} + +	spin_unlock_bh(&vvs->rx_lock); + +	return total; +} +  static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk,  						 struct msghdr *msg,  						 int flags) @@ -557,9 +611,9 @@ virtio_transport_seqpacket_dequeue(struct vsock_sock *vsk,  				   int flags)  {  	if (flags & MSG_PEEK) -		return -EOPNOTSUPP; - -	return virtio_transport_seqpacket_do_dequeue(vsk, msg, flags); +		return virtio_transport_seqpacket_do_peek(vsk, msg); +	else +		return virtio_transport_seqpacket_do_dequeue(vsk, msg, flags);  }  EXPORT_SYMBOL_GPL(virtio_transport_seqpacket_dequeue);  | 
