Пример #1
0
/**
 * I/O thread for the memory backend.
 *
 * @returns IPRT status code.
 *
 * @param hThread    The thread handle.
 * @param pvUser     Opaque user data.
 */
static int vdIoBackendMemThread(RTTHREAD hThread, void *pvUser)
{
    PVDIOBACKENDMEM pIoBackend = (PVDIOBACKENDMEM)pvUser;

    while (pIoBackend->fRunning)
    {
        int rc = RTSemEventWait(pIoBackend->EventSem, RT_INDEFINITE_WAIT);
        if (RT_FAILURE(rc) || !pIoBackend->fRunning)
            break;

        PVDIOBACKENDREQ pReq;
        PPVDIOBACKENDREQ ppReq;
        size_t cbData;
        uint32_t cReqsWaiting = ASMAtomicXchgU32(&pIoBackend->cReqsWaiting, 0);

        while (cReqsWaiting)
        {
            int rcReq = VINF_SUCCESS;

            /* Do we have another request? */
            RTCircBufAcquireReadBlock(pIoBackend->pRequestRing, sizeof(PVDIOBACKENDREQ), (void **)&ppReq, &cbData);
            Assert(!ppReq || cbData == sizeof(PVDIOBACKENDREQ));
            RTCircBufReleaseReadBlock(pIoBackend->pRequestRing, cbData);

            pReq = *ppReq;
            cReqsWaiting--;

            LogFlowFunc(("Processing request\n"));
            switch (pReq->enmTxDir)
            {
                case VDIOTXDIR_READ:
                {
                    RTSGBUF SgBuf;
                    RTSgBufInit(&SgBuf, pReq->aSegs, pReq->cSegs);
                    rcReq = VDMemDiskRead(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &SgBuf);
                    break;
                }
                case VDIOTXDIR_WRITE:
                {
                    RTSGBUF SgBuf;
                    RTSgBufInit(&SgBuf, pReq->aSegs, pReq->cSegs);
                    rcReq = VDMemDiskWrite(pReq->pMemDisk, pReq->off, pReq->cbTransfer, &SgBuf);
                    break;
                }
                case VDIOTXDIR_FLUSH:
                    break;
                default:
                    AssertMsgFailed(("Invalid TX direction!\n"));
            }

            /* Notify completion. */
            pReq->pfnComplete(pReq->pvUser, rcReq);
            RTMemFree(pReq);
        }
    }

    return VINF_SUCCESS;
}
Пример #2
0
VBOXDDU_DECL(int) VSCSIDeviceReqCreate(VSCSIDEVICE hVScsiDevice, PVSCSIREQ phVScsiReq,
                                       uint32_t iLun, uint8_t *pbCDB, size_t cbCDB,
                                       size_t cbSGList, unsigned cSGListEntries,
                                       PCRTSGSEG paSGList, uint8_t *pbSense,
                                       size_t cbSense, void *pvVScsiReqUser)
{
    PVSCSIDEVICEINT pVScsiDevice = (PVSCSIDEVICEINT)hVScsiDevice;
    PVSCSIREQINT    pVScsiReq    = NULL;

    /* Parameter checks */
    AssertPtrReturn(pVScsiDevice, VERR_INVALID_HANDLE);
    AssertPtrReturn(phVScsiReq, VERR_INVALID_POINTER);
    AssertPtrReturn(pbCDB, VERR_INVALID_PARAMETER);
    AssertReturn(cbCDB > 0, VERR_INVALID_PARAMETER);

    pVScsiReq = (PVSCSIREQINT)RTMemCacheAlloc(pVScsiDevice->hCacheReq);
    if (!pVScsiReq)
        return VERR_NO_MEMORY;

    pVScsiReq->iLun           = iLun;
    pVScsiReq->pbCDB          = pbCDB;
    pVScsiReq->cbCDB          = cbCDB;
    pVScsiReq->pbSense        = pbSense;
    pVScsiReq->cbSense        = cbSense;
    pVScsiReq->pvVScsiReqUser = pvVScsiReqUser;

    if (cSGListEntries)
        RTSgBufInit(&pVScsiReq->SgBuf, paSGList, cSGListEntries);

    *phVScsiReq = pVScsiReq;

    return VINF_SUCCESS;
}
Пример #3
0
static DECLCALLBACK(int) drvdiskintStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
                                              PCRTSGSEG paSeg, unsigned cSeg,
                                              size_t cbWrite, void *pvUser)
{
     LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d pvUser=%#p\n", __FUNCTION__,
             uOffset, paSeg, cSeg, cbWrite, pvUser));
    PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
    PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_WRITE, uOffset, paSeg, cSeg, cbWrite, pvUser);
    AssertPtr(pIoReq);

    if (pThis->fTraceRequests)
        drvdiskintIoReqAdd(pThis, pIoReq);

    if (pThis->hIoLogger)
    {
        RTSGBUF SgBuf;

        RTSgBufInit(&SgBuf, paSeg, cSeg);

        int rc2 = VDDbgIoLogStart(pThis->hIoLogger, true, VDDBGIOLOGREQ_WRITE, uOffset,
                                  cbWrite, &SgBuf, &pIoReq->hIoLogEntry);
        AssertRC(rc2);
    }

    int rc = pThis->pDrvMediaAsync->pfnStartWrite(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
                                                  cbWrite, pIoReq);
    if (rc == VINF_VD_ASYNC_IO_FINISHED)
    {
        /* Record the write. */
        if  (pThis->fCheckConsistency)
        {
            int rc2 = drvdiskintWriteRecord(pThis, paSeg, cSeg, uOffset, cbWrite);
            AssertRC(rc2);
        }

        if (pThis->hIoLogger)
        {
            int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, NULL);
            AssertRC(rc2);
        }

        if (pThis->fTraceRequests)
            drvdiskintIoReqRemove(pThis, pIoReq);

        RTMemFree(pIoReq);
    }
    else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
        RTMemFree(pIoReq);

    LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
    return rc;
}
Пример #4
0
RTDECL(int) RTZipGzipCompressIoStream(RTVFSIOSTREAM hVfsIosDst, uint32_t fFlags, uint8_t uLevel, PRTVFSIOSTREAM phVfsIosZip)
{
    AssertPtrReturn(hVfsIosDst, VERR_INVALID_HANDLE);
    AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
    AssertPtrReturn(phVfsIosZip, VERR_INVALID_POINTER);
    AssertReturn(uLevel > 0 && uLevel <= 9, VERR_INVALID_PARAMETER);

    uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosDst);
    AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);

    /*
     * Create the compression I/O stream.
     */
    RTVFSIOSTREAM    hVfsIos;
    PRTZIPGZIPSTREAM pThis;
    int rc = RTVfsNewIoStream(&g_rtZipGzipOps, sizeof(RTZIPGZIPSTREAM), RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
                              &hVfsIos, (void **)&pThis);
    if (RT_SUCCESS(rc))
    {
        pThis->hVfsIos      = hVfsIosDst;
        pThis->offStream    = 0;
        pThis->fDecompress  = false;
        pThis->SgSeg.pvSeg  = &pThis->abBuffer[0];
        pThis->SgSeg.cbSeg  = sizeof(pThis->abBuffer);
        RTSgBufInit(&pThis->SgBuf, &pThis->SgSeg, 1);

        RT_ZERO(pThis->Zlib);
        pThis->Zlib.opaque    = pThis;
        pThis->Zlib.next_out  = &pThis->abBuffer[0];
        pThis->Zlib.avail_out = sizeof(pThis->abBuffer);

        rc = deflateInit2(&pThis->Zlib,
                          uLevel,
                          Z_DEFLATED,
                          15 /* Windows Size */ + 16 /* GZIP header */,
                          9 /* Max memory level for optimal speed */,
                          Z_DEFAULT_STRATEGY);

        if (rc >= 0)
        {
            *phVfsIosZip = hVfsIos;
            return VINF_SUCCESS;
        }

        rc = rtZipGzipConvertErrFromZlib(pThis, rc); /** @todo cleaning up in this situation is going to go wrong. */
        RTVfsIoStrmRelease(hVfsIos);
    }
    else
        RTVfsIoStrmRelease(hVfsIosDst);
    return rc;
}
Пример #5
0
int VDIoBackendMemTransfer(PVDIOBACKENDMEM pIoBackend, PVDMEMDISK pMemDisk,
                           VDIOTXDIR enmTxDir, uint64_t off, size_t cbTransfer,
                           PRTSGBUF pSgBuf, PFNVDIOCOMPLETE pfnComplete, void *pvUser)
{
    PVDIOBACKENDREQ pReq = NULL;
    PPVDIOBACKENDREQ ppReq = NULL;
    size_t cbData;
    unsigned cSegs = 0;

    LogFlowFunc(("Queuing request\n"));

    if (enmTxDir != VDIOTXDIR_FLUSH)
        RTSgBufSegArrayCreate(pSgBuf, NULL, &cSegs, cbTransfer);

    pReq = (PVDIOBACKENDREQ)RTMemAlloc(RT_OFFSETOF(VDIOBACKENDREQ, aSegs[cSegs]));
    if (!pReq)
        return VERR_NO_MEMORY;

    RTCircBufAcquireWriteBlock(pIoBackend->pRequestRing, sizeof(PVDIOBACKENDREQ), (void **)&ppReq, &cbData);
    if (!pReq)
    {
        RTMemFree(pReq);
        return VERR_NO_MEMORY;
    }

    Assert(cbData == sizeof(PVDIOBACKENDREQ));
    pReq->enmTxDir    = enmTxDir;
    pReq->cbTransfer  = cbTransfer;
    pReq->off         = off;
    pReq->pMemDisk    = pMemDisk;
    pReq->pfnComplete = pfnComplete;
    pReq->pvUser      = pvUser;
    if (enmTxDir != VDIOTXDIR_FLUSH)
    {
        RTSgBufSegArrayCreate(pSgBuf, &pReq->aSegs[0], &cSegs, cbTransfer);
        RTSgBufInit(&pReq->SgBuf, pReq->aSegs, cSegs);
    }

    *ppReq = pReq;
    RTCircBufReleaseWriteBlock(pIoBackend->pRequestRing, sizeof(PVDIOBACKENDREQ));
    uint32_t cReqsWaiting = ASMAtomicIncU32(&pIoBackend->cReqsWaiting);
    if (cReqsWaiting == 1)
        vdIoBackendMemThreadPoke(pIoBackend);

    return VINF_SUCCESS;
}
Пример #6
0
static DECLCALLBACK(int) drvdiskintAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
{
    PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface);
    PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)pvUser;
    int rc = VINF_SUCCESS;

    LogFlowFunc(("pIoReq=%#p\n", pIoReq));

    /* Remove from the active list. */
    if (pThis->fTraceRequests)
        drvdiskintIoReqRemove(pThis, pIoReq);

    if (RT_SUCCESS(rcReq) && pThis->fCheckConsistency)
    {
        if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
            rc = drvdiskintReadVerify(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
        else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE)
            rc = drvdiskintWriteRecord(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
        else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_DISCARD)
            rc = drvdiskintDiscardRecords(pThis, pIoReq->paRanges, pIoReq->cRanges);
        else
            AssertMsg(pIoReq->enmTxDir == DRVDISKAIOTXDIR_FLUSH, ("Huh?\n"));

        AssertRC(rc);
    }

    if (pThis->hIoLogger)
    {
        RTSGBUF SgBuf;

        if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
            RTSgBufInit(&SgBuf, pIoReq->paSeg, pIoReq->cSeg);

        int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, rc, &SgBuf);
        AssertRC(rc2);
    }

    void *pvUserComplete = pIoReq->pvUser;

    drvdiskintIoReqFree(pThis, pIoReq);

    rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvUserComplete, rcReq);

    return rc;
}
Пример #7
0
/** @copydoc PDMIMEDIA::pfnWrite */
static DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
                                         uint64_t off, const void *pvBuf,
                                         size_t cbWrite)
{
    int rc = VINF_SUCCESS;
    VDIOLOGENT hIoLogEntry;
    PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);

    if (pThis->hIoLogger)
    {
        RTSGSEG Seg;
        RTSGBUF SgBuf;

        Seg.pvSeg = (void *)pvBuf;
        Seg.cbSeg = cbWrite;
        RTSgBufInit(&SgBuf, &Seg, 1);

        rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_WRITE, off,
                             cbWrite, &SgBuf, &hIoLogEntry);
        AssertRC(rc);
    }

    rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);

    if (pThis->hIoLogger)
    {
        int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, NULL);
        AssertRC(rc2);
    }

    if (RT_FAILURE(rc))
        return rc;

    if (pThis->fCheckConsistency)
    {
        /* Record the write. */
        RTSGSEG Seg;
        Seg.cbSeg = cbWrite;
        Seg.pvSeg = (void *)pvBuf;
        rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
    }

    return rc;
}
Пример #8
0
/** @copydoc PDMIMEDIA::pfnRead */
static DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
                                        uint64_t off, void *pvBuf, size_t cbRead)
{
    int rc = VINF_SUCCESS;
    VDIOLOGENT hIoLogEntry;
    PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);

    if (pThis->hIoLogger)
    {
        rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_READ, off,
                             cbRead, NULL, &hIoLogEntry);
        AssertRC(rc);
    }

    rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);

    if (pThis->hIoLogger)
    {
        RTSGSEG Seg;
        RTSGBUF SgBuf;

        Seg.pvSeg = pvBuf;
        Seg.cbSeg = cbRead;
        RTSgBufInit(&SgBuf, &Seg, 1);

        int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, &SgBuf);
        AssertRC(rc2);
    }

    if (RT_FAILURE(rc))
        return rc;

    if (pThis->fCheckConsistency)
    {
        /* Verify the read. */
        RTSGSEG Seg;
        Seg.cbSeg = cbRead;
        Seg.pvSeg = pvBuf;
        rc = drvdiskintReadVerify(pThis, &Seg, 1, off, cbRead);
    }

    return rc;
}
Пример #9
0
RTDECL(int) RTZipGzipDecompressIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSIOSTREAM phVfsIosOut)
{
    AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE);
    AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
    AssertPtrReturn(phVfsIosOut, VERR_INVALID_POINTER);

    uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn);
    AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);

    /*
     * Create the decompression I/O stream.
     */
    RTVFSIOSTREAM    hVfsIos;
    PRTZIPGZIPSTREAM pThis;
    int rc = RTVfsNewIoStream(&g_rtZipGzipOps, sizeof(RTZIPGZIPSTREAM), RTFILE_O_READ, NIL_RTVFS, NIL_RTVFSLOCK,
                              &hVfsIos, (void **)&pThis);
    if (RT_SUCCESS(rc))
    {
        pThis->hVfsIos      = hVfsIosIn;
        pThis->offStream    = 0;
        pThis->fDecompress  = true;
        pThis->SgSeg.pvSeg  = &pThis->abBuffer[0];
        pThis->SgSeg.cbSeg  = sizeof(pThis->abBuffer);
        RTSgBufInit(&pThis->SgBuf, &pThis->SgSeg, 1);

        memset(&pThis->Zlib, 0, sizeof(pThis->Zlib));
        pThis->Zlib.opaque  = pThis;
        rc = inflateInit2(&pThis->Zlib, MAX_WBITS + 16 /* autodetect gzip header */);
        if (rc >= 0)
        {
            /*
             * Read the gzip header from the input stream to check that it's
             * a gzip stream.
             *
             * Note!. Since we've told zlib to check for the gzip header, we
             *        prebuffer what we read in the input buffer so it can
             *        be handed on to zlib later on.
             */
            rc = RTVfsIoStrmRead(pThis->hVfsIos, pThis->abBuffer, sizeof(RTZIPGZIPHDR), true /*fBlocking*/, NULL /*pcbRead*/);
            if (RT_SUCCESS(rc))
            {
                /* Validate the header and make a copy of it. */
                PCRTZIPGZIPHDR pHdr = (PCRTZIPGZIPHDR)pThis->abBuffer;
                if (   pHdr->bId1 != RTZIPGZIPHDR_ID1
                    || pHdr->bId2 != RTZIPGZIPHDR_ID2
                    || pHdr->fFlags & ~RTZIPGZIPHDR_FLG_VALID_MASK)
                    rc = VERR_ZIP_BAD_HEADER;
                else if (pHdr->bCompressionMethod != RTZIPGZIPHDR_CM_DEFLATE)
                    rc = VERR_ZIP_UNSUPPORTED_METHOD;
                else
                {
                    pThis->Hdr = *pHdr;
                    pThis->Zlib.avail_in = sizeof(RTZIPGZIPHDR);
                    pThis->Zlib.next_in  = &pThis->abBuffer[0];

                    /* Parse on if there are names or comments. */
                    if (pHdr->fFlags & (RTZIPGZIPHDR_FLG_NAME | RTZIPGZIPHDR_FLG_COMMENT))
                    {
                        /** @todo Can implement this when someone needs the
                         *        name or comment for something useful. */
                    }
                    if (RT_SUCCESS(rc))
                    {
                        *phVfsIosOut = hVfsIos;
                        return VINF_SUCCESS;
                    }
                }
            }
        }
        else
            rc = rtZipGzipConvertErrFromZlib(pThis, rc); /** @todo cleaning up in this situation is going to go wrong. */
        RTVfsIoStrmRelease(hVfsIos);
    }
    else
        RTVfsIoStrmRelease(hVfsIosIn);
    return rc;
}
Пример #10
0
/**
 * Verifies a read request.
 *
 * @returns VBox status code.
 * @param   pThis    Disk integrity driver instance data.
 * @param   paSeg    Segment array of the containing the data buffers to verify.
 * @param   cSeg     Number of segments.
 * @param   off      Start offset.
 * @param   cbWrite  Number of bytes to verify.
 */
