/* The shared rings and indexes. */
struct xen_netif_tx_back_ring tx;
struct xen_netif_rx_back_ring rx;
+ atomic_t ring_refcnt;
+ wait_queue_head_t waiting_to_unmap;
/* Frontend feature information. */
u8 can_sg:1;
void xenvif_get(struct xenvif *vif);
void xenvif_put(struct xenvif *vif);
+void xenvif_get_rings(struct xenvif *vif);
+void xenvif_put_rings(struct xenvif *vif);
int xenvif_xenbus_init(void);
atomic_inc(&vif->refcnt);
}
+void xenvif_get_rings(struct xenvif *vif)
+{
+ atomic_inc(&vif->ring_refcnt);
+}
+
void xenvif_put(struct xenvif *vif)
{
if (atomic_dec_and_test(&vif->refcnt))
wake_up(&vif->waiting_to_free);
}
+void xenvif_put_rings(struct xenvif *vif)
+{
+ if (atomic_dec_and_test(&vif->ring_refcnt))
+ wake_up(&vif->waiting_to_unmap);
+}
+
int xenvif_schedulable(struct xenvif *vif)
{
return netif_running(vif->dev) && netif_carrier_ok(vif->dev);
/* Reserve ring slots for the worst-case number of fragments. */
vif->rx_req_cons_peek += xen_netbk_count_skb_slots(vif, skb);
xenvif_get(vif);
+ xenvif_get_rings(vif);
if (vif->can_queue && xen_netbk_must_stop_queue(vif))
netif_stop_queue(dev);
vif->dev = dev;
INIT_LIST_HEAD(&vif->schedule_list);
INIT_LIST_HEAD(&vif->notify_list);
+ init_waitqueue_head(&vif->waiting_to_unmap);
vif->credit_bytes = vif->remaining_credit = ~0UL;
vif->credit_usec = 0UL;
if (netif_carrier_ok(vif->dev))
xenvif_carrier_off(vif);
+ disable_irq(vif->irq);
+ xen_netbk_unmap_frontend_rings(vif);
if (vif->irq) {
unbind_from_irqhandler(vif->irq, vif);
vif->irq = 0;
}
-
- xen_netbk_unmap_frontend_rings(vif);
}
void xenvif_free(struct xenvif *vif)
xenvif_put(vif);
npo.meta_cons += sco->meta_slots_used;
dev_kfree_skb(skb);
+ xenvif_put_rings(vif);
}
list_for_each_entry_safe(vif, tmp, ¬ify, notify_list) {
void xen_netbk_unmap_frontend_rings(struct xenvif *vif)
{
+ atomic_dec(&vif->ring_refcnt);
+ wait_event(vif->waiting_to_unmap, atomic_read(&vif->ring_refcnt) == 0);
+
if (vif->tx.sring)
xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif),
vif->tx.sring);
int err = -ENOMEM;
+ atomic_set(&vif->ring_refcnt, 1);
+
err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif),
tx_ring_ref, &addr);
if (err)