Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 28 Sep 2009 22:47:50 +0200
From:      Fredrik Lindberg <fli@shapeshifter.se>
To:        "Sean C. Farley" <scf@FreeBSD.org>
Cc:        freebsd-emulation@FreeBSD.org
Subject:   Re: Panic with vboxnet drivers
Message-ID:  <4AC120F6.7090701@shapeshifter.se>
In-Reply-To: <alpine.BSF.2.00.0909221337580.13791@thor.farley.org>
References:  <alpine.BSF.2.00.0909221337580.13791@thor.farley.org>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------090600080206040601090501
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Sean C. Farley wrote:
> While I have had no trouble with two systems running with the tap patch, 
> I am experiencing some lockups when using the vboxnet* drivers.
> 

Sorry about the late response.

> I have five witness logs (attached):
> 1. The first one appeared when I tried to run VirtualBox with vboxnetadp
>    loaded via loader.conf.  VirtualBox will not be able to find the
>    VirtualBox network drivers this way, so I unloaded and loaded
>    vboxnetadp from the command line for the following logs.

Need to look a bit more on this one.

> 2. The next three logs are LOR's (sleepable after non-sleepable)
>    concerning VirtualBox's "IPRT Fast Mutex Semaphore" which is an sx.
>    I am not sure I am reading the backtrace correctly.  It looks like
>    the call to RTSemFastMutexRequest(), which calls sx_xlock(), is the
>    effect.  I just do not know where the cause, i.e.,
>    RTSemFastMutexRequest(), is being called.

Yeah, this was a real one. The call to RTSemFastMutexRequest is inside
the virtual ethernet switch.  I've attached a patch that defers
processing to avoid the sleepable after non-sleepable case.
Hopefully this fixes the panic you're seeing as well.

Fredrik




--------------090600080206040601090501
Content-Type: text/plain;
 name="vboxnetflt-locking.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="vboxnetflt-locking.patch"

Index: src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c	(revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/freebsd/VBoxNetFlt-freebsd.c	(working copy)
@@ -43,6 +43,8 @@
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/syscallsubr.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
 
 #include <net/if.h>
 #include <net/if_var.h>
@@ -78,8 +80,6 @@
 static ng_rcvdata_t    ng_vboxnetflt_rcvdata;
 static ng_disconnect_t    ng_vboxnetflt_disconnect;
 static int        ng_vboxnetflt_mod_event(module_t mod, int event, void *data);
-static int        ng_vboxnetflt_rcv_in(hook_p node, item_p item);
-static int        ng_vboxnetflt_rcv_out(hook_p node, item_p item);
 
 /** Netgraph node type */
 #define NG_VBOXNETFLT_NODE_TYPE    "vboxnetflt"
@@ -112,8 +112,8 @@
 {
     .version =    NG_ABI_VERSION,
     .name =        NG_VBOXNETFLT_NODE_TYPE,
-    .mod_event =    vboxnetflt_modevent,    
-    .constructor =    ng_vboxnetflt_constructor,    
+    .mod_event =    vboxnetflt_modevent,
+    .constructor =    ng_vboxnetflt_constructor,
     .rcvmsg =     ng_vboxnetflt_rcvmsg,
     .shutdown =    ng_vboxnetflt_shutdown,
     .newhook =    ng_vboxnetflt_newhook,
@@ -267,16 +267,12 @@
     if (strcmp(name, NG_VBOXNETFLT_HOOK_IN) == 0)
     {
 #if __FreeBSD_version >= 800000
-        NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_in);
         NG_HOOK_SET_TO_INBOUND(hook);
 #endif
         pThis->u.s.input = hook;
     }
     else if (strcmp(name, NG_VBOXNETFLT_HOOK_OUT) == 0)
     {
-#if __FreeBSD_version >= 800000
-        NG_HOOK_SET_RCVDATA(hook, ng_vboxnetflt_rcv_out);
-#endif
         pThis->u.s.output = hook;
     }
     else
@@ -310,161 +306,171 @@
 
 /**
  * Handle data on netgraph hooks.
+ * Frames processing is deferred to a taskqueue because this might
+ * be called with non-sleepable locks held and code paths inside
+ * the virtual switch might sleep.
  */
 static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item)
 {
     const node_p node = NG_HOOK_NODE(hook);
     PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+    struct ifnet *ifp = pThis->u.s.ifp;
     struct mbuf *m;
+    struct m_tag *mtag;
+    bool fActive;
 
+    fActive = ASMAtomicUoReadBool(&pThis->fActive);
+
+    NGI_GET_M(item, m);
+    NG_FREE_ITEM(item);
+
+    /* Locate tag to see if processing should be skipped for this frame */
+    mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
+    if (mtag != NULL)
+    {
+        m_tag_unlink(m, mtag);
+        m_tag_free(mtag);
+    }
+
+    /*
+     * Handle incoming hook. This is connected to the
+     * input path of the interface, thus handling incoming frames.
+     */
     if (pThis->u.s.input == hook)
-        return ng_vboxnetflt_rcv_in(hook, item);
+    {
+        if (mtag != NULL || !fActive)
+        {
+            ether_demux(ifp, m);
+            return (0);
+        }
+        mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+        _IF_ENQUEUE(&pThis->u.s.inq, m);
+        mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+        taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin);
+    }
+    /**
+     * Handle mbufs on the outgoing hook, frames going to the interface
+     */
     else if (pThis->u.s.output == hook)
