tstVDIo.cpp revision c299849be8ae3544715e8806e1433cae67d93e2e
/* $Id$ */
/** @file
*
* VBox HDD container test utility - I/O replay.
*/
/*
* Copyright (C) 2011-2014 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.
*/
#define LOGGROUP LOGGROUP_DEFAULT
#include <iprt/initterm.h>
#include <iprt/semaphore.h>
#include <iprt/critsect.h>
#include "VDMemDisk.h"
#include "VDIoBackend.h"
#include "VDIoRnd.h"
#include "VDScript.h"
#include "BuiltinTests.h"
/** forward declaration for the global test data pointer. */
typedef struct VDTESTGLOB *PVDTESTGLOB;
/**
* A virtual file backed by memory.
*/
typedef struct VDFILE
{
/** Pointer to the next file. */
/** Name of the file. */
char *pszName;
/** Storage backing the file. */
/** Flag whether the file is read locked. */
bool fReadLock;
/** Flag whether the file is write locked. */
bool fWriteLock;
/** Statistics: Number of reads. */
unsigned cReads;
/** Statistics: Number of writes. */
unsigned cWrites;
/** Statistics: Number of flushes. */
unsigned cFlushes;
/** Statistics: Number of async reads. */
unsigned cAsyncReads;
/** Statistics: Number of async writes. */
unsigned cAsyncWrites;
/** Statistics: Number of async flushes. */
unsigned cAsyncFlushes;
/**
* VD storage object.
*/
typedef struct VDSTORAGE
{
/** Pointer to the file. */
/** Completion callback of the VD layer. */
} VDSTORAGE, *PVDSTORAGE;
/**
* A virtual disk.
*/
typedef struct VDDISK
{
/** List node. */
/** Name of the disk handle for identification. */
char *pszName;
/** HDD handle to operate on. */
/** Memory disk used for data verification. */
/** Critical section to serialize access to the memory disk. */
/** Physical CHS Geometry. */
/** Logical CHS geometry. */
/** Global test data. */
/**
* A data buffer with a pattern.
*/
typedef struct VDPATTERN
{
/** List node. */
/** Name of the pattern. */
char *pszName;
/** Size of the pattern. */
/** Pointer to the buffer containing the pattern. */
void *pvPattern;
} VDPATTERN, *PVDPATTERN;
/**
* Global VD test state.
*/
typedef struct VDTESTGLOB
{
/** List of active virtual disks. */
/** Head of the active file list. */
/** Head of the pattern list. */
/** I/O backend, common data. */
/** Error interface. */
/** Pointer to the per disk interface list. */
/** I/O interface. */
/** Pointer to the per image interface list. */
/** I/O RNG handle. */
/** Current storage backend to use. */
char *pszIoBackend;
/** Testcase handle. */
} VDTESTGLOB;
/**
* Transfer direction.
*/
typedef enum VDIOREQTXDIR
{
VDIOREQTXDIR_READ = 0,
} VDIOREQTXDIR;
/**
* I/O request.
*/
typedef struct VDIOREQ
{
/** Transfer type. */
/** slot index. */
unsigned idx;
/** Start offset. */
/** Size to transfer. */
/** S/G Buffer */
/** Data segment */
/** Flag whether the request is outstanding or not. */
volatile bool fOutstanding;
/** Buffer to use for reads. */
void *pvBufRead;
/** Opaque user data. */
void *pvUser;
/**
* I/O test data.
*/
typedef struct VDIOTEST
{
/** Start offset. */
/** End offset. */
/** Flag whether random or sequential access is wanted */
bool fRandomAccess;
/** Block size. */
/** Number of bytes to transfer. */
/** Chance in percent to get a write. */
unsigned uWriteChance;
/** Pointer to the I/O data generator. */
/** Pointer to the data pattern to use. */
/** Data dependent on the I/O mode (sequential or random). */
union
{
/** Next offset for sequential access. */
/** Data for random acess. */
struct
{
/** Number of valid entries in the bitmap. */
/** Pointer to the bitmap marking accessed blocks. */
/** Number of unaccessed blocks. */
} Rnd;
} u;
static DECLCALLBACK(int) vdScriptHandlerIoPatternCreateFromNumber(PVDSCRIPTARG paScriptArgs, void *pvUser);
static DECLCALLBACK(int) vdScriptHandlerIoPatternCreateFromFile(PVDSCRIPTARG paScriptArgs, void *pvUser);
/* create action */
const VDSCRIPTTYPE g_aArgCreate[] =
{
};
/* open action */
const VDSCRIPTTYPE g_aArgOpen[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_STRING, /* name */
VDSCRIPTTYPE_STRING, /* backend */
VDSCRIPTTYPE_BOOL, /* async */
VDSCRIPTTYPE_BOOL, /* shareable */
VDSCRIPTTYPE_BOOL, /* readonly */
VDSCRIPTTYPE_BOOL, /* discard */
VDSCRIPTTYPE_BOOL, /* ignoreflush */
VDSCRIPTTYPE_BOOL, /* honorsame */
};
/* I/O action */
const VDSCRIPTTYPE g_aArgIo[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_BOOL, /* async */
VDSCRIPTTYPE_UINT32, /* max-reqs */
VDSCRIPTTYPE_STRING, /* mode */
VDSCRIPTTYPE_UINT64, /* size */
VDSCRIPTTYPE_UINT64, /* blocksize */
VDSCRIPTTYPE_UINT64, /* offStart */
VDSCRIPTTYPE_UINT64, /* offEnd */
VDSCRIPTTYPE_UINT32, /* writes */
VDSCRIPTTYPE_STRING /* pattern */
};
/* flush action */
const VDSCRIPTTYPE g_aArgFlush[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_BOOL /* async */
};
/* merge action */
const VDSCRIPTTYPE g_aArgMerge[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_UINT32, /* from */
VDSCRIPTTYPE_UINT32 /* to */
};
/* Compact a disk */
const VDSCRIPTTYPE g_aArgCompact[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_UINT32 /* image */
};
/* Discard a part of a disk */
const VDSCRIPTTYPE g_aArgDiscard[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_BOOL, /* async */
VDSCRIPTTYPE_STRING /* ranges */
};
/* Compact a disk */
const VDSCRIPTTYPE g_aArgCopy[] =
{
VDSCRIPTTYPE_STRING, /* diskfrom */
VDSCRIPTTYPE_STRING, /* diskto */
VDSCRIPTTYPE_UINT32, /* imagefrom */
VDSCRIPTTYPE_STRING, /* backend */
VDSCRIPTTYPE_STRING, /* filename */
VDSCRIPTTYPE_BOOL, /* movebyrename */
VDSCRIPTTYPE_UINT64, /* size */
VDSCRIPTTYPE_UINT32, /* fromsame */
VDSCRIPTTYPE_UINT32 /* tosame */
};
/* close action */
const VDSCRIPTTYPE g_aArgClose[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_STRING, /* mode */
VDSCRIPTTYPE_BOOL /* delete */
};
/* print file size action */
const VDSCRIPTTYPE g_aArgPrintFileSize[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_UINT32 /* image */
};
/* print file size action */
const VDSCRIPTTYPE g_aArgIoLogReplay[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_STRING /* iolog */
};
/* I/O RNG create action */
const VDSCRIPTTYPE g_aArgIoRngCreate[] =
{
VDSCRIPTTYPE_UINT32, /* size */
VDSCRIPTTYPE_STRING, /* mode */
VDSCRIPTTYPE_UINT32, /* seed */
};
/* I/O pattern create action */
const VDSCRIPTTYPE g_aArgIoPatternCreateFromNumber[] =
{
VDSCRIPTTYPE_STRING, /* name */
VDSCRIPTTYPE_UINT32, /* size */
VDSCRIPTTYPE_UINT32 /* pattern */
};
/* I/O pattern create action */
const VDSCRIPTTYPE g_aArgIoPatternCreateFromFile[] =
{
VDSCRIPTTYPE_STRING, /* name */
VDSCRIPTTYPE_STRING /* file */
};
/* I/O pattern destroy action */
const VDSCRIPTTYPE g_aArgIoPatternDestroy[] =
{
VDSCRIPTTYPE_STRING /* name */
};
/* Sleep */
const VDSCRIPTTYPE g_aArgSleep[] =
{
VDSCRIPTTYPE_UINT32 /* time */
};
/* Dump memory file */
const VDSCRIPTTYPE g_aArgDumpFile[] =
{
VDSCRIPTTYPE_STRING, /* file */
VDSCRIPTTYPE_STRING /* path */
};
/* Create virtual disk handle */
const VDSCRIPTTYPE g_aArgCreateDisk[] =
{
VDSCRIPTTYPE_STRING, /* name */
VDSCRIPTTYPE_BOOL /* verify */
};
/* Create virtual disk handle */
const VDSCRIPTTYPE g_aArgDestroyDisk[] =
{
VDSCRIPTTYPE_STRING /* name */
};
/* Compare virtual disks */
const VDSCRIPTTYPE g_aArgCompareDisks[] =
{
VDSCRIPTTYPE_STRING, /* disk1 */
VDSCRIPTTYPE_STRING /* disk2 */
};
/* Dump disk info */
const VDSCRIPTTYPE g_aArgDumpDiskInfo[] =
{
VDSCRIPTTYPE_STRING /* disk */
};
/* Print message */
const VDSCRIPTTYPE g_aArgPrintMsg[] =
{
VDSCRIPTTYPE_STRING /* msg */
};
/* Show statistics */
const VDSCRIPTTYPE g_aArgShowStatistics[] =
{
VDSCRIPTTYPE_STRING /* file */
};
/* Reset statistics */
const VDSCRIPTTYPE g_aArgResetStatistics[] =
{
VDSCRIPTTYPE_STRING /* file */
};
/* Resize disk. */
const VDSCRIPTTYPE g_aArgResize[] =
{
VDSCRIPTTYPE_STRING, /* disk */
VDSCRIPTTYPE_UINT64 /* size */
};
/* Set file backend. */
const VDSCRIPTTYPE g_aArgSetFileBackend[] =
{
VDSCRIPTTYPE_STRING /* new file backend */
};
const VDSCRIPTCALLBACK g_aScriptActions[] =
{
/* pcszFnName enmTypeReturn paArgDesc cArgDescs pfnHandler */
{"printfilesize", VDSCRIPTTYPE_VOID, g_aArgPrintFileSize, RT_ELEMENTS(g_aArgPrintFileSize), vdScriptHandlerPrintFileSize},
{"ioreplay", VDSCRIPTTYPE_VOID, g_aArgIoLogReplay, RT_ELEMENTS(g_aArgIoLogReplay), vdScriptHandlerIoLogReplay},
{"iorngcreate", VDSCRIPTTYPE_VOID, g_aArgIoRngCreate, RT_ELEMENTS(g_aArgIoRngCreate), vdScriptHandlerIoRngCreate},
{"iopatterncreatefromnumber", VDSCRIPTTYPE_VOID, g_aArgIoPatternCreateFromNumber, RT_ELEMENTS(g_aArgIoPatternCreateFromNumber), vdScriptHandlerIoPatternCreateFromNumber},
{"iopatterncreatefromfile", VDSCRIPTTYPE_VOID, g_aArgIoPatternCreateFromFile, RT_ELEMENTS(g_aArgIoPatternCreateFromFile), vdScriptHandlerIoPatternCreateFromFile},
{"iopatterndestroy", VDSCRIPTTYPE_VOID, g_aArgIoPatternDestroy, RT_ELEMENTS(g_aArgIoPatternDestroy), vdScriptHandlerIoPatternDestroy},
{"dumpfile", VDSCRIPTTYPE_VOID, g_aArgDumpFile, RT_ELEMENTS(g_aArgDumpFile), vdScriptHandlerDumpFile},
{"createdisk", VDSCRIPTTYPE_VOID, g_aArgCreateDisk, RT_ELEMENTS(g_aArgCreateDisk), vdScriptHandlerCreateDisk},
{"destroydisk", VDSCRIPTTYPE_VOID, g_aArgDestroyDisk, RT_ELEMENTS(g_aArgDestroyDisk), vdScriptHandlerDestroyDisk},
{"comparedisks", VDSCRIPTTYPE_VOID, g_aArgCompareDisks, RT_ELEMENTS(g_aArgCompareDisks), vdScriptHandlerCompareDisks},
{"dumpdiskinfo", VDSCRIPTTYPE_VOID, g_aArgDumpDiskInfo, RT_ELEMENTS(g_aArgDumpDiskInfo), vdScriptHandlerDumpDiskInfo},
{"showstatistics", VDSCRIPTTYPE_VOID, g_aArgShowStatistics, RT_ELEMENTS(g_aArgShowStatistics), vdScriptHandlerShowStatistics},
{"resetstatistics", VDSCRIPTTYPE_VOID, g_aArgResetStatistics, RT_ELEMENTS(g_aArgResetStatistics), vdScriptHandlerResetStatistics},
{"setfilebackend", VDSCRIPTTYPE_VOID, g_aArgSetFileBackend, RT_ELEMENTS(g_aArgSetFileBackend), vdScriptHandlerSetFileBackend},
};
{
return VINF_SUCCESS;
}
{
RTPrintf("\n");
}
{
RTPrintf("tstVD: ");
return VINF_SUCCESS;
}
{
int rc = VINF_SUCCESS;
const char *pcszBackend = NULL;
bool fBase = false;
bool fDynamic = true;
bool fIgnoreFlush = false;
bool fHonorSame = false;
fBase = true;
fBase = false;
else
{
}
fDynamic = false;
fDynamic = true;
else
{
}
if (RT_SUCCESS(rc))
{
if (pDisk)
{
unsigned fOpenFlags = VD_OPEN_FLAGS_ASYNC_IO;
unsigned fImageFlags = VD_IMAGE_FLAGS_NONE;
if (!fDynamic)
if (fIgnoreFlush)
if (fHonorSame)
if (fBase)
else
}
else
rc = VERR_NOT_FOUND;
}
return rc;
}
{
int rc = VINF_SUCCESS;
const char *pcszBackend = NULL;
bool fShareable = false;
bool fReadonly = false;
bool fAsyncIo = true;
bool fDiscard = false;
bool fIgnoreFlush = false;
bool fHonorSame = false;
if (RT_SUCCESS(rc))
{
if (pDisk)
{
unsigned fOpenFlags = 0;
if (fAsyncIo)
if (fShareable)
if (fReadonly)
if (fDiscard)
if (fIgnoreFlush)
if (fHonorSame)
}
else
rc = VERR_NOT_FOUND;
}
return rc;
}
{
int rc = VINF_SUCCESS;
bool fAsync = false;
bool fRandomAcc = false;
bool fDataProviderRnd = false;
bool fPrintStats = false;
unsigned cMaxReqs = 0;
uint8_t uWriteChance = 0;
const char *pcszPattern = NULL;
fRandomAcc = false;
fRandomAcc = true;
else
{
}
if ( RT_SUCCESS(rc)
&& fAsync
&& !cMaxReqs)
if (RT_SUCCESS(rc))
{
if (!pDisk)
rc = VERR_NOT_FOUND;
}
if (RT_SUCCESS(rc))
{
/* Set defaults if not set by the user. */
{
if (offEnd == 0)
return VERR_INVALID_STATE;
}
if (!cbIo)
}
if ( RT_SUCCESS(rc)
{
if (!pPattern)
rc = VERR_NOT_FOUND;
}
if (RT_SUCCESS(rc))
{
rc = tstVDIoTestInit(&IoTest, pGlob, fRandomAcc, cbIo, cbBlkSize, offStart, offEnd, uWriteChance, pPattern);
if (RT_SUCCESS(rc))
{
{
/* Init requests. */
for (unsigned i = 0; i < cMaxTasksOutstanding; i++)
{
{
rc = VERR_NO_MEMORY;
break;
}
}
while ( tstVDIoTestRunning(&IoTest)
&& RT_SUCCESS(rc))
{
bool fTasksOutstanding = false;
unsigned idx = 0;
/* Submit all idling requests. */
while ( idx < cMaxTasksOutstanding
&& tstVDIoTestRunning(&IoTest))
{
{
if (RT_SUCCESS(rc))
{
if (!fAsync)
{
{
case VDIOREQTXDIR_READ:
{
if (RT_SUCCESS(rc)
&& pDisk->pMemDiskVerify)
{
{
}
}
break;
}
case VDIOREQTXDIR_WRITE:
{
if (RT_SUCCESS(rc)
&& pDisk->pMemDiskVerify)
{
}
break;
}
case VDIOREQTXDIR_FLUSH:
{
break;
}
case VDIOREQTXDIR_DISCARD:
AssertMsgFailed(("Invalid\n"));
}
if (RT_SUCCESS(rc))
idx++;
}
else
{
{
case VDIOREQTXDIR_READ:
{
break;
}
case VDIOREQTXDIR_WRITE:
{
break;
}
case VDIOREQTXDIR_FLUSH:
{
break;
}
case VDIOREQTXDIR_DISCARD:
AssertMsgFailed(("Invalid\n"));
}
if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
{
idx++;
fTasksOutstanding = true;
rc = VINF_SUCCESS;
}
else if (rc == VINF_VD_ASYNC_IO_FINISHED)
{
{
case VDIOREQTXDIR_READ:
{
if (pDisk->pMemDiskVerify)
{
{
}
}
break;
}
case VDIOREQTXDIR_WRITE:
{
if (pDisk->pMemDiskVerify)
{
}
break;
}
case VDIOREQTXDIR_FLUSH:
break;
case VDIOREQTXDIR_DISCARD:
AssertMsgFailed(("Invalid\n"));
}
if (rc != VERR_INVALID_STATE)
rc = VINF_SUCCESS;
}
}
if (RT_FAILURE(rc))
}
}
}
/* Wait for a request to complete. */
if ( fAsync
{
}
}
/* Cleanup, wait for all tasks to complete. */
while (fAsync)
{
unsigned idx = 0;
bool fAllIdle = true;
while (idx < cMaxTasksOutstanding)
{
{
fAllIdle = false;
break;
}
idx++;
}
if (!fAllIdle)
{
}
else
break;
}
for (unsigned i = 0; i < cMaxTasksOutstanding; i++)
{
}
}
else
rc = VERR_NO_MEMORY;
}
}
return rc;
}
{
int rc = VINF_SUCCESS;
bool fAsync = false;
if (RT_SUCCESS(rc))
{
if (!pDisk)
rc = VERR_NOT_FOUND;
else if (fAsync)
{
if (RT_SUCCESS(rc))
{
if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
{
}
else if (rc == VINF_VD_ASYNC_IO_FINISHED)
rc = VINF_SUCCESS;
}
}
else
}
return rc;
}
{
int rc = VINF_SUCCESS;
unsigned nImageFrom = 0;
unsigned nImageTo = 0;
if (!pDisk)
rc = VERR_NOT_FOUND;
else
{
/** @todo: Provide progress interface to test that cancelation
* doesn't corrupt the data.
*/
}
return rc;
}
{
int rc = VINF_SUCCESS;
unsigned nImage = 0;
if (!pDisk)
rc = VERR_NOT_FOUND;
else
{
/** @todo: Provide progress interface to test that cancelation
* doesn't corrupt the data.
*/
}
return rc;
}
{
int rc = VINF_SUCCESS;
bool fAsync = false;
const char *pcszRanges = NULL;
if (!pDisk)
rc = VERR_NOT_FOUND;
else
{
unsigned cRanges = 0;
/*
* Parse the range string which should look like this:
* n,off1,cb1,off2,cb2,...
*
* <n> gives the number of ranges in the string and every off<i>,cb<i>
* pair afterwards is a start offset + number of bytes to discard entry.
*/
do
{
break;
if (!cRanges)
{
break;
}
if (!paRanges)
{
rc = VERR_NO_MEMORY;
break;
}
if (*pcszRanges != ',')
{
break;
}
pcszRanges++;
/* Retrieve each pair from the string. */
for (unsigned i = 0; i < cRanges; i++)
{
break;
if (*pcszRanges != ',')
{
switch (*pcszRanges)
{
case 'k':
case 'K':
{
break;
}
case 'm':
case 'M':
{
break;
}
case 'g':
case 'G':
{
break;
}
default:
{
}
}
if (RT_SUCCESS(rc))
pcszRanges++;
}
if (*pcszRanges != ',')
{
break;
}
pcszRanges++;
break;
if (*pcszRanges != ',')
{
switch (*pcszRanges)
{
case 'k':
case 'K':
{
break;
}
case 'm':
case 'M':
{
break;
}
case 'g':
case 'G':
{
break;
}
default:
{
}
}
if (RT_SUCCESS(rc))
pcszRanges++;
}
if ( *pcszRanges != ','
{
break;
}
pcszRanges++;
}
} while (0);
if (RT_SUCCESS(rc))
{
if (!fAsync)
else
{
if (RT_SUCCESS(rc))
{
if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
{
}
else if (rc == VINF_VD_ASYNC_IO_FINISHED)
rc = VINF_SUCCESS;
}
}
if ( RT_SUCCESS(rc)
&& pDisk->pMemDiskVerify)
{
for (unsigned i = 0; i < cRanges; i++)
{
if (pv)
{
}
else
{
rc = VERR_NO_MEMORY;
break;
}
}
}
}
if (paRanges)
}
return rc;
}
{
int rc = VINF_SUCCESS;
const char *pcszDiskFrom = NULL;
const char *pcszDiskTo = NULL;
unsigned nImageFrom = 0;
const char *pcszBackend = NULL;
const char *pcszFilename = NULL;
bool fMoveByRename = false;
unsigned nImageFromSame = VD_IMAGE_CONTENT_UNKNOWN;
unsigned nImageToSame = VD_IMAGE_CONTENT_UNKNOWN;
rc = VERR_NOT_FOUND;
else
{
/** @todo: Provide progress interface to test that cancelation
* works as intended.
*/
}
return rc;
}
{
int rc = VINF_SUCCESS;
bool fAll = false;
bool fDelete = false;
fAll = true;
fAll = false;
else
{
}
if ( fAll
&& fDelete)
{
RTPrintf("mode=all doesn't work with delete=yes\n");
}
if (RT_SUCCESS(rc))
{
if (pDisk)
{
if (fAll)
else
}
else
rc = VERR_NOT_FOUND;
}
return rc;
}
{
int rc = VINF_SUCCESS;
unsigned nImage = 0;
if (pDisk)
else
rc = VERR_NOT_FOUND;
return rc;
}
{
int rc = VINF_SUCCESS;
if (pDisk)
{
if (RT_SUCCESS(rc))
{
/* Loop through events. */
while ( RT_SUCCESS(rc)
&& enmEvent != VDIOLOGEVENT_END)
{
bool fAsync = false;
if (RT_FAILURE(rc))
break;
switch (enmReq)
{
case VDDBGIOLOGREQ_READ:
{
if ( RT_SUCCESS(rc)
{
if (pvBuf)
else
rc = VERR_NO_MEMORY;
}
if ( RT_SUCCESS(rc)
&& !fAsync)
else if (RT_SUCCESS(rc))
break;
}
case VDDBGIOLOGREQ_WRITE:
{
if (rc == VERR_BUFFER_OVERFLOW)
{
if (pvBuf)
{
}
else
rc = VERR_NO_MEMORY;
}
if ( RT_SUCCESS(rc)
&& !fAsync)
else if (RT_SUCCESS(rc))
break;
}
case VDDBGIOLOGREQ_FLUSH:
{
if ( RT_SUCCESS(rc)
&& !fAsync)
else if (RT_SUCCESS(rc))
break;
}
case VDDBGIOLOGREQ_DISCARD:
{
unsigned cRanges = 0;
if ( RT_SUCCESS(rc)
&& !fAsync)
{
}
else if (RT_SUCCESS(rc))
break;
}
default:
}
if (RT_SUCCESS(rc))
{
/* Get matching complete event. */
if (RT_SUCCESS(rc))
{
int rcReq;
}
}
if (RT_SUCCESS(rc))
}
}
}
else
rc = VERR_NOT_FOUND;
return rc;
}
{
int rc = VINF_SUCCESS;
const char *pcszSeeder = NULL;
{
RTPrintf("I/O RNG already exists\n");
}
else
{
uint64_t uSeedToUse = 0;
uSeedToUse = uSeed;
{
if (RT_SUCCESS(rc))
{
}
}
if (RT_SUCCESS(rc))
}
return rc;
}
{
{
}
else
RTPrintf("WARNING: No I/O RNG active, faulty script. Continuing\n");
return VINF_SUCCESS;
}
static DECLCALLBACK(int) vdScriptHandlerIoPatternCreateFromNumber(PVDSCRIPTARG paScriptArgs, void *pvUser)
{
int rc = VINF_SUCCESS;
uint64_t u64Pattern = 0;
if (!pPattern)
{
if (pPattern)
{
/* Fill the buffer. */
{
}
}
else
rc = VERR_NO_MEMORY;
}
else
return rc;
}
static DECLCALLBACK(int) vdScriptHandlerIoPatternCreateFromFile(PVDSCRIPTARG paScriptArgs, void *pvUser)
{
int rc = VINF_SUCCESS;
if (!pPattern)
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (pPattern)
{
if (RT_SUCCESS(rc))
else
{
}
}
else
rc = VERR_NO_MEMORY;
}
}
}
else
return rc;
}
{
int rc = VINF_SUCCESS;
if (pPattern)
{
}
else
rc = VERR_NOT_FOUND;
return rc;
}
{
int rc = VINF_SUCCESS;
return rc;
}
{
int rc = VINF_SUCCESS;
const char *pcszPathToDump = NULL;
/* Check for the file. */
bool fFound = false;
{
{
fFound = true;
break;
}
}
if (fFound)
{
//rc = VDMemDiskWriteToFile(pIt->pIo, pcszPathToDump);
}
else
return rc;
}
{
int rc = VINF_SUCCESS;
bool fVerify = false;
if (pDisk)
else
{
if (pDisk)
{
{
rc = VINF_SUCCESS;
if (fVerify)
{
if (RT_SUCCESS(rc))
{
if (RT_FAILURE(rc))
}
}
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
else
{
if (fVerify)
{
}
}
}
}
else
rc = VERR_NO_MEMORY;
if (RT_FAILURE(rc))
}
else
rc = VERR_NO_MEMORY;
}
return rc;
}
{
int rc = VINF_SUCCESS;
if (pDisk)
{
if (pDisk->pMemDiskVerify)
{
}
}
else
rc = VERR_NOT_FOUND;
return rc;
}
{
int rc = VINF_SUCCESS;
{
{
else
{
{
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
{
break;
}
}
else
{
break;
}
}
}
}
else
{
if (pbBuf1)
if (pbBuf2)
rc = VERR_NO_MEMORY;
}
}
else
rc = VERR_NOT_FOUND;
return rc;
}
{
int rc = VINF_SUCCESS;
if (pDisk)
else
rc = VERR_NOT_FOUND;
return rc;
}
{
return VINF_SUCCESS;
}
{
int rc = VINF_SUCCESS;
/* Check for the file. */
bool fFound = false;
{
{
fFound = true;
break;
}
}
if (fFound)
{
RTPrintf("Statistics %s: \n"
" sync reads=%u writes=%u flushes=%u\n"
" async reads=%u writes=%u flushes=%u\n",
}
else
return rc;
}
{
int rc = VINF_SUCCESS;
/* Check for the file. */
bool fFound = false;
{
{
fFound = true;
break;
}
}
if (fFound)
{
pIt->cAsyncReads = 0;
pIt->cAsyncWrites = 0;
pIt->cAsyncFlushes = 0;
}
else
return rc;
}
{
int rc = VINF_SUCCESS;
if (pDisk)
{
}
else
rc = VERR_NOT_FOUND;
return rc;
}
{
int rc = VINF_SUCCESS;
if (!pGlob->pszIoBackend)
rc = VERR_NO_MEMORY;
return rc;
}
void **ppStorage)
{
int rc = VINF_SUCCESS;
bool fFound = false;
/*
* Some backends use ./ for paths, strip it.
* @todo: Implement proper directory support for the
* memory filesystem.
*/
&& *pszLocation == '.'
pszLocation += 2;
/* Check if the file exists. */
{
{
fFound = true;
break;
}
}
{
/* If the file exists delete the memory disk. */
if (fFound)
else
{
/* Create completey new. */
if (pIt)
{
{
}
else
rc = VERR_NO_MEMORY;
if (RT_FAILURE(rc))
{
}
else
}
else
rc = VERR_NO_MEMORY;
}
}
{
if (!fFound)
}
else
if (RT_SUCCESS(rc))
{
if (!pStorage)
rc = VERR_NO_MEMORY;
}
return rc;
}
{
return VINF_SUCCESS;
}
{
int rc = VINF_SUCCESS;
bool fFound = false;
/*
* Some backends use ./ for paths, strip it.
* @todo: Implement proper directory support for the
* memory filesystem.
*/
&& *pcszFilename == '.'
pcszFilename += 2;
/* Check if the file exists. */
{
{
fFound = true;
break;
}
}
if (fFound)
{
}
else
return rc;
}
static DECLCALLBACK(int) tstVDIoFileMove(void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)
{
int rc = VINF_SUCCESS;
bool fFound = false;
/* Check if the file exists. */
{
{
fFound = true;
break;
}
}
if (fFound)
{
if (pszNew)
{
}
else
rc = VERR_NO_MEMORY;
}
else
return rc;
}
static DECLCALLBACK(int) tstVDIoFileGetFreeSpace(void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)
{
return VINF_SUCCESS;
}
static DECLCALLBACK(int) tstVDIoFileGetModificationTime(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
{
/** @todo: Implement */
return VINF_SUCCESS;
}
{
}
{
}
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
if (pcbWritten)
*pcbWritten = cbBuffer;
}
return rc;
}
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
if (pcbRead)
}
return rc;
}
{
return rc;
}
void **ppTask)
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
}
return rc;
}
void **ppTask)
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
}
return rc;
}
void **ppTask)
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
}
return rc;
}
{
int rc = VINF_SUCCESS;
if (fRandomAcc)
{
? 1
: 0));
rc = VERR_NO_MEMORY;
}
else
pIoTest->u.offNext = pIoTest->offEnd < pIoTest->offStart ? pIoTest->offStart - cbBlkSize : offStart;
return rc;
}
{
if (pIoTest->fRandomAccess)
}
{
}
{
return pIoReq->fOutstanding;
}
/**
* Returns true with the given chance in percent.
*
* @returns true or false
* @param iPercentage The percentage of the chance to return true.
*/
{
}
{
int rc = VINF_SUCCESS;
{
/* Read or Write? */
pIoReq->enmTxDir = tstVDIoTestIsTrue(pIoTest, pIoTest->uWriteChance) ? VDIOREQTXDIR_WRITE : VDIOREQTXDIR_READ;
{
else
}
else
{
/* Read */
}
if (RT_SUCCESS(rc))
{
if (pIoTest->fRandomAccess)
{
int idx = -1;
/* In case this is the last request we don't need to search further. */
{
int idxIo;
/*
* If the bit is marked free use it, otherwise search for the next free bit
* and if that doesn't work use the first free bit.
*/
{
if (idxIo != -1)
}
else
}
{
/* New round, clear everything. */
}
else
}
else
{
{
}
else
{
? 0
}
}
pIoReq->fOutstanding = true;
}
}
else
return rc;
}
{
if (pDisk->pMemDiskVerify)
{
{
case VDIOREQTXDIR_READ:
{
}
case VDIOREQTXDIR_WRITE:
{
break;
}
case VDIOREQTXDIR_FLUSH:
case VDIOREQTXDIR_DISCARD:
break;
}
}
return;
}
/**
* Returns the disk handle by name or NULL if not found
*
* @returns Disk handle or NULL if the disk could not be found.
*
* @param pGlob Global test state.
* @param pcszDisk Name of the disk to get.
*/
{
bool fFound = false;
{
{
fFound = true;
break;
}
}
}
/**
* Returns the I/O pattern handle by name of NULL if not found.
*
* @returns I/O pattern handle or NULL if the pattern could not be found.
*
* @param pGlob Global test state.
* @param pcszName Name of the pattern.
*/
{
bool fFound = false;
{
{
fFound = true;
break;
}
}
}
/**
* Creates a new pattern with the given name and an
* allocated pattern buffer.
*
* @returns Pointer to a new pattern buffer or NULL on failure.
* @param pcszName Name of the pattern.
* @param cbPattern Size of the pattern buffer.
*/
{
{
}
else
{
if (pPattern)
if (pszName)
if (pvPattern)
}
return pPattern;
}
{
return VERR_INVALID_PARAMETER;
return VINF_SUCCESS;
}
/**
* Executes the given script.
*
* @returns nothing.
* @param pszScript The script to execute.
*/
static void tstVDIoScriptExec(const char *pszScript)
{
int rc = VINF_SUCCESS;
if (!GlobTest.pszIoBackend)
{
RTPrintf("Out of memory allocating I/O backend string\n");
return;
}
/* Init global test data. */
if (RT_SUCCESS(rc))
{
/* Init I/O backend. */
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (RT_FAILURE(rc))
{
}
else
}
}
else
RTPrintf("Creating the I/O backend failed rc=%Rrc\n");
}
else
}
/**
* Executes the given I/O script using the new scripting engine.
*
* @returns nothing.
*
* @param pcszFilename The script to execute.
*/
static void tstVDIoScriptRun(const char *pcszFilename)
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
}
else
}
/**
* Run builtin tests.
*
* @returns nothing.
*/
static void tstVDIoRunBuiltinTests(void)
{
for (unsigned i = 0; i < g_cVDIoTests; i++)
{
}
}
/**
* Shows help message.
*/
static void printUsage(void)
{
RTPrintf("Usage:\n"
"--script <filename> Script to execute\n");
}
static const RTGETOPTDEF g_aOptions[] =
{
};
{
int rc;
char c;
if (RT_FAILURE(rc))
return RTEXITCODE_FAILURE;
if (argc == 1)
{
return RTEXITCODE_SUCCESS;
}
while ( RT_SUCCESS(rc)
{
switch (c)
{
case 's':
break;
case 'h':
printUsage();
break;
default: /* Default is to run built in tests if no arguments are given (automated testing). */
}
}
rc = VDShutdown();
if (RT_FAILURE(rc))
return RTEXITCODE_SUCCESS;
}