~ubuntu-branches/ubuntu/trusty/virtualbox/trusty-proposed

« back to all changes in this revision

Viewing changes to src/VBox/Storage/Debug/VDDbgIoLog.cpp

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2013-03-07 16:38:36 UTC
  • mfrom: (1.1.13) (3.1.20 experimental)
  • Revision ID: package-import@ubuntu.com-20130307163836-p93jpbgx39tp3gb4
Tags: 4.2.8-dfsg-0ubuntu1
* New upstream release. (Closes: #691148)
  - Fixes compatibility with kernel 3.8. (Closes: #700823; LP: #1101867)
* Switch to my @debian.org email address.
* Move package to contrib as virtualbox 4.2 needs a non-free compiler to
  build the BIOS.
* Build-depend on libdevmapper-dev.
* Refresh patches.
  - Drop 36-fix-ftbfs-xserver-112.patch, cve-2012-3221.patch,
    CVE-2013-0420.patch 37-kcompat-3.6.patch and 38-kcompat-3.7.patch.
* Drop all virtualbox-ose transitional packages.
* Drop the virtualbox-fuse package as vdfuse fails to build with
  virtualbox 4.2.
* Update install files and VBox.sh.
* Bump required kbuild version to 0.1.9998svn2577.
* Fix path to VBoxCreateUSBNode.sh in virtualbox.postinst. (Closes: #700479)
* Add an init script to virtuabox-guest-x11 which loads the vboxvideo
  kernel module. The X Server 1.13 doesn't load it anymore. (Closes: #686994)
* Update man pages. (Closes: #680053)
* Add 36-python-multiarch.patch from Rico Tzschichholz to fix detection of
  python in multiarch paths using pkg-config.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: VDDbgIoLog.cpp $ */
 
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)
 
41
typedef 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)
 
63
typedef 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)
 
98
typedef 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)
 
114
typedef 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
 */
 
130
typedef 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. */
 
152
typedef VDIOLOGGERINT *PVDIOLOGGERINT;
 
153
 
 
154
/**
 
155
 * I/O log entry data.
 
156
 */
 
157
typedef 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. */
 
167
typedef 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
 */
 
179
static 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
 */
 
212
static 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
 */
 
234
static 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
 
 
260
VBOXDDU_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
 
 
300
VBOXDDU_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
 
 
341
VBOXDDU_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
 
 
355
VBOXDDU_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
 
 
369
VBOXDDU_DECL(uint32_t) VDDbgIoLogGetFlags(VDIOLOGGER hIoLogger)
 
370
{
 
371
    PVDIOLOGGERINT pIoLogger = hIoLogger;
 
372
 
 
373
    AssertPtrReturn(pIoLogger, 0);
 
374
 
 
375
    return pIoLogger->fFlags;
 
376
}
 
377
 
 
378
VBOXDDU_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
 
 
452
VBOXDDU_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
 
 
525
VBOXDDU_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
 
 
569
VBOXDDU_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
 
 
619
VBOXDDU_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
 
 
647
VBOXDDU_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
 
 
699
VBOXDDU_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
 
 
764
VBOXDDU_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