DrvDiskIntegrity.cpp revision 060db742c6ecb43560beec8754fb5b9c13bd7856
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * VBox storage devices: Disk integrity check.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2010 Oracle Corporation
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * available from http://www.virtualbox.org. This file is free software;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * you can redistribute it and/or modify it under the terms of the GNU
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * General Public License (GPL) as published by the Free Software
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/*******************************************************************************
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync* Header Files *
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync*******************************************************************************/
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/*******************************************************************************
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync* Structures and Typedefs *
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync*******************************************************************************/
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * Transfer direction.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync /** Read */
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync /** Write */
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync /** Flush */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * async I/O request.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync /** Transfer direction. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** Start offset. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** Transfer size. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** Segment array. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** Number of array entries. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** User argument */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Slot in the array. */
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync /** Start timestamp */
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync /** Completion timestamp. */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync * I/O log entry.
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsynctypedef struct IOLOGENT
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync /** Start offset */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync /** Write size */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync /** Number of references to this entry. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Disk segment.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /** AVL core. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /** Size of the segment */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /** Data for this segment */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync /** Numbner of entries in the I/O array. */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync /** Array of I/O log references. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Active requests list entry.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Pointer to the request. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Start timestamp. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Disk integrity driver instance data.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @implements PDMIMEDIA
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /** Pointer driver instance. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /** Pointer to the media driver below us.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * This is NULL if the media is not mounted. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /** Our media interface */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** Pointer to the media async driver below us.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * This is NULL if the media is not mounted. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** Our media async interface */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** The async media port interface above. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /** Our media async port interface */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Flag whether consistency checks are enabled. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /** AVL tree containing the disk blocks to check. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Flag whether async request tracing is enabled. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Interval the thread should check for expired requests (milliseconds). */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Expire timeout for a request (milliseconds). */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Thread which checks for lost requests. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Event semaphore */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Flag whether the thread should run. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Array containing active requests. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /** Next free slot in the array */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync volatile unsigned iNextFreeSlot;
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync /** Flag whether we check for requests completing twice. */
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync /** Number of requests we go back. */
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync /** Array of completed but still observed requests. */
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync /** Current entry in the array. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Allocate a new I/O request.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @returns New I/O request.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync * @param enmTxDir Transfer direction.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param off Start offset.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param paSeg Segment array.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param cSeg Number of segments.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param cbTransfer Number of bytes to transfer.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param pvUser User argument.
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsyncstatic PDRVDISKAIOREQ drvdiskintIoReqAlloc(DRVDISKAIOTXDIR enmTxDir, uint64_t off, PCRTSGSEG paSeg,
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)RTMemAlloc(sizeof(DRVDISKAIOREQ));
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * Free a async I/O request.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * @returns nothing.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * @param pThis Disk driver.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync * @param pIoReq The I/O request to free.
a98c2afd05b2949737f73ec954d227712f3b0146vboxsyncstatic void drvdiskintIoReqFree(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync /* Search if the I/O request completed already. */
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync RTMsgError("Request %#p completed already!\n", pIoReq);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync RTMsgError("Start timestamp %llu Completion timestamp %llu (completed after %llu ms)\n",
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync pIoReq->tsStart, pIoReq->tsComplete, pIoReq->tsComplete - pIoReq->tsStart);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Record a successful write to the virtual disk.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @returns VBox status code.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param pThis Disk integrity driver instance data.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param paSeg Segment array of the write to record.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param cSeg Number of segments.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param off Start offset.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param cbWrite Number of bytes to record.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsyncstatic int drvdiskintWriteRecord(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
6114ff5789db75ff28460a056ed422ee03d8f0ebvboxsync LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbWrite=%u\n",
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* Update the segments */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync PIOLOGENT pIoLogEnt = (PIOLOGENT)RTMemAllocZ(sizeof(IOLOGENT));
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync bool fSet = false;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync unsigned offSeg = 0;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* Get next segment */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* Create new segment */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync pSeg = (PDRVDISKSEGMENT)RTMemAllocZ(RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbRange / 512]));
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync pSeg->Core.KeyLast = offCurr + (RTFOFF)cbRange - 1;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
e93dfb5368911523b10cd2f506c44f5fbd47abf3vboxsync size_t cbCopied = RTSgBufCopyToBuf(&SgBuf, pSeg->pbSeg + offSeg, cbRange);
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync /* Update the I/O log pointers */
bf27591c0d413dd4d7ba41cf89f117171968d462vboxsync AssertMsg(uSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * Verifies a read request.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @returns VBox status code.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param pThis Disk integrity driver instance data.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param paSeg Segment array of the containing the data buffers to verify.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param cSeg Number of segments.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param off Start offset.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync * @param cbWrite Number of bytes to verify.
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsyncstatic int drvdiskintReadVerify(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
6114ff5789db75ff28460a056ed422ee03d8f0ebvboxsync LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbRead=%u\n",
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* Compare read data */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync bool fCmp = false;
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync unsigned offSeg = 0;
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* Get next segment */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* No data in the tree for this read. Assume everything is ok. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync else if (offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync if (RTSgBufCmpEx(&SgBuf, &SgBufCmp, cbRange, &cbOff, true))
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync /* Corrupted disk, print I/O log entry of the last write which accessed this range. */
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync AssertMsg(cSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync RTMsgError("Corrupted disk at offset %llu (%u bytes in the current read buffer)!\n",
1426407ebd84624dd10808b452b19d1fc4f6835avboxsync RTMsgError("Last write to this sector started at offset %llu with %u bytes (%u references to this log entry)\n",
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Adds a request to the active list.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @returns nothing.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @param pThis The driver instance data.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @param pIoReq The request to add.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic void drvdiskintIoReqAdd(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pThis->iNextFreeSlot];
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /* Search for the next one. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync while (pThis->apReqActive[pThis->iNextFreeSlot].pIoReq)
7de81a482cdfc1bbf53600a4f6cdd4c892ee460cvboxsync pThis->iNextFreeSlot = (pThis->iNextFreeSlot+1) % RT_ELEMENTS(pThis->apReqActive);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Removes a request from the active list.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @returns nothing.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @param pThis The driver instance data.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @param pIoReq The request to remove.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic void drvdiskintIoReqRemove(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pIoReq->iSlot];
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * Thread checking for expired requests.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @returns IPRT status code.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @param pThread Thread handle.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync * @param pvUser Opaque user data.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsyncstatic int drvdiskIntIoReqExpiredCheck(RTTHREAD pThread, void *pvUser)
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync PDRVDISKINTEGRITY pThis = (PDRVDISKINTEGRITY)pvUser;
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync int rc = RTSemEventWait(pThis->SemEvent, pThis->uCheckIntervalMs);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /* Get current timestamp for comparison. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /* Go through the array and check for expired requests. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[i];
c7ff622115966b69b482bd2896662e40d823b22fvboxsync PDRVDISKAIOREQ pIoReq = ASMAtomicReadPtrT(&pReqActive->pIoReq, PDRVDISKAIOREQ);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync && (tsCurr - pReqActive->tsStart) >= pThis->uExpireIntervalMs)
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync RTMsgError("Request %#p expired (active for %llu ms already)\n",
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/* -=-=-=-=- IMedia -=-=-=-=- */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIA. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync#define PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMedia)) )
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIAASYNC. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync#define PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsync)) )
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/*******************************************************************************
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync* Media interface methods *
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync*******************************************************************************/
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/** @copydoc PDMIMEDIA::pfnRead */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsyncstatic DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync int rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /* Verify the read. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = drvdiskintReadVerify(pThis, &Seg, 1, off, cbRead);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/** @copydoc PDMIMEDIA::pfnWrite */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsyncstatic DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync int rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /* Record the write. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsyncstatic DECLCALLBACK(int) drvdiskintStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
7de81a482cdfc1bbf53600a4f6cdd4c892ee460cvboxsync LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d pvUser=%#p\n", __FUNCTION__,
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_READ, uOffset, paSeg, cSeg, cbRead, pvUser);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync int rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* Verify the read now. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync int rc2 = drvdiskintReadVerify(pThis, paSeg, cSeg, uOffset, cbRead);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsyncstatic DECLCALLBACK(int) drvdiskintStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
7de81a482cdfc1bbf53600a4f6cdd4c892ee460cvboxsync LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d pvUser=%#p\n", __FUNCTION__,
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_WRITE, uOffset, paSeg, cSeg, cbWrite, pvUser);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync int rc = pThis->pDrvMediaAsync->pfnStartWrite(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* Verify the read now. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync int rc2 = drvdiskintWriteRecord(pThis, paSeg, cSeg, uOffset, cbWrite);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync/** @copydoc PDMIMEDIAASYNC::pfnStartFlush */
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsyncstatic DECLCALLBACK(int) drvdiskintStartFlush(PPDMIMEDIAASYNC pInterface, void *pvUser)
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_FLUSH, 0, NULL, 0, 0, pvUser);
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync return pThis->pDrvMediaAsync->pfnStartFlush(pThis->pDrvMediaAsync, pIoReq);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/** @copydoc PDMIMEDIA::pfnFlush */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(int) drvdiskintFlush(PPDMIMEDIA pInterface)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/** @copydoc PDMIMEDIA::pfnGetSize */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(uint64_t) drvdiskintGetSize(PPDMIMEDIA pInterface)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/** @copydoc PDMIMEDIA::pfnIsReadOnly */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(bool) drvdiskintIsReadOnly(PPDMIMEDIA pInterface)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(int) drvdiskintBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(int) drvdiskintBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(int) drvdiskintBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(int) drvdiskintBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/** @copydoc PDMIMEDIA::pfnGetUuid */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(int) drvdiskintGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, pUuid);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync#define PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsyncPort))) )
f687f34bd232be13744edbc0cc5155fa5d4540edvboxsyncstatic DECLCALLBACK(int) drvdiskintAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /* Remove from the active list. */
f687f34bd232be13744edbc0cc5155fa5d4540edvboxsync rc = drvdiskintReadVerify(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE)
f687f34bd232be13744edbc0cc5155fa5d4540edvboxsync rc = drvdiskintWriteRecord(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync AssertMsg(pIoReq->enmTxDir == DRVDISKAIOTXDIR_FLUSH, ("Huh?\n"));
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvUserComplete, rcReq);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/* -=-=-=-=- IBase -=-=-=-=- */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(void *) drvdiskintQueryInterface(PPDMIBASE pInterface, const char *pszIID)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
6114ff5789db75ff28460a056ed422ee03d8f0ebvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->pDrvMediaAsync ? &pThis->IMediaAsync : NULL);
6114ff5789db75ff28460a056ed422ee03d8f0ebvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, &pThis->IMediaAsyncPort);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync/* -=-=-=-=- driver interface -=-=-=-=- */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic int drvdiskintTreeDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @copydoc FNPDMDRVDESTRUCT
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync /* Free all requests */
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Construct a disk integrity driver instance.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * @copydoc FNPDMDRVCONSTRUCT
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsyncstatic DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Validate configuration.
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync "TraceRequests\0"
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync "CheckIntervalMs\0"
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync "ExpireIntervalMs\0"
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync "CheckDoubleCompletions\0"
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync "HistorySize\0"))
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Initialize most of the data members.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* IBase. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* IMedia */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* IMediaAsync */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pThis->IMediaAsync.pfnStartRead = drvdiskintStartRead;
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pThis->IMediaAsync.pfnStartWrite = drvdiskintStartWrite;
34b5a73592441cbfacb85c2f2261648c1d25ad31vboxsync pThis->IMediaAsync.pfnStartFlush = drvdiskintStartFlush;
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* IMediaAsyncPort. */
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvdiskintAsyncTransferCompleteNotify;
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Try attach driver below and query it's media interface.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync /* Try to attach async media port interface above.*/
b26de2ddb274b0e52de6652ad8b45259be2b9913vboxsync pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /* Create the AVL tree. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync /* Init event semaphore. */
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
3e88c818fff5c64b5eff43d5daf4596bd87230c5vboxsync 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
a98c2afd05b2949737f73ec954d227712f3b0146vboxsync pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync * Block driver registration record.
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* u32Version */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* szName */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync "DiskIntegrity",
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* szRCMod */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* szR0Mod */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pszDescription */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync "Disk integrity driver.",
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* fFlags */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* fClass. */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* cMaxInstances */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* cbInstance */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnConstruct */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnDestruct */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnRelocate */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnIOCtl */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnPowerOn */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnReset */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnSuspend */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnResume */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnAttach */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnDetach */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnPowerOff */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* pfnSoftReset */
fb7b8c126ea3bc0adf9dd2b2b6a43870ee41853avboxsync /* u32EndVersion */