Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vsock/virtio: add SIOCOUTQ support for all virtio based transports

Introduce support for virtio_transport_unsent_bytes
ioctl for virtio_transport, vhost_vsock and vsock_loopback.

For all transports the unsent bytes counter is incremented
in virtio_transport_get_credit.

In virtio_transport (G2H) and in vhost-vsock (H2G) the counter
is decremented when the skbuff is consumed. In vsock_loopback the
same skbuff is passed from the transmitter to the receiver, so
the counter is decremented before queuing the skbuff to the
receiver.

Signed-off-by: Luigi Leonardi <luigi.leonardi@outlook.com>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Luigi Leonardi and committed by
David S. Miller
e6ab4500 744500d8

+53 -2
+3 -1
drivers/vhost/vsock.c
··· 244 244 restart_tx = true; 245 245 } 246 246 247 - consume_skb(skb); 247 + virtio_transport_consume_skb_sent(skb, true); 248 248 } 249 249 } while(likely(!vhost_exceeds_weight(vq, ++pkts, total_len))); 250 250 if (added) ··· 450 450 .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue, 451 451 .notify_buffer_size = virtio_transport_notify_buffer_size, 452 452 .notify_set_rcvlowat = virtio_transport_notify_set_rcvlowat, 453 + 454 + .unsent_bytes = virtio_transport_unsent_bytes, 453 455 454 456 .read_skb = virtio_transport_read_skb, 455 457 },
+6
include/linux/virtio_vsock.h
··· 133 133 u32 tx_cnt; 134 134 u32 peer_fwd_cnt; 135 135 u32 peer_buf_alloc; 136 + size_t bytes_unsent; 136 137 137 138 /* Protected by rx_lock */ 138 139 u32 fwd_cnt; ··· 193 192 s64 virtio_transport_stream_has_data(struct vsock_sock *vsk); 194 193 s64 virtio_transport_stream_has_space(struct vsock_sock *vsk); 195 194 u32 virtio_transport_seqpacket_has_data(struct vsock_sock *vsk); 195 + 196 + ssize_t virtio_transport_unsent_bytes(struct vsock_sock *vsk); 197 + 198 + void virtio_transport_consume_skb_sent(struct sk_buff *skb, 199 + bool consume); 196 200 197 201 int virtio_transport_do_socket_init(struct vsock_sock *vsk, 198 202 struct vsock_sock *psk);
+3 -1
net/vmw_vsock/virtio_transport.c
··· 311 311 312 312 virtqueue_disable_cb(vq); 313 313 while ((skb = virtqueue_get_buf(vq, &len)) != NULL) { 314 - consume_skb(skb); 314 + virtio_transport_consume_skb_sent(skb, true); 315 315 added = true; 316 316 } 317 317 } while (!virtqueue_enable_cb(vq)); ··· 539 539 .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue, 540 540 .notify_buffer_size = virtio_transport_notify_buffer_size, 541 541 .notify_set_rcvlowat = virtio_transport_notify_set_rcvlowat, 542 + 543 + .unsent_bytes = virtio_transport_unsent_bytes, 542 544 543 545 .read_skb = virtio_transport_read_skb, 544 546 },
+35
net/vmw_vsock/virtio_transport_common.c
··· 463 463 } 464 464 EXPORT_SYMBOL_GPL(virtio_transport_inc_tx_pkt); 465 465 466 + void virtio_transport_consume_skb_sent(struct sk_buff *skb, bool consume) 467 + { 468 + struct sock *s = skb->sk; 469 + 470 + if (s && skb->len) { 471 + struct vsock_sock *vs = vsock_sk(s); 472 + struct virtio_vsock_sock *vvs; 473 + 474 + vvs = vs->trans; 475 + 476 + spin_lock_bh(&vvs->tx_lock); 477 + vvs->bytes_unsent -= skb->len; 478 + spin_unlock_bh(&vvs->tx_lock); 479 + } 480 + 481 + if (consume) 482 + consume_skb(skb); 483 + } 484 + EXPORT_SYMBOL_GPL(virtio_transport_consume_skb_sent); 485 + 466 486 u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 credit) 467 487 { 468 488 u32 ret; ··· 495 475 if (ret > credit) 496 476 ret = credit; 497 477 vvs->tx_cnt += ret; 478 + vvs->bytes_unsent += ret; 498 479 spin_unlock_bh(&vvs->tx_lock); 499 480 500 481 return ret; ··· 509 488 510 489 spin_lock_bh(&vvs->tx_lock); 511 490 vvs->tx_cnt -= credit; 491 + vvs->bytes_unsent -= credit; 512 492 spin_unlock_bh(&vvs->tx_lock); 513 493 } 514 494 EXPORT_SYMBOL_GPL(virtio_transport_put_credit); ··· 1111 1089 kfree(vvs); 1112 1090 } 1113 1091 EXPORT_SYMBOL_GPL(virtio_transport_destruct); 1092 + 1093 + ssize_t virtio_transport_unsent_bytes(struct vsock_sock *vsk) 1094 + { 1095 + struct virtio_vsock_sock *vvs = vsk->trans; 1096 + size_t ret; 1097 + 1098 + spin_lock_bh(&vvs->tx_lock); 1099 + ret = vvs->bytes_unsent; 1100 + spin_unlock_bh(&vvs->tx_lock); 1101 + 1102 + return ret; 1103 + } 1104 + EXPORT_SYMBOL_GPL(virtio_transport_unsent_bytes); 1114 1105 1115 1106 static int virtio_transport_reset(struct vsock_sock *vsk, 1116 1107 struct sk_buff *skb)
+6
net/vmw_vsock/vsock_loopback.c
··· 98 98 .notify_buffer_size = virtio_transport_notify_buffer_size, 99 99 .notify_set_rcvlowat = virtio_transport_notify_set_rcvlowat, 100 100 101 + .unsent_bytes = virtio_transport_unsent_bytes, 102 + 101 103 .read_skb = virtio_transport_read_skb, 102 104 }, 103 105 ··· 125 123 spin_unlock_bh(&vsock->pkt_queue.lock); 126 124 127 125 while ((skb = __skb_dequeue(&pkts))) { 126 + /* Decrement the bytes_unsent counter without deallocating skb 127 + * It is freed by the receiver. 128 + */ 129 + virtio_transport_consume_skb_sent(skb, false); 128 130 virtio_transport_deliver_tap_pkt(skb); 129 131 virtio_transport_recv_pkt(&loopback_transport, skb); 130 132 }