VirtualBox

Changeset 62004 in vbox for trunk


Ignore:
Timestamp:
Jul 4, 2016 1:06:44 PM (9 years ago)
Author:
vboxsync
Message:

Storage/iSCSI: Fix possible endless reconnect loop if logging in to the target succeeds but any other requests cause a disconnect. Limit the amount of logins between successful I/O requests to 3, more login attempts are denied and cause the VM to suspend with the apporpriate error about an unrespnsive iSCSI target

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Storage/ISCSI.cpp

    r61978 r62004  
    612612    /** Table of commands waiting for a response from the target. */
    613613    PISCSICMD           aCmdsWaiting[ISCSI_CMD_WAITING_ENTRIES];
     614    /** Number of logins since last successful I/O.
     615     * Used to catch the case where logging succeeds but
     616     * processing read/write/flushes cause a disconnect.
     617     */
     618    volatile uint32_t   cLoginsSinceIo;
    614619
    615620    /** Release log counter. */
     
    12611266
    12621267    Assert(pImage->state == ISCSISTATE_FREE);
     1268
     1269    /*
     1270     * If there were too many logins without any successful I/O just fail
     1271     * and assume the target is not working properly.
     1272     */
     1273    if (ASMAtomicReadU32(&pImage->cLoginsSinceIo) == 3)
     1274        return VERR_BROKEN_PIPE;
    12631275
    12641276    RTSemMutexRequest(pImage->Mutex, RT_INDEFINITE_WAIT);
     
    17131725        pImage->state = ISCSISTATE_NORMAL;
    17141726
     1727    if (RT_SUCCESS(rc))
     1728        ASMAtomicIncU32(&pImage->cLoginsSinceIo);
     1729
    17151730    RTSemMutexRelease(pImage->Mutex);
    17161731
     
    20402055
    20412056out:
     2057    if (RT_SUCCESS(rc))
     2058        ASMAtomicWriteU32(&pImage->cLoginsSinceIo, 0);
    20422059    LogFlowFunc(("returns %Rrc\n", rc));
    20432060    return rc;
     
    32833300
    32843301/**
     3302 * Clears all RX/TX PDU states and returns the command for the current
     3303 * pending TX PDU if existing.
     3304 *
     3305 * @returns Pointer to the iSCSI command for the current PDU transmitted or NULL
     3306 *          if none is waiting.
     3307 * @param   pImage    iSCSI connection state.
     3308 */
     3309static PISCSICMD iscsiPDURxTxClear(PISCSIIMAGE pImage)
     3310{
     3311    PISCSICMD pIScsiCmdHead = NULL;
     3312    PISCSIPDUTX pIScsiPDUTx = NULL;
     3313
     3314    /* Reset PDU we are receiving. */
     3315    iscsiRecvPDUReset(pImage);
     3316
     3317    /*
     3318     * Abort all PDUs we are about to transmit,
     3319     * the command need a new Itt if the relogin is successful.
     3320     */
     3321    while (pImage->pIScsiPDUTxHead)
     3322    {
     3323        pIScsiPDUTx = pImage->pIScsiPDUTxHead;
     3324        pImage->pIScsiPDUTxHead = pIScsiPDUTx->pNext;
     3325
     3326        PISCSICMD pIScsiCmd = pIScsiPDUTx->pIScsiCmd;
     3327        if (pIScsiCmd)
     3328        {
     3329            /* Place on command list. */
     3330            pIScsiCmd->pNext = pIScsiCmdHead;
     3331            pIScsiCmdHead = pIScsiCmd;
     3332        }
     3333        RTMemFree(pIScsiPDUTx);
     3334    }
     3335
     3336    /* Clear the tail pointer (safety precaution). */
     3337    pImage->pIScsiPDUTxTail = NULL;
     3338
     3339    /* Clear the current PDU too. */
     3340    if (pImage->pIScsiPDUTxCur)
     3341    {
     3342        pIScsiPDUTx = pImage->pIScsiPDUTxCur;
     3343
     3344        pImage->pIScsiPDUTxCur = NULL;
     3345        PISCSICMD pIScsiCmd = pIScsiPDUTx->pIScsiCmd;
     3346        if (pIScsiCmd)
     3347        {
     3348            pIScsiCmd->pNext = pIScsiCmdHead;
     3349            pIScsiCmdHead = pIScsiCmd;
     3350        }
     3351        RTMemFree(pIScsiPDUTx);
     3352    }
     3353
     3354    return pIScsiCmdHead;
     3355}
     3356
     3357/**
     3358 * Rests the iSCSI connection state and returns a list of iSCSI commands pending
     3359 * when this was called.
     3360 *
     3361 * @returns Pointer to the head of the pending iSCSI command list.
     3362 * @param   pImage    iSCSI connection state.
     3363 */
     3364static PISCSICMD iscsiReset(PISCSIIMAGE pImage)
     3365{
     3366    PISCSICMD pIScsiCmdHead = NULL;
     3367    PISCSICMD pIScsiCmdCur = NULL;
     3368
     3369    /* Clear all in flight PDUs. */
     3370    pIScsiCmdHead = iscsiPDURxTxClear(pImage);
     3371
     3372    /*
     3373     * Get all commands which are waiting for a response
     3374     * They need to be resend too after a successful reconnect.
     3375     */
     3376    PISCSICMD pIScsiCmd = iscsiCmdRemoveAll(pImage);
     3377    if (pIScsiCmd)
     3378    {
     3379        pIScsiCmdCur = pIScsiCmd;
     3380        while (pIScsiCmdCur->pNext)
     3381            pIScsiCmdCur = pIScsiCmdCur->pNext;
     3382
     3383        /*
     3384         * Place them in front of the list because they are the oldest requests
     3385         * and need to be processed first to minimize the risk to time out.
     3386         */
     3387        pIScsiCmdCur->pNext = pIScsiCmdHead;
     3388        pIScsiCmdHead = pIScsiCmd;
     3389    }
     3390
     3391    return pIScsiCmdHead;
     3392}
     3393
     3394/**
    32853395 * Reattaches the to the target after an error aborting
    32863396 * pending commands and resending them.
     
    32903400static void iscsiReattach(PISCSIIMAGE pImage)
    32913401{
    3292     int rc = VINF_SUCCESS;
    3293     PISCSICMD pIScsiCmdHead = NULL;
    3294     PISCSICMD pIScsiCmd = NULL;
    3295     PISCSICMD pIScsiCmdCur = NULL;
    3296     PISCSIPDUTX pIScsiPDUTx = NULL;
    3297 
    32983402    /* Close connection. */
    32993403    iscsiTransportClose(pImage);
    33003404    pImage->state = ISCSISTATE_FREE;
    33013405
    3302     /* Reset PDU we are receiving. */
    3303     iscsiRecvPDUReset(pImage);
    3304 
    3305     /*
    3306      * Abort all PDUs we are about to transmit,
    3307      * the command need a new Itt if the relogin is successful.
    3308      */
    3309     while (pImage->pIScsiPDUTxHead)
    3310     {
    3311         pIScsiPDUTx = pImage->pIScsiPDUTxHead;
    3312         pImage->pIScsiPDUTxHead = pIScsiPDUTx->pNext;
    3313 
    3314         pIScsiCmd = pIScsiPDUTx->pIScsiCmd;
    3315 
    3316         if (pIScsiCmd)
    3317         {
    3318             /* Place on command list. */
    3319             pIScsiCmd->pNext = pIScsiCmdHead;
    3320             pIScsiCmdHead = pIScsiCmd;
    3321         }
    3322         RTMemFree(pIScsiPDUTx);
    3323     }
    3324 
    3325     /* Clear the tail pointer (safety precaution). */
    3326     pImage->pIScsiPDUTxTail = NULL;
    3327 
    3328     /* Clear the current PDU too. */
    3329     if (pImage->pIScsiPDUTxCur)
    3330     {
    3331         pIScsiPDUTx = pImage->pIScsiPDUTxCur;
    3332 
    3333         pImage->pIScsiPDUTxCur = NULL;
    3334         pIScsiCmd = pIScsiPDUTx->pIScsiCmd;
    3335 
    3336         if (pIScsiCmd)
    3337         {
    3338             pIScsiCmd->pNext = pIScsiCmdHead;
    3339             pIScsiCmdHead = pIScsiCmd;
    3340         }
    3341         RTMemFree(pIScsiPDUTx);
    3342     }
    3343 
    3344     /*
    3345      * Get all commands which are waiting for a response
    3346      * They need to be resend too after a successful reconnect.
    3347      */
    3348     pIScsiCmd = iscsiCmdRemoveAll(pImage);
    3349 
    3350     if (pIScsiCmd)
    3351     {
    3352         pIScsiCmdCur = pIScsiCmd;
    3353         while (pIScsiCmdCur->pNext)
    3354             pIScsiCmdCur = pIScsiCmdCur->pNext;
    3355 
    3356         /*
    3357          * Place them in front of the list because they are the oldest requests
    3358          * and need to be processed first to minimize the risk to time out.
    3359          */
    3360         pIScsiCmdCur->pNext = pIScsiCmdHead;
    3361         pIScsiCmdHead = pIScsiCmd;
    3362     }
     3406    /* Reset the state and get the currently pending commands. */
     3407    PISCSICMD pIScsiCmdHead = iscsiReset(pImage);
    33633408
    33643409    /* Try to attach. */
    3365     rc = iscsiAttach(pImage);
     3410    int rc = iscsiAttach(pImage);
    33663411    if (RT_SUCCESS(rc))
    33673412    {
     
    33713416        while (pIScsiCmdHead)
    33723417        {
    3373             pIScsiCmd = pIScsiCmdHead;
     3418            PISCSICMD pIScsiCmd = pIScsiCmdHead;
    33743419            pIScsiCmdHead = pIScsiCmdHead->pNext;
    33753420
     
    33773422
    33783423            rc = iscsiPDUTxPrepare(pImage, pIScsiCmd);
    3379             AssertRC(rc);
    3380         }
    3381     }
    3382     else
     3424            if (RT_FAILURE(rc))
     3425                break;
     3426        }
     3427
     3428        if (RT_FAILURE(rc))
     3429        {
     3430            /* Another error, just give up and report an error. */
     3431            PISCSICMD pIScsiCmd = iscsiReset(pImage);
     3432
     3433            /* Concatenate both lists together so we can abort all requests below. */
     3434            if (pIScsiCmd)
     3435            {
     3436                PISCSICMD pIScsiCmdCur = pIScsiCmd;
     3437                while (pIScsiCmdCur->pNext)
     3438                    pIScsiCmdCur = pIScsiCmdCur->pNext;
     3439
     3440                pIScsiCmdCur->pNext = pIScsiCmdHead;
     3441                pIScsiCmdHead = pIScsiCmd;
     3442            }
     3443        }
     3444    }
     3445
     3446    if (RT_FAILURE(rc))
    33833447    {
    33843448        /*
     
    33883452        while (pIScsiCmdHead)
    33893453        {
    3390             pIScsiCmd = pIScsiCmdHead;
     3454            PISCSICMD pIScsiCmd = pIScsiCmdHead;
    33913455            pIScsiCmdHead = pIScsiCmdHead->pNext;
    33923456
     
    34513515                        {
    34523516                            rc = iscsiPDUTxPrepare(pImage, pIScsiCmd);
    3453                             AssertRC(rc);
     3517                            if (RT_FAILURE(rc))
     3518                                iscsiReattach(pImage);
    34543519                        }
    34553520                        else
     
    36983763    size_t cbTransfered = 0;
    36993764    PSCSIREQ pScsiReq = (PSCSIREQ)pvUser;
     3765
     3766    if (RT_SUCCESS(rcReq))
     3767        ASMAtomicWriteU32(&pImage->cLoginsSinceIo, 0);
    37003768
    37013769    if (   RT_SUCCESS(rcReq)
     
    38943962    pImage->cISCSIRetries   = 10;
    38953963    pImage->state           = ISCSISTATE_FREE;
     3964    pImage->cLoginsSinceIo  = 0;
    38963965    pImage->pvRecvPDUBuf    = RTMemAlloc(ISCSI_RECV_PDU_BUFFER_SIZE);
    38973966    pImage->cbRecvPDUBuf    = ISCSI_RECV_PDU_BUFFER_SIZE;
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