-        return ng_vboxnetflt_rcv_out(hook, item);
+    {
+        if (mtag != NULL || !fActive)
+            return ether_output_frame(ifp, m);
+        mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+        _IF_ENQUEUE(&pThis->u.s.outq, m);
+        mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+        taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout);
+    }
     else
     {
-        NGI_GET_M(item, m);
-        NG_FREE_ITEM(item);
+        m_freem(m);
     }
     return (0);
 }
 
+static int ng_vboxnetflt_shutdown(node_p node)
+{
+    PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
+    bool fActive;
+
+    /* Prevent node shutdown if we're active */
+    fActive = ASMAtomicUoReadBool(&pThis->fActive);
+    if (fActive)
+        return (EBUSY);
+    NG_NODE_UNREF(node);
+    return (0);
+}
+
+static int ng_vboxnetflt_disconnect(hook_p hook)
+{
+    return (0);
+}
+
 /**
- * Handle incoming hook. This is connected to the
- * input path of the interface, thus handling incoming frames.
+ * Input processing task, handles incoming frames
  */
-static int ng_vboxnetflt_rcv_in(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDinput(void *arg, int pending)
 {
+    PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
     struct mbuf *m, *m0;
-    struct m_tag *mtag;
-    const node_p node = NG_HOOK_NODE(hook);
-    PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
     struct ifnet *ifp = pThis->u.s.ifp;
-    bool fActive, fDropIt = false;
     unsigned int cSegs = 0;
+    bool fDropIt = false, fActive;
     PINTNETSG pSG;
 
-    NGI_GET_M(item, m);
-    NG_FREE_ITEM(item);
-
-    fActive = ASMAtomicUoReadBool(&pThis->fActive);
-    if (!fActive)
-        goto out;
-
-    mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
-    if (mtag != NULL)
-    {
-        m_tag_unlink(m, mtag);
-        m_tag_free(mtag);
-        goto out;
-    }
     vboxNetFltRetain(pThis, true /* fBusy */);
-
-    for (m0 = m; m0 != NULL; m0 = m0->m_next)
+    for (;;)
     {
-        if (m0->m_len > 0)
-            cSegs++;
-    }
+        mtx_lock_spin(&pThis->u.s.inq.ifq_mtx);
+        _IF_DEQUEUE(&pThis->u.s.inq, m);
+        mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx);
+        if (m == NULL)
+            break;
 
+        for (m0 = m; m0 != NULL; m0 = m0->m_next)
+            if (m0->m_len > 0)
+                cSegs++;
+
 #ifdef PADD_RUNT_FRAMES_FROM_HOST
-    if (m_length(m, NULL) < 60)
-        cSegs++;
+        if (m_length(m, NULL) < 60)
+            cSegs++;
 #endif
 
-    /* Create a copy of the mbuf and hand it to the virtual switch */
-    pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
-    vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
-    fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_WIRE);
-    RTMemTmpFree(pSG);
+        /* Create a copy and deliver to the virtual switch */
+        pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+        vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+        fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+        RTMemTmpFree(pSG);
+        if (fDropIt)
+            m_freem(m);
+        else
+            ether_demux(ifp, m);
+    }
     vboxNetFltRelease(pThis, true /* fBusy */);
-
-out:
-    /* Only deliver it to the host stack if the destination weren't a guest */
-    if (fDropIt)
-    {
-        m_freem(m);
-        return (0);
-    }
-    ether_demux(ifp, m);
-    return (0);
 }
 
 /**
- * Handle mbufs on the outgoing hook, frames going to the interface
+ * Output processing task, handles outgoing frames
  */
-static int ng_vboxnetflt_rcv_out(hook_p hook, item_p item)
+static void vboxNetFltFreeBSDoutput(void *arg, int pending)
 {
+    PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg;
     struct mbuf *m, *m0;
-    struct m_tag *mtag;
-    const node_p node = NG_HOOK_NODE(hook);
-    PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
     struct ifnet *ifp = pThis->u.s.ifp;
     unsigned int cSegs = 0;
     bool fDropIt = false, fActive;
     PINTNETSG pSG;
 
-    NGI_GET_M(item, m);
-    NG_FREE_ITEM(item);
-
-    fActive = ASMAtomicUoReadBool(&pThis->fActive);
-    if (!fActive)
-        return ether_output_frame(ifp, m);
-
     vboxNetFltRetain(pThis, true /* fBusy */);
-    /* Pass directly to interface if the packet originated from us */
-    mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL);
-    if (mtag != NULL)
+    for (;;)
     {
-        m_tag_unlink(m, mtag);
-        m_tag_free(mtag);
-        goto out;
-    }
+        mtx_lock_spin(&pThis->u.s.outq.ifq_mtx);
+        _IF_DEQUEUE(&pThis->u.s.outq, m);
+        mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx);
+        if (m == NULL)
+            break;
 
