Message ID | 20230419132119.124457-5-jean-philippe@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Fix vhost-net, scsi and vsock | expand |
On Wed, 19 Apr 2023 14:21:08 +0100 Jean-Philippe Brucker <jean-philippe@linaro.org> wrote: Hi, > All vhost devices should perform the same operations when initializing > the IRQFD. Move it to virtio/vhost.c > > This fixes vsock, which didn't go through the irq__add_irqfd() helper > and couldn't be used on systems that require GSI translation (GICv2m). > > Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org> > --- > include/kvm/virtio.h | 8 ++++++++ > virtio/net.c | 30 ++++-------------------------- > virtio/scsi.c | 15 ++------------- > virtio/vhost.c | 35 +++++++++++++++++++++++++++++++++++ > virtio/vsock.c | 26 +++----------------------- > 5 files changed, 52 insertions(+), 62 deletions(-) > > diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h > index 4a364a02..96c7b3ea 100644 > --- a/include/kvm/virtio.h > +++ b/include/kvm/virtio.h > @@ -77,6 +77,10 @@ struct virt_queue { > u16 endian; > bool use_event_idx; > bool enabled; > + > + /* vhost IRQ handling */ > + int gsi; > + int irqfd; > }; > > /* > @@ -252,6 +256,10 @@ void virtio_vhost_set_vring(struct kvm *kvm, int vhost_fd, u32 index, > struct virt_queue *queue); > void virtio_vhost_set_vring_kick(struct kvm *kvm, int vhost_fd, > u32 index, int event_fd); > +void virtio_vhost_set_vring_call(struct kvm *kvm, int vhost_fd, u32 index, > + u32 gsi, struct virt_queue *queue); > +void virtio_vhost_reset_vring(struct kvm *kvm, int vhost_fd, u32 index, > + struct virt_queue *queue); > > int virtio_transport_parser(const struct option *opt, const char *arg, int unset); > > diff --git a/virtio/net.c b/virtio/net.c > index b935d24f..519dcbb7 100644 > --- a/virtio/net.c > +++ b/virtio/net.c > @@ -4,12 +4,12 @@ > #include "kvm/mutex.h" > #include "kvm/util.h" > #include "kvm/kvm.h" > -#include "kvm/irq.h" > #include "kvm/uip.h" > #include "kvm/guest_compat.h" > #include "kvm/iovec.h" > #include "kvm/strbuf.h" > > +#include <linux/list.h> > #include <linux/vhost.h> > #include <linux/virtio_net.h> > #include <linux/if_tun.h> > @@ -25,7 +25,6 @@ > #include <sys/ioctl.h> > #include <sys/types.h> > #include <sys/wait.h> > -#include <sys/eventfd.h> > > #define VIRTIO_NET_QUEUE_SIZE 256 > #define VIRTIO_NET_NUM_QUEUES 8 > @@ -44,8 +43,6 @@ struct net_dev_queue { > pthread_t thread; > struct mutex lock; > pthread_cond_t cond; > - int gsi; > - int irqfd; > }; > > struct net_dev { > @@ -647,11 +644,7 @@ static void exit_vq(struct kvm *kvm, void *dev, u32 vq) > struct net_dev *ndev = dev; > struct net_dev_queue *queue = &ndev->queues[vq]; > > - if (!is_ctrl_vq(ndev, vq) && queue->gsi) { So this first condition here seems to be lost in the transformation. Is or was that never needed? Apart from that the changes look fine. Cheers, Andre > - irq__del_irqfd(kvm, queue->gsi, queue->irqfd); > - close(queue->irqfd); > - queue->gsi = queue->irqfd = 0; > - } > + virtio_vhost_reset_vring(kvm, ndev->vhost_fd, vq, &queue->vq); > > /* > * TODO: vhost reset owner. It's the only way to cleanly stop vhost, but > @@ -675,27 +668,12 @@ static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) > { > struct net_dev *ndev = dev; > struct net_dev_queue *queue = &ndev->queues[vq]; > - struct vhost_vring_file file; > - int r; > > if (ndev->vhost_fd == 0) > return; > > - file = (struct vhost_vring_file) { > - .index = vq, > - .fd = eventfd(0, 0), > - }; > - > - r = irq__add_irqfd(kvm, gsi, file.fd, -1); > - if (r < 0) > - die_perror("KVM_IRQFD failed"); > - > - queue->irqfd = file.fd; > - queue->gsi = gsi; > - > - r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_CALL, &file); > - if (r < 0) > - die_perror("VHOST_SET_VRING_CALL failed"); > + virtio_vhost_set_vring_call(kvm, ndev->vhost_fd, vq, gsi, > + &queue->vq); > } > > static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd) > diff --git a/virtio/scsi.c b/virtio/scsi.c > index 1f757404..29acf57c 100644 > --- a/virtio/scsi.c > +++ b/virtio/scsi.c > @@ -92,25 +92,14 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq) > > static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) > { > - struct vhost_vring_file file; > struct scsi_dev *sdev = dev; > int r; > > if (sdev->vhost_fd == 0) > return; > > - file = (struct vhost_vring_file) { > - .index = vq, > - .fd = eventfd(0, 0), > - }; > - > - r = irq__add_irqfd(kvm, gsi, file.fd, -1); > - if (r < 0) > - die_perror("KVM_IRQFD failed"); > - > - r = ioctl(sdev->vhost_fd, VHOST_SET_VRING_CALL, &file); > - if (r < 0) > - die_perror("VHOST_SET_VRING_CALL failed"); > + virtio_vhost_set_vring_call(kvm, sdev->vhost_fd, vq, gsi, > + &sdev->vqs[vq]); > > if (vq > 0) > return; > diff --git a/virtio/vhost.c b/virtio/vhost.c > index 3acfd30a..cd83645c 100644 > --- a/virtio/vhost.c > +++ b/virtio/vhost.c > @@ -1,9 +1,12 @@ > +#include "kvm/irq.h" > #include "kvm/virtio.h" > > #include <linux/kvm.h> > #include <linux/vhost.h> > #include <linux/list.h> > > +#include <sys/eventfd.h> > + > void virtio_vhost_init(struct kvm *kvm, int vhost_fd) > { > struct kvm_mem_bank *bank; > @@ -79,3 +82,35 @@ void virtio_vhost_set_vring_kick(struct kvm *kvm, int vhost_fd, > if (r < 0) > die_perror("VHOST_SET_VRING_KICK failed"); > } > + > +void virtio_vhost_set_vring_call(struct kvm *kvm, int vhost_fd, u32 index, > + u32 gsi, struct virt_queue *queue) > +{ > + int r; > + struct vhost_vring_file file = { > + .index = index, > + .fd = eventfd(0, 0), > + }; > + > + r = irq__add_irqfd(kvm, gsi, file.fd, -1); > + if (r < 0) > + die_perror("KVM_IRQFD failed"); > + > + r = ioctl(vhost_fd, VHOST_SET_VRING_CALL, &file); > + if (r < 0) > + die_perror("VHOST_SET_VRING_CALL failed"); > + > + queue->irqfd = file.fd; > + queue->gsi = gsi; > +} > + > +void virtio_vhost_reset_vring(struct kvm *kvm, int vhost_fd, u32 index, > + struct virt_queue *queue) > + > +{ > + if (queue->gsi) { > + irq__del_irqfd(kvm, queue->gsi, queue->irqfd); > + close(queue->irqfd); > + queue->gsi = queue->irqfd = 0; > + } > +} > diff --git a/virtio/vsock.c b/virtio/vsock.c > index 0ada9e09..559fbaba 100644 > --- a/virtio/vsock.c > +++ b/virtio/vsock.c > @@ -131,33 +131,13 @@ static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) > > static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) > { > - struct vhost_vring_file file; > struct vsock_dev *vdev = dev; > - struct kvm_irqfd irq; > - int r; > - > - if (vdev->vhost_fd == -1) > - return; > > - if (is_event_vq(vq)) > + if (vdev->vhost_fd == -1 || is_event_vq(vq)) > return; > > - irq = (struct kvm_irqfd) { > - .gsi = gsi, > - .fd = eventfd(0, 0), > - }; > - file = (struct vhost_vring_file) { > - .index = vq, > - .fd = irq.fd, > - }; > - > - r = ioctl(kvm->vm_fd, KVM_IRQFD, &irq); > - if (r < 0) > - die_perror("KVM_IRQFD failed"); > - > - r = ioctl(vdev->vhost_fd, VHOST_SET_VRING_CALL, &file); > - if (r < 0) > - die_perror("VHOST_SET_VRING_CALL failed"); > + virtio_vhost_set_vring_call(kvm, vdev->vhost_fd, vq, gsi, > + &vdev->vqs[vq]); > } > > static unsigned int get_vq_count(struct kvm *kvm, void *dev)
On Thu, Apr 20, 2023 at 03:52:49PM +0100, Andre Przywara wrote: > > struct net_dev { > > @@ -647,11 +644,7 @@ static void exit_vq(struct kvm *kvm, void *dev, u32 vq) > > struct net_dev *ndev = dev; > > struct net_dev_queue *queue = &ndev->queues[vq]; > > > > - if (!is_ctrl_vq(ndev, vq) && queue->gsi) { > > So this first condition here seems to be lost in the transformation. Is > or was that never needed? Hm, good question. The theory is that it was never needed, because the control virtqueue is owned by kvmtool and not vhost, so we never set queue->gsi for the control queue, in which case virtio_vhost_reset_vring() is a nop. However in net, notify_vq_gsi() doesn't actually check which vq this is, and does set queue->gsi for the control queue. It's a bug but hasn't caused trouble so far because the Linux guest doesn't setup MSIs for the control queue (it polls the queue until the command completes). I'll add a check to notify_vq_gsi(). > Apart from that the changes look fine. > Thanks for reviewing this! Jean
diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h index 4a364a02..96c7b3ea 100644 --- a/include/kvm/virtio.h +++ b/include/kvm/virtio.h @@ -77,6 +77,10 @@ struct virt_queue { u16 endian; bool use_event_idx; bool enabled; + + /* vhost IRQ handling */ + int gsi; + int irqfd; }; /* @@ -252,6 +256,10 @@ void virtio_vhost_set_vring(struct kvm *kvm, int vhost_fd, u32 index, struct virt_queue *queue); void virtio_vhost_set_vring_kick(struct kvm *kvm, int vhost_fd, u32 index, int event_fd); +void virtio_vhost_set_vring_call(struct kvm *kvm, int vhost_fd, u32 index, + u32 gsi, struct virt_queue *queue); +void virtio_vhost_reset_vring(struct kvm *kvm, int vhost_fd, u32 index, + struct virt_queue *queue); int virtio_transport_parser(const struct option *opt, const char *arg, int unset); diff --git a/virtio/net.c b/virtio/net.c index b935d24f..519dcbb7 100644 --- a/virtio/net.c +++ b/virtio/net.c @@ -4,12 +4,12 @@ #include "kvm/mutex.h" #include "kvm/util.h" #include "kvm/kvm.h" -#include "kvm/irq.h" #include "kvm/uip.h" #include "kvm/guest_compat.h" #include "kvm/iovec.h" #include "kvm/strbuf.h" +#include <linux/list.h> #include <linux/vhost.h> #include <linux/virtio_net.h> #include <linux/if_tun.h> @@ -25,7 +25,6 @@ #include <sys/ioctl.h> #include <sys/types.h> #include <sys/wait.h> -#include <sys/eventfd.h> #define VIRTIO_NET_QUEUE_SIZE 256 #define VIRTIO_NET_NUM_QUEUES 8 @@ -44,8 +43,6 @@ struct net_dev_queue { pthread_t thread; struct mutex lock; pthread_cond_t cond; - int gsi; - int irqfd; }; struct net_dev { @@ -647,11 +644,7 @@ static void exit_vq(struct kvm *kvm, void *dev, u32 vq) struct net_dev *ndev = dev; struct net_dev_queue *queue = &ndev->queues[vq]; - if (!is_ctrl_vq(ndev, vq) && queue->gsi) { - irq__del_irqfd(kvm, queue->gsi, queue->irqfd); - close(queue->irqfd); - queue->gsi = queue->irqfd = 0; - } + virtio_vhost_reset_vring(kvm, ndev->vhost_fd, vq, &queue->vq); /* * TODO: vhost reset owner. It's the only way to cleanly stop vhost, but @@ -675,27 +668,12 @@ static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) { struct net_dev *ndev = dev; struct net_dev_queue *queue = &ndev->queues[vq]; - struct vhost_vring_file file; - int r; if (ndev->vhost_fd == 0) return; - file = (struct vhost_vring_file) { - .index = vq, - .fd = eventfd(0, 0), - }; - - r = irq__add_irqfd(kvm, gsi, file.fd, -1); - if (r < 0) - die_perror("KVM_IRQFD failed"); - - queue->irqfd = file.fd; - queue->gsi = gsi; - - r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_CALL, &file); - if (r < 0) - die_perror("VHOST_SET_VRING_CALL failed"); + virtio_vhost_set_vring_call(kvm, ndev->vhost_fd, vq, gsi, + &queue->vq); } static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd) diff --git a/virtio/scsi.c b/virtio/scsi.c index 1f757404..29acf57c 100644 --- a/virtio/scsi.c +++ b/virtio/scsi.c @@ -92,25 +92,14 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq) static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) { - struct vhost_vring_file file; struct scsi_dev *sdev = dev; int r; if (sdev->vhost_fd == 0) return; - file = (struct vhost_vring_file) { - .index = vq, - .fd = eventfd(0, 0), - }; - - r = irq__add_irqfd(kvm, gsi, file.fd, -1); - if (r < 0) - die_perror("KVM_IRQFD failed"); - - r = ioctl(sdev->vhost_fd, VHOST_SET_VRING_CALL, &file); - if (r < 0) - die_perror("VHOST_SET_VRING_CALL failed"); + virtio_vhost_set_vring_call(kvm, sdev->vhost_fd, vq, gsi, + &sdev->vqs[vq]); if (vq > 0) return; diff --git a/virtio/vhost.c b/virtio/vhost.c index 3acfd30a..cd83645c 100644 --- a/virtio/vhost.c +++ b/virtio/vhost.c @@ -1,9 +1,12 @@ +#include "kvm/irq.h" #include "kvm/virtio.h" #include <linux/kvm.h> #include <linux/vhost.h> #include <linux/list.h> +#include <sys/eventfd.h> + void virtio_vhost_init(struct kvm *kvm, int vhost_fd) { struct kvm_mem_bank *bank; @@ -79,3 +82,35 @@ void virtio_vhost_set_vring_kick(struct kvm *kvm, int vhost_fd, if (r < 0) die_perror("VHOST_SET_VRING_KICK failed"); } + +void virtio_vhost_set_vring_call(struct kvm *kvm, int vhost_fd, u32 index, + u32 gsi, struct virt_queue *queue) +{ + int r; + struct vhost_vring_file file = { + .index = index, + .fd = eventfd(0, 0), + }; + + r = irq__add_irqfd(kvm, gsi, file.fd, -1); + if (r < 0) + die_perror("KVM_IRQFD failed"); + + r = ioctl(vhost_fd, VHOST_SET_VRING_CALL, &file); + if (r < 0) + die_perror("VHOST_SET_VRING_CALL failed"); + + queue->irqfd = file.fd; + queue->gsi = gsi; +} + +void virtio_vhost_reset_vring(struct kvm *kvm, int vhost_fd, u32 index, + struct virt_queue *queue) + +{ + if (queue->gsi) { + irq__del_irqfd(kvm, queue->gsi, queue->irqfd); + close(queue->irqfd); + queue->gsi = queue->irqfd = 0; + } +} diff --git a/virtio/vsock.c b/virtio/vsock.c index 0ada9e09..559fbaba 100644 --- a/virtio/vsock.c +++ b/virtio/vsock.c @@ -131,33 +131,13 @@ static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) { - struct vhost_vring_file file; struct vsock_dev *vdev = dev; - struct kvm_irqfd irq; - int r; - - if (vdev->vhost_fd == -1) - return; - if (is_event_vq(vq)) + if (vdev->vhost_fd == -1 || is_event_vq(vq)) return; - irq = (struct kvm_irqfd) { - .gsi = gsi, - .fd = eventfd(0, 0), - }; - file = (struct vhost_vring_file) { - .index = vq, - .fd = irq.fd, - }; - - r = ioctl(kvm->vm_fd, KVM_IRQFD, &irq); - if (r < 0) - die_perror("KVM_IRQFD failed"); - - r = ioctl(vdev->vhost_fd, VHOST_SET_VRING_CALL, &file); - if (r < 0) - die_perror("VHOST_SET_VRING_CALL failed"); + virtio_vhost_set_vring_call(kvm, vdev->vhost_fd, vq, gsi, + &vdev->vqs[vq]); } static unsigned int get_vq_count(struct kvm *kvm, void *dev)
All vhost devices should perform the same operations when initializing the IRQFD. Move it to virtio/vhost.c This fixes vsock, which didn't go through the irq__add_irqfd() helper and couldn't be used on systems that require GSI translation (GICv2m). Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org> --- include/kvm/virtio.h | 8 ++++++++ virtio/net.c | 30 ++++-------------------------- virtio/scsi.c | 15 ++------------- virtio/vhost.c | 35 +++++++++++++++++++++++++++++++++++ virtio/vsock.c | 26 +++----------------------- 5 files changed, 52 insertions(+), 62 deletions(-)