DrvDiskIntegrity.cpp revision 7de81a482cdfc1bbf53600a4f6cdd4c892ee460c
/* $Id$ */
/** @file
* VBox storage devices: Disk integrity check.
*/
/*
* Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/semaphore.h>
#include "Builtins.h"
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* async I/O request.
*/
typedef struct DRVDISKAIOREQ
{
/** Flag whether this is a read or write request. */
bool fRead;
/** Start offset. */
/** Transfer size. */
/** Segment array. */
/** Number of array entries. */
unsigned cSeg;
/** User argument */
void *pvUser;
/** Slot in the array. */
unsigned iSlot;
/**
* I/O log entry.
*/
typedef struct IOLOGENT
{
/** Start offset */
/** Write size */
/** Number of references to this entry. */
unsigned cRefs;
/**
* Disk segment.
*/
typedef struct DRVDISKSEGMENT
{
/** AVL core. */
/** Size of the segment */
/** Data for this segment */
/** Numbner of entries in the I/O array. */
unsigned cIoLogEntries;
/** Array of I/O log references. */
/**
* Active requests list entry.
*/
typedef struct DRVDISKAIOREQACTIVE
{
/** Pointer to the request. */
volatile PDRVDISKAIOREQ pIoReq;
/** Start timestamp. */
/**
* Disk integrity driver instance data.
*
* @implements PDMIMEDIA
*/
typedef struct DRVDISKINTEGRITY
{
/** Pointer driver instance. */
/** Pointer to the media driver below us.
* This is NULL if the media is not mounted. */
/** Our media interface */
/** Pointer to the media async driver below us.
* This is NULL if the media is not mounted. */
/** Our media async interface */
/** The async media port interface above. */
/** Our media async port interface */
/** Flag whether consistency checks are enabled. */
bool fCheckConsistency;
/** AVL tree containing the disk blocks to check. */
/** Flag whether async request tracing is enabled. */
bool fTraceRequests;
/** Interval the thread should check for expired requests (milliseconds). */
/** Expire timeout for a request (milliseconds). */
/** Thread which checks for lost requests. */
/** Event semaphore */
/** Flag whether the thread should run. */
bool fRunning;
/** Array containing active requests. */
/** Next free slot in the array */
volatile unsigned iNextFreeSlot;
/**
* Allocate a new I/O request.
*
* @returns New I/O request.
* @param fRead Flag whether this is a read or a write.
* @param off Start offset.
* @param paSeg Segment array.
* @param cSeg Number of segments.
* @param cbTransfer Number of bytes to transfer.
* @param pvUser User argument.
*/
{
{
}
return pIoReq;
}
/**
* 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.
*/
{
int rc = VINF_SUCCESS;
LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbWrite=%u\n",
/* Update the segments */
if (!pIoLogEnt)
return VERR_NO_MEMORY;
while (cbLeft)
{
bool fSet = false;
unsigned offSeg = 0;
if (!pSeg)
{
/* Get next segment */
if ( !pSeg
else
/* Create new segment */
if (pSeg)
{
else
{
fSet = true;
}
}
}
else
{
fSet = true;
}
if (fSet)
{
/* Update the I/O log pointers */
{
if (pIoLogOld)
{
}
offSeg += 512;
}
}
else
}
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.
*/
{
int rc = VINF_SUCCESS;
LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbRead=%u\n",
/* Compare read data */
while (cbLeft)
{
bool fCmp = false;
unsigned offSeg = 0;
if (!pSeg)
{
/* Get next segment */
if (!pSeg)
{
/* No data in the tree for this read. Assume everything is ok. */
}
else
}
else
{
fCmp = true;
}
if (fCmp)
{
{
/* Corrupted disk, print I/O log entry of the last write which accessed this range. */
RTMsgError("Corrupted disk at offset %llu (%u bytes in the current read buffer)!\n",
RTMsgError("Last write to this sector started at offset %llu with %u bytes (%u references to this log entry)\n",
}
}
else
}
return rc;
}
/**
* Adds a request to the active list.
*
* @returns nothing.
* @param pThis The driver instance data.
* @param pIoReq The request to add.
*/
{
/* Search for the next one. */
}
/**
* Removes a request from the active list.
*
* @returns nothing.
* @param pThis The driver instance data.
* @param pIoReq The request to remove.
*/
{
}
/**
* Thread checking for expired requests.
*
* @returns IPRT status code.
* @param pThread Thread handle.
* @param pvUser Opaque user data.
*/
{
{
break;
/* Get current timestamp for comparison. */
/* Go through the array and check for expired requests. */
{
if ( pIoReq
{
RTMsgError("Request %#p expired (active for %llu ms already)\n",
}
}
}
return VINF_SUCCESS;
}
/* -=-=-=-=- IMedia -=-=-=-=- */
/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIA. */
#define PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMedia)) )
/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIAASYNC. */
#define PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsync)) )
/*******************************************************************************
* Media interface methods *
*******************************************************************************/
/** @copydoc PDMIMEDIA::pfnRead */
{
if (RT_FAILURE(rc))
return rc;
if (pThis->fCheckConsistency)
{
/* Verify the read. */
}
return rc;
}
/** @copydoc PDMIMEDIA::pfnWrite */
{
if (RT_FAILURE(rc))
return rc;
if (pThis->fCheckConsistency)
{
/* Record the write. */
}
return rc;
}
{
if (pThis->fTraceRequests)
if (rc == VINF_VD_ASYNC_IO_FINISHED)
{
/* Verify the read now. */
if (pThis->fCheckConsistency)
{
}
if (pThis->fTraceRequests)
}
return rc;
}
{
if (pThis->fTraceRequests)
if (rc == VINF_VD_ASYNC_IO_FINISHED)
{
/* Verify the read now. */
if (pThis->fCheckConsistency)
{
}
if (pThis->fTraceRequests)
}
return rc;
}
/** @copydoc PDMIMEDIA::pfnFlush */
{
}
/** @copydoc PDMIMEDIA::pfnGetSize */
{
}
/** @copydoc PDMIMEDIA::pfnIsReadOnly */
{
}
/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
{
}
/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
{
}
/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
{
}
/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
{
}
/** @copydoc PDMIMEDIA::pfnGetUuid */
{
}
/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
#define PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsyncPort))) )
static DECLCALLBACK(int) drvdiskintAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
{
int rc = VINF_SUCCESS;
/* Remove from the active list. */
if (pThis->fTraceRequests)
{
else
}
rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pIoReq->pvUser, rcReq);
return rc;
}
/* -=-=-=-=- IBase -=-=-=-=- */
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
{
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->pDrvMediaAsync ? &pThis->IMediaAsync : NULL);
return NULL;
}
/* -=-=-=-=- driver interface -=-=-=-=- */
{
return VINF_SUCCESS;
}
/**
* @copydoc FNPDMDRVDESTRUCT
*/
{
if (pThis->pTreeSegments)
{
}
if (pThis->fTraceRequests)
{
}
}
/**
* Construct a disk integrity driver instance.
*
* @copydoc FNPDMDRVCONSTRUCT
*/
{
int rc = VINF_SUCCESS;
/*
* Validate configuration.
*/
"TraceRequests\0"
"CheckIntervalMs\0"
"ExpireIntervalMs\0"))
rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
/*
* Initialize most of the data members.
*/
/* IBase. */
/* IMedia */
/* IMediaAsync */
/* IMediaAsyncPort. */
/*
* Try attach driver below and query it's media interface.
*/
if (RT_FAILURE(rc))
N_("No media or async media interface below"));
/* Try to attach async media port interface above.*/
if (pThis->fCheckConsistency)
{
/* Create the AVL tree. */
if (!pThis->pTreeSegments)
rc = VERR_NO_MEMORY;
}
if (pThis->fTraceRequests)
{
{
}
pThis->iNextFreeSlot = 0;
/* Init event semaphore. */
0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
}
return rc;
}
/**
* Block driver registration record.
*/
const PDMDRVREG g_DrvDiskIntegrity =
{
/* u32Version */
/* szName */
"DiskIntegrity",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"Disk integrity driver.",
/* fFlags */
/* fClass. */
/* cMaxInstances */
~0,
/* cbInstance */
sizeof(DRVDISKINTEGRITY),
/* pfnConstruct */
/* pfnDestruct */
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32EndVersion */
};