VirtualBox

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

Last change on this file since 40240 was 38876, checked in by vboxsync, 13 years ago

Storage: Add async discard API

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