VirtualBox

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

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

fix OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.5 KB
Line 
1/* $Id: VDDbgIoLog.cpp 38552 2011-08-26 14:17:03Z 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 uint8_t u8Type;
66 /** Flag whether this is a sync or async request. */
67 uint8_t u8AsyncIo;
68 /** Id of the entry. */
69 uint64_t u64Id;
70 /** Transfer direction. */
71 uint8_t u8TxDir;
72 /** Start offset. */
73 uint64_t u64Off;
74 /** Size of the request. */
75 uint64_t u64IoSize;
76} IoLogEntryStart;
77#pragma pack()
78
79/**
80 * I/O log entry markign the completion of an I/O transaction.
81 */
82#pragma pack(1)
83typedef struct IoLogEntryComplete
84{
85 /** Event type. */
86 uint8_t u8Type;
87 /** Id of the matching start entry. */
88 uint64_t u64Id;
89 /** Status code the request completed with */
90 int32_t i32Rc;
91 /** Number of milliseconds the request needed to complete. */
92 uint64_t msDuration;
93 /** Number of bytes of data following this entry. */
94 uint64_t u64IoBuffer;
95} IoLogEntryComplete;
96#pragma pack()
97
98/*******************************************************************************
99* Constants And Macros, Structures and Typedefs *
100*******************************************************************************/
101
102/**
103 * I/O logger instance data.
104 */
105typedef struct VDIOLOGGERINT
106{
107 /** File handle. */
108 RTFILE hFile;
109 /** Current offset to append new entries to. */
110 uint64_t offWriteNext;
111 /** Offset to read the next entry from. */
112 uint64_t offReadNext;
113 /** Flags given during creation. */
114 uint32_t fFlags;
115 /** Id for the next entry. */
116 uint64_t idNext;
117 /** Memory cache for the I/O log entries. */
118 RTMEMCACHE hMemCacheIoLogEntries;
119 /** Mutex section protecting the logger. */
120 RTSEMFASTMUTEX hMtx;
121 /** Cached event type of the next event. */
122 uint8_t u8EventTypeNext;
123} VDIOLOGGERINT;
124/** Pointer to the internal I/O logger instance data. */
125typedef VDIOLOGGERINT *PVDIOLOGGERINT;
126
127/**
128 * I/O log entry data.
129 */
130typedef struct VDIOLOGENTINT
131{
132 /** Id of the start entry. */
133 uint64_t idStart;
134 /** Timestamnp when the request started. */
135 uint64_t tsStart;
136 /** Size of the buffer to write on success. */
137 size_t cbIo;
138} VDIOLOGENTINT;
139/** Pointer to the internal I/O log entry data. */
140typedef VDIOLOGENTINT *PVDIOLOGENTINT;
141
142/*******************************************************************************
143* Internal Functions *
144*******************************************************************************/
145
146/**
147 * Creates a new empty I/O logger.
148 *
149 * @returns VBox status code.
150 * @param ppIoLogger Where to store the new I/O logger handle.
151 */
152static int vddbgIoLoggerCreate(PVDIOLOGGERINT *ppIoLogger)
153{
154 int rc = VINF_SUCCESS;
155 PVDIOLOGGERINT pIoLogger = NULL;
156
157 pIoLogger = (PVDIOLOGGERINT)RTMemAllocZ(sizeof(VDIOLOGGERINT));
158 if (pIoLogger)
159 {
160 rc = RTSemFastMutexCreate(&pIoLogger->hMtx);
161 if (RT_SUCCESS(rc))
162 {
163 rc = RTMemCacheCreate(&pIoLogger->hMemCacheIoLogEntries, sizeof(VDIOLOGENTINT),
164 0, UINT32_MAX, NULL, NULL, NULL, 0);
165 if (RT_SUCCESS(rc))
166 {
167 *ppIoLogger = pIoLogger;
168 return rc;
169 }
170 }
171 RTMemFree(pIoLogger);
172 }
173 else
174 rc = VERR_NO_MEMORY;
175
176 return rc;
177}
178
179/**
180 * Update the header of the I/O logger to the current state.
181 *
182 * @returns VBox status code.
183 * @param pIoLogger The I/O logger to update.
184 */
185static int vddbgIoLoggerHeaderUpdate(PVDIOLOGGERINT pIoLogger)
186{
187 int rc = VINF_SUCCESS;
188 IoLogHeader Hdr;
189
190 memcpy(Hdr.szMagic, VDIOLOG_MAGIC, sizeof(Hdr.szMagic));
191 Hdr.fFlags = RT_H2LE_U32(pIoLogger->fFlags);
192 Hdr.u64Id = RT_H2LE_U64(pIoLogger->idNext);
193 rc = RTFileWriteAt(pIoLogger->hFile, 0, &Hdr, sizeof(Hdr), NULL);
194
195 return rc;
196}
197
198/**
199 * Writes data from the given S/G buffer into the I/O log.
200 *
201 * @returns VBox status code.
202 * @param pIoLogger The I/O logger to use.
203 * @param off The start offset in the log to write to.
204 * @param pSgBuf The S/G buffer to write.
205 * @param cbSgBuf How much data to write.
206 */
207static int vddbgIoLogWriteSgBuf(PVDIOLOGGERINT pIoLogger, uint64_t off, PCRTSGBUF pSgBuf, size_t cbSgBuf)
208{
209 int rc = VINF_SUCCESS;
210 RTSGBUF SgBuf;
211
212 RTSgBufClone(&SgBuf, pSgBuf);
213
214 while (cbSgBuf)
215 {
216 void *pvSeg;
217 size_t cbSeg = cbSgBuf;
218
219 pvSeg = RTSgBufGetNextSegment(&SgBuf, &cbSeg);
220 AssertPtrBreakStmt(pvSeg, rc = VERR_INTERNAL_ERROR);
221
222 rc = RTFileWriteAt(pIoLogger->hFile, off, pvSeg, cbSeg, NULL);
223 if (RT_FAILURE(rc))
224 break;
225
226 cbSgBuf -= cbSeg;
227 off += cbSeg;
228 }
229
230 return rc;
231}
232
233VBOXDDU_DECL(int) VDDbgIoLogCreate(PVDIOLOGGER phIoLogger, const char *pszFilename, uint32_t fFlags)
234{
235 int rc = VINF_SUCCESS;
236 PVDIOLOGGERINT pIoLogger = NULL;
237
238 AssertPtrReturn(phIoLogger, VERR_INVALID_POINTER);
239 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
240 AssertReturn(!(fFlags & ~VDDBG_IOLOG_VALID_MASK), VERR_INVALID_PARAMETER);
241
242 rc = vddbgIoLoggerCreate(&pIoLogger);
243 if (RT_SUCCESS(rc))
244 {
245 pIoLogger->fFlags = fFlags;
246 pIoLogger->hFile = NIL_RTFILE;
247
248 /* Create new log. */
249 rc = RTFileOpen(&pIoLogger->hFile, pszFilename, RTFILE_O_DENY_NONE | RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_READ);
250 if (RT_SUCCESS(rc))
251 {
252 rc = vddbgIoLoggerHeaderUpdate(pIoLogger);
253 if (RT_SUCCESS(rc))
254 {
255 pIoLogger->offWriteNext = sizeof(IoLogHeader);
256 pIoLogger->offReadNext = sizeof(IoLogHeader);
257 }
258 }
259
260 if (RT_SUCCESS(rc))
261 *phIoLogger = pIoLogger;
262 else
263 {
264 if (pIoLogger->hFile != NIL_RTFILE)
265 RTFileClose(pIoLogger->hFile);
266 RTMemFree(pIoLogger);
267 }
268 }
269
270 return rc;
271}
272
273VBOXDDU_DECL(int) VDDbgIoLogOpen(PVDIOLOGGER phIoLogger, const char *pszFilename)
274{
275 int rc = VINF_SUCCESS;
276 PVDIOLOGGERINT pIoLogger = NULL;
277
278 AssertPtrReturn(phIoLogger, VERR_INVALID_POINTER);
279 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
280
281 rc = vddbgIoLoggerCreate(&pIoLogger);
282 if (RT_SUCCESS(rc))
283 {
284 /* open existing log. */
285 rc = RTFileOpen(&pIoLogger->hFile, pszFilename, RTFILE_O_DENY_NONE | RTFILE_O_OPEN | RTFILE_O_WRITE | RTFILE_O_READ);
286 if (RT_SUCCESS(rc))
287 {
288 IoLogHeader Hdr;
289 uint64_t cbLog;
290
291 rc = RTFileGetSize(pIoLogger->hFile, &cbLog);
292
293 /* Read the header. */
294 if (RT_SUCCESS(rc))
295 rc = RTFileRead(pIoLogger->hFile, &Hdr, sizeof(Hdr), NULL);
296
297 if ( RT_SUCCESS(rc)
298 && !memcmp(Hdr.szMagic, VDIOLOG_MAGIC, sizeof(Hdr.szMagic)))
299 {
300 pIoLogger->fFlags = RT_LE2H_U32(Hdr.fFlags);
301 pIoLogger->offWriteNext = cbLog;
302 pIoLogger->offReadNext = sizeof(Hdr);
303 pIoLogger->idNext = RT_LE2H_U64(Hdr.u64Id);
304 }
305 else if (RT_SUCCESS(rc))
306 rc = VERR_INVALID_PARAMETER;
307 }
308 }
309
310 return rc;
311}
312
313VBOXDDU_DECL(void) VDDbgIoLogDestroy(VDIOLOGGER hIoLogger)
314{
315 PVDIOLOGGERINT pIoLogger = hIoLogger;
316
317 AssertPtrReturnVoid(pIoLogger);
318
319 vddbgIoLoggerHeaderUpdate(pIoLogger);
320 RTFileFlush(pIoLogger->hFile);
321 RTFileClose(pIoLogger->hFile);
322 RTMemCacheDestroy(pIoLogger->hMemCacheIoLogEntries);
323 RTSemFastMutexDestroy(pIoLogger->hMtx);
324 RTMemFree(pIoLogger);
325}
326
327VBOXDDU_DECL(int) VDDbgIoLogCommit(VDIOLOGGER hIoLogger)
328{
329 int rc = VINF_SUCCESS;
330 PVDIOLOGGERINT pIoLogger = hIoLogger;
331
332 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
333
334 rc = vddbgIoLoggerHeaderUpdate(pIoLogger);
335 if (RT_SUCCESS(rc))
336 rc = RTFileFlush(pIoLogger->hFile);
337
338 return rc;
339}
340
341VBOXDDU_DECL(uint32_t) VDDbgIoLogGetFlags(VDIOLOGGER hIoLogger)
342{
343 PVDIOLOGGERINT pIoLogger = hIoLogger;
344
345 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
346
347 return pIoLogger->fFlags;
348}
349
350VBOXDDU_DECL(int) VDDbgIoLogStart(VDIOLOGGER hIoLogger, bool fAsync, VDDBGIOLOGTXDIR enmTxDir, uint64_t off, size_t cbIo, PCRTSGBUF pSgBuf,
351 PVDIOLOGENT phIoLogEntry)
352{
353 int rc = VINF_SUCCESS;
354 PVDIOLOGGERINT pIoLogger = hIoLogger;
355 PVDIOLOGENTINT pIoLogEntry = NULL;
356
357 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
358 AssertPtrReturn(phIoLogEntry, VERR_INVALID_POINTER);
359 AssertReturn(enmTxDir > VDDBGIOLOGTXDIR_INVALID && enmTxDir <= VDDBGIOLOGTXDIR_FLUSH, VERR_INVALID_PARAMETER);
360
361 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
362 AssertRCReturn(rc, rc);
363
364 pIoLogEntry = (PVDIOLOGENTINT)RTMemCacheAlloc(pIoLogger->hMemCacheIoLogEntries);
365 if (pIoLogEntry)
366 {
367 IoLogEntryStart Entry;
368
369 pIoLogEntry->idStart = pIoLogger->idNext++;
370
371 Entry.u8Type = VDIOLOG_EVENT_START;
372 Entry.u8AsyncIo = fAsync ? 1 : 0;
373 Entry.u8TxDir = (uint8_t)enmTxDir;
374 Entry.u64Off = RT_H2LE_U64(off);
375 Entry.u64IoSize = RT_H2LE_U64(cbIo);
376 Entry.u64Id = RT_H2LE_U64(pIoLogEntry->idStart);
377
378 /* Write new entry. */
379 rc = RTFileWriteAt(pIoLogger->hFile, pIoLogger->offWriteNext, &Entry, sizeof(Entry), NULL);
380 if (RT_SUCCESS(rc))
381 {
382 pIoLogger->offWriteNext += sizeof(Entry);
383
384 if ( enmTxDir == VDDBGIOLOGTXDIR_WRITE
385 && (pIoLogger->fFlags & VDDBG_IOLOG_LOG_DATA_WRITTEN))
386 {
387 /* Write data. */
388 rc = vddbgIoLogWriteSgBuf(pIoLogger, pIoLogger->offWriteNext, pSgBuf, cbIo);
389 if (RT_FAILURE(rc))
390 {
391 pIoLogger->offWriteNext -= sizeof(Entry);
392 rc = RTFileSetSize(pIoLogger->hFile, pIoLogger->offWriteNext);
393 }
394 else
395 pIoLogger->offWriteNext += cbIo;
396 }
397 }
398
399 if (RT_SUCCESS(rc))
400 {
401 pIoLogEntry->tsStart = RTTimeProgramMilliTS();
402
403 if ( enmTxDir == VDDBGIOLOGTXDIR_READ
404 && (pIoLogger->fFlags & VDDBG_IOLOG_LOG_DATA_READ))
405 pIoLogEntry->cbIo = cbIo;
406 else
407 pIoLogEntry->cbIo = 0;
408
409 *phIoLogEntry = pIoLogEntry;
410 }
411 else
412 {
413 pIoLogger->idNext--;
414 RTMemCacheFree(pIoLogger->hMemCacheIoLogEntries, pIoLogEntry);
415 }
416 }
417 else
418 rc = VERR_NO_MEMORY;
419
420 RTSemFastMutexRelease(pIoLogger->hMtx);
421 return rc;
422}
423
424VBOXDDU_DECL(int) VDDbgIoLogComplete(VDIOLOGGER hIoLogger, VDIOLOGENT hIoLogEntry, int rcReq, PCRTSGBUF pSgBuf)
425{
426 int rc = VINF_SUCCESS;
427 PVDIOLOGGERINT pIoLogger = hIoLogger;
428 PVDIOLOGENTINT pIoLogEntry = hIoLogEntry;
429
430 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
431 AssertPtrReturn(pIoLogEntry, VERR_INVALID_HANDLE);
432
433 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
434 AssertRCReturn(rc, rc);
435
436 IoLogEntryComplete Entry;
437
438 Entry.u8Type = VDIOLOG_EVENT_COMPLETE;
439 Entry.u64Id = RT_H2LE_U64(pIoLogEntry->idStart);
440 Entry.msDuration = RTTimeProgramMilliTS() - RT_H2LE_U64(pIoLogEntry->tsStart);
441 Entry.i32Rc = (int32_t)RT_H2LE_U32((uint32_t)rcReq);
442 Entry.u64IoBuffer = RT_H2LE_U64(pIoLogEntry->cbIo);
443
444 /* Write new entry. */
445 rc = RTFileWriteAt(pIoLogger->hFile, pIoLogger->offWriteNext, &Entry, sizeof(Entry), NULL);
446 if (RT_SUCCESS(rc))
447 {
448 pIoLogger->offWriteNext += sizeof(Entry);
449
450 if (pIoLogEntry->cbIo)
451 {
452 rc = vddbgIoLogWriteSgBuf(pIoLogger, pIoLogger->offWriteNext, pSgBuf, pIoLogEntry->cbIo);
453 if (RT_SUCCESS(rc))
454 pIoLogger->offWriteNext += pIoLogEntry->cbIo;
455 else
456 {
457 pIoLogger->offWriteNext -= sizeof(Entry);
458 rc = RTFileSetSize(pIoLogger->hFile, pIoLogger->offWriteNext);
459 }
460 }
461 }
462
463 RTMemCacheFree(pIoLogger->hMemCacheIoLogEntries, pIoLogEntry);
464 RTSemFastMutexRelease(pIoLogger->hMtx);
465 return rc;
466}
467
468VBOXDDU_DECL(int) VDDbgIoLogEventTypeGetNext(VDIOLOGGER hIoLogger, VDIOLOGEVENT *penmEvent)
469{
470 int rc = VINF_SUCCESS;
471 PVDIOLOGGERINT pIoLogger = hIoLogger;
472
473 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
474 AssertPtrReturn(penmEvent, VERR_INVALID_POINTER);
475
476 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
477 AssertRCReturn(rc, rc);
478
479 if (pIoLogger->offReadNext == pIoLogger->offWriteNext)
480 {
481 *penmEvent = VDIOLOGEVENT_END;
482 RTSemFastMutexRelease(pIoLogger->hMtx);
483 return VINF_SUCCESS;
484 }
485
486 if (!pIoLogger->u8EventTypeNext)
487 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext, &pIoLogger->u8EventTypeNext, sizeof(uint8_t), NULL);
488
489 if (RT_SUCCESS(rc))
490 {
491 Assert(pIoLogger->u8EventTypeNext != 0);
492
493 switch (pIoLogger->u8EventTypeNext)
494 {
495 case VDIOLOG_EVENT_START:
496 *penmEvent = VDIOLOGEVENT_START;
497 break;
498 case VDIOLOG_EVENT_COMPLETE:
499 *penmEvent = VDIOLOGEVENT_COMPLETE;
500 break;
501 default:
502 AssertMsgFailed(("Invalid event type %d\n", pIoLogger->u8EventTypeNext));
503 }
504 }
505
506 RTSemFastMutexRelease(pIoLogger->hMtx);
507 return rc;
508}
509
510VBOXDDU_DECL(int) VDDbgIoLogEventGetStart(VDIOLOGGER hIoLogger, uint64_t *pidEvent, bool *pfAsync, PVDDBGIOLOGTXDIR penmTxDir,
511 uint64_t *poff, size_t *pcbIo, size_t cbBuf, void *pvBuf)
512{
513 int rc = VINF_SUCCESS;
514 PVDIOLOGGERINT pIoLogger = hIoLogger;
515
516 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
517 AssertPtrReturn(pidEvent, VERR_INVALID_POINTER);
518 AssertPtrReturn(pfAsync, VERR_INVALID_POINTER);
519 AssertPtrReturn(penmTxDir, VERR_INVALID_POINTER);
520 AssertPtrReturn(poff, VERR_INVALID_POINTER);
521 AssertPtrReturn(pcbIo, VERR_INVALID_POINTER);
522
523 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
524 AssertRCReturn(rc, rc);
525
526 if (pIoLogger->u8EventTypeNext == VDIOLOG_EVENT_START)
527 {
528 IoLogEntryStart Entry;
529 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext, &Entry, sizeof(Entry), NULL);
530 if (RT_SUCCESS(rc))
531 {
532 *penmTxDir = (VDDBGIOLOGTXDIR)Entry.u8TxDir;
533 *pfAsync = (bool)Entry.u8AsyncIo;
534 *pidEvent = RT_LE2H_U64(Entry.u64Id);
535 *poff = RT_LE2H_U64(Entry.u64Off);
536 *pcbIo = RT_LE2H_U64(Entry.u64IoSize);
537
538 if ( *penmTxDir == VDDBGIOLOGTXDIR_WRITE
539 && (pIoLogger->fFlags & VDDBG_IOLOG_LOG_DATA_WRITTEN))
540 {
541 /* Read data. */
542 if (cbBuf < *pcbIo)
543 rc = VERR_BUFFER_OVERFLOW;
544 else
545 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext + sizeof(Entry), pvBuf, *pcbIo, NULL);
546
547 if (rc != VERR_BUFFER_OVERFLOW)
548 pIoLogger->offReadNext += *pcbIo + sizeof(Entry);
549 }
550 else
551 pIoLogger->offReadNext += sizeof(Entry);
552 }
553 }
554 else
555 rc = VERR_INVALID_STATE;
556
557 RTSemFastMutexRelease(pIoLogger->hMtx);
558 return rc;
559}
560
561VBOXDDU_DECL(int) VDDbgIoLogEventGetComplete(VDIOLOGGER hIoLogger, uint64_t *pidEvent, int *pRc,
562 uint64_t *pmsDuration, size_t *pcbIo, size_t cbBuf, void *pvBuf)
563{
564 int rc = VINF_SUCCESS;
565 PVDIOLOGGERINT pIoLogger = hIoLogger;
566
567 AssertPtrReturn(pIoLogger, VERR_INVALID_HANDLE);
568 AssertPtrReturn(pidEvent, VERR_INVALID_POINTER);
569 AssertPtrReturn(pmsDuration, VERR_INVALID_POINTER);
570 AssertPtrReturn(pcbIo, VERR_INVALID_POINTER);
571
572 rc = RTSemFastMutexRequest(pIoLogger->hMtx);
573 AssertRCReturn(rc, rc);
574
575 if (pIoLogger->u8EventTypeNext == VDIOLOG_EVENT_COMPLETE)
576 {
577 IoLogEntryComplete Entry;
578 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext, &Entry, sizeof(Entry), NULL);
579 if (RT_SUCCESS(rc))
580 {
581 *pidEvent = RT_LE2H_U64(Entry.u64Id);
582 *pRc = (int)RT_LE2H_U32((int32_t)Entry.i32Rc);
583 *pmsDuration = RT_LE2H_U64(Entry.msDuration);
584 *pcbIo = RT_LE2H_U64(Entry.u64IoBuffer);
585
586 if (*pcbIo)
587 {
588 /* Read data. */
589 if (cbBuf < *pcbIo)
590 rc = VERR_BUFFER_OVERFLOW;
591 else
592 rc = RTFileReadAt(pIoLogger->hFile, pIoLogger->offReadNext + sizeof(Entry), pvBuf, *pcbIo, NULL);
593
594 if (rc != VERR_BUFFER_OVERFLOW)
595 pIoLogger->offReadNext += *pcbIo + sizeof(Entry);
596 }
597 else
598 pIoLogger->offReadNext += sizeof(Entry);
599 }
600 }
601 else
602 rc = VERR_INVALID_STATE;
603
604 RTSemFastMutexRelease(pIoLogger->hMtx);
605 return rc;
606}
607
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