VDDbgIoLog.cpp revision 0560d845b0638cde2d51fe9ba84b4847eb9fbb47
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * VD Debug library - I/O logger.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * Copyright (C) 2011 Oracle Corporation
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * available from http://www.virtualbox.org. This file is free software;
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * you can redistribute it and/or modify it under the terms of the GNU
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * General Public License (GPL) as published by the Free Software
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync/*******************************************************************************
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync* Header Files *
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync*******************************************************************************/
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync/*******************************************************************************
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync* Structures in a I/O log file, little endian *
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync*******************************************************************************/
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * I/O log header.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsynctypedef struct IoLogHeader
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Magic string */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Flags for the log file. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Id counter. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync/** Event type - I/O request start. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync/** Event type - I/O request complete. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * I/O log entry marking the start of a new I/O transaction.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Event type. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Flag whether this is a sync or async request. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Id of the entry. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Transfer direction. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Start offset. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Size of the request. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * I/O log entry markign the completion of an I/O transaction.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Event type. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Id of the matching start entry. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Status code the request completed with */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Number of milliseconds the request needed to complete. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Number of bytes of data following this entry. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync/*******************************************************************************
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync* Constants And Macros, Structures and Typedefs *
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync*******************************************************************************/
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * I/O logger instance data.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** File handle. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Current offset to append new entries to. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Offset to read the next entry from. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Flags given during creation. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Id for the next entry. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Memory cache for the I/O log entries. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Mutex section protecting the logger. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Cached event type of the next event. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync/** Pointer to the internal I/O logger instance data. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * I/O log entry data.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Id of the start entry. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Timestamnp when the request started. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /** Size of the buffer to write on success. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync/** Pointer to the internal I/O log entry data. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync/*******************************************************************************
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync* Internal Functions *
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync*******************************************************************************/
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * Creates a new empty I/O logger.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * @returns VBox status code.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * @param ppIoLogger Where to store the new I/O logger handle.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncstatic int vddbgIoLoggerCreate(PVDIOLOGGERINT *ppIoLogger)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync pIoLogger = (PVDIOLOGGERINT)RTMemAllocZ(sizeof(VDIOLOGGERINT));
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTMemCacheCreate(&pIoLogger->hMemCacheIoLogEntries, sizeof(VDIOLOGENTINT),
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * Update the header of the I/O logger to the current state.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * @returns VBox status code.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * @param pIoLogger The I/O logger to update.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncstatic int vddbgIoLoggerHeaderUpdate(PVDIOLOGGERINT pIoLogger)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync memcpy(Hdr.szMagic, VDIOLOG_MAGIC, sizeof(Hdr.szMagic));
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileWriteAt(pIoLogger->hFile, 0, &Hdr, sizeof(Hdr), NULL);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * Writes data from the given S/G buffer into the I/O log.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * @returns VBox status code.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * @param pIoLogger The I/O logger to use.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * @param off The start offset in the log to write to.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * @param pSgBuf The S/G buffer to write.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync * @param cbSgBuf How much data to write.
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncstatic int vddbgIoLogWriteSgBuf(PVDIOLOGGERINT pIoLogger, uint64_t off, PCRTSGBUF pSgBuf, size_t cbSgBuf)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync AssertPtrBreakStmt(pvSeg, rc = VERR_INTERNAL_ERROR);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileWriteAt(pIoLogger->hFile, off, pvSeg, cbSeg, NULL);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncVBOXDDU_DECL(int) VDDbgIoLogCreate(PVDIOLOGGER phIoLogger, const char *pszFilename, uint32_t fFlags)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync AssertReturn(!(fFlags & ~VDDBG_IOLOG_VALID_MASK), VERR_INVALID_PARAMETER);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /* Create new log. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileOpen(&pIoLogger->hFile, pszFilename, RTFILE_O_DENY_NONE | RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_READ);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncVBOXDDU_DECL(int) VDDbgIoLogOpen(PVDIOLOGGER phIoLogger, const char *pszFilename)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /* open existing log. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileOpen(&pIoLogger->hFile, pszFilename, RTFILE_O_DENY_NONE | RTFILE_O_OPEN | RTFILE_O_WRITE | RTFILE_O_READ);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /* Read the header. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileRead(pIoLogger->hFile, &Hdr, sizeof(Hdr), NULL);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync && !memcmp(Hdr.szMagic, VDIOLOG_MAGIC, sizeof(Hdr.szMagic)))
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncVBOXDDU_DECL(void) VDDbgIoLogDestroy(VDIOLOGGER hIoLogger)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync RTMemCacheDestroy(pIoLogger->hMemCacheIoLogEntries);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncVBOXDDU_DECL(int) VDDbgIoLogCommit(VDIOLOGGER hIoLogger)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncVBOXDDU_DECL(uint32_t) VDDbgIoLogGetFlags(VDIOLOGGER hIoLogger)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncVBOXDDU_DECL(int) VDDbgIoLogStart(VDIOLOGGER hIoLogger, bool fAsync, VDDBGIOLOGTXDIR enmTxDir, uint64_t off, size_t cbIo, PCRTSGBUF pSgBuf,
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync AssertPtrReturn(phIoLogEntry, VERR_INVALID_POINTER);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync AssertReturn(enmTxDir > VDDBGIOLOGTXDIR_INVALID && enmTxDir <= VDDBGIOLOGTXDIR_FLUSH, VERR_INVALID_PARAMETER);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync pIoLogEntry = (PVDIOLOGENTINT)RTMemCacheAlloc(pIoLogger->hMemCacheIoLogEntries);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /* Write new entry. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileWriteAt(pIoLogger->hFile, pIoLogger->offWriteNext, &Entry, sizeof(Entry), NULL);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync && (pIoLogger->fFlags & VDDBG_IOLOG_LOG_DATA_WRITTEN))
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /* Write data. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = vddbgIoLogWriteSgBuf(pIoLogger, pIoLogger->offWriteNext, pSgBuf, cbIo);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileSetSize(pIoLogger->hFile, pIoLogger->offWriteNext);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync && (pIoLogger->fFlags & VDDBG_IOLOG_LOG_DATA_READ))
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync RTMemCacheFree(pIoLogger->hMemCacheIoLogEntries, pIoLogEntry);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncVBOXDDU_DECL(int) VDDbgIoLogComplete(VDIOLOGGER hIoLogger, VDIOLOGENT hIoLogEntry, int rcReq, PCRTSGBUF pSgBuf)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync Entry.msDuration = RTTimeProgramMilliTS() - RT_H2LE_U64(pIoLogEntry->tsStart);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync Entry.i32Rc = (int32_t)RT_H2LE_U32((uint32_t)rcReq);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync Entry.u64IoBuffer = RT_H2LE_U64(pIoLogEntry->cbIo);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /* Write new entry. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileWriteAt(pIoLogger->hFile, pIoLogger->offWriteNext, &Entry, sizeof(Entry), NULL);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = vddbgIoLogWriteSgBuf(pIoLogger, pIoLogger->offWriteNext, pSgBuf, pIoLogEntry->cbIo);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileSetSize(pIoLogger->hFile, pIoLogger->offWriteNext);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync RTMemCacheFree(pIoLogger->hMemCacheIoLogEntries, pIoLogEntry);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncVBOXDDU_DECL(int) VDDbgIoLogEventTypeGetNext(VDIOLOGGER hIoLogger, VDIOLOGEVENT *penmEvent)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync if (pIoLogger->offReadNext == pIoLogger->offWriteNext)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext, &pIoLogger->u8EventTypeNext, sizeof(uint8_t), NULL);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync AssertMsgFailed(("Invalid event type %d\n", pIoLogger->u8EventTypeNext));
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncVBOXDDU_DECL(int) VDDbgIoLogEventGetStart(VDIOLOGGER hIoLogger, uint64_t *pidEvent, bool *pfAsync, PVDDBGIOLOGTXDIR penmTxDir,
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync uint64_t *poff, size_t *pcbIo, size_t cbBuf, void *pvBuf)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync if (pIoLogger->u8EventTypeNext == VDIOLOG_EVENT_START)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext, &Entry, sizeof(Entry), NULL);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync && (pIoLogger->fFlags & VDDBG_IOLOG_LOG_DATA_WRITTEN))
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /* Read data. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext + sizeof(Entry), pvBuf, *pcbIo, NULL);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsyncVBOXDDU_DECL(int) VDDbgIoLogEventGetComplete(VDIOLOGGER hIoLogger, uint64_t *pidEvent, int *pRc,
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync uint64_t *pmsDuration, size_t *pcbIo, size_t cbBuf, void *pvBuf)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync AssertPtrReturn(pmsDuration, VERR_INVALID_POINTER);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync if (pIoLogger->u8EventTypeNext == VDIOLOG_EVENT_COMPLETE)
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext, &Entry, sizeof(Entry), NULL);
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync /* Read data. */
0560d845b0638cde2d51fe9ba84b4847eb9fbb47vboxsync rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext + sizeof(Entry), pvBuf, *pcbIo, NULL);