static int drvdiskintReadVerify(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
                                uint64_t off, size_t cbRead)
{
    int rc = VINF_SUCCESS;

    LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbRead=%u\n",
                 pThis, paSeg, cSeg, off, cbRead));

    Assert(off % 512 == 0);
    Assert(cbRead % 512 == 0);

    /* Compare read data */
    size_t cbLeft   = cbRead;
    RTFOFF offCurr  = (RTFOFF)off;
    RTSGBUF SgBuf;

    RTSgBufInit(&SgBuf, paSeg, cSeg);

    while (cbLeft)
    {
        PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
        size_t cbRange  = 0;
        bool fCmp       = false;
        unsigned offSeg = 0;

        if (!pSeg)
        {
            /* Get next segment */
            pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
            if (!pSeg)
            {
                /* No data in the tree for this read. Assume everything is ok. */
                cbRange = cbLeft;
            }
            else if (offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
                cbRange = cbLeft;
            else
                cbRange = pSeg->Core.Key - offCurr;
        }
        else
        {
            fCmp    = true;
            offSeg  = offCurr - pSeg->Core.Key;
            cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
        }

        if (fCmp)
        {
            RTSGSEG Seg;
            RTSGBUF SgBufCmp;
            size_t cbOff = 0;

            Seg.cbSeg = cbRange;
            Seg.pvSeg = pSeg->pbSeg + offSeg;

            RTSgBufInit(&SgBufCmp, &Seg, 1);
            if (RTSgBufCmpEx(&SgBuf, &SgBufCmp, cbRange, &cbOff, true))
            {
                /* Corrupted disk, print I/O log entry of the last write which accessed this range. */
                uint32_t cSector = (offSeg + cbOff) / 512;
                AssertMsg(cSector < pSeg->cIoLogEntries, ("Internal bug!\n"));

                RTMsgError("Corrupted disk at offset %llu (%u bytes in the current read buffer)!\n",
                           offCurr + cbOff, cbOff);
                RTMsgError("Last write to this sector started at offset %llu with %u bytes (%u references to this log entry)\n",
                           pSeg->apIoLog[cSector]->off,
                           pSeg->apIoLog[cSector]->cbWrite,
                           pSeg->apIoLog[cSector]->cRefs);
                RTAssertDebugBreak();
            }
        }
        else
            RTSgBufAdvance(&SgBuf, cbRange);

        offCurr += cbRange;
        cbLeft  -= cbRange;
    }

    return rc;
}
Пример #11
0
/**
 * Record a successful write to the virtual disk.
 *
 * @returns VBox status code.
 * @param   pThis    Disk integrity driver instance data.
 * @param   paSeg    Segment array of the write to record.
 * @param   cSeg     Number of segments.
 * @param   off      Start offset.
 * @param   cbWrite  Number of bytes to record.
 */
