/** * 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 VDMemDiskWrite(PVDMEMDISK pMemDisk, uint64_t off, size_t cbWrite, PRTSGBUF pSgBuf) { int rc = VINF_SUCCESS; LogFlowFunc(("pMemDisk=%#p off=%llu cbWrite=%zu pSgBuf=%#p\n", pMemDisk, off, cbWrite, pSgBuf)); AssertPtrReturn(pMemDisk, VERR_INVALID_POINTER); AssertPtrReturn(pSgBuf, VERR_INVALID_POINTER); /* Check for a write beyond the end of a disk. */ if ( !pMemDisk->fGrowable && (off + cbWrite) > pMemDisk->cbDisk) return VERR_INVALID_PARAMETER; /* Update the segments */ size_t cbLeft = cbWrite; uint64_t offCurr = off; while ( cbLeft && RT_SUCCESS(rc)) { PVDMEMDISKSEG pSeg = (PVDMEMDISKSEG)RTAvlrU64RangeGet(pMemDisk->pTreeSegments, offCurr); size_t cbRange = 0; unsigned offSeg = 0; if (!pSeg) { /* Get next segment */ pSeg = (PVDMEMDISKSEG)RTAvlrU64GetBestFit(pMemDisk->pTreeSegments, offCurr, true); if ( !pSeg || offCurr + cbLeft <= pSeg->Core.Key) cbRange = cbLeft; else cbRange = pSeg->Core.Key - offCurr; /* Create new segment */ pSeg = (PVDMEMDISKSEG)RTMemAllocZ(sizeof(VDMEMDISKSEG)); if (pSeg) { pSeg->Core.Key = offCurr; pSeg->Core.KeyLast = offCurr + cbRange - 1; pSeg->pvSeg = RTMemAllocZ(cbRange); if (!pSeg->pvSeg) { RTMemFree(pSeg); rc = VERR_NO_MEMORY; } else { bool fInserted = RTAvlrU64Insert(pMemDisk->pTreeSegments, &pSeg->Core); AssertMsg(fInserted, ("Bug!\n")); } } else rc = VERR_NO_MEMORY; } else { offSeg = offCurr - pSeg->Core.Key; cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr)); } if (RT_SUCCESS(rc)) { AssertPtr(pSeg); size_t cbCopied = RTSgBufCopyToBuf(pSgBuf, (uint8_t *)pSeg->pvSeg + offSeg, cbRange); Assert(cbCopied == cbRange); } offCurr += cbRange; cbLeft -= cbRange; } /* Update size of the disk. */ if ( RT_SUCCESS(rc) && pMemDisk->fGrowable && (off + cbWrite) > pMemDisk->cbDisk) { pMemDisk->cbDisk = off + cbWrite; } return rc; }