/** * 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; }
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; }
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; }
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; }
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; }
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; }
/** @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; }
/** @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; }
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; }
/** * 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; }
/** * 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; }
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; }