VirtualBox

Ignore:
Timestamp:
Sep 23, 2010 11:44:42 AM (14 years ago)
Author:
vboxsync
Message:

Solaris/VBoxNetFlt: fix deadlock with PromiscReq and ModWritePut (#5262)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFlt-solaris.c

    r31847 r32710  
    216216    ddi_prop_op,                    /* property ops */
    217217    &g_VBoxNetFltSolarisStreamTab,
    218     D_NEW | D_MP | D_MTQPAIR,      /* compat. flag */
     218    D_NEW | D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL, /* compat. flag */
    219219    CB_REV                          /* revision */
    220220};
     
    255255    DEVICE_NAME,
    256256    &g_VBoxNetFltSolarisStreamTab,
    257     D_NEW | D_MP | D_MTQPAIR
     257    D_NEW | D_MP | D_MTQPAIR | D_MTOUTPERIM | D_MTOCEXCL
    258258};
    259259
     
    344344#endif
    345345    size_t cLoopback;                     /* loopback queue size list */
    346     timeout_id_t TimeoutId;               /* timeout id of promisc. req */
     346    timeout_id_t volatile TimeoutId;      /* timeout id of promisc. req */
    347347    PVBOXNETFLTPACKETID pHead;            /* loopback packet identifier head */
    348348    PVBOXNETFLTPACKETID pTail;            /* loopback packet identifier tail */
     
    897897    if (pStream->Type == kPromiscStream)
    898898    {
     899        /*
     900         * If there are any timeout scheduled, we need to make sure they are cancelled.
     901         */
     902        vboxnetflt_promisc_stream_t *pPromiscStream = (vboxnetflt_promisc_stream_t *)pStream;
     903        timeout_id_t TimeoutId = ASMAtomicReadPtr(&pPromiscStream->TimeoutId);
     904        if (TimeoutId)
     905        {
     906            quntimeout(WR(pPromiscStream->Stream.pReadQueue), TimeoutId);
     907            ASMAtomicWritePtr(&pPromiscStream->TimeoutId, NULL);
     908        }
     909
    899910        flushq(pQueue, FLUSHALL);
    900911        flushq(WR(pQueue), FLUSHALL);
     
    12991310
    13001311/**
    1301  * Send fake promiscous mode requests downstream.
    1302  *
    1303  * @param   pQueue          Pointer to the read queue.
    1304  * @param   fPromisc        Whether to enable promiscous mode or not.
    1305  * @param   PromiscLevel    Promiscous level; DL_PROMISC_PHYS/SAP/MULTI.
     1312 * Callback function for qwriter to send promiscuous request messages
     1313 * downstream.
     1314 *
     1315 * @param   pQueue          Pointer to the write queue.
     1316 * @param   fPromisc        Whether to send promiscuous ON or OFF requests.
    13061317 *
    13071318 * @returns VBox status code.
     
    13461357    }
    13471358
    1348     qreply(pQueue, pPromiscPhysMsg);
    1349     qreply(pQueue, pPromiscSapMsg);
     1359    putnext(pQueue, pPromiscPhysMsg);
     1360    putnext(pQueue, pPromiscSapMsg);
    13501361
    13511362    return VINF_SUCCESS;
     
    13531364
    13541365
    1355 /*
    1356  * Callback wrapper for qtimeout to safely send promiscuous off request.
    1357  *
    1358  * @param   pvData      Pointer to a vboxnetflt_promisc_params_t structure, will be freed by us.
     1366/**
     1367 * Callback wrapper for qwriter() to safely send promiscuous requests. This is
     1368 * called at the outer perimeter with exclusive lock held.
     1369 *
     1370 * @param pQueue            Pointer to the write queue.
     1371 * @param pMsg              A one byte message indicates a Promisc ON, otherwise
     1372 *                          a promiscuous OFF request. See
     1373 *                          vboxNetFltSolarisPromiscReqWrap().
     1374 */
     1375static void vboxNetFltSolarisPromiscReqWrapExcl(queue_t *pQueue, mblk_t *pMsg)
     1376{
     1377    /*
     1378     * Paranoia.
     1379     */
     1380    AssertReturnVoid(pQueue);
     1381    if (RT_UNLIKELY(!pMsg))
     1382        LogRel((DEVICE_NAME ":VBoxNetFltSolarisPromiscReqWrapExcl pQueue=%p missing message!\n", pQueue));
     1383
     1384    bool fPromisc = (MBLKL(pMsg) == 1);
     1385    freemsg(pMsg);
     1386    pMsg = NULL;
     1387    int rc = vboxNetFltSolarisPromiscReq(pQueue, fPromisc);
     1388    if (RT_FAILURE(rc))
     1389        LogRel((DEVICE_NAME ":VBoxNetFltSolarisPromiscReqWrapExcl vboxNetFltSolarisPromiscReq failed. rc=%d\n", rc));
     1390    else
     1391        LogRel((DEVICE_NAME ":VBoxNetFltSolarisPromiscReqWrapExcl success fPromisc=%d\n", fPromisc));
     1392}
     1393
     1394
     1395/**
     1396 * Callback wrapper for qtimeout() to safely send promiscuous requests. This is
     1397 * called at the inner perimenter with shared lock.
     1398 *
     1399 * @param pvData            Pointer to vboxnetflt_promisc_params_t. See
     1400 *                          vboxNetFltPortOsSetActive().
    13591401 */
    13601402static void vboxNetFltSolarisPromiscReqWrap(void *pvData)
     
    13681410            && pPromiscStream->Stream.pReadQueue)
    13691411        {
    1370             pPromiscStream->TimeoutId = 0;
    1371             vboxNetFltSolarisPromiscReq(pPromiscStream->Stream.pReadQueue, pParams->fPromiscOn);
     1412            /*
     1413             * Use size of message to indicate to qwriter callback whether it must send
     1414             * promiscuous On or Off messages. This is ugly but easier and more efficient than
     1415             * scheduling two separate qwriter callbacks with prepared messages to putnext.
     1416             */
     1417            size_t cbMsg = pParams->fPromiscOn ? 1 : 2;
     1418            mblk_t *pMsg = allocb(cbMsg, BPRI_HI);
     1419            if (RT_UNLIKELY(!pMsg))
     1420            {
     1421                LogRel((DEVICE_NAME ":Failed to alloc message of %u bytes\n", cbMsg));
     1422                return;
     1423            }
     1424
     1425            /*
     1426             * Move the data pointer so we can use MBLKL, as MBLKSIZE gets the db_lim which is
     1427             * always aligned.
     1428             */
     1429            pMsg->b_wptr += cbMsg;
     1430
     1431            /*
     1432             * Upgrade inner perimeter lock to exclusive outer perimeter lock and
     1433             * then call putnext while we are at the outer perimeter.
     1434             */
     1435            qwriter(WR(pPromiscStream->Stream.pReadQueue), pMsg, vboxNetFltSolarisPromiscReqWrapExcl, PERIM_OUTER);
     1436            ASMAtomicWritePtr(&pPromiscStream->TimeoutId, NULL);
    13721437        }
    13731438        RTMemFree(pParams);
     
    20222087    if (pThis->u.s.hIface)
    20232088    {
    2024         /*
    2025          * If there are any timeout scheduled, we need to make sure they are cancelled.
    2026          */
    2027         vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream, vboxnetflt_promisc_stream_t *);
    2028         if (   pPromiscStream
    2029             && pPromiscStream->TimeoutId)
    2030         {
    2031             quntimeout(WR(pPromiscStream->Stream.pReadQueue), pPromiscStream->TimeoutId);
    2032         }
    2033 
    20342089        ldi_close(pThis->u.s.hIface, FREAD | FWRITE, kcred);
    20352090        pThis->u.s.hIface = NULL;
     
    36233678    if (RT_LIKELY(pData))
    36243679    {
     3680        /*
     3681         * See #5262 as to why we need to do all this qtimeout/qwriter tricks.
     3682         */
    36253683        vboxnetflt_promisc_stream_t *pPromiscStream = ASMAtomicUoReadPtrT(&pThis->u.s.pPromiscStream, vboxnetflt_promisc_stream_t *);
    36263684        if (   pPromiscStream
     
    36293687            pData->pThis      = pThis;
    36303688            pData->fPromiscOn = fActive;
    3631             if (pPromiscStream->TimeoutId != 0)
     3689            if (ASMAtomicReadPtr(&pPromiscStream->TimeoutId))
    36323690                quntimeout(WR(pPromiscStream->Stream.pReadQueue), pPromiscStream->TimeoutId);
    3633             pPromiscStream->TimeoutId = qtimeout(WR(pPromiscStream->Stream.pReadQueue), vboxNetFltSolarisPromiscReqWrap, pData, 1 /* ticks */);
    3634             return;
    3635         }
     3691            timeout_id_t TimeoutId = qtimeout(WR(pPromiscStream->Stream.pReadQueue), vboxNetFltSolarisPromiscReqWrap, pData, 1 /* ticks */);
     3692            ASMAtomicWritePtr(&pPromiscStream->TimeoutId, TimeoutId);
     3693            return; /* pData will be freed by vboxNetFltSolarisPromiscReqWrap() */
     3694        }
     3695        else
     3696            LogRel((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d missing stream!\n", pThis, fActive));
    36363697        RTMemFree(pData);
    36373698    }
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette