VirtualBox

source: vbox/trunk/src/VBox/Storage/Debug/VDDbgIoLog.cpp@ 48935

Last change on this file since 48935 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.6 KB
Line 
1/* $Id: VDDbgIoLog.cpp 44529 2013-02-04 15:54:15Z vboxsync $ */
2/** @file
3 *
4 * VD Debug library - I/O logger.
5 */
6
7/*
8 * Copyright (C) 2011-2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOGGROUP LOGGROUP_DEFAULT
23#include <VBox/vddbg.h>
24#include <VBox/err.h>
25#include <VBox/log.h>
26#include <iprt/mem.h>
27#include <iprt/memcache.h>
28#include <iprt/file.h>
29#include <iprt/string.h>
30#include <iprt/semaphore.h>
31#include <iprt/asm.h>
32
33/*******************************************************************************
34* Structures in a I/O log file, little endian *
35*******************************************************************************/
36
37/**
38 * I/O log header.
39 */
40#pragma pack(1)
41typedef struct IoLogHeader
42{
43 /** Magic string */
44 char szMagic[8];
45 /** Flags for the log file. */
46 uint32_t fFlags;
47 /** Id counter. */
48 uint64_t u64Id;
49} IoLogHeader;
50#pragma pack()
51
52#define VDIOLOG_MAGIC "VDIOLOG"
53
54/** Event type - I/O request start. */
55#define VDIOLOG_EVENT_START 0x01
56/** Event type - I/O request complete. */
57#define VDIOLOG_EVENT_COMPLETE 0x02
58
59/**
60 * I/O log entry marking the start of a new I/O transaction.
61 */
62#pragma pack(1)
63typedef struct IoLogEntryStart
64{
65 /** Event type. */
66 uint32_t u32Type;
67 /** Transfer type. */
68 uint32_t u32ReqType;
69 /** Flag whether this is a sync or async request. */
70 uint8_t u8AsyncIo;
71 /** Id of the entry. */
72 uint64_t u64Id;
73 /** Type dependent data. */
74 union
75 {
76 /** I/O. */
77 struct
78 {
79 /** Start offset. */
80 uint64_t u64Off;
81 /** Size of the request. */
82 uint64_t u64IoSize;
83 } Io;
84 /** Discard */
85 struct
86 {
87 /** Number of ranges to discard. */
88 uint32_t cRanges;
89 } Discard;
90 };
91} IoLogEntryStart;
92#pragma pack()
93
94/**
95 * I/O log entry markign the completion of an I/O transaction.
96 */
97#pragma pack(1)
98typedef struct IoLogEntryComplete
99{
100 /** Event type. */
101 uint32_t u32Type;
102 /** Id of the matching start entry. */
103 uint64_t u64Id;
104 /** Status code the request completed with */
105 int32_t i32Rc;
106 /** Number of milliseconds the request needed to complete. */
107 uint64_t msDuration;
108 /** Number of bytes of data following this entry. */
109 uint64_t u64IoBuffer;
110} IoLogEntryComplete;
111#pragma pack()
112
113#pragma pack(1)
114typedef struct IoLogEntryDiscard
115{
116 /** Start offset. */
117 uint64_t u64Off;
118 /** Number of bytes to discard. */
119 uint32_t u32Discard;
120} IoLogEntryDiscard;
121#pragma pack()
122
123/*******************************************************************************
124* Constants And Macros, Structures and Typedefs *
125*******************************************************************************/
126
127/**
128 * I/O logger instance data.
129 */
130typedef struct VDIOLOGGERINT
131{
132 /** File handle. */
133 RTFILE hFile;
134 /** Current offset to append new entries to. */
135 uint64_t offWriteNext;
136 /** Offset to read the next entry from. */
137 uint64_t offReadNext;
138 /** Flags given during creation. */
139 uint32_t fFlags;
140 /** Id for the next entry. */
141 uint64_t idNext;
142 /** Memory cache for the I/O log entries. */
143 RTMEMCACHE hMemCacheIoLogEntries;
144 /** Mutex section protecting the logger. */
145 RTSEMFASTMUTEX hMtx;
146 /** Cached event type of the next event. */
147 uint32_t u32EventTypeNext;
148 /** Cached request type of the next request. */
149 VDDBGIOLOGREQ enmReqTypeNext;
150} VDIOLOGGERINT;
151/** Pointer to the internal I/O logger instance data. */
152typedef VDIOLOGGERINT *PVDIOLOGGERINT;
153
154/**
155 * I/O log entry data.
156 */
157typedef struct VDIOLOGENTINT
158{
159 /** Id of the start entry. */
160 uint64_t idStart;
161 /** Timestamnp when the request started. */
162 uint64_t tsStart;
163 /** Size of the buffer to write on success. */
164 size_t cbIo;
165} VDIOLOGENTINT;
166/** Pointer to the internal I/O log entry data. */
167typedef VDIOLOGENTINT *PVDIOLOGENTINT;
168
169/*******************************************************************************
170* Internal Functions *
171*******************************************************************************/
172
173/**
174 * Creates a new empty I/O logger.
175 *
176 * @returns VBox status code.
177 * @param ppIoLogger Where to store the new I/O logger handle.
178 */
179static int vddbgIoLoggerCreate(PVDIOLOGGERINT *ppIoLogger)
180{
181 int rc = VINF_SUCCESS;
182 PVDIOLOGGERINT pIoLogger = NULL;
183
184 pIoLogger = (PVDIOLOGGERINT)RTMemAllocZ(sizeof(VDIOLOGGERINT));
185 if (pIoLogger)
186 {
187 rc = RTSemFastMutexCreate(&pIoLogger->hMtx);
188 if (RT_SUCCESS(rc))
189 {
190 rc = RTMemCacheCreate(&pIoLogger->hMemCacheIoLogEntries, sizeof(VDIOLOGENTINT),
191 0, UINT32_MAX, NULL, NULL, NULL, 0);
192 if (RT_SUCCESS(rc))
193 {
194 *ppIoLogger = pIoLogger;
195 return rc;
196 }
197 }
198 RTMemFree(pIoLogger);
199 }
200 else
201 rc = VERR_NO_MEMORY;
202
203 return rc;
204}
205
206/**
207 * Update the header of the I/O logger to the current state.
208 *
209 * @returns VBox status code.
210 * @param pIoLogger The I/O logger to update.
211 */
212static int vddbgIoLoggerHeaderUpdate(PVDIOLOGGERINT pIoLogger)
213{
214 int rc = VINF_SUCCESS;
215 IoLogHeader Hdr;
216
217 memcpy(Hdr.szMagic, VDIOLOG_MAGIC, sizeof(Hdr.szMagic));
218 Hdr.fFlags = RT_H2LE_U32(pIoLogger->fFlags);
219 Hdr.u64Id = RT_H2LE_U64(pIoLogger->idNext);
220 rc = RTFileWriteAt(pIoLogger->hFile, 0, &Hdr, sizeof(Hdr), NULL);
221
222 return rc;
223}
224
225/**
226 * Writes data from the given S/G buffer into the I/O log.
227 *
228 * @returns VBox status code.
229 * @param pIoLogger The I/O logger to use.
230 * @param off The start offset in the log to write to.
231 * @param pSgBuf The S/G buffer to write.
232 * @param cbSgBuf How much data to write.
233 */
234static int vddbgIoLogWriteSgBuf(PVDIOLOGGERINT pIoLogger, uint64_t off, PCRTSGBUF pSgBuf, size_t cbSgBuf)
235{
236 int rc = VINF_SUCCESS;
237 RTSGBUF SgBuf;
238
239 RTSgBufClone(&SgBuf, pSgBuf);
240
241 while (cbSgBuf)
242 {
243 void *pvSeg;
244 size_t cbSeg = cbSgBuf;
245
246 pvSeg = RTSgBufGetNextSegment(&SgBuf, &cbSeg);
247 AssertPtrBreakStmt(pvSeg, rc = VERR_INTERNAL_ERROR);
248
249 rc = RTFileWriteAt(pIoLogger->hFile, off, pvSeg, cbSeg, NULL);
250 if (RT_FAILURE(rc))
251 break;
252
253 cbSgBuf -= cbSeg;
254 off += cbSeg;
255 }
256
257 return rc;
258}
259
260VBOXDDU_DECL(int) VDDbgIoLogCreate(PVDIOLOGGER phIoLogger, const char *pszFilename, uint32_t fFlags)
261{
262 int rc = VINF_SUCCESS;
263 PVDIOLOGGERINT pIoLogger = NULL;
264
265 AssertPtrReturn(phIoLogger, VERR_INVALID_POINTER);
266 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
267 AssertReturn(!(fFlags & ~VDDBG_IOLOG_VALID_MASK), VERR_INVALID_PARAMETER);
268
269 rc = vddbgIoLoggerCreate(&pIoLogger);
270 if (RT_SUCCESS(rc))
271 {
272 pIoLogger->fFlags = fFlags;
273 pIoLogger->hFile = NIL_RTFILE;
274
275 /* Create new log. */
276 rc = RTFileOpen(&pIoLogger->hFile, pszFilename, RTFILE_O_DENY_NONE | RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_READ);
277 if (RT_SUCCESS(rc))
278 {
279 rc = vddbgIoLoggerHeaderUpdate(pIoLogger);
280 if (RT_SUCCESS(rc))
281 {
282 pIoLogger->offWriteNext = sizeof(IoLogHeader);
283 pIoLogger->offReadNext = sizeof(IoLogHeader);
284 }
285 }
286
287 if (RT_SUCCESS(rc))
288 *phIoLogger = pIoLogger;
289 else
290 {
291 if (pIoLogger->hFile != NIL_RTFILE)
292 RTFileClose(pIoLogger->hFile);
293 RTMemFree(pIoLogger);
294 }
295 }
296
297 return rc;
298}
299
300VBOXDDU_DECL(int) VDDbgIoLogOpen(PVDIOLOGGER phIoLogger, const char *pszFilename)
301{
302 int rc = VINF_SUCCESS;
303 PVDIOLOGGERINT pIoLogger = NULL;
304
305 AssertPtrReturn(phIoLogger, VERR_INVALID_POINTER);
306 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
307
308 rc = vddbgIoLoggerCreate(&pIoLogger);
309 if (RT_SUCCESS(rc))
310 {
311 /* open existing log. */
312 rc = RTFileOpen(&pIoLogger->hFile, pszFilename, RTFILE_O_DENY_NONE | RTFILE_O_OPEN | RTFILE_O_WRITE | RTFILE_O_READ);
313 if (RT_SUCCESS(rc))
314 {
315 IoLogHeader Hdr;
316 uint64_t cbLog;
317
318 rc = RTFileGetSize(pIoLogger->hFile, &cbLog);
319
320 /* Read the header. */
321 if (RT_SUCCESS(rc))
322 rc = RTFileRead(pIoLogger->hFile, &Hdr, sizeof(Hdr), NULL);
323
324 if ( RT_SUCCESS(rc)
325 && !memcmp(Hdr.szMagic, VDIOLOG_MAGIC, sizeof(Hdr.szMagic)))
326 {
327 pIoLogger->fFlags = RT_LE2H_U32(Hdr.fFlags);
328 pIoLogger->offWriteNext = cbLog;
329 pIoLogger->offReadNext = sizeof(Hdr);
330 pIoLogger->idNext = RT_LE2H_U64(Hdr.u64Id);
331 *phIoLogger = pIoLogger;
332 }
333 else if (RT_SUCCESS(rc))
334 rc = VERR_INVALID_PARAMETER;
335 }
336 }
337
338 return rc;
339}
340
341VBOXDDU_DECL(void) VDDbgIoLogDestroy(VDIOLOGGER hIoLogger)
342{
343 PVDIOLOGGERINT pIoLogger = hIoLogger;
344
345 AssertPtrReturnVoid(pIoLogger);
346
347 vddbgIoLoggerHeaderUpdate(pIoLogger);
348 RTFileFlush(pIoLogger->hFile);
349 RTFileClose(pIoLogger->hFile);
350 RTMemCacheDestroy(pIoLogger->hMemCacheIoLogEntries);
351 RTSemFastMutexDestroy(pIoLogger->hMtx);
352 RTMemFree(pIoLogger);
353}
354
355VBOXDDU_DECL(int) VDDbgIoLogCommit(VDIOLOGGER hIoLogger)
356{
357 int rc = VINF_SUCCESS;
358 PVDIOLOGGERINT pIoLogger = hIoLogger;
359
360 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
361
362 rc = vddbgIoLoggerHeaderUpdate(pIoLogger);
363 if (RT_SUCCESS(rc))
364 rc = RTFileFlush(pIoLogger->hFile);
365
366 return rc;
367}
368
369VBOXDDU_DECL(uint32_t) VDDbgIoLogGetFlags(VDIOLOGGER hIoLogger)
370{
371 PVDIOLOGGERINT pIoLogger = hIoLogger;
372
373 AssertPtrReturn(pIoLogger, 0);
374
375 return pIoLogger->fFlags;
376}
377
378VBOXDDU_DECL(int) VDDbgIoLogStart(VDIOLOGGER hIoLogger, bool fAsync, VDDBGIOLOGREQ enmTxDir, uint64_t off, size_t cbIo, PCRTSGBUF pSgBuf,
379 PVDIOLOGENT phIoLogEntry)
380{
381 int rc = VINF_SUCCESS;
382 PVDIOLOGGERINT pIoLogger = hIoLogger;
383 PVDIOLOGENTINT pIoLogEntry = NULL;
384
385 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
386 AssertPtrReturn(phIoLogEntry, VERR_INVALID_POINTER);
387 AssertReturn(enmTxDir > VDDBGIOLOGREQ_INVALID && enmTxDir <= VDDBGIOLOGREQ_FLUSH, VERR_INVALID_PARAMETER);
388
389 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
390 AssertRCReturn(rc, rc);
391
392 pIoLogEntry = (PVDIOLOGENTINT)RTMemCacheAlloc(pIoLogger->hMemCacheIoLogEntries);
393 if (pIoLogEntry)
394 {
395 IoLogEntryStart Entry;
396
397 pIoLogEntry->idStart = pIoLogger->idNext++;
398
399 Entry.u32Type = VDIOLOG_EVENT_START;
400 Entry.u8AsyncIo = fAsync ? 1 : 0;
401 Entry.u32ReqType = enmTxDir;
402 Entry.u64Id = RT_H2LE_U64(pIoLogEntry->idStart);
403 Entry.Io.u64Off = RT_H2LE_U64(off);
404 Entry.Io.u64IoSize = RT_H2LE_U64(cbIo);
405
406 /* Write new entry. */
407 rc = RTFileWriteAt(pIoLogger->hFile, pIoLogger->offWriteNext, &Entry, sizeof(Entry), NULL);
408 if (RT_SUCCESS(rc))
409 {
410 pIoLogger->offWriteNext += sizeof(Entry);
411
412 if ( enmTxDir == VDDBGIOLOGREQ_WRITE
413 && (pIoLogger->fFlags & VDDBG_IOLOG_LOG_DATA_WRITTEN))
414 {
415 /* Write data. */
416 rc = vddbgIoLogWriteSgBuf(pIoLogger, pIoLogger->offWriteNext, pSgBuf, cbIo);
417 if (RT_FAILURE(rc))
418 {
419 pIoLogger->offWriteNext -= sizeof(Entry);
420 rc = RTFileSetSize(pIoLogger->hFile, pIoLogger->offWriteNext);
421 }
422 else
423 pIoLogger->offWriteNext += cbIo;
424 }
425 }
426
427 if (RT_SUCCESS(rc))
428 {
429 pIoLogEntry->tsStart = RTTimeProgramMilliTS();
430
431 if ( enmTxDir == VDDBGIOLOGREQ_READ
432 && (pIoLogger->fFlags & VDDBG_IOLOG_LOG_DATA_READ))
433 pIoLogEntry->cbIo = cbIo;
434 else
435 pIoLogEntry->cbIo = 0;
436
437 *phIoLogEntry = pIoLogEntry;
438 }
439 else
440 {
441 pIoLogger->idNext--;
442 RTMemCacheFree(pIoLogger->hMemCacheIoLogEntries, pIoLogEntry);
443 }
444 }
445 else
446 rc = VERR_NO_MEMORY;
447
448 RTSemFastMutexRelease(pIoLogger->hMtx);
449 return rc;
450}
451
452VBOXDDU_DECL(int) VDDbgIoLogStartDiscard(VDIOLOGGER hIoLogger, bool fAsync, PCRTRANGE paRanges, unsigned cRanges,
453 PVDIOLOGENT phIoLogEntry)
454{
455 int rc = VINF_SUCCESS;
456 PVDIOLOGGERINT pIoLogger = hIoLogger;
457 PVDIOLOGENTINT pIoLogEntry = NULL;
458
459 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
460 AssertPtrReturn(phIoLogEntry, VERR_INVALID_POINTER);
461
462 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
463 AssertRCReturn(rc, rc);
464
465 pIoLogEntry = (PVDIOLOGENTINT)RTMemCacheAlloc(pIoLogger->hMemCacheIoLogEntries);
466 if (pIoLogEntry)
467 {
468 IoLogEntryStart Entry;
469
470 pIoLogEntry->idStart = pIoLogger->idNext++;
471
472 Entry.u32Type = VDIOLOG_EVENT_START;
473 Entry.u8AsyncIo = fAsync ? 1 : 0;
474 Entry.u32ReqType = VDDBGIOLOGREQ_DISCARD;
475 Entry.u64Id = RT_H2LE_U64(pIoLogEntry->idStart);
476 Entry.Discard.cRanges = RT_H2LE_U32(cRanges);
477
478 /* Write new entry. */
479 rc = RTFileWriteAt(pIoLogger->hFile, pIoLogger->offWriteNext, &Entry, sizeof(Entry), NULL);
480 if (RT_SUCCESS(rc))
481 {
482 pIoLogger->offWriteNext += sizeof(Entry);
483
484 IoLogEntryDiscard DiscardRange;
485
486 for (unsigned i = 0; i < cRanges; i++)
487 {
488 DiscardRange.u64Off = RT_H2LE_U64(paRanges[i].offStart);
489 DiscardRange.u32Discard = RT_H2LE_U32(paRanges[i].cbRange);
490 rc = RTFileWriteAt(pIoLogger->hFile, pIoLogger->offWriteNext + i*sizeof(DiscardRange),
491 &DiscardRange, sizeof(DiscardRange), NULL);
492 if (RT_FAILURE(rc))
493 break;
494 }
495
496 if (RT_FAILURE(rc))
497 {
498 pIoLogger->offWriteNext -= sizeof(Entry);
499 rc = RTFileSetSize(pIoLogger->hFile, pIoLogger->offWriteNext);
500 }
501 else
502 pIoLogger->offWriteNext += cRanges * sizeof(DiscardRange);
503 }
504
505 if (RT_SUCCESS(rc))
506 {
507 pIoLogEntry->tsStart = RTTimeProgramMilliTS();
508 pIoLogEntry->cbIo = 0;
509
510 *phIoLogEntry = pIoLogEntry;
511 }
512 else
513 {
514 pIoLogger->idNext--;
515 RTMemCacheFree(pIoLogger->hMemCacheIoLogEntries, pIoLogEntry);
516 }
517 }
518 else
519 rc = VERR_NO_MEMORY;
520
521 RTSemFastMutexRelease(pIoLogger->hMtx);
522 return rc;
523}
524
525VBOXDDU_DECL(int) VDDbgIoLogComplete(VDIOLOGGER hIoLogger, VDIOLOGENT hIoLogEntry, int rcReq, PCRTSGBUF pSgBuf)
526{
527 int rc = VINF_SUCCESS;
528 PVDIOLOGGERINT pIoLogger = hIoLogger;
529 PVDIOLOGENTINT pIoLogEntry = hIoLogEntry;
530
531 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
532 AssertPtrReturn(pIoLogEntry, VERR_INVALID_HANDLE);
533
534 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
535 AssertRCReturn(rc, rc);
536
537 IoLogEntryComplete Entry;
538
539 Entry.u32Type = VDIOLOG_EVENT_COMPLETE;
540 Entry.u64Id = RT_H2LE_U64(pIoLogEntry->idStart);
541 Entry.msDuration = RTTimeProgramMilliTS() - RT_H2LE_U64(pIoLogEntry->tsStart);
542 Entry.i32Rc = (int32_t)RT_H2LE_U32((uint32_t)rcReq);
543 Entry.u64IoBuffer = RT_H2LE_U64(pIoLogEntry->cbIo);
544
545 /* Write new entry. */
546 rc = RTFileWriteAt(pIoLogger->hFile, pIoLogger->offWriteNext, &Entry, sizeof(Entry), NULL);
547 if (RT_SUCCESS(rc))
548 {
549 pIoLogger->offWriteNext += sizeof(Entry);
550
551 if (pIoLogEntry->cbIo)
552 {
553 rc = vddbgIoLogWriteSgBuf(pIoLogger, pIoLogger->offWriteNext, pSgBuf, pIoLogEntry->cbIo);
554 if (RT_SUCCESS(rc))
555 pIoLogger->offWriteNext += pIoLogEntry->cbIo;
556 else
557 {
558 pIoLogger->offWriteNext -= sizeof(Entry);
559 rc = RTFileSetSize(pIoLogger->hFile, pIoLogger->offWriteNext);
560 }
561 }
562 }
563
564 RTMemCacheFree(pIoLogger->hMemCacheIoLogEntries, pIoLogEntry);
565 RTSemFastMutexRelease(pIoLogger->hMtx);
566 return rc;
567}
568
569VBOXDDU_DECL(int) VDDbgIoLogEventTypeGetNext(VDIOLOGGER hIoLogger, VDIOLOGEVENT *penmEvent)
570{
571 int rc = VINF_SUCCESS;
572 PVDIOLOGGERINT pIoLogger = hIoLogger;
573
574 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
575 AssertPtrReturn(penmEvent, VERR_INVALID_POINTER);
576
577 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
578 AssertRCReturn(rc, rc);
579
580 if (pIoLogger->offReadNext == pIoLogger->offWriteNext)
581 {
582 *penmEvent = VDIOLOGEVENT_END;
583 RTSemFastMutexRelease(pIoLogger->hMtx);
584 return VINF_SUCCESS;
585 }
586
587 if (!pIoLogger->u32EventTypeNext)
588 {
589 uint32_t abBuf[2];
590 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext, &abBuf, sizeof(abBuf), NULL);
591 if (RT_SUCCESS(rc))
592 {
593 pIoLogger->u32EventTypeNext = abBuf[0];
594 pIoLogger->enmReqTypeNext = (VDDBGIOLOGREQ)abBuf[1];
595 }
596 }
597
598 if (RT_SUCCESS(rc))
599 {
600 Assert(pIoLogger->u32EventTypeNext != VDIOLOGEVENT_INVALID);
601
602 switch (pIoLogger->u32EventTypeNext)
603 {
604 case VDIOLOG_EVENT_START:
605 *penmEvent = VDIOLOGEVENT_START;
606 break;
607 case VDIOLOG_EVENT_COMPLETE:
608 *penmEvent = VDIOLOGEVENT_COMPLETE;
609 break;
610 default:
611 AssertMsgFailed(("Invalid event type %d\n", pIoLogger->u32EventTypeNext));
612 }
613 }
614
615 RTSemFastMutexRelease(pIoLogger->hMtx);
616 return rc;
617}
618
619VBOXDDU_DECL(int) VDDbgIoLogReqTypeGetNext(VDIOLOGGER hIoLogger, PVDDBGIOLOGREQ penmReq)
620{
621 int rc = VINF_SUCCESS;
622 PVDIOLOGGERINT pIoLogger = hIoLogger;
623
624 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
625 AssertPtrReturn(penmReq, VERR_INVALID_POINTER);
626
627 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
628 AssertRCReturn(rc, rc);
629
630 if (pIoLogger->offReadNext == pIoLogger->offWriteNext)
631 {
632 *penmReq = VDDBGIOLOGREQ_INVALID;
633 RTSemFastMutexRelease(pIoLogger->hMtx);
634 return VERR_INVALID_STATE;
635 }
636
637 if (RT_SUCCESS(rc))
638 {
639 Assert(pIoLogger->enmReqTypeNext != VDDBGIOLOGREQ_INVALID);
640 *penmReq = pIoLogger->enmReqTypeNext;
641 }
642
643 RTSemFastMutexRelease(pIoLogger->hMtx);
644 return rc;
645}
646
647VBOXDDU_DECL(int) VDDbgIoLogEventGetStart(VDIOLOGGER hIoLogger, uint64_t *pidEvent, bool *pfAsync,
648 uint64_t *poff, size_t *pcbIo, size_t cbBuf, void *pvBuf)
649{
650 int rc = VINF_SUCCESS;
651 PVDIOLOGGERINT pIoLogger = hIoLogger;
652
653 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
654 AssertPtrReturn(pidEvent, VERR_INVALID_POINTER);
655 AssertPtrReturn(pfAsync, VERR_INVALID_POINTER);
656 AssertPtrReturn(poff, VERR_INVALID_POINTER);
657 AssertPtrReturn(pcbIo, VERR_INVALID_POINTER);
658
659 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
660 AssertRCReturn(rc, rc);
661
662 if (pIoLogger->u32EventTypeNext == VDIOLOG_EVENT_START)
663 {
664 IoLogEntryStart Entry;
665 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext, &Entry, sizeof(Entry), NULL);
666 if (RT_SUCCESS(rc))
667 {
668 *pfAsync = (bool)Entry.u8AsyncIo;
669 *pidEvent = RT_LE2H_U64(Entry.u64Id);
670 *poff = RT_LE2H_U64(Entry.Io.u64Off);
671 *pcbIo = RT_LE2H_U64(Entry.Io.u64IoSize);
672
673 if ( pIoLogger->enmReqTypeNext == VDDBGIOLOGREQ_WRITE
674 && (pIoLogger->fFlags & VDDBG_IOLOG_LOG_DATA_WRITTEN))
675 {
676 /* Read data. */
677 if (cbBuf < *pcbIo)
678 rc = VERR_BUFFER_OVERFLOW;
679 else
680 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext + sizeof(Entry), pvBuf, *pcbIo, NULL);
681
682 if (rc != VERR_BUFFER_OVERFLOW)
683 pIoLogger->offReadNext += *pcbIo + sizeof(Entry);
684 }
685 else
686 pIoLogger->offReadNext += sizeof(Entry);
687 }
688 }
689 else
690 rc = VERR_INVALID_STATE;
691
692 if (RT_SUCCESS(rc))
693 pIoLogger->u32EventTypeNext = 0;
694
695 RTSemFastMutexRelease(pIoLogger->hMtx);
696 return rc;
697}
698
699VBOXDDU_DECL(int) VDDbgIoLogEventGetStartDiscard(VDIOLOGGER hIoLogger, uint64_t *pidEvent, bool *pfAsync,
700 PRTRANGE *ppaRanges, unsigned *pcRanges)
701{
702 int rc = VINF_SUCCESS;
703 PVDIOLOGGERINT pIoLogger = hIoLogger;
704
705 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
706 AssertPtrReturn(pidEvent, VERR_INVALID_POINTER);
707 AssertPtrReturn(pfAsync, VERR_INVALID_POINTER);
708
709 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
710 AssertRCReturn(rc, rc);
711
712 if ( pIoLogger->u32EventTypeNext == VDIOLOG_EVENT_START
713 && pIoLogger->enmReqTypeNext == VDDBGIOLOGREQ_DISCARD)
714 {
715 IoLogEntryStart Entry;
716 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext, &Entry, sizeof(Entry), NULL);
717 if (RT_SUCCESS(rc))
718 {
719 PRTRANGE paRanges = NULL;
720 IoLogEntryDiscard DiscardRange;
721
722 pIoLogger->offReadNext += sizeof(Entry);
723 *pfAsync = (bool)Entry.u8AsyncIo;
724 *pidEvent = RT_LE2H_U64(Entry.u64Id);
725 *pcRanges = RT_LE2H_U32(Entry.Discard.cRanges);
726
727 paRanges = (PRTRANGE)RTMemAllocZ(*pcRanges * sizeof(RTRANGE));
728 if (paRanges)
729 {
730 for (unsigned i = 0; i < *pcRanges; i++)
731 {
732 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext + i*sizeof(DiscardRange),
733 &DiscardRange, sizeof(DiscardRange), NULL);
734 if (RT_FAILURE(rc))
735 break;
736
737 paRanges[i].offStart = RT_LE2H_U64(DiscardRange.u64Off);
738 paRanges[i].cbRange = RT_LE2H_U32(DiscardRange.u32Discard);
739 }
740
741 if (RT_SUCCESS(rc))
742 {
743 pIoLogger->offReadNext += *pcRanges * sizeof(DiscardRange);
744 *ppaRanges = paRanges;
745 }
746 else
747 pIoLogger->offReadNext -= sizeof(Entry);
748 }
749 else
750 rc = VERR_NO_MEMORY;
751 }
752 }
753 else
754 rc = VERR_INVALID_STATE;
755
756 if (RT_SUCCESS(rc))
757 pIoLogger->u32EventTypeNext = 0;
758
759 RTSemFastMutexRelease(pIoLogger->hMtx);
760 return rc;
761
762}
763
764VBOXDDU_DECL(int) VDDbgIoLogEventGetComplete(VDIOLOGGER hIoLogger, uint64_t *pidEvent, int *pRc,
765 uint64_t *pmsDuration, size_t *pcbIo, size_t cbBuf, void *pvBuf)
766{
767 int rc = VINF_SUCCESS;
768 PVDIOLOGGERINT pIoLogger = hIoLogger;
769
770 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
771 AssertPtrReturn(pidEvent, VERR_INVALID_POINTER);
772 AssertPtrReturn(pmsDuration, VERR_INVALID_POINTER);
773 AssertPtrReturn(pcbIo, VERR_INVALID_POINTER);
774
775 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
776 AssertRCReturn(rc, rc);
777
778 if (pIoLogger->u32EventTypeNext == VDIOLOG_EVENT_COMPLETE)
779 {
780 IoLogEntryComplete Entry;
781 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext, &Entry, sizeof(Entry), NULL);
782 if (RT_SUCCESS(rc))
783 {
784 *pidEvent = RT_LE2H_U64(Entry.u64Id);
785 *pRc = (int)RT_LE2H_U32((int32_t)Entry.i32Rc);
786 *pmsDuration = RT_LE2H_U64(Entry.msDuration);
787 *pcbIo = RT_LE2H_U64(Entry.u64IoBuffer);
788
789 if (*pcbIo)
790 {
791 /* Read data. */
792 if (cbBuf < *pcbIo)
793 rc = VERR_BUFFER_OVERFLOW;
794 else
795 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext + sizeof(Entry), pvBuf, *pcbIo, NULL);
796
797 if (rc != VERR_BUFFER_OVERFLOW)
798 pIoLogger->offReadNext += *pcbIo + sizeof(Entry);
799 }
800 else
801 pIoLogger->offReadNext += sizeof(Entry);
802 }
803 }
804 else
805 rc = VERR_INVALID_STATE;
806
807 if (RT_SUCCESS(rc))
808 pIoLogger->u32EventTypeNext = 0;
809
810 RTSemFastMutexRelease(pIoLogger->hMtx);
811 return rc;
812}
813
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette