Grab device locks when moving data through network devices in the host->guest direction.
Index: kvm-userspace.io/qemu/hw/e1000.c =================================================================== --- kvm-userspace.io.orig/qemu/hw/e1000.c +++ kvm-userspace.io/qemu/hw/e1000.c @@ -1008,6 +1008,7 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, d->vc = qemu_new_vlan_client(nd->vlan, e1000_receive, e1000_can_receive, d); + d->vc->qemu_dev = &d->dev.qemu_dev; snprintf(d->vc->info_str, sizeof(d->vc->info_str), "%s macaddr=%02x:%02x:%02x:%02x:%02x:%02x", info_str, Index: kvm-userspace.io/qemu/net.h =================================================================== --- kvm-userspace.io.orig/qemu/net.h +++ kvm-userspace.io/qemu/net.h @@ -13,6 +13,7 @@ struct VLANClientState { void *opaque; struct VLANClientState *next; struct VLANState *vlan; + QEMUDevice *qemu_dev; char info_str[256]; }; Index: kvm-userspace.io/qemu/qemu-device.h =================================================================== --- kvm-userspace.io.orig/qemu/qemu-device.h +++ kvm-userspace.io/qemu/qemu-device.h @@ -88,6 +88,8 @@ static inline void qemu_mutex_init(qemu_ #endif /* DEBUG_PTHREADS */ #endif /* _POSIX_THREADS */ +#define NOLOCK -1 + struct QEMUDevice { qemu_mutex_t lock; }; Index: kvm-userspace.io/qemu/vl.c =================================================================== --- kvm-userspace.io.orig/qemu/vl.c +++ kvm-userspace.io/qemu/vl.c @@ -3830,6 +3830,18 @@ VLANClientState *qemu_new_vlan_client(VL return vc; } +void qemu_net_lock(VLANClientState *vc) +{ + if (vc->qemu_dev != NOLOCK) + qemu_mutex_lock(&vc->qemu_dev->lock); +} + +void qemu_net_unlock(VLANClientState *vc) +{ + if (vc->qemu_dev != NOLOCK) + qemu_mutex_unlock(&vc->qemu_dev->lock); +} + int qemu_can_send_packet(VLANClientState *vc1) { VLANState *vlan = vc1->vlan; @@ -3855,7 +3867,9 @@ void qemu_send_packet(VLANClientState *v #endif for(vc = vlan->first_client; vc != NULL; vc = vc->next) { if (vc != vc1) { + qemu_net_lock(vc); vc->fd_read(vc->opaque, buf, size); + qemu_net_unlock(vc); } } } @@ -4131,6 +4145,7 @@ static TAPState *net_tap_fd_init(VLANSta s->no_poll = 0; enable_sigio_timer(fd); s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s); + s->vc->qemu_dev = NOLOCK; qemu_set_fd_handler2(s->fd, tap_read_poll, tap_send, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd); return s; Index: kvm-userspace.io/qemu/hw/virtio-net.c =================================================================== --- kvm-userspace.io.orig/qemu/hw/virtio-net.c +++ kvm-userspace.io/qemu/hw/virtio-net.c @@ -64,7 +64,6 @@ typedef struct VirtIONet int can_receive; int tap_fd; struct VirtIONet *next; - int do_notify; QEMUTimer *tx_timer; int tx_timer_active; } VirtIONet; @@ -113,6 +112,8 @@ static void virtio_net_receive(void *opa struct virtio_net_hdr *hdr; int offset, i; + assert_is_locked(&n->vdev.pci_dev.qemu_dev.lock); + /* FIXME: the drivers really need to set their status better */ if (n->rx_vq->vring.avail == NULL) { n->can_receive = 0; @@ -144,6 +145,18 @@ static void virtio_net_receive(void *opa virtio_notify(&n->vdev, n->rx_vq); } + +void virtio_net_lock(VirtIONet *vnet) +{ + qemu_mutex_lock(&vnet->vdev.pci_dev.qemu_dev.lock); +} + +void virtio_net_unlock(VirtIONet *vnet) +{ + qemu_mutex_unlock(&vnet->vdev.pci_dev.qemu_dev.lock); +} + + /* -net tap receive handler */ void virtio_net_poll(void) { @@ -160,31 +173,39 @@ void virtio_net_poll(void) tv.tv_sec = 0; tv.tv_usec = 0; - while (1) { + do { + did_notify = 0; // Prepare the set of device to select from for (vnet = VirtIONetHead; vnet; vnet = vnet->next) { + int ret; if (vnet->tap_fd == -1) continue; - vnet->do_notify = 0; + virtio_net_lock(vnet); //first check if the driver is ok - if (!virtio_net_can_receive(vnet)) + ret = virtio_net_can_receive(vnet); + if (!ret) { + virtio_net_unlock(vnet); continue; + } /* FIXME: the drivers really need to set their status better */ if (vnet->rx_vq->vring.avail == NULL) { vnet->can_receive = 0; + virtio_net_unlock(vnet); continue; } + virtio_net_unlock(vnet); + FD_SET(vnet->tap_fd, &rfds); if (max_fd < vnet->tap_fd) max_fd = vnet->tap_fd; } if (select(max_fd + 1, &rfds, NULL, NULL, &tv) <= 0) - break; + return; // Now check who has data pending in the tap for (vnet = VirtIONetHead; vnet; vnet = vnet->next) { @@ -192,14 +213,17 @@ void virtio_net_poll(void) if (!FD_ISSET(vnet->tap_fd, &rfds)) continue; + virtio_net_lock(vnet); if (virtqueue_pop(vnet->rx_vq, &elem) == 0) { vnet->can_receive = 0; + virtio_net_unlock(vnet); continue; } hdr = (void *)elem.in_sg[0].iov_base; hdr->flags = 0; hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE; + virtio_net_unlock(vnet); again: len = readv(vnet->tap_fd, &elem.in_sg[1], elem.in_num - 1); if (len == -1) { @@ -208,21 +232,13 @@ again: else fprintf(stderr, "reading network error %d", len); } + did_notify = 1; + virtio_net_lock(vnet); virtqueue_push(vnet->rx_vq, &elem, sizeof(*hdr) + len); - vnet->do_notify = 1; + virtio_notify(&vnet->vdev, vnet->rx_vq); + virtio_net_unlock(vnet); } - - /* signal other side */ - did_notify = 0; - for (vnet = VirtIONetHead; vnet; vnet = vnet->next) - if (vnet->do_notify) { - virtio_notify(&vnet->vdev, vnet->rx_vq); - did_notify++; - } - if (!did_notify) - break; - } - + } while (did_notify); } /* TX */ @@ -231,6 +247,8 @@ static void virtio_net_flush_tx(VirtIONe VirtQueueElement elem; int count = 0; + assert_is_locked(&n->vdev.pci_dev.qemu_dev.lock); + if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) return; @@ -280,8 +298,10 @@ static void virtio_net_tx_timer(void *op if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) return; + virtio_net_lock(n); n->tx_vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY; virtio_net_flush_tx(n, n->tx_vq); + virtio_net_unlock(n); } PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) -- ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel