[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH for stable 3.10] xen-netback: drop SKB from internal queue if frontend is disconnected



In 88a810def7 ("xen-netback: fix refcnt unbalance for 3.10"), we moved
the ref counting code from xenvif_disconnect to xenvif_free.

It can occur that frontend is disconnected while there's still SKB
stuck in netback's rx_queue in rare case. When netback thread wakes up,
it will try to write to an already unmapped ring, resulting in kernel
oops.

Moving the ref counting back to xenvif_disconnect isn't an option as it
reintroduces an old bug. Further more, writing into a dead frontend's
ring and memory is just wrong. Dropping those SKBs seems to be a good
strategy.

This patch fixes that corner case: introduce a flag to indicate whether
frontend ring is mapped. If the ring is unmapped, just drop those SKBs.

This bug only manifests in 3.10 kernel. Kernel >=3.12 doesn't have it.

Reported-by: Philipp Hahn <hahn@xxxxxxxxxxxxx>
Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx>
Signed-off-by: Philipp Hahn <hahn@xxxxxxxxxxxxx>
Tested-by: Philipp Hahn <hahn@xxxxxxxxxxxxx>
Cc: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
 drivers/net/xen-netback/common.h    |    1 +
 drivers/net/xen-netback/interface.c |    1 +
 drivers/net/xen-netback/netback.c   |   13 +++++++++++++
 3 files changed, 15 insertions(+)

diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index f2faa77..3418215 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -66,6 +66,7 @@ struct xenvif {
        /* The shared rings and indexes. */
        struct xen_netif_tx_back_ring tx;
        struct xen_netif_rx_back_ring rx;
+       bool ring_mapped;
 
        /* Frontend feature information. */
        u8 can_sg:1;
diff --git a/drivers/net/xen-netback/interface.c 
b/drivers/net/xen-netback/interface.c
index 540a796..cfdff0d 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -271,6 +271,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t 
domid,
        vif->dev = dev;
        INIT_LIST_HEAD(&vif->schedule_list);
        INIT_LIST_HEAD(&vif->notify_list);
+       vif->ring_mapped = false;
 
        vif->credit_bytes = vif->remaining_credit = ~0UL;
        vif->credit_usec  = 0UL;
diff --git a/drivers/net/xen-netback/netback.c 
b/drivers/net/xen-netback/netback.c
index 70b830f..aa3f0de 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -720,6 +720,16 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk)
                vif = netdev_priv(skb->dev);
                nr_frags = skb_shinfo(skb)->nr_frags;
 
+               /* In rare case that frontend is disconnected while
+                * there's still SKBs stuck in netback internal
+                * rx_queue, drop these SKBs.
+                */
+               if (unlikely(!vif->ring_mapped)) {
+                       dev_kfree_skb(skb);
+                       xenvif_put(vif);
+                       continue;
+               }
+
                sco = (struct skb_cb_overlay *)skb->cb;
                sco->meta_slots_used = netbk_gop_skb(skb, &npo);
 
@@ -1864,6 +1874,8 @@ static int xen_netbk_kthread(void *data)
 
 void xen_netbk_unmap_frontend_rings(struct xenvif *vif)
 {
+       vif->ring_mapped = false;
+
        if (vif->tx.sring)
                xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif),
                                        vif->tx.sring);
@@ -1899,6 +1911,7 @@ int xen_netbk_map_frontend_rings(struct xenvif *vif,
        BACK_RING_INIT(&vif->rx, rxs, PAGE_SIZE);
 
        vif->rx_req_cons_peek = 0;
+       vif->ring_mapped = true;
 
        return 0;
 
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.