To allow canceling all packets of a connection. Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com> Signed-off-by: Peng Tao <bergwolf at gmail.com> --- drivers/vhost/vsock.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/net/af_vsock.h | 3 +++ 2 files changed, 44 insertions(+) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index a504e2e0..fef8808 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -218,6 +218,46 @@ vhost_transport_send_pkt(struct virtio_vsock_pkt *pkt) return len; } +static int +vhost_transport_cancel_pkt(struct vsock_sock *vsk) +{ + struct vhost_vsock *vsock; + struct virtio_vsock_pkt *pkt, *n; + int cnt = 0; + LIST_HEAD(freeme); + + /* Find the vhost_vsock according to guest context id */ + vsock = vhost_vsock_get(vsk->remote_addr.svm_cid); + if (!vsock) + return -ENODEV; + + spin_lock_bh(&vsock->send_pkt_list_lock); + list_for_each_entry_safe(pkt, n, &vsock->send_pkt_list, list) { + if (pkt->cancel_token != vsk) + continue; + list_move(&pkt->list, &freeme); + } + spin_unlock_bh(&vsock->send_pkt_list_lock); + + list_for_each_entry_safe(pkt, n, &freeme, list) { + if (pkt->reply) + cnt++; + list_del(&pkt->list); + virtio_transport_free_pkt(pkt); + } + + if (cnt) { + struct vhost_virtqueue *tx_vq = &vsock->vqs[VSOCK_VQ_TX]; + int new_cnt; + + new_cnt = atomic_sub_return(cnt, &vsock->queued_replies); + if (new_cnt + cnt >= tx_vq->num && new_cnt < tx_vq->num) + vhost_poll_queue(&tx_vq->poll); + } + + return 0; +} + static struct virtio_vsock_pkt * vhost_vsock_alloc_pkt(struct vhost_virtqueue *vq, unsigned int out, unsigned int in) @@ -664,6 +704,7 @@ static struct virtio_transport vhost_transport = { .release = virtio_transport_release, .connect = virtio_transport_connect, .shutdown = virtio_transport_shutdown, + .cancel_pkt = vhost_transport_cancel_pkt, .dgram_enqueue = virtio_transport_dgram_enqueue, .dgram_dequeue = virtio_transport_dgram_dequeue, diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index f275896..f32ed9a 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -100,6 +100,9 @@ struct vsock_transport { void (*destruct)(struct vsock_sock *); void (*release)(struct vsock_sock *); + /* Cancel all pending packets sent on vsock. */ + int (*cancel_pkt)(struct vsock_sock *vsk); + /* Connections. */ int (*connect)(struct vsock_sock *); -- 2.7.4
Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com> Signed-off-by: Peng Tao <bergwolf at gmail.com> --- net/vmw_vsock/virtio_transport.c | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c index 936d7ee..b7b78ce 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -170,6 +170,47 @@ virtio_transport_send_pkt(struct virtio_vsock_pkt *pkt) return len; } +static int +virtio_transport_cancel_pkt(struct vsock_sock *vsk) +{ + struct virtio_vsock *vsock; + struct virtio_vsock_pkt *pkt, *n; + int cnt = 0; + LIST_HEAD(freeme); + + vsock = virtio_vsock_get(); + if (!vsock) { + return -ENODEV; + } + + spin_lock_bh(&vsock->send_pkt_list_lock); + list_for_each_entry_safe(pkt, n, &vsock->send_pkt_list, list) { + if (pkt->cancel_token != vsk) + continue; + list_move(&pkt->list, &freeme); + } + spin_unlock_bh(&vsock->send_pkt_list_lock); + + list_for_each_entry_safe(pkt, n, &freeme, list) { + if (pkt->reply) + cnt++; + list_del(&pkt->list); + virtio_transport_free_pkt(pkt); + } + + if (cnt) { + struct virtqueue *rx_vq = vsock->vqs[VSOCK_VQ_RX]; + int new_cnt; + + new_cnt = atomic_sub_return(cnt, &vsock->queued_replies); + if (new_cnt + cnt >= virtqueue_get_vring_size(rx_vq) && + new_cnt < virtqueue_get_vring_size(rx_vq)) + queue_work(virtio_vsock_workqueue, &vsock->rx_work); + } + + return 0; +} + static void virtio_vsock_rx_fill(struct virtio_vsock *vsock) { int buf_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE; @@ -419,6 +460,7 @@ static struct virtio_transport virtio_transport = { .release = virtio_transport_release, .connect = virtio_transport_connect, .shutdown = virtio_transport_shutdown, + .cancel_pkt = virtio_transport_cancel_pkt, .dgram_bind = virtio_transport_dgram_bind, .dgram_dequeue = virtio_transport_dgram_dequeue, -- 2.7.4
Peng Tao
2016-Dec-12 12:21 UTC
[PATCH v4 4/4] vsock: cancel packets when failing to connect
Otherwise we'll leave the packets queued until releasing vsock device. E.g., if guest is slow to start up, resulting ETIMEDOUT on connect, guest will get the connect requests from failed host sockets. Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com> Reviewed-by: Jorgen Hansen <jhansen at vmware.com> Signed-off-by: Peng Tao <bergwolf at gmail.com> --- net/vmw_vsock/af_vsock.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 8a398b3..c73b03a 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1101,10 +1101,19 @@ static const struct proto_ops vsock_dgram_ops = { .sendpage = sock_no_sendpage, }; +static int vsock_transport_cancel_pkt(struct vsock_sock *vsk) +{ + if (!transport->cancel_pkt) + return -EOPNOTSUPP; + + return transport->cancel_pkt(vsk); +} + static void vsock_connect_timeout(struct work_struct *work) { struct sock *sk; struct vsock_sock *vsk; + int cancel = 0; vsk = container_of(work, struct vsock_sock, dwork.work); sk = sk_vsock(vsk); @@ -1115,8 +1124,11 @@ static void vsock_connect_timeout(struct work_struct *work) sk->sk_state = SS_UNCONNECTED; sk->sk_err = ETIMEDOUT; sk->sk_error_report(sk); + cancel = 1; } release_sock(sk); + if (cancel) + vsock_transport_cancel_pkt(vsk); sock_put(sk); } @@ -1223,11 +1235,13 @@ static int vsock_stream_connect(struct socket *sock, struct sockaddr *addr, err = sock_intr_errno(timeout); sk->sk_state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED; + vsock_transport_cancel_pkt(vsk); goto out_wait; } else if (timeout == 0) { err = -ETIMEDOUT; sk->sk_state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED; + vsock_transport_cancel_pkt(vsk); goto out_wait; } -- 2.7.4
Jorgen S. Hansen
2016-Dec-13 10:04 UTC
[PATCH v4 2/4] vhost-vsock: add pkt cancel capability
> On Dec 12, 2016, at 1:21 PM, Peng Tao <bergwolf at gmail.com> wrote: > > To allow canceling all packets of a connection. > > Reviewed-by: Stefan Hajnoczi <stefanha at redhat.com> > Signed-off-by: Peng Tao <bergwolf at gmail.com> > --- > drivers/vhost/vsock.c | 41 +++++++++++++++++++++++++++++++++++++++++ > include/net/af_vsock.h | 3 +++ > 2 files changed, 44 insertions(+) > > diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c > index a504e2e0..fef8808 100644 > --- a/drivers/vhost/vsock.c > +++ b/drivers/vhost/vsock.c > @@ -218,6 +218,46 @@ vhost_transport_send_pkt(struct virtio_vsock_pkt *pkt) > return len; > } > > +static int > +vhost_transport_cancel_pkt(struct vsock_sock *vsk) > +{ > + struct vhost_vsock *vsock; > + struct virtio_vsock_pkt *pkt, *n; > + int cnt = 0; > + LIST_HEAD(freeme); > + > + /* Find the vhost_vsock according to guest context id */ > + vsock = vhost_vsock_get(vsk->remote_addr.svm_cid); > + if (!vsock) > + return -ENODEV; > + > + spin_lock_bh(&vsock->send_pkt_list_lock); > + list_for_each_entry_safe(pkt, n, &vsock->send_pkt_list, list) { > + if (pkt->cancel_token != vsk) > + continue; > + list_move(&pkt->list, &freeme); > + } > + spin_unlock_bh(&vsock->send_pkt_list_lock); > + > + list_for_each_entry_safe(pkt, n, &freeme, list) { > + if (pkt->reply) > + cnt++; > + list_del(&pkt->list); > + virtio_transport_free_pkt(pkt); > + } > + > + if (cnt) { > + struct vhost_virtqueue *tx_vq = &vsock->vqs[VSOCK_VQ_TX]; > + int new_cnt; > + > + new_cnt = atomic_sub_return(cnt, &vsock->queued_replies); > + if (new_cnt + cnt >= tx_vq->num && new_cnt < tx_vq->num) > + vhost_poll_queue(&tx_vq->poll); > + } > + > + return 0; > +} > + > static struct virtio_vsock_pkt * > vhost_vsock_alloc_pkt(struct vhost_virtqueue *vq, > unsigned int out, unsigned int in) > @@ -664,6 +704,7 @@ static struct virtio_transport vhost_transport = { > .release = virtio_transport_release, > .connect = virtio_transport_connect, > .shutdown = virtio_transport_shutdown, > + .cancel_pkt = vhost_transport_cancel_pkt, > > .dgram_enqueue = virtio_transport_dgram_enqueue, > .dgram_dequeue = virtio_transport_dgram_dequeue, > diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h > index f275896..f32ed9a 100644 > --- a/include/net/af_vsock.h > +++ b/include/net/af_vsock.h > @@ -100,6 +100,9 @@ struct vsock_transport { > void (*destruct)(struct vsock_sock *); > void (*release)(struct vsock_sock *); > > + /* Cancel all pending packets sent on vsock. */ > + int (*cancel_pkt)(struct vsock_sock *vsk); > + > /* Connections. */ > int (*connect)(struct vsock_sock *); > > -- > 2.7.4 >Reviewed-by: Jorgen Hansen <jhansen at vmware.com>