VDDbgIoLog.cpp revision f0c94ab153ce14e9218d36949f474a37a94ede9c
/* $Id$ */
/** @file
*
* VD Debug library - I/O logger.
*/
/*
* Copyright (C) 2011 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 *
*******************************************************************************/
#define LOGGROUP LOGGROUP_DEFAULT
#include <iprt/memcache.h>
#include <iprt/semaphore.h>
/*******************************************************************************
* Structures in a I/O log file, little endian *
*******************************************************************************/
/**
* I/O log header.
*/
#pragma pack(1)
typedef struct IoLogHeader
{
/** Magic string */
char szMagic[8];
/** Flags for the log file. */
/** Id counter. */
} IoLogHeader;
#pragma pack()
#define VDIOLOG_MAGIC "VDIOLOG"
/** Event type - I/O request start. */
#define VDIOLOG_EVENT_START 0x01
/** Event type - I/O request complete. */
#define VDIOLOG_EVENT_COMPLETE 0x02
/**
* I/O log entry marking the start of a new I/O transaction.
*/
#pragma pack(1)
typedef struct IoLogEntryStart
{
/** Event type. */
/** Transfer type. */
/** Flag whether this is a sync or async request. */
/** Id of the entry. */
/** Type dependent data. */
union
{
/** I/O. */
struct
{
/** Start offset. */
/** Size of the request. */
} Io;
/** Discard */
struct
{
/** Number of ranges to discard. */
} Discard;
};
#pragma pack()
/**
* I/O log entry markign the completion of an I/O transaction.
*/
#pragma pack(1)
typedef struct IoLogEntryComplete
{
/** Event type. */
/** Id of the matching start entry. */
/** Status code the request completed with */
/** Number of milliseconds the request needed to complete. */
/** Number of bytes of data following this entry. */
#pragma pack()
#pragma pack(1)
typedef struct IoLogEntryDiscard
{
/** Start offset. */
/** Number of bytes to discard. */
#pragma pack()
/*******************************************************************************
* Constants And Macros, Structures and Typedefs *
*******************************************************************************/
/**
* I/O logger instance data.
*/
typedef struct VDIOLOGGERINT
{
/** File handle. */
/** Current offset to append new entries to. */
/** Offset to read the next entry from. */
/** Flags given during creation. */
/** Id for the next entry. */
/** Memory cache for the I/O log entries. */
/** Mutex section protecting the logger. */
/** Cached event type of the next event. */
/** Cached request type of the next request. */
/** Pointer to the internal I/O logger instance data. */
typedef VDIOLOGGERINT *PVDIOLOGGERINT;
/**
* I/O log entry data.
*/
typedef struct VDIOLOGENTINT
{
/** Id of the start entry. */
/** Timestamnp when the request started. */
/** Size of the buffer to write on success. */
/** Pointer to the internal I/O log entry data. */
typedef VDIOLOGENTINT *PVDIOLOGENTINT;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/**
* Creates a new empty I/O logger.
*
* @returns VBox status code.
* @param ppIoLogger Where to store the new I/O logger handle.
*/
{
int rc = VINF_SUCCESS;
if (pIoLogger)
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
*ppIoLogger = pIoLogger;
return rc;
}
}
}
else
rc = VERR_NO_MEMORY;
return rc;
}
/**
* Update the header of the I/O logger to the current state.
*
* @returns VBox status code.
* @param pIoLogger The I/O logger to update.
*/
{
int rc = VINF_SUCCESS;
return rc;
}
/**
* Writes data from the given S/G buffer into the I/O log.
*
* @returns VBox status code.
* @param pIoLogger The I/O logger to use.
* @param off The start offset in the log to write to.
* @param pSgBuf The S/G buffer to write.
* @param cbSgBuf How much data to write.
*/
static int vddbgIoLogWriteSgBuf(PVDIOLOGGERINT pIoLogger, uint64_t off, PCRTSGBUF pSgBuf, size_t cbSgBuf)
{
int rc = VINF_SUCCESS;
while (cbSgBuf)
{
void *pvSeg;
if (RT_FAILURE(rc))
break;
}
return rc;
}
VBOXDDU_DECL(int) VDDbgIoLogCreate(PVDIOLOGGER phIoLogger, const char *pszFilename, uint32_t fFlags)
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
/* Create new log. */
rc = RTFileOpen(&pIoLogger->hFile, pszFilename, RTFILE_O_DENY_NONE | RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_READ);
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
}
}
if (RT_SUCCESS(rc))
*phIoLogger = pIoLogger;
else
{
}
}
return rc;
}
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
/* open existing log. */
rc = RTFileOpen(&pIoLogger->hFile, pszFilename, RTFILE_O_DENY_NONE | RTFILE_O_OPEN | RTFILE_O_WRITE | RTFILE_O_READ);
if (RT_SUCCESS(rc))
{
/* Read the header. */
if (RT_SUCCESS(rc))
if ( RT_SUCCESS(rc)
{
}
else if (RT_SUCCESS(rc))
}
}
return rc;
}
{
}
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
return rc;
}
{
}
VBOXDDU_DECL(int) VDDbgIoLogStart(VDIOLOGGER hIoLogger, bool fAsync, VDDBGIOLOGREQ enmTxDir, uint64_t off, size_t cbIo, PCRTSGBUF pSgBuf,
{
int rc = VINF_SUCCESS;
AssertReturn(enmTxDir > VDDBGIOLOGREQ_INVALID && enmTxDir <= VDDBGIOLOGREQ_FLUSH, VERR_INVALID_PARAMETER);
if (pIoLogEntry)
{
/* Write new entry. */
if (RT_SUCCESS(rc))
{
if ( enmTxDir == VDDBGIOLOGREQ_WRITE
{
/* Write data. */
if (RT_FAILURE(rc))
{
}
else
}
}
if (RT_SUCCESS(rc))
{
if ( enmTxDir == VDDBGIOLOGREQ_READ
else
pIoLogEntry->cbIo = 0;
}
else
{
}
}
else
rc = VERR_NO_MEMORY;
return rc;
}
VBOXDDU_DECL(int) VDDbgIoLogStartDiscard(VDIOLOGGER hIoLogger, bool fAsync, PVDRANGE paRanges, unsigned cRanges,
{
int rc = VINF_SUCCESS;
if (pIoLogEntry)
{
/* Write new entry. */
if (RT_SUCCESS(rc))
{
for (unsigned i = 0; i < cRanges; i++)
{
if (RT_FAILURE(rc))
break;
}
if (RT_FAILURE(rc))
{
}
else
}
if (RT_SUCCESS(rc))
{
pIoLogEntry->cbIo = 0;
}
else
{
}
}
else
rc = VERR_NO_MEMORY;
return rc;
}
VBOXDDU_DECL(int) VDDbgIoLogComplete(VDIOLOGGER hIoLogger, VDIOLOGENT hIoLogEntry, int rcReq, PCRTSGBUF pSgBuf)
{
int rc = VINF_SUCCESS;
/* Write new entry. */
if (RT_SUCCESS(rc))
{
if (pIoLogEntry->cbIo)
{
if (RT_SUCCESS(rc))
else
{
}
}
}
return rc;
}
{
int rc = VINF_SUCCESS;
{
return VINF_SUCCESS;
}
if (!pIoLogger->u32EventTypeNext)
{
if (RT_SUCCESS(rc))
{
}
}
if (RT_SUCCESS(rc))
{
switch (pIoLogger->u32EventTypeNext)
{
case VDIOLOG_EVENT_START:
break;
case VDIOLOG_EVENT_COMPLETE:
break;
default:
}
}
return rc;
}
{
int rc = VINF_SUCCESS;
{
return VERR_INVALID_STATE;
}
if (RT_SUCCESS(rc))
{
}
return rc;
}
{
int rc = VINF_SUCCESS;
{
if (RT_SUCCESS(rc))
{
{
/* Read data. */
else
if (rc != VERR_BUFFER_OVERFLOW)
}
else
}
}
else
return rc;
}
VBOXDDU_DECL(int) VDDbgIoLogEventGetStartDiscard(VDIOLOGGER hIoLogger, uint64_t *pidEvent, bool *pfAsync,
{
int rc = VINF_SUCCESS;
{
if (RT_SUCCESS(rc))
{
if (paRanges)
{
for (unsigned i = 0; i < *pcRanges; i++)
{
if (RT_FAILURE(rc))
break;
}
if (RT_SUCCESS(rc))
{
}
else
}
else
rc = VERR_NO_MEMORY;
}
}
else
return rc;
}
{
int rc = VINF_SUCCESS;
{
if (RT_SUCCESS(rc))
{
if (*pcbIo)
{
/* Read data. */
else
if (rc != VERR_BUFFER_OVERFLOW)
}
else
}
}
else
return rc;
}