-    for (m0 = m; m0 != NULL; m0 = m0->m_next)
-    {
-        if (m0->m_len > 0)
-            cSegs++;
-    }
+        for (m0 = m; m0 != NULL; m0 = m0->m_next)
+            if (m0->m_len > 0)
+                cSegs++;
 
 #ifdef PADD_RUNT_FRAMES_FROM_HOST
-    if (m_length(m, NULL) < 60)
-        cSegs++;
+        if (m_length(m, NULL) < 60)
+            cSegs++;
 #endif
-    /* Create a copy and deliver to the virtual switch */
-    pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
-    vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
-    fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
-    RTMemTmpFree(pSG);
+        /* Create a copy and deliver to the virtual switch */
+        pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
+        vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0);
+        fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+        RTMemTmpFree(pSG);
 
-out:
+        if (fDropIt)
+            m_freem(m);
+        else
+            ether_output_frame(ifp, m);
+    }
     vboxNetFltRelease(pThis, true /* fBusy */);
-    if (fDropIt)
-    {
-        m_freem(m);
-        return (0);
-    }
-
-    return ether_output_frame(ifp, m);
 }
 
-static int ng_vboxnetflt_shutdown(node_p node)
-{
-    PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node);
-    bool fActive;
-
-    /* Prevent node shutdown if we're active */
-    fActive = ASMAtomicUoReadBool(&pThis->fActive);
-    if (fActive)
-        return (EBUSY);
-    NG_NODE_UNREF(node);
-    return (0);
-}
-
-static int ng_vboxnetflt_disconnect(hook_p hook)
-{
-    return (0);
-}
-
 /**
  * Called to deliver a frame to either the host, the wire or both.
  */
@@ -536,13 +542,23 @@
 
     /* Create a new netgraph node for this instance */
     if (ng_make_node_common(&ng_vboxnetflt_typestruct, &node) != 0)
-        return VERR_INTERNAL_ERROR;        
+        return VERR_INTERNAL_ERROR;
 
     RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
     ASMAtomicUoWritePtr((void * volatile *)&pThis->u.s.ifp, ifp);
     pThis->u.s.node = node;
     bcopy(IF_LLADDR(ifp), &pThis->u.s.Mac, ETHER_ADDR_LEN);
     ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+    /* Initialize deferred input queue */
+    bzero(&pThis->u.s.inq, sizeof(struct ifqueue));
+    mtx_init(&pThis->u.s.inq.ifq_mtx, "vboxnetflt inq", NULL, MTX_SPIN);
+    TASK_INIT(&pThis->u.s.tskin, 0, vboxNetFltFreeBSDinput, pThis);
+
+    /* Initialize deferred output queue */
+    bzero(&pThis->u.s.outq, sizeof(struct ifqueue));
+    mtx_init(&pThis->u.s.outq.ifq_mtx, "vboxnetflt outq", NULL, MTX_SPIN);
+    TASK_INIT(&pThis->u.s.tskout, 0, vboxNetFltFreeBSDoutput, pThis);
+
     RTSpinlockRelease(pThis->hSpinlock, &Tmp);
 
     NG_NODE_SET_PRIVATE(node, pThis);
@@ -571,7 +587,10 @@
     }
 
     if (ifp0 != NULL)
+    {
+        vboxNetFltOsDeleteInstance(pThis);
         vboxNetFltOsInitInstance(pThis, NULL);
+    }
 
     return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
 }
@@ -579,6 +598,12 @@
 void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
 {
 
+    taskqueue_drain(taskqueue_fast, &pThis->u.s.tskin);
+    taskqueue_drain(taskqueue_fast, &pThis->u.s.tskout);
+
+    mtx_destroy(&pThis->u.s.inq.ifq_mtx);
+    mtx_destroy(&pThis->u.s.outq.ifq_mtx);
+
     if (pThis->u.s.node != NULL)
         ng_rmnode_self(pThis->u.s.node);
     pThis->u.s.node = NULL;
Index: src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h
===================================================================
--- src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h	(revision 23391)
+++ src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFltInternal.h	(working copy)
@@ -206,6 +206,14 @@
             hook_p output;
             /** Original interface flags */
             unsigned int flags;
+            /** Input queue */
+            struct ifqueue inq;
+            /** Output queue */
+            struct ifqueue outq;
+            /** Input task */
+            struct task tskin;
+            /** Output task */
+            struct task tskout;
             /** The MAC address of the interface. */
             RTMAC Mac;
             /** @} */
@@ -241,6 +249,8 @@
 # endif
 #elif defined(RT_OS_LINUX)
         uint8_t abPadding[320];
+#elif defined(RT_OS_FREEBSD)
+        uint8_t abPadding[256];
 #else
         uint8_t abPadding[128];
 #endif

--------------090600080206040601090501--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4AC120F6.7090701>