static int drvdiskintWriteRecord(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
                                 uint64_t off, size_t cbWrite)
{
    int rc = VINF_SUCCESS;

    LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbWrite=%u\n",
                 pThis, paSeg, cSeg, off, cbWrite));

    /* Update the segments */
    size_t cbLeft   = cbWrite;
    RTFOFF offCurr  = (RTFOFF)off;
    RTSGBUF SgBuf;
    PIOLOGENT pIoLogEnt = (PIOLOGENT)RTMemAllocZ(sizeof(IOLOGENT));
    if (!pIoLogEnt)
        return VERR_NO_MEMORY;

    pIoLogEnt->off     = off;
    pIoLogEnt->cbWrite = cbWrite;
    pIoLogEnt->cRefs   = 0;

    RTSgBufInit(&SgBuf, paSeg, cSeg);

    while (cbLeft)
    {
        PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
        size_t cbRange  = 0;
        bool fSet       = false;
        unsigned offSeg = 0;

        if (!pSeg)
        {
            /* Get next segment */
            pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
            if (   !pSeg
                || offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
                cbRange = cbLeft;
            else
                cbRange = pSeg->Core.Key - offCurr;

            Assert(cbRange % 512 == 0);

            /* Create new segment */
            pSeg = (PDRVDISKSEGMENT)RTMemAllocZ(RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbRange / 512]));
            if (pSeg)
            {
                pSeg->Core.Key      = offCurr;
                pSeg->Core.KeyLast  = offCurr + (RTFOFF)cbRange - 1;
                pSeg->cbSeg         = cbRange;
                pSeg->pbSeg         = (uint8_t *)RTMemAllocZ(cbRange);
                pSeg->cIoLogEntries = cbRange / 512;
                if (!pSeg->pbSeg)
                    RTMemFree(pSeg);
                else
                {
                    bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
                    AssertMsg(fInserted, ("Bug!\n"));
                    fSet = true;
                }
            }
        }
        else
        {
            fSet    = true;
            offSeg  = offCurr - pSeg->Core.Key;
            cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
        }

        if (fSet)
        {
            AssertPtr(pSeg);
            size_t cbCopied = RTSgBufCopyToBuf(&SgBuf, pSeg->pbSeg + offSeg, cbRange);
            Assert(cbCopied == cbRange);

            /* Update the I/O log pointers */
            Assert(offSeg % 512 == 0);
            Assert(cbRange % 512 == 0);
            while (offSeg < cbRange)
            {
                uint32_t uSector = offSeg / 512;
                PIOLOGENT pIoLogOld = NULL;

                AssertMsg(uSector < pSeg->cIoLogEntries, ("Internal bug!\n"));

                pIoLogOld = pSeg->apIoLog[uSector];
                if (pIoLogOld)
                {
                    pIoLogOld->cRefs--;
                    if (!pIoLogOld->cRefs)
                        RTMemFree(pIoLogOld);
                }

                pSeg->apIoLog[uSector] = pIoLogEnt;
                pIoLogEnt->cRefs++;

                offSeg += 512;
            }
        }
        else
            RTSgBufAdvance(&SgBuf, cbRange);

        offCurr += cbRange;
        cbLeft  -= cbRange;
    }

    return rc;
}
Пример #12
0
int VDMemDiskCmp(PVDMEMDISK pMemDisk, uint64_t off, size_t cbCmp, PRTSGBUF pSgBuf)
{
    LogFlowFunc(("pMemDisk=%#p off=%llx cbCmp=%u pSgBuf=%#p\n",
                 pMemDisk, off, cbCmp, pSgBuf));

    /* Compare data */
    size_t   cbLeft   = cbCmp;
    uint64_t offCurr  = off;

    while (cbLeft)
    {
        PVDMEMDISKSEG pSeg = (PVDMEMDISKSEG)RTAvlrU64Get(pMemDisk->pTreeSegments, offCurr);
        size_t cbRange  = 0;
        bool fCmp       = false;
        unsigned offSeg = 0;

        if (!pSeg)
        {
            /* Get next segment */
            pSeg = (PVDMEMDISKSEG)RTAvlrU64GetBestFit(pMemDisk->pTreeSegments, offCurr, true);
            if (!pSeg)
            {
                /* No data in the tree for this read. Assume everything is ok. */
                cbRange = cbLeft;
            }
            else if (offCurr + cbLeft <= pSeg->Core.Key)
                cbRange = cbLeft;
            else
                cbRange = pSeg->Core.Key - offCurr;
        }
        else
        {
            fCmp    = true;
            offSeg  = offCurr - pSeg->Core.Key;
            cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
        }

        if (fCmp)
        {
            RTSGSEG Seg;
            RTSGBUF SgBufCmp;
            size_t cbOff = 0;
            int rc = 0;

            Seg.cbSeg = cbRange;
            Seg.pvSeg = (uint8_t *)pSeg->pvSeg + offSeg;

            RTSgBufInit(&SgBufCmp, &Seg, 1);
            rc = RTSgBufCmpEx(pSgBuf, &SgBufCmp, cbRange, &cbOff, true);
            if (rc)
                return rc;
        }
        else
            RTSgBufAdvance(pSgBuf, cbRange);

        offCurr += cbRange;
        cbLeft  -= cbRange;
    }

    return 0;
}