VirtualBox

Changeset 52358 in vbox


Ignore:
Timestamp:
Aug 12, 2014 8:43:35 AM (10 years ago)
Author:
vboxsync
Message:

Storage/VD,VHD: Fix crash with certain VHD images with only partial filled sector bitmaps

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/list.h

    r48782 r52358  
    403403}
    404404
     405/**
     406 * List concatenation.
     407 *
     408 * @returns nothing.
     409 * @param   pListDst            The destination list.
     410 * @param   pListSrc            The source list to concatenate.
     411 */
     412DECLINLINE(void) RTListConcatenate(PRTLISTANCHOR pListDst, PRTLISTANCHOR pListSrc)
     413{
     414    if (!RTListIsEmpty(pListSrc))
     415    {
     416        PRTLISTNODE pFirst = pListSrc->pNext;
     417        PRTLISTNODE pLast = pListSrc->pPrev;
     418
     419        pListDst->pPrev->pNext = pFirst;
     420        pFirst->pPrev          = pListDst->pPrev;
     421        pLast->pNext           = pListDst;
     422        pListDst->pPrev        = pLast;
     423
     424        /* Finally remove the elements from the source list */
     425        RTListInit(pListSrc);
     426    }
     427}
     428
    405429RT_C_DECLS_END
    406430
  • trunk/src/VBox/Storage/VD.cpp

    r52268 r52358  
    579579    /** Size of the data stored with this entry. */
    580580    size_t           cbMeta;
     581    /** Shadow buffer which is used in case a write is still active and other
     582     * writes update the shadow buffer. */
     583    uint8_t         *pbDataShw;
     584    /** List of I/O contexts updating the shadow buffer while there is a write
     585     * in progress. */
     586    RTLISTNODE       ListIoCtxShwWrites;
    581587    /** Data stored - variable size. */
    582588    uint8_t          abData[1];
     
    15451551        pMetaXfer->pIoStorage   = pIoStorage;
    15461552        pMetaXfer->cRefs        = 0;
     1553        pMetaXfer->pbDataShw    = NULL;
    15471554        RTListInit(&pMetaXfer->ListIoCtxWaiting);
     1555        RTListInit(&pMetaXfer->ListIoCtxShwWrites);
    15481556    }
    15491557    return pMetaXfer;
     
    40134021}
    40144022
     4023static void vdIoCtxContinueDeferredList(PVDIOSTORAGE pIoStorage, PRTLISTANCHOR pListWaiting,
     4024                                        PFNVDXFERCOMPLETED pfnComplete, void *pvUser, int rcReq)
     4025{
     4026    LogFlowFunc(("pIoStorage=%#p pListWaiting=%#p pfnComplete=%#p pvUser=%#p rcReq=%Rrc\n",
     4027                 pIoStorage, pListWaiting, pfnComplete, pvUser, rcReq));
     4028
     4029    /* Go through the waiting list and continue the I/O contexts. */
     4030    while (!RTListIsEmpty(pListWaiting))
     4031    {
     4032        int rc = VINF_SUCCESS;
     4033        bool fContinue = true;
     4034        PVDIOCTXDEFERRED pDeferred = RTListGetFirst(pListWaiting, VDIOCTXDEFERRED, NodeDeferred);
     4035        PVDIOCTX pIoCtx = pDeferred->pIoCtx;
     4036        RTListNodeRemove(&pDeferred->NodeDeferred);
     4037
     4038        RTMemFree(pDeferred);
     4039        ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
     4040
     4041        if (pfnComplete)
     4042            rc = pfnComplete(pIoStorage->pVDIo->pBackendData, pIoCtx, pvUser, rcReq);
     4043
     4044        LogFlow(("Completion callback for I/O context %#p returned %Rrc\n", pIoCtx, rc));
     4045
     4046        if (RT_SUCCESS(rc))
     4047        {
     4048            rc = vdIoCtxContinue(pIoCtx, rcReq);
     4049            AssertRC(rc);
     4050        }
     4051        else
     4052            Assert(rc == VERR_VD_ASYNC_IO_IN_PROGRESS);
     4053    }
     4054}
     4055
    40154056/**
    40164057 * Internal - Called when a meta transfer completed.
     
    40294070
    40304071    fFlush = VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_FLUSH;
    4031     VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
    40324072
    40334073    if (!fFlush)
     
    40414081            bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key) != NULL;
    40424082            Assert(fRemoved);
     4083            /* If this was a write check if there is a shadow buffer with updated data. */
     4084            if (pMetaXfer->pbDataShw)
     4085            {
     4086                Assert(VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_WRITE);
     4087                Assert(!RTListIsEmpty(&pMetaXfer->ListIoCtxShwWrites));
     4088                RTListConcatenate(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxShwWrites);
     4089                RTMemFree(pMetaXfer->pbDataShw);
     4090                pMetaXfer->pbDataShw = NULL;
     4091            }
    40434092            RTMemFree(pMetaXfer);
    40444093        }
     
    40524101        RTListMove(&ListIoCtxWaiting, &pMetaXfer->ListIoCtxWaiting);
    40534102
    4054     /* Go through the waiting list and continue the I/O contexts. */
    4055     while (!RTListIsEmpty(&ListIoCtxWaiting))
    4056     {
    4057         int rc = VINF_SUCCESS;
    4058         bool fContinue = true;
    4059         PVDIOCTXDEFERRED pDeferred = RTListGetFirst(&ListIoCtxWaiting, VDIOCTXDEFERRED, NodeDeferred);
    4060         PVDIOCTX pIoCtx = pDeferred->pIoCtx;
    4061         RTListNodeRemove(&pDeferred->NodeDeferred);
    4062 
    4063         RTMemFree(pDeferred);
    4064         ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
    4065 
    4066         if (pfnComplete)
    4067             rc = pfnComplete(pIoStorage->pVDIo->pBackendData, pIoCtx, pvUser, rcReq);
    4068 
    4069         LogFlow(("Completion callback for I/O context %#p returned %Rrc\n", pIoCtx, rc));
    4070 
    4071         if (RT_SUCCESS(rc))
    4072         {
    4073             rc = vdIoCtxContinue(pIoCtx, rcReq);
    4074             AssertRC(rc);
     4103    VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
     4104    vdIoCtxContinueDeferredList(pIoStorage, &ListIoCtxWaiting, pfnComplete, pvUser, rcReq);
     4105
     4106    /*
     4107     * If there is a shadow buffer and the previous write was successful update with the
     4108     * new data and trigger a new write.
     4109     */
     4110    if (   pMetaXfer->pbDataShw
     4111        && RT_SUCCESS(rcReq)
     4112        && VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE)
     4113    {
     4114        LogFlowFunc(("pMetaXfer=%#p Updating from shadow buffer and triggering new write\n", pMetaXfer));
     4115        memcpy(pMetaXfer->abData, pMetaXfer->pbDataShw, pMetaXfer->cbMeta);
     4116        RTMemFree(pMetaXfer->pbDataShw);
     4117        pMetaXfer->pbDataShw = NULL;
     4118        Assert(!RTListIsEmpty(&pMetaXfer->ListIoCtxShwWrites));
     4119
     4120        /* Setup a new I/O write. */
     4121        PVDIOTASK pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvUser, pMetaXfer);
     4122        if (RT_LIKELY(pIoTask))
     4123        {
     4124            void *pvTask = NULL;
     4125            RTSGSEG Seg;
     4126
     4127            Seg.cbSeg = pMetaXfer->cbMeta;
     4128            Seg.pvSeg = pMetaXfer->abData;
     4129
     4130            VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE);
     4131            rcReq = pIoStorage->pVDIo->pInterfaceIo->pfnWriteAsync(pIoStorage->pVDIo->pInterfaceIo->Core.pvUser,
     4132                                                                   pIoStorage->pStorage,
     4133                                                                   pMetaXfer->Core.Key, &Seg, 1,
     4134                                                                   pMetaXfer->cbMeta, pIoTask,
     4135                                                                   &pvTask);
     4136            if (   RT_SUCCESS(rcReq)
     4137                || rcReq != VERR_VD_ASYNC_IO_IN_PROGRESS)
     4138            {
     4139                VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
     4140                vdIoTaskFree(pDisk, pIoTask);
     4141            }
     4142            else
     4143                RTListMove(&pMetaXfer->ListIoCtxWaiting, &pMetaXfer->ListIoCtxShwWrites);
    40754144        }
    40764145        else
    4077             Assert(rc == VERR_VD_ASYNC_IO_IN_PROGRESS);
     4146            rcReq = VERR_NO_MEMORY;
     4147
     4148        /* Cleanup if there was an error or the request completed already. */
     4149        if (rcReq != VERR_VD_ASYNC_IO_IN_PROGRESS)
     4150            vdIoCtxContinueDeferredList(pIoStorage, &pMetaXfer->ListIoCtxShwWrites, pfnComplete, pvUser, rcReq);
    40784151    }
    40794152
    40804153    /* Remove if not used anymore. */
    4081     if (RT_SUCCESS(rcReq) && !fFlush)
     4154    if (!fFlush)
    40824155    {
    40834156        pMetaXfer->cRefs--;
     
    46834756                Assert(pMetaXfer->cbMeta >= cbRead);
    46844757                Assert(pMetaXfer->Core.Key == (RTFOFF)uOffset);
    4685                 memcpy(pvBuf, pMetaXfer->abData, cbRead);
     4758                if (pMetaXfer->pbDataShw)
     4759                    memcpy(pvBuf, pMetaXfer->pbDataShw, cbRead);
     4760                else
     4761                    memcpy(pvBuf, pMetaXfer->abData, cbRead);
    46864762                *ppMetaXfer = pMetaXfer;
    46874763            }
     
    47454821        }
    47464822
    4747         Assert(VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE);
    4748 
    4749         pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer);
    4750         if (!pIoTask)
    4751         {
    4752             RTMemFree(pMetaXfer);
    4753             return VERR_NO_MEMORY;
    4754         }
    4755 
    4756         memcpy(pMetaXfer->abData, pvBuf, cbWrite);
    4757         Seg.cbSeg = cbWrite;
    4758         Seg.pvSeg = pMetaXfer->abData;
    4759 
    4760         ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
    4761 
    4762         VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE);
    4763         rc = pVDIo->pInterfaceIo->pfnWriteAsync(pVDIo->pInterfaceIo->Core.pvUser,
    4764                                                 pIoStorage->pStorage,
    4765                                                 uOffset, &Seg, 1, cbWrite, pIoTask,
    4766                                                 &pvTask);
    4767         if (RT_SUCCESS(rc))
    4768         {
    4769             VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
    4770             ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
    4771             vdIoTaskFree(pDisk, pIoTask);
    4772             if (fInTree && !pMetaXfer->cRefs)
     4823        if (VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_NONE)
     4824        {
     4825            pIoTask = vdIoTaskMetaAlloc(pIoStorage, pfnComplete, pvCompleteUser, pMetaXfer);
     4826            if (!pIoTask)
    47734827            {
    4774                 LogFlow(("Removing meta xfer=%#p\n", pMetaXfer));
    4775                 bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key) != NULL;
    4776                 AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n"));
     4828                RTMemFree(pMetaXfer);
     4829                return VERR_NO_MEMORY;
     4830            }
     4831
     4832            memcpy(pMetaXfer->abData, pvBuf, cbWrite);
     4833            Seg.cbSeg = cbWrite;
     4834            Seg.pvSeg = pMetaXfer->abData;
     4835
     4836            ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
     4837
     4838            VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_WRITE);
     4839            rc = pVDIo->pInterfaceIo->pfnWriteAsync(pVDIo->pInterfaceIo->Core.pvUser,
     4840                                                    pIoStorage->pStorage,
     4841                                                    uOffset, &Seg, 1, cbWrite, pIoTask,
     4842                                                    &pvTask);
     4843            if (RT_SUCCESS(rc))
     4844            {
     4845                VDMETAXFER_TXDIR_SET(pMetaXfer->fFlags, VDMETAXFER_TXDIR_NONE);
     4846                ASMAtomicDecU32(&pIoCtx->cMetaTransfersPending);
     4847                vdIoTaskFree(pDisk, pIoTask);
     4848                if (fInTree && !pMetaXfer->cRefs)
     4849                {
     4850                    LogFlow(("Removing meta xfer=%#p\n", pMetaXfer));
     4851                    bool fRemoved = RTAvlrFileOffsetRemove(pIoStorage->pTreeMetaXfers, pMetaXfer->Core.Key) != NULL;
     4852                    AssertMsg(fRemoved, ("Metadata transfer wasn't removed\n"));
     4853                    RTMemFree(pMetaXfer);
     4854                    pMetaXfer = NULL;
     4855                }
     4856            }
     4857            else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
     4858            {
     4859                PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
     4860                AssertPtr(pDeferred);
     4861
     4862                RTListInit(&pDeferred->NodeDeferred);
     4863                pDeferred->pIoCtx = pIoCtx;
     4864
     4865                if (!fInTree)
     4866                {
     4867                    bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core);
     4868                    Assert(fInserted);
     4869                }
     4870
     4871                RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred);
     4872            }
     4873            else
     4874            {
    47774875                RTMemFree(pMetaXfer);
    47784876                pMetaXfer = NULL;
    47794877            }
    47804878        }
    4781         else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
    4782         {
    4783             PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
    4784             AssertPtr(pDeferred);
    4785 
    4786             RTListInit(&pDeferred->NodeDeferred);
    4787             pDeferred->pIoCtx = pIoCtx;
    4788 
    4789             if (!fInTree)
     4879        else
     4880        {
     4881            /* I/O is in progress, update shadow buffer and add to waiting list. */
     4882            Assert(VDMETAXFER_TXDIR_GET(pMetaXfer->fFlags) == VDMETAXFER_TXDIR_WRITE);
     4883            if (!pMetaXfer->pbDataShw)
    47904884            {
    4791                 bool fInserted = RTAvlrFileOffsetInsert(pIoStorage->pTreeMetaXfers, &pMetaXfer->Core);
    4792                 Assert(fInserted);
     4885                /* Allocate shadow buffer and set initial state. */
     4886                LogFlowFunc(("pMetaXfer=%#p Creating shadow buffer\n", pMetaXfer));
     4887                pMetaXfer->pbDataShw = (uint8_t *)RTMemAlloc(pMetaXfer->cbMeta);
     4888                if (RT_LIKELY(pMetaXfer->pbDataShw))
     4889                    memcpy(pMetaXfer->pbDataShw, pMetaXfer->abData, pMetaXfer->cbMeta);
     4890                else
     4891                    rc = VERR_NO_MEMORY;
    47934892            }
    47944893
    4795             RTListAppend(&pMetaXfer->ListIoCtxWaiting, &pDeferred->NodeDeferred);
    4796         }
    4797         else
    4798         {
    4799             RTMemFree(pMetaXfer);
    4800             pMetaXfer = NULL;
     4894            if (RT_SUCCESS(rc))
     4895            {
     4896                /* Update with written data and append to waiting list. */
     4897                PVDIOCTXDEFERRED pDeferred = (PVDIOCTXDEFERRED)RTMemAllocZ(sizeof(VDIOCTXDEFERRED));
     4898                if (pDeferred)
     4899                {
     4900                    LogFlowFunc(("pMetaXfer=%#p Updating shadow buffer\n", pMetaXfer));
     4901
     4902                    RTListInit(&pDeferred->NodeDeferred);
     4903                    pDeferred->pIoCtx = pIoCtx;
     4904                    ASMAtomicIncU32(&pIoCtx->cMetaTransfersPending);
     4905                    memcpy(pMetaXfer->pbDataShw, pvBuf, cbWrite);
     4906                    RTListAppend(&pMetaXfer->ListIoCtxShwWrites, &pDeferred->NodeDeferred);
     4907                }
     4908                else
     4909                {
     4910                    /*
     4911                     * Free shadow buffer if there is no one depending on it, i.e.
     4912                     * we just allocated it.
     4913                     */
     4914                    if (RTListIsEmpty(&pMetaXfer->ListIoCtxShwWrites))
     4915                    {
     4916                        RTMemFree(pMetaXfer->pbDataShw);
     4917                        pMetaXfer->pbDataShw = NULL;
     4918                    }
     4919                    rc = VERR_NO_MEMORY;
     4920                }
     4921            }
    48014922        }
    48024923    }
  • trunk/src/VBox/Storage/VHD.cpp

    r52277 r52358  
    623623    if (fFlags == VHDIMAGEEXPAND_ALL_SUCCESS)
    624624    {
     625        pImage->pBlockAllocationTable[pExpand->idxBatAllocated] = RT_BE2H_U32(pExpand->idxBlockBe);
    625626        RTMemFree(pExpand);
    626627    }
     
    16911692                 */
    16921693                rc = vdIfIoIntFileWriteUser(pImage->pIfIo, pImage->pStorage,
    1693                                             pImage->uCurrentEndOfFile + pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE,
     1694                                            pImage->uCurrentEndOfFile + (pImage->cDataBlockBitmapSectors + (cSector % pImage->cSectorsPerDataBlock)) * VHD_SECTOR_SIZE,
    16941695                                            pIoCtx, cbWrite,
    16951696                                            vhdAsyncExpansionDataComplete,
     
    17291730                 * Set the new end of the file and link the new block into the BAT.
    17301731                 */
    1731                 pImage->pBlockAllocationTable[cBlockAllocationTableEntry] = pImage->uCurrentEndOfFile / VHD_SECTOR_SIZE;
    17321732                pImage->uCurrentEndOfFile += pImage->cDataBlockBitmapSectors * VHD_SECTOR_SIZE + pImage->cbDataBlock;
    17331733
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