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
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel