/** * Thread checking for expired requests. * * @returns IPRT status code. * @param pThread Thread handle. * @param pvUser Opaque user data. */ static int drvdiskIntIoReqExpiredCheck(RTTHREAD pThread, void *pvUser) { PDRVDISKINTEGRITY pThis = (PDRVDISKINTEGRITY)pvUser; while (pThis->fRunning) { int rc = RTSemEventWait(pThis->SemEvent, pThis->uCheckIntervalMs); if (!pThis->fRunning) break; Assert(rc == VERR_TIMEOUT); /* Get current timestamp for comparison. */ uint64_t tsCurr = RTTimeSystemMilliTS(); /* Go through the array and check for expired requests. */ for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++) { PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[i]; PDRVDISKAIOREQ pIoReq = ASMAtomicReadPtrT(&pReqActive->pIoReq, PDRVDISKAIOREQ); if ( pIoReq && (tsCurr > pReqActive->tsStart) && (tsCurr - pReqActive->tsStart) >= pThis->uExpireIntervalMs) { RTMsgError("Request %#p expired (active for %llu ms already)\n", pIoReq, tsCurr - pReqActive->tsStart); RTAssertDebugBreak(); } } } return VINF_SUCCESS; }
/** * Free a async I/O request. * * @returns nothing. * @param pThis Disk driver. * @param pIoReq The I/O request to free. */ static void drvdiskintIoReqFree(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq) { if (pThis->fCheckDoubleCompletion) { /* Search if the I/O request completed already. */ for (unsigned i = 0; i < pThis->cEntries; i++) { if (RT_UNLIKELY(pThis->papIoReq[i] == pIoReq)) { RTMsgError("Request %#p completed already!\n", pIoReq); RTMsgError("Start timestamp %llu Completion timestamp %llu (completed after %llu ms)\n", pIoReq->tsStart, pIoReq->tsComplete, pIoReq->tsComplete - pIoReq->tsStart); RTAssertDebugBreak(); } } pIoReq->tsComplete = RTTimeSystemMilliTS(); Assert(!pThis->papIoReq[pThis->iEntry]); pThis->papIoReq[pThis->iEntry] = pIoReq; pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries; if (pThis->papIoReq[pThis->iEntry]) { RTMemFree(pThis->papIoReq[pThis->iEntry]); pThis->papIoReq[pThis->iEntry] = NULL; } } else RTMemFree(pIoReq); }
static void tstPDMACStressTestFileVerify(PPDMACTESTFILE pTestFile, PPDMACTESTFILETASK pTestTask) { size_t cbLeft = pTestTask->DataSeg.cbSeg; RTFOFF off = pTestTask->off; uint8_t *pbBuf = (uint8_t *)pTestTask->DataSeg.pvSeg; while (cbLeft) { size_t cbCompare; unsigned iSeg = off / pTestFile->cbFileSegment; PPDMACTESTFILESEG pSeg = &pTestFile->paSegs[iSeg]; uint8_t *pbTestPattern; unsigned offSeg = off - pSeg->off; cbCompare = RT_MIN(cbLeft, pSeg->cbSegment - offSeg); pbTestPattern = pSeg->pbData + offSeg; if (memcmp(pbBuf, pbTestPattern, cbCompare)) { unsigned idx = 0; while ( (pbBuf[idx] == pbTestPattern[idx]) && (idx < cbCompare)) idx++; RTMsgError("Unexpected data for off=%RTfoff size=%u\n" "Expected %c got %c\n", pTestTask->off + idx, pTestTask->DataSeg.cbSeg, pbTestPattern[idx], pbBuf[idx]); RTAssertDebugBreak(); } pbBuf += cbCompare; off += cbCompare; cbLeft -= cbCompare; } }
/** * 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; }