DrvDiskIntegrity.cpp revision 4baafe1fca22c5d6994633d8a00278ddc4d734f1
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * VBox storage devices: Disk integrity check.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Copyright (C) 2006-2010 Oracle Corporation
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * available from http://www.virtualbox.org. This file is free software;
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * General Public License (GPL) as published by the Free Software
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/*******************************************************************************
b6cba2c351e97805b97998ebe48e03ecef16b59avboxsync* Header Files *
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync*******************************************************************************/
8112e0942f1128329b99b22a20b395963d4abceavboxsync/*******************************************************************************
8112e0942f1128329b99b22a20b395963d4abceavboxsync* Structures and Typedefs *
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync*******************************************************************************/
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Transfer direction.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Read */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Write */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Flush */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Discard */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * async I/O request.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Transfer direction. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Start offset. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Transfer size. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Segment array. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Number of array entries. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** User argument */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Slot in the array. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /** Start timestamp */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /** Completion timestamp. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /** I/O log entry if configured. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /** Ranges to discard. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /** Number of ranges. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * I/O log entry.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsynctypedef struct IOLOGENT
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Start offset */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Write size */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Number of references to this entry. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Disk segment.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** AVL core. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Size of the segment */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Data for this segment */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Number of entries in the I/O array. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Array of I/O log references. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Active requests list entry.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Pointer to the request. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Start timestamp. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Disk integrity driver instance data.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @implements PDMIMEDIA
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync /** Pointer driver instance. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Pointer to the media driver below us.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * This is NULL if the media is not mounted. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Our media interface */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** The media port interface above. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Media port interface */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Pointer to the media async driver below us.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * This is NULL if the media is not mounted. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Our media async interface */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** The async media port interface above. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Our media async port interface */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Flag whether consistency checks are enabled. */
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync /** AVL tree containing the disk blocks to check. */
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync /** Flag whether async request tracing is enabled. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /** Interval the thread should check for expired requests (milliseconds). */
6cd65034f702d9b4122249011835e9639a7bc660vboxsync /** Expire timeout for a request (milliseconds). */
6cd65034f702d9b4122249011835e9639a7bc660vboxsync /** Thread which checks for lost requests. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Event semaphore */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Flag whether the thread should run. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Array containing active requests. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Next free slot in the array */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync volatile unsigned iNextFreeSlot;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Flag whether we check for requests completing twice. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Number of requests we go back. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Array of completed but still observed requests. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Current entry in the array. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** I/O logger to use if enabled. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Allocate a new I/O request.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @returns New I/O request.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param enmTxDir Transfer direction.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param off Start offset.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param paSeg Segment array.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param cSeg Number of segments.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param cbTransfer Number of bytes to transfer.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pvUser User argument.
33f7a1bbfb625f3401368928cd5e9317ca04881dvboxsyncstatic PDRVDISKAIOREQ drvdiskintIoReqAlloc(DRVDISKAIOTXDIR enmTxDir, uint64_t off, PCRTSGSEG paSeg,
8112e0942f1128329b99b22a20b395963d4abceavboxsync PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)RTMemAlloc(sizeof(DRVDISKAIOREQ));
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * Free a async I/O request.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @returns nothing.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @param pThis Disk driver.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @param pIoReq The I/O request to free.
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsyncstatic void drvdiskintIoReqFree(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* Search if the I/O request completed already. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync RTMsgError("Request %#p completed already!\n", pIoReq);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync RTMsgError("Start timestamp %llu Completion timestamp %llu (completed after %llu ms)\n",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync pIoReq->tsStart, pIoReq->tsComplete, pIoReq->tsComplete - pIoReq->tsStart);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic void drvdiskintIoLogEntryRelease(PIOLOGENT pIoLogEnt)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Record a successful write to the virtual disk.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @returns VBox status code.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @param pThis Disk integrity driver instance data.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @param paSeg Segment array of the write to record.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @param cSeg Number of segments.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @param off Start offset.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @param cbWrite Number of bytes to record.
8112e0942f1128329b99b22a20b395963d4abceavboxsyncstatic int drvdiskintWriteRecord(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
8112e0942f1128329b99b22a20b395963d4abceavboxsync LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbWrite=%u\n",
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* Update the segments */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PIOLOGENT pIoLogEnt = (PIOLOGENT)RTMemAllocZ(sizeof(IOLOGENT));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
500d759609a43a472c7a29b58f3479ed319a5a76vboxsync bool fSet = false;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync unsigned offSeg = 0;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Get next segment */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* Create new segment */
0e3950d85821ff3f0f9191f7bf0efe7b3510a808vboxsync pSeg = (PDRVDISKSEGMENT)RTMemAllocZ(RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbRange / 512]));
0e3950d85821ff3f0f9191f7bf0efe7b3510a808vboxsync pSeg->Core.KeyLast = offCurr + (RTFOFF)cbRange - 1;
8112e0942f1128329b99b22a20b395963d4abceavboxsync bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
500d759609a43a472c7a29b58f3479ed319a5a76vboxsync cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
0e3950d85821ff3f0f9191f7bf0efe7b3510a808vboxsync size_t cbCopied = RTSgBufCopyToBuf(&SgBuf, pSeg->pbSeg + offSeg, cbRange);
0e3950d85821ff3f0f9191f7bf0efe7b3510a808vboxsync /* Update the I/O log pointers */
0e3950d85821ff3f0f9191f7bf0efe7b3510a808vboxsync AssertMsg(uSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * Verifies a read request.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @returns VBox status code.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @param pThis Disk integrity driver instance data.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @param paSeg Segment array of the containing the data buffers to verify.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @param cSeg Number of segments.
37b83e04cd69f1fdddc315640acef2cdfddb0f46vboxsync * @param off Start offset.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @param cbWrite Number of bytes to verify.
37b83e04cd69f1fdddc315640acef2cdfddb0f46vboxsyncstatic int drvdiskintReadVerify(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbRead=%u\n",
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* Compare read data */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync bool fCmp = false;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync unsigned offSeg = 0;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Get next segment */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* No data in the tree for this read. Assume everything is ok. */
8112e0942f1128329b99b22a20b395963d4abceavboxsync else if (offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync if (RTSgBufCmpEx(&SgBuf, &SgBufCmp, cbRange, &cbOff, true))
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Corrupted disk, print I/O log entry of the last write which accessed this range. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync AssertMsg(cSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync RTMsgError("Corrupted disk at offset %llu (%u bytes in the current read buffer)!\n",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync RTMsgError("Last write to this sector started at offset %llu with %u bytes (%u references to this log entry)\n",
8112e0942f1128329b99b22a20b395963d4abceavboxsync * Discards the given ranges from the disk.
1a1433dbc5e55f83cbcde6aa9f045c2dc7eeb9e7vboxsync * @returns VBox status code.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @param pThis Disk integrity driver instance data.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @param paRanges Array of ranges to discard.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @param cRanges Number of ranges in the array.
8112e0942f1128329b99b22a20b395963d4abceavboxsyncstatic int drvdiskintDiscardRecords(PDRVDISKINTEGRITY pThis, PCRTRANGE paRanges, unsigned cRanges)
8112e0942f1128329b99b22a20b395963d4abceavboxsync LogFlowFunc(("pThis=%#p paRanges=%#p cRanges=%u\n", pThis, paRanges, cRanges));
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync for (unsigned i = 0; i < cRanges; i++)
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync LogFlowFunc(("Discarding off=%llu cbRange=%zu\n", offStart, cbLeft));
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offStart);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* Get next segment */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offStart, true);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync || (RTFOFF)offStart + (RTFOFF)cbLeft <= pSeg->Core.Key)
8112e0942f1128329b99b22a20b395963d4abceavboxsync cbRange = RT_MIN(cbRange, pSeg->Core.KeyLast - offStart + 1);
8112e0942f1128329b99b22a20b395963d4abceavboxsync LogFlowFunc(("cbRange=%zu cbPreLeft=%zu cbPostLeft=%zu\n",
8112e0942f1128329b99b22a20b395963d4abceavboxsync RTAvlrFileOffsetRemove(pThis->pTreeSegments, pSeg->Core.Key);
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* Just free the whole segment. */
8112e0942f1128329b99b22a20b395963d4abceavboxsync LogFlowFunc(("Freeing whole segment pSeg=%#p\n", pSeg));
8112e0942f1128329b99b22a20b395963d4abceavboxsync for (unsigned idx = 0; idx < pSeg->cIoLogEntries; idx++)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Realloc to new size and insert. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync pSeg->pbSeg = (uint8_t *)RTMemRealloc(pSeg->pbSeg, cbPreLeft);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync for (unsigned idx = cbPreLeft / 512; idx < pSeg->cIoLogEntries; idx++)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync pSeg = (PDRVDISKSEGMENT)RTMemRealloc(pSeg, RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbPreLeft / 512]));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync pSeg->Core.KeyLast = pSeg->Core.Key + cbPreLeft - 1;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
874be5c5b701726b68fa1391022ae2f5c7768894vboxsync /* Move data to the front and realloc. */
874be5c5b701726b68fa1391022ae2f5c7768894vboxsync LogFlowFunc(("Move data and realloc segment pSeg=%#p\n", pSeg));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync memmove(pSeg->pbSeg, pSeg->pbSeg + cbRange, cbPostLeft);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync for (unsigned idx = 0; idx < cbPostLeft /512; idx++)
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync pSeg->apIoLog[idx] = pSeg->apIoLog[(cbRange / 512) + idx];
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync pSeg = (PDRVDISKSEGMENT)RTMemRealloc(pSeg, RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbPostLeft / 512]));
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync pSeg->pbSeg = (uint8_t *)RTMemRealloc(pSeg->pbSeg, cbPostLeft);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* Split the segment into 2 new segments. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync PDRVDISKSEGMENT pSegPost = (PDRVDISKSEGMENT)RTMemAllocZ(RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbPostLeft / 512]));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync pSegPost->Core.Key = pSeg->Core.Key + cbPreLeft + cbRange;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync pSegPost->pbSeg = (uint8_t *)RTMemAllocZ(cbPostLeft);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync memcpy(pSegPost->pbSeg, pSeg->pbSeg + cbPreLeft + cbRange, cbPostLeft);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync for (unsigned idx = 0; idx < cbPostLeft / 512; idx++)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync pSegPost->apIoLog[idx] = pSeg->apIoLog[((cbPreLeft + cbRange) / 512) + idx];
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSegPost->Core);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Shrink the current segment. */
8112e0942f1128329b99b22a20b395963d4abceavboxsync pSeg->pbSeg = (uint8_t *)RTMemRealloc(pSeg->pbSeg, cbPreLeft);
8112e0942f1128329b99b22a20b395963d4abceavboxsync for (unsigned idx = cbPreLeft / 512; idx < (cbPreLeft + cbRange) / 512; idx++)
8112e0942f1128329b99b22a20b395963d4abceavboxsync pSeg = (PDRVDISKSEGMENT)RTMemRealloc(pSeg, RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbPreLeft / 512]));
8112e0942f1128329b99b22a20b395963d4abceavboxsync pSeg->Core.KeyLast = pSeg->Core.Key + cbPreLeft - 1;
8112e0942f1128329b99b22a20b395963d4abceavboxsync bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
8112e0942f1128329b99b22a20b395963d4abceavboxsync } /* if (cbPreLeft && cbPostLeft) */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * Adds a request to the active list.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @returns nothing.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @param pThis The driver instance data.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @param pIoReq The request to add.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsyncstatic void drvdiskintIoReqAdd(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pThis->iNextFreeSlot];
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* Search for the next one. */
8112e0942f1128329b99b22a20b395963d4abceavboxsync while (pThis->apReqActive[pThis->iNextFreeSlot].pIoReq)
8112e0942f1128329b99b22a20b395963d4abceavboxsync pThis->iNextFreeSlot = (pThis->iNextFreeSlot+1) % RT_ELEMENTS(pThis->apReqActive);
8112e0942f1128329b99b22a20b395963d4abceavboxsync * Removes a request from the active list.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @returns nothing.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @param pThis The driver instance data.
8112e0942f1128329b99b22a20b395963d4abceavboxsync * @param pIoReq The request to remove.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic void drvdiskintIoReqRemove(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pIoReq->iSlot];
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * Thread checking for expired requests.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @returns IPRT status code.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @param pThread Thread handle.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @param pvUser Opaque user data.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic int drvdiskIntIoReqExpiredCheck(RTTHREAD pThread, void *pvUser)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = (PDRVDISKINTEGRITY)pvUser;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync int rc = RTSemEventWait(pThis->SemEvent, pThis->uCheckIntervalMs);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Get current timestamp for comparison. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Go through the array and check for expired requests. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[i];
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKAIOREQ pIoReq = ASMAtomicReadPtrT(&pReqActive->pIoReq, PDRVDISKAIOREQ);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync && (tsCurr - pReqActive->tsStart) >= pThis->uExpireIntervalMs)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync RTMsgError("Request %#p expired (active for %llu ms already)\n",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/* -=-=-=-=- IMedia -=-=-=-=- */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIA. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync#define PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMedia)) )
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIAASYNC. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync#define PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsync)) )
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/*******************************************************************************
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync* Media interface methods *
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync*******************************************************************************/
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** @copydoc PDMIMEDIA::pfnRead */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_READ, off,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, &SgBuf);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Verify the read. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = drvdiskintReadVerify(pThis, &Seg, 1, off, cbRead);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** @copydoc PDMIMEDIA::pfnWrite */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_WRITE, off,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, NULL);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Record the write. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(int) drvdiskintStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync LogFlow(("%s: uOffset=%llu paSeg=%#p cSeg=%u cbRead=%d pvUser=%#p\n", __FUNCTION__,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_READ, uOffset, paSeg, cSeg, cbRead, pvUser);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync int rc2 = VDDbgIoLogStart(pThis->hIoLogger, true, VDDBGIOLOGREQ_READ, uOffset,
eac945b2260779f7c5d44d8015bcc4779498c6f9vboxsync int rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
eac945b2260779f7c5d44d8015bcc4779498c6f9vboxsync /* Verify the read now. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync int rc2 = drvdiskintReadVerify(pThis, paSeg, cSeg, uOffset, cbRead);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, &SgBuf);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(int) drvdiskintStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d pvUser=%#p\n", __FUNCTION__,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_WRITE, uOffset, paSeg, cSeg, cbWrite, pvUser);
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync int rc2 = VDDbgIoLogStart(pThis->hIoLogger, true, VDDBGIOLOGREQ_WRITE, uOffset,
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync int rc = pThis->pDrvMediaAsync->pfnStartWrite(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync /* Record the write. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync int rc2 = drvdiskintWriteRecord(pThis, paSeg, cSeg, uOffset, cbWrite);
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, NULL);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync/** @copydoc PDMIMEDIAASYNC::pfnStartFlush */
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsyncstatic DECLCALLBACK(int) drvdiskintStartFlush(PPDMIMEDIAASYNC pInterface, void *pvUser)
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_FLUSH, 0, NULL, 0, 0, pvUser);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync rc = VDDbgIoLogStart(pThis->hIoLogger, true, VDDBGIOLOGREQ_FLUSH, 0,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync rc = pThis->pDrvMediaAsync->pfnStartFlush(pThis->pDrvMediaAsync, pIoReq);
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, NULL);
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync/** @copydoc PDMIMEDIAASYNC::pfnStartDiscard */
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsyncstatic DECLCALLBACK(int) drvdiskintStartDiscard(PPDMIMEDIAASYNC pInterface, PCRTRANGE paRanges, unsigned cRanges, void *pvUser)
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_DISCARD, 0, NULL, 0, 0, pvUser);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = VDDbgIoLogStartDiscard(pThis->hIoLogger, true, paRanges, cRanges, &hIoLogEntry);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = pThis->pDrvMediaAsync->pfnStartDiscard(pThis->pDrvMediaAsync, paRanges, cRanges, pIoReq);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, NULL);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** @copydoc PDMIMEDIA::pfnFlush */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(int) drvdiskintFlush(PPDMIMEDIA pInterface)
8112e0942f1128329b99b22a20b395963d4abceavboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_FLUSH, 0,
8112e0942f1128329b99b22a20b395963d4abceavboxsync int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, NULL);
8112e0942f1128329b99b22a20b395963d4abceavboxsync/** @copydoc PDMIMEDIA::pfnGetSize */
8112e0942f1128329b99b22a20b395963d4abceavboxsyncstatic DECLCALLBACK(uint64_t) drvdiskintGetSize(PPDMIMEDIA pInterface)
8112e0942f1128329b99b22a20b395963d4abceavboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
8112e0942f1128329b99b22a20b395963d4abceavboxsync return pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
8112e0942f1128329b99b22a20b395963d4abceavboxsync/** @copydoc PDMIMEDIA::pfnIsReadOnly */
8112e0942f1128329b99b22a20b395963d4abceavboxsyncstatic DECLCALLBACK(bool) drvdiskintIsReadOnly(PPDMIMEDIA pInterface)
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
8112e0942f1128329b99b22a20b395963d4abceavboxsync return pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
8112e0942f1128329b99b22a20b395963d4abceavboxsync/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
8112e0942f1128329b99b22a20b395963d4abceavboxsyncstatic DECLCALLBACK(int) drvdiskintBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
8112e0942f1128329b99b22a20b395963d4abceavboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
8112e0942f1128329b99b22a20b395963d4abceavboxsync return pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
8112e0942f1128329b99b22a20b395963d4abceavboxsync/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
8112e0942f1128329b99b22a20b395963d4abceavboxsyncstatic DECLCALLBACK(int) drvdiskintBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
8112e0942f1128329b99b22a20b395963d4abceavboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync return pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsyncstatic DECLCALLBACK(int) drvdiskintBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
fdd17dc68230654ee0796918863927fca10a9f0avboxsync return pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(int) drvdiskintBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync return pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** @copydoc PDMIMEDIA::pfnGetUuid */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(int) drvdiskintGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync return pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, pUuid);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** @copydoc PDMIMEDIA::pfnDiscard */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(int) drvdiskintDiscard(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = VDDbgIoLogStartDiscard(pThis->hIoLogger, false, paRanges, cRanges, &hIoLogEntry);
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync rc = pThis->pDrvMedia->pfnDiscard(pThis->pDrvMedia, paRanges, cRanges);
3fe24a3690526efc4cceece3819d628caadf3140vboxsync int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, NULL);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = drvdiskintDiscardRecords(pThis, paRanges, cRanges);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync#define PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsyncPort))) )
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(int) drvdiskintAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Remove from the active list. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = drvdiskintReadVerify(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = drvdiskintWriteRecord(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_DISCARD)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = drvdiskintDiscardRecords(pThis, pIoReq->paRanges, pIoReq->cRanges);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync AssertMsg(pIoReq->enmTxDir == DRVDISKAIOTXDIR_FLUSH, ("Huh?\n"));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, rc, &SgBuf);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvUserComplete, rcReq);
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync/* -=-=-=-=- IMediaPort -=-=-=-=- */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** Makes a PDRVBLOCK out of a PPDMIMEDIAPORT. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync#define PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaPort))) )
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsyncstatic DECLCALLBACK(int) drvdiskintQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync return pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, ppcszController,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/* -=-=-=-=- IBase -=-=-=-=- */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(void *) drvdiskintQueryInterface(PPDMIBASE pInterface, const char *pszIID)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->pDrvMediaAsync ? &pThis->IMediaAsync : NULL);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, &pThis->IMediaAsyncPort);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->IMediaPort);
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync/* -=-=-=-=- driver interface -=-=-=-=- */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic int drvdiskintTreeDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @copydoc FNPDMDRVDESTRUCT
3aab9f739cebfaa93f6a5a51e293310619d55a5bvboxsyncstatic DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
3aab9f739cebfaa93f6a5a51e293310619d55a5bvboxsync PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* Free all requests */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
874be5c5b701726b68fa1391022ae2f5c7768894vboxsync * Construct a disk integrity driver instance.
874be5c5b701726b68fa1391022ae2f5c7768894vboxsync * @copydoc FNPDMDRVCONSTRUCT
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * Validate configuration.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
8112e0942f1128329b99b22a20b395963d4abceavboxsync "TraceRequests\0"
8112e0942f1128329b99b22a20b395963d4abceavboxsync "CheckIntervalMs\0"
8112e0942f1128329b99b22a20b395963d4abceavboxsync "ExpireIntervalMs\0"
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync "CheckDoubleCompletions\0"
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync "HistorySize\0"
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync "IoLog\0"))
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
8112e0942f1128329b99b22a20b395963d4abceavboxsync rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
8112e0942f1128329b99b22a20b395963d4abceavboxsync rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = CFGMR3QueryStringAlloc(pCfg, "IoLog", &pszIoLogFilename);
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync Assert(RT_SUCCESS(rc) || rc == VERR_CFGM_VALUE_NOT_FOUND);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Initialize most of the data members.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* IBase. */
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* IMedia */
8865816a3d875ec1a036af307fbb484af107f014vboxsync pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
8865816a3d875ec1a036af307fbb484af107f014vboxsync pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
8865816a3d875ec1a036af307fbb484af107f014vboxsync pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
f8bec4d0d62cd1f6e3e5eabf8f2703aef91a6dbevboxsync pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
f8bec4d0d62cd1f6e3e5eabf8f2703aef91a6dbevboxsync pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync /* IMediaAsync */
8865816a3d875ec1a036af307fbb484af107f014vboxsync pThis->IMediaAsync.pfnStartRead = drvdiskintStartRead;
8865816a3d875ec1a036af307fbb484af107f014vboxsync pThis->IMediaAsync.pfnStartWrite = drvdiskintStartWrite;
8865816a3d875ec1a036af307fbb484af107f014vboxsync pThis->IMediaAsync.pfnStartFlush = drvdiskintStartFlush;
8865816a3d875ec1a036af307fbb484af107f014vboxsync /* IMediaAsyncPort. */
8865816a3d875ec1a036af307fbb484af107f014vboxsync pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvdiskintAsyncTransferCompleteNotify;
8865816a3d875ec1a036af307fbb484af107f014vboxsync /* IMediaPort. */
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation;
8865816a3d875ec1a036af307fbb484af107f014vboxsync /* Query the media port interface above us. */
8865816a3d875ec1a036af307fbb484af107f014vboxsync pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
f8bec4d0d62cd1f6e3e5eabf8f2703aef91a6dbevboxsync return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
8865816a3d875ec1a036af307fbb484af107f014vboxsync /* Try to attach async media port interface above.*/
8865816a3d875ec1a036af307fbb484af107f014vboxsync pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
8865816a3d875ec1a036af307fbb484af107f014vboxsync * Try attach driver below and query it's media interface.
8865816a3d875ec1a036af307fbb484af107f014vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
f8bec4d0d62cd1f6e3e5eabf8f2703aef91a6dbevboxsync pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
8865816a3d875ec1a036af307fbb484af107f014vboxsync return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
8865816a3d875ec1a036af307fbb484af107f014vboxsync pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync pThis->IMediaAsync.pfnStartDiscard = drvdiskintStartDiscard;
8865816a3d875ec1a036af307fbb484af107f014vboxsync /* Create the AVL tree. */
f8bec4d0d62cd1f6e3e5eabf8f2703aef91a6dbevboxsync pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
8865816a3d875ec1a036af307fbb484af107f014vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync /* Init event semaphore. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync rc = VDDbgIoLogCreate(&pThis->hIoLogger, pszIoLogFilename, VDDBG_IOLOG_LOG_DATA);
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync * Block driver registration record.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* u32Version */
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync /* szName */
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync "DiskIntegrity",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* szRCMod */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* szR0Mod */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pszDescription */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync "Disk integrity driver.",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* fFlags */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* fClass. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* cMaxInstances */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* cbInstance */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnConstruct */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnDestruct */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnRelocate */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnIOCtl */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnPowerOn */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnReset */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnSuspend */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnResume */
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync /* pfnAttach */
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync /* pfnDetach */
3fe24a3690526efc4cceece3819d628caadf3140vboxsync /* pfnPowerOff */
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync /* pfnSoftReset */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* u32EndVersion */