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

Reply via email to