VirtualBox

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

Last change on this file since 67954 was 62482, checked in by vboxsync, 8 years ago

(C) 2016

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