VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp@ 81301

Last change on this file since 81301 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.1 KB
Line 
1/* $Id: DrvDiskIntegrity.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBox storage devices: Disk integrity check.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_DISK_INTEGRITY
23#include <VBox/vmm/pdmdrv.h>
24#include <VBox/vmm/pdmstorageifs.h>
25#include <iprt/assert.h>
26#include <iprt/string.h>
27#include <iprt/uuid.h>
28#include <iprt/avl.h>
29#include <iprt/mem.h>
30#include <iprt/memcache.h>
31#include <iprt/message.h>
32#include <iprt/sg.h>
33#include <iprt/time.h>
34#include <iprt/tracelog.h>
35#include <iprt/semaphore.h>
36#include <iprt/asm.h>
37
38#include "VBoxDD.h"
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44
45/**
46 * Transfer direction.
47 */
48typedef enum DRVDISKAIOTXDIR
49{
50 /** Invalid. */
51 DRVDISKAIOTXDIR_INVALID = 0,
52 /** Read */
53 DRVDISKAIOTXDIR_READ,
54 /** Write */
55 DRVDISKAIOTXDIR_WRITE,
56 /** Flush */
57 DRVDISKAIOTXDIR_FLUSH,
58 /** Discard */
59 DRVDISKAIOTXDIR_DISCARD,
60 /** Read after write for immediate verification. */
61 DRVDISKAIOTXDIR_READ_AFTER_WRITE
62} DRVDISKAIOTXDIR;
63
64/**
65 * async I/O request.
66 */
67typedef struct DRVDISKAIOREQ
68{
69 /** Transfer direction. */
70 DRVDISKAIOTXDIR enmTxDir;
71 /** Start offset. */
72 uint64_t off;
73 /** Transfer size. */
74 size_t cbTransfer;
75 /** Segment array. */
76 PCRTSGSEG paSeg;
77 /** Number of array entries. */
78 unsigned cSeg;
79 /** User argument */
80 void *pvUser;
81 /** Slot in the array. */
82 unsigned iSlot;
83 /** Start timestamp */
84 uint64_t tsStart;
85 /** Completion timestamp. */
86 uint64_t tsComplete;
87 /** Ranges to discard. */
88 PCRTRANGE paRanges;
89 /** Number of ranges. */
90 unsigned cRanges;
91 /** I/O segment for the extended media interface
92 * to hold the data. */
93 RTSGSEG IoSeg;
94} DRVDISKAIOREQ, *PDRVDISKAIOREQ;
95
96/**
97 * I/O log entry.
98 */
99typedef struct IOLOGENT
100{
101 /** Start offset */
102 uint64_t off;
103 /** Write size */
104 size_t cbWrite;
105 /** Number of references to this entry. */
106 unsigned cRefs;
107} IOLOGENT, *PIOLOGENT;
108
109/**
110 * Disk segment.
111 */
112typedef struct DRVDISKSEGMENT
113{
114 /** AVL core. */
115 AVLRFOFFNODECORE Core;
116 /** Size of the segment */
117 size_t cbSeg;
118 /** Data for this segment */
119 uint8_t *pbSeg;
120 /** Number of entries in the I/O array. */
121 unsigned cIoLogEntries;
122 /** Array of I/O log references. */
123 PIOLOGENT apIoLog[1];
124} DRVDISKSEGMENT, *PDRVDISKSEGMENT;
125
126/**
127 * Active requests list entry.
128 */
129typedef struct DRVDISKAIOREQACTIVE
130{
131 /** Pointer to the request. */
132 volatile PDRVDISKAIOREQ pIoReq;
133 /** Start timestamp. */
134 uint64_t tsStart;
135} DRVDISKAIOREQACTIVE, *PDRVDISKAIOREQACTIVE;
136
137/**
138 * Disk integrity driver instance data.
139 *
140 * @implements PDMIMEDIA
141 * @implements PDMIMEDIAPORT
142 * @implements PDMIMEDIAEX
143 * @implements PDMIMEDIAEXPORT
144 * @implements PDMIMEDIAMOUNT
145 * @implements PDMIMEDIAMOUNTNOTIFY
146 */
147typedef struct DRVDISKINTEGRITY
148{
149 /** Pointer driver instance. */
150 PPDMDRVINS pDrvIns;
151 /** Pointer to the media driver below us.
152 * This is NULL if the media is not mounted. */
153 PPDMIMEDIA pDrvMedia;
154 /** Our media interface */
155 PDMIMEDIA IMedia;
156
157 /** The media port interface above. */
158 PPDMIMEDIAPORT pDrvMediaPort;
159 /** Media port interface */
160 PDMIMEDIAPORT IMediaPort;
161
162 /** The extended media port interface above. */
163 PPDMIMEDIAEXPORT pDrvMediaExPort;
164 /** Our extended media port interface */
165 PDMIMEDIAEXPORT IMediaExPort;
166
167 /** The extended media interface below. */
168 PPDMIMEDIAEX pDrvMediaEx;
169 /** Our extended media interface */
170 PDMIMEDIAEX IMediaEx;
171
172 /** The mount interface below. */
173 PPDMIMOUNT pDrvMount;
174 /** Our mount interface */
175 PDMIMOUNT IMount;
176
177 /** The mount notify interface above. */
178 PPDMIMOUNTNOTIFY pDrvMountNotify;
179 /** Our mount notify interface. */
180 PDMIMOUNTNOTIFY IMountNotify;
181
182 /** Flag whether consistency checks are enabled. */
183 bool fCheckConsistency;
184 /** Flag whether the RAM disk was prepopulated. */
185 bool fPrepopulateRamDisk;
186 /** AVL tree containing the disk blocks to check. */
187 PAVLRFOFFTREE pTreeSegments;
188
189 /** Flag whether async request tracing is enabled. */
190 bool fTraceRequests;
191 /** Interval the thread should check for expired requests (milliseconds). */
192 uint32_t uCheckIntervalMs;
193 /** Expire timeout for a request (milliseconds). */
194 uint32_t uExpireIntervalMs;
195 /** Thread which checks for lost requests. */
196 RTTHREAD hThread;
197 /** Event semaphore */
198 RTSEMEVENT SemEvent;
199 /** Flag whether the thread should run. */
200 bool fRunning;
201 /** Array containing active requests. */
202 DRVDISKAIOREQACTIVE apReqActive[128];
203 /** Next free slot in the array */
204 volatile unsigned iNextFreeSlot;
205 /** Request cache. */
206 RTMEMCACHE hReqCache;
207
208 /** Flag whether we check for requests completing twice. */
209 bool fCheckDoubleCompletion;
210 /** Number of requests we go back. */
211 unsigned cEntries;
212 /** Array of completed but still observed requests. */
213 PDRVDISKAIOREQ *papIoReq;
214 /** Current entry in the array. */
215 unsigned iEntry;
216
217 /** Flag whether to do a immediate read after write for verification. */
218 bool fReadAfterWrite;
219 /** Flag whether to record the data to write before the write completed successfully.
220 * Useful in case the data is modified in place later on (encryption for instance). */
221 bool fRecordWriteBeforeCompletion;
222 /** Flag whether to validate memory buffers when the extended media interface is used. */
223 bool fValidateMemBufs;
224
225 /** I/O logger to use if enabled. */
226 RTTRACELOGWR hIoLogger;
227 /** Size of the opaque handle until our tracking structure starts in bytes. */
228 size_t cbIoReqOpaque;
229} DRVDISKINTEGRITY, *PDRVDISKINTEGRITY;
230
231
232/**
233 * Read/Write event items.
234 */
235static const RTTRACELOGEVTITEMDESC g_aEvtItemsReadWrite[] =
236{
237 { "Async", "Flag whether the request is asynchronous", RTTRACELOGTYPE_BOOL, 0 },
238 { "Offset", "Offset to start reading/writing from/to", RTTRACELOGTYPE_UINT64, 0 },
239 { "Size", "Number of bytes to transfer", RTTRACELOGTYPE_SIZE, 0 }
240};
241
242/**
243 * Flush event items.
244 */
245static const RTTRACELOGEVTITEMDESC g_aEvtItemsFlush[] =
246{
247 { "Async", "Flag whether the request is asynchronous", RTTRACELOGTYPE_BOOL, 0 }
248};
249
250/**
251 * I/O request complete items.
252 */
253static const RTTRACELOGEVTITEMDESC g_aEvtItemsComplete[] =
254{
255 { "Status", "Status code the request completed with", RTTRACELOGTYPE_INT32, 0 }
256};
257
258/** Read event descriptor. */
259static const RTTRACELOGEVTDESC g_EvtRead =
260 { "Read", "Read data from disk", RTTRACELOGEVTSEVERITY_DEBUG, RT_ELEMENTS(g_aEvtItemsReadWrite), &g_aEvtItemsReadWrite[0] };
261/** Write event descriptor. */
262static const RTTRACELOGEVTDESC g_EvtWrite =
263 { "Write", "Write data to disk", RTTRACELOGEVTSEVERITY_DEBUG, RT_ELEMENTS(g_aEvtItemsReadWrite), &g_aEvtItemsReadWrite[0] };
264/** Flush event descriptor. */
265static const RTTRACELOGEVTDESC g_EvtFlush =
266 { "Flush", "Flush written data to disk", RTTRACELOGEVTSEVERITY_DEBUG, RT_ELEMENTS(g_aEvtItemsFlush), &g_aEvtItemsFlush[0] };
267/** I/O request complete event descriptor. */
268static const RTTRACELOGEVTDESC g_EvtComplete =
269 { "Complete", "A previously started I/O request completed", RTTRACELOGEVTSEVERITY_DEBUG,
270 RT_ELEMENTS(g_aEvtItemsComplete), &g_aEvtItemsComplete[0]};
271
272#define DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(a_pThis, a_hIoReq) ((*(PDRVDISKAIOREQ *)((uintptr_t)(a_hIoReq) + (a_pThis)->cbIoReqOpaque)))
273#define DISKINTEGRITY_IOREQ_HANDLE_2_UPPER_OPAQUE(a_pThis, a_hIoReq) ((void *)((uintptr_t)(a_hIoReq) + (a_pThis)->cbIoReqOpaque + sizeof(PDRVDISKAIOREQ)))
274#define DISKINTEGRITY_IOREQ_ALLOC_2_DRVDISKAIOREQ(a_pvIoReqAlloc) (*(PDRVDISKAIOREQ *)(a_pvIoReqAlloc))
275#define DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(a_pvIoReqAlloc) ((void *)((uintptr_t)(a_pvIoReqAlloc) + sizeof(PDRVDISKAIOREQ)))
276
277static void drvdiskintIoReqCheckForDoubleCompletion(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq,
278 bool fMediaEx)
279{
280 /* Search if the I/O request completed already. */
281 for (unsigned i = 0; i < pThis->cEntries; i++)
282 {
283 if (RT_UNLIKELY(pThis->papIoReq[i] == pIoReq))
284 {
285 RTMsgError("Request %#p completed already!\n", pIoReq);
286 if (!fMediaEx)
287 RTMsgError("Start timestamp %llu Completion timestamp %llu (completed after %llu ms)\n",
288 pIoReq->tsStart, pIoReq->tsComplete, pIoReq->tsComplete - pIoReq->tsStart);
289 RTAssertDebugBreak();
290 }
291 }
292
293 pIoReq->tsComplete = RTTimeSystemMilliTS();
294 Assert(!pThis->papIoReq[pThis->iEntry]);
295 pThis->papIoReq[pThis->iEntry] = pIoReq;
296
297 pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
298 if (pThis->papIoReq[pThis->iEntry])
299 {
300 if (!fMediaEx)
301 RTMemFree(pThis->papIoReq[pThis->iEntry]);
302 pThis->papIoReq[pThis->iEntry] = NULL;
303 }
304}
305
306static void drvdiskintIoLogEntryRelease(PIOLOGENT pIoLogEnt)
307{
308 pIoLogEnt->cRefs--;
309 if (!pIoLogEnt->cRefs)
310 RTMemFree(pIoLogEnt);
311}
312
313/**
314 * Record a successful write to the virtual disk.
315 *
316 * @returns VBox status code.
317 * @param pThis Disk integrity driver instance data.
318 * @param paSeg Segment array of the write to record.
319 * @param cSeg Number of segments.
320 * @param off Start offset.
321 * @param cbWrite Number of bytes to record.
322 */
323static int drvdiskintWriteRecord(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
324 uint64_t off, size_t cbWrite)
325{
326 int rc = VINF_SUCCESS;
327
328 LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbWrite=%u\n",
329 pThis, paSeg, cSeg, off, cbWrite));
330
331 /* Update the segments */
332 size_t cbLeft = cbWrite;
333 RTFOFF offCurr = (RTFOFF)off;
334 RTSGBUF SgBuf;
335 PIOLOGENT pIoLogEnt = (PIOLOGENT)RTMemAllocZ(sizeof(IOLOGENT));
336 if (!pIoLogEnt)
337 return VERR_NO_MEMORY;
338
339 pIoLogEnt->off = off;
340 pIoLogEnt->cbWrite = cbWrite;
341 pIoLogEnt->cRefs = 0;
342
343 RTSgBufInit(&SgBuf, paSeg, cSeg);
344
345 while (cbLeft)
346 {
347 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
348 size_t cbRange = 0;
349 bool fSet = false;
350 unsigned offSeg = 0;
351
352 if (!pSeg)
353 {
354 /* Get next segment */
355 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
356 if ( !pSeg
357 || offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
358 cbRange = cbLeft;
359 else
360 cbRange = pSeg->Core.Key - offCurr;
361
362 Assert(cbRange % 512 == 0);
363
364 /* Create new segment */
365 pSeg = (PDRVDISKSEGMENT)RTMemAllocZ(RT_UOFFSETOF_DYN(DRVDISKSEGMENT, apIoLog[cbRange / 512]));
366 if (pSeg)
367 {
368 pSeg->Core.Key = offCurr;
369 pSeg->Core.KeyLast = offCurr + (RTFOFF)cbRange - 1;
370 pSeg->cbSeg = cbRange;
371 pSeg->pbSeg = (uint8_t *)RTMemAllocZ(cbRange);
372 pSeg->cIoLogEntries = (uint32_t)cbRange / 512;
373 if (!pSeg->pbSeg)
374 RTMemFree(pSeg);
375 else
376 {
377 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
378 AssertMsg(fInserted, ("Bug!\n")); RT_NOREF(fInserted);
379 fSet = true;
380 }
381 }
382 }
383 else
384 {
385 fSet = true;
386 offSeg = offCurr - pSeg->Core.Key;
387 cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
388 }
389
390 if (fSet)
391 {
392 AssertPtr(pSeg);
393 size_t cbCopied = RTSgBufCopyToBuf(&SgBuf, pSeg->pbSeg + offSeg, cbRange);
394 Assert(cbCopied == cbRange); RT_NOREF(cbCopied);
395
396 /* Update the I/O log pointers */
397 Assert(offSeg % 512 == 0);
398 Assert(cbRange % 512 == 0);
399 while (offSeg < cbRange)
400 {
401 uint32_t uSector = offSeg / 512;
402 PIOLOGENT pIoLogOld = NULL;
403
404 AssertMsg(uSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
405
406 pIoLogOld = pSeg->apIoLog[uSector];
407 if (pIoLogOld)
408 {
409 pIoLogOld->cRefs--;
410 if (!pIoLogOld->cRefs)
411 RTMemFree(pIoLogOld);
412 }
413
414 pSeg->apIoLog[uSector] = pIoLogEnt;
415 pIoLogEnt->cRefs++;
416
417 offSeg += 512;
418 }
419 }
420 else
421 RTSgBufAdvance(&SgBuf, cbRange);
422
423 offCurr += cbRange;
424 cbLeft -= cbRange;
425 }
426
427 return rc;
428}
429
430/**
431 * Verifies a read request.
432 *
433 * @returns VBox status code.
434 * @param pThis Disk integrity driver instance data.
435 * @param paSeg Segment array of the containing the data buffers to verify.
436 * @param cSeg Number of segments.
437 * @param off Start offset.
438 * @param cbRead Number of bytes to verify.
439 */
440static int drvdiskintReadVerify(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
441 uint64_t off, size_t cbRead)
442{
443 int rc = VINF_SUCCESS;
444
445 LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbRead=%u\n",
446 pThis, paSeg, cSeg, off, cbRead));
447
448 Assert(off % 512 == 0);
449 Assert(cbRead % 512 == 0);
450
451 /* Compare read data */
452 size_t cbLeft = cbRead;
453 RTFOFF offCurr = (RTFOFF)off;
454 RTSGBUF SgBuf;
455
456 RTSgBufInit(&SgBuf, paSeg, cSeg);
457
458 while (cbLeft)
459 {
460 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
461 size_t cbRange = 0;
462 bool fCmp = false;
463 unsigned offSeg = 0;
464
465 if (!pSeg)
466 {
467 /* Get next segment */
468 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
469 if (!pSeg)
470 {
471 /* No data in the tree for this read. Assume everything is ok. */
472 cbRange = cbLeft;
473 }
474 else if (offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
475 cbRange = cbLeft;
476 else
477 cbRange = pSeg->Core.Key - offCurr;
478
479 if (pThis->fPrepopulateRamDisk)
480 {
481 /* No segment means everything should be 0 for this part. */
482 if (!RTSgBufIsZero(&SgBuf, cbRange))
483 {
484 RTMsgError("Corrupted disk at offset %llu (expected everything to be 0)!\n",
485 offCurr);
486 RTAssertDebugBreak();
487 }
488 }
489 }
490 else
491 {
492 fCmp = true;
493 offSeg = offCurr - pSeg->Core.Key;
494 cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
495 }
496
497 if (fCmp)
498 {
499 RTSGSEG Seg;
500 RTSGBUF SgBufCmp;
501 size_t cbOff = 0;
502
503 Seg.cbSeg = cbRange;
504 Seg.pvSeg = pSeg->pbSeg + offSeg;
505
506 RTSgBufInit(&SgBufCmp, &Seg, 1);
507 if (RTSgBufCmpEx(&SgBuf, &SgBufCmp, cbRange, &cbOff, true))
508 {
509 /* Corrupted disk, print I/O log entry of the last write which accessed this range. */
510 uint32_t cSector = (offSeg + (uint32_t)cbOff) / 512;
511 AssertMsg(cSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
512
513 RTMsgError("Corrupted disk at offset %llu (%u bytes in the current read buffer)!\n",
514 offCurr + cbOff, cbOff);
515 RTMsgError("Last write to this sector started at offset %llu with %u bytes (%u references to this log entry)\n",
516 pSeg->apIoLog[cSector]->off,
517 pSeg->apIoLog[cSector]->cbWrite,
518 pSeg->apIoLog[cSector]->cRefs);
519 RTAssertDebugBreak();
520 }
521 }
522 else
523 RTSgBufAdvance(&SgBuf, cbRange);
524
525 offCurr += cbRange;
526 cbLeft -= cbRange;
527 }
528
529 return rc;
530}
531
532/**
533 * Discards the given ranges from the disk.
534 *
535 * @returns VBox status code.
536 * @param pThis Disk integrity driver instance data.
537 * @param paRanges Array of ranges to discard.
538 * @param cRanges Number of ranges in the array.
539 */
540static int drvdiskintDiscardRecords(PDRVDISKINTEGRITY pThis, PCRTRANGE paRanges, unsigned cRanges)
541{
542 int rc = VINF_SUCCESS;
543
544 LogFlowFunc(("pThis=%#p paRanges=%#p cRanges=%u\n", pThis, paRanges, cRanges));
545
546 for (unsigned i = 0; i < cRanges; i++)
547 {
548 uint64_t offStart = paRanges[i].offStart;
549 size_t cbLeft = paRanges[i].cbRange;
550
551 LogFlowFunc(("Discarding off=%llu cbRange=%zu\n", offStart, cbLeft));
552
553 while (cbLeft)
554 {
555 size_t cbRange;
556 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offStart);
557
558 if (!pSeg)
559 {
560 /* Get next segment */
561 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offStart, true);
562 if ( !pSeg
563 || (RTFOFF)offStart + (RTFOFF)cbLeft <= pSeg->Core.Key)
564 cbRange = cbLeft;
565 else
566 cbRange = pSeg->Core.Key - offStart;
567
568 Assert(!(cbRange % 512));
569 }
570 else
571 {
572 size_t cbPreLeft, cbPostLeft;
573
574 cbRange = RT_MIN(cbLeft, pSeg->Core.KeyLast - offStart + 1);
575 cbPreLeft = offStart - pSeg->Core.Key;
576 cbPostLeft = pSeg->cbSeg - cbRange - cbPreLeft;
577
578 Assert(!(cbRange % 512));
579 Assert(!(cbPreLeft % 512));
580 Assert(!(cbPostLeft % 512));
581
582 LogFlowFunc(("cbRange=%zu cbPreLeft=%zu cbPostLeft=%zu\n",
583 cbRange, cbPreLeft, cbPostLeft));
584
585 RTAvlrFileOffsetRemove(pThis->pTreeSegments, pSeg->Core.Key);
586
587 if (!cbPreLeft && !cbPostLeft)
588 {
589 /* Just free the whole segment. */
590 LogFlowFunc(("Freeing whole segment pSeg=%#p\n", pSeg));
591 RTMemFree(pSeg->pbSeg);
592 for (unsigned idx = 0; idx < pSeg->cIoLogEntries; idx++)
593 drvdiskintIoLogEntryRelease(pSeg->apIoLog[idx]);
594 RTMemFree(pSeg);
595 }
596 else if (cbPreLeft && !cbPostLeft)
597 {
598 /* Realloc to new size and insert. */
599 LogFlowFunc(("Realloc segment pSeg=%#p\n", pSeg));
600 pSeg->pbSeg = (uint8_t *)RTMemRealloc(pSeg->pbSeg, cbPreLeft);
601 for (unsigned idx = (uint32_t)(cbPreLeft / 512); idx < pSeg->cIoLogEntries; idx++)
602 drvdiskintIoLogEntryRelease(pSeg->apIoLog[idx]);
603 pSeg = (PDRVDISKSEGMENT)RTMemRealloc(pSeg, RT_UOFFSETOF_DYN(DRVDISKSEGMENT, apIoLog[cbPreLeft / 512]));
604 pSeg->Core.KeyLast = pSeg->Core.Key + cbPreLeft - 1;
605 pSeg->cbSeg = cbPreLeft;
606 pSeg->cIoLogEntries = (uint32_t)(cbPreLeft / 512);
607 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
608 Assert(fInserted); RT_NOREF(fInserted);
609 }
610 else if (!cbPreLeft && cbPostLeft)
611 {
612 /* Move data to the front and realloc. */
613 LogFlowFunc(("Move data and realloc segment pSeg=%#p\n", pSeg));
614 memmove(pSeg->pbSeg, pSeg->pbSeg + cbRange, cbPostLeft);
615 for (unsigned idx = 0; idx < cbRange / 512; idx++)
616 drvdiskintIoLogEntryRelease(pSeg->apIoLog[idx]);
617 for (unsigned idx = 0; idx < cbPostLeft /512; idx++)
618 pSeg->apIoLog[idx] = pSeg->apIoLog[(cbRange / 512) + idx];
619 pSeg = (PDRVDISKSEGMENT)RTMemRealloc(pSeg, RT_UOFFSETOF_DYN(DRVDISKSEGMENT, apIoLog[cbPostLeft / 512]));
620 pSeg->pbSeg = (uint8_t *)RTMemRealloc(pSeg->pbSeg, cbPostLeft);
621 pSeg->Core.Key += cbRange;
622 pSeg->cbSeg = cbPostLeft;
623 pSeg->cIoLogEntries = (uint32_t)(cbPostLeft / 512);
624 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
625 Assert(fInserted); RT_NOREF(fInserted);
626 }
627 else
628 {
629 /* Split the segment into 2 new segments. */
630 LogFlowFunc(("Split segment pSeg=%#p\n", pSeg));
631 PDRVDISKSEGMENT pSegPost = (PDRVDISKSEGMENT)RTMemAllocZ(RT_UOFFSETOF_DYN(DRVDISKSEGMENT, apIoLog[cbPostLeft / 512]));
632 if (pSegPost)
633 {
634 pSegPost->Core.Key = pSeg->Core.Key + cbPreLeft + cbRange;
635 pSegPost->Core.KeyLast = pSeg->Core.KeyLast;
636 pSegPost->cbSeg = cbPostLeft;
637 pSegPost->pbSeg = (uint8_t *)RTMemAllocZ(cbPostLeft);
638 pSegPost->cIoLogEntries = (uint32_t)(cbPostLeft / 512);
639 if (!pSegPost->pbSeg)
640 RTMemFree(pSegPost);
641 else
642 {
643 memcpy(pSegPost->pbSeg, pSeg->pbSeg + cbPreLeft + cbRange, cbPostLeft);
644 for (unsigned idx = 0; idx < (uint32_t)(cbPostLeft / 512); idx++)
645 pSegPost->apIoLog[idx] = pSeg->apIoLog[((cbPreLeft + cbRange) / 512) + idx];
646
647 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSegPost->Core);
648 Assert(fInserted); RT_NOREF(fInserted);
649 }
650 }
651
652 /* Shrink the current segment. */
653 pSeg->pbSeg = (uint8_t *)RTMemRealloc(pSeg->pbSeg, cbPreLeft);
654 for (unsigned idx = (uint32_t)(cbPreLeft / 512); idx < (uint32_t)((cbPreLeft + cbRange) / 512); idx++)
655 drvdiskintIoLogEntryRelease(pSeg->apIoLog[idx]);
656 pSeg = (PDRVDISKSEGMENT)RTMemRealloc(pSeg, RT_UOFFSETOF_DYN(DRVDISKSEGMENT, apIoLog[cbPreLeft / 512]));
657 pSeg->Core.KeyLast = pSeg->Core.Key + cbPreLeft - 1;
658 pSeg->cbSeg = cbPreLeft;
659 pSeg->cIoLogEntries = (uint32_t)(cbPreLeft / 512);
660 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
661 Assert(fInserted); RT_NOREF(fInserted);
662 } /* if (cbPreLeft && cbPostLeft) */
663 }
664
665 offStart += cbRange;
666 cbLeft -= cbRange;
667 }
668 }
669
670 LogFlowFunc(("returns rc=%Rrc\n", rc));
671 return rc;
672}
673
674/**
675 * Adds a request to the active list.
676 *
677 * @returns nothing.
678 * @param pThis The driver instance data.
679 * @param pIoReq The request to add.
680 */
681static void drvdiskintIoReqAdd(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
682{
683 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pThis->iNextFreeSlot];
684
685 Assert(!pReqActive->pIoReq);
686 pReqActive->tsStart = pIoReq->tsStart;
687 pReqActive->pIoReq = pIoReq;
688 pIoReq->iSlot = pThis->iNextFreeSlot;
689
690 /* Search for the next one. */
691 while (pThis->apReqActive[pThis->iNextFreeSlot].pIoReq)
692 pThis->iNextFreeSlot = (pThis->iNextFreeSlot+1) % RT_ELEMENTS(pThis->apReqActive);
693}
694
695/**
696 * Removes a request from the active list.
697 *
698 * @returns nothing.
699 * @param pThis The driver instance data.
700 * @param pIoReq The request to remove.
701 */
702static void drvdiskintIoReqRemove(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
703{
704 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pIoReq->iSlot];
705
706 Assert(pReqActive->pIoReq == pIoReq);
707
708 ASMAtomicWriteNullPtr(&pReqActive->pIoReq);
709}
710
711/**
712 * Thread checking for expired requests.
713 *
714 * @returns IPRT status code.
715 * @param pThread Thread handle.
716 * @param pvUser Opaque user data.
717 */
718static DECLCALLBACK(int) drvdiskIntIoReqExpiredCheck(RTTHREAD pThread, void *pvUser)
719{
720 PDRVDISKINTEGRITY pThis = (PDRVDISKINTEGRITY)pvUser;
721
722 RT_NOREF(pThread);
723
724 while (pThis->fRunning)
725 {
726 int rc = RTSemEventWait(pThis->SemEvent, pThis->uCheckIntervalMs);
727
728 if (!pThis->fRunning)
729 break;
730
731 Assert(rc == VERR_TIMEOUT); RT_NOREF(rc);
732
733 /* Get current timestamp for comparison. */
734 uint64_t tsCurr = RTTimeSystemMilliTS();
735
736 /* Go through the array and check for expired requests. */
737 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
738 {
739 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[i];
740 PDRVDISKAIOREQ pIoReq = ASMAtomicReadPtrT(&pReqActive->pIoReq, PDRVDISKAIOREQ);
741
742 if ( pIoReq
743 && (tsCurr > pReqActive->tsStart)
744 && (tsCurr - pReqActive->tsStart) >= pThis->uExpireIntervalMs)
745 {
746 RTMsgError("Request %#p expired (active for %llu ms already)\n",
747 pIoReq, tsCurr - pReqActive->tsStart);
748 RTAssertDebugBreak();
749 }
750 }
751 }
752
753 return VINF_SUCCESS;
754}
755
756/**
757 * Verify a completed read after write request.
758 *
759 * @returns VBox status code.
760 * @param pThis The driver instance data.
761 * @param pIoReq The request to be verified.
762 */
763static int drvdiskintReadAfterWriteVerify(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
764{
765 int rc = VINF_SUCCESS;
766
767 if (pThis->fCheckConsistency)
768 rc = drvdiskintReadVerify(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
769 else /** @todo Implement read after write verification without a memory based image of the disk. */
770 AssertMsgFailed(("TODO\n"));
771
772 return rc;
773}
774
775
776/**
777 * Fires a read event if enabled.
778 *
779 * @returns nothing.
780 * @param pThis The driver instance data.
781 * @param uGrp The group ID.
782 * @param fAsync Flag whether this is an async request.
783 * @param off The offset to put into the event log.
784 * @param cbRead Amount of bytes to read.
785 */
786DECLINLINE(void) drvdiskintTraceLogFireEvtRead(PDRVDISKINTEGRITY pThis, uintptr_t uGrp, bool fAsync, uint64_t off, size_t cbRead)
787{
788 if (pThis->hIoLogger)
789 {
790 int rc = RTTraceLogWrEvtAddL(pThis->hIoLogger, &g_EvtRead, RTTRACELOG_WR_ADD_EVT_F_GRP_START,
791 (RTTRACELOGEVTGRPID)uGrp, 0, fAsync, off, cbRead);
792 AssertRC(rc);
793 }
794}
795
796
797/**
798 * Fires a write event if enabled.
799 *
800 * @returns nothing.
801 * @param pThis The driver instance data.
802 * @param uGrp The group ID.
803 * @param fAsync Flag whether this is an async request.
804 * @param off The offset to put into the event log.
805 * @param cbWrite Amount of bytes to write.
806 */
807DECLINLINE(void) drvdiskintTraceLogFireEvtWrite(PDRVDISKINTEGRITY pThis, uintptr_t uGrp, bool fAsync, uint64_t off, size_t cbWrite)
808{
809 if (pThis->hIoLogger)
810 {
811 int rc = RTTraceLogWrEvtAddL(pThis->hIoLogger, &g_EvtWrite, RTTRACELOG_WR_ADD_EVT_F_GRP_START,
812 (RTTRACELOGEVTGRPID)uGrp, 0, fAsync, off, cbWrite);
813 AssertRC(rc);
814 }
815}
816
817
818/**
819 * Fires a flush event if enabled.
820 *
821 * @returns nothing.
822 * @param pThis The driver instance data.
823 * @param uGrp The group ID.
824 * @param fAsync Flag whether this is an async request.
825 */
826DECLINLINE(void) drvdiskintTraceLogFireEvtFlush(PDRVDISKINTEGRITY pThis, uintptr_t uGrp, bool fAsync)
827{
828 if (pThis->hIoLogger)
829 {
830 int rc = RTTraceLogWrEvtAddL(pThis->hIoLogger, &g_EvtFlush, RTTRACELOG_WR_ADD_EVT_F_GRP_START,
831 (RTTRACELOGEVTGRPID)uGrp, 0, fAsync);
832 AssertRC(rc);
833 }
834}
835
836
837/**
838 * Fires a request complete event if enabled.
839 *
840 * @returns nothing.
841 * @param pThis The driver instance data.
842 * @param uGrp The group ID.
843 * @param rcReq Status code the request completed with.
844 * @param pSgBuf The S/G buffer holding the data.
845 */
846DECLINLINE(void) drvdiskintTraceLogFireEvtComplete(PDRVDISKINTEGRITY pThis, uintptr_t uGrp, int rcReq, PRTSGBUF pSgBuf)
847{
848 RT_NOREF(pSgBuf);
849
850 if (pThis->hIoLogger)
851 {
852 int rc = RTTraceLogWrEvtAddL(pThis->hIoLogger, &g_EvtComplete, RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH,
853 (RTTRACELOGEVTGRPID)uGrp, 0, rcReq);
854 AssertRC(rc);
855 }
856}
857
858
859/* -=-=-=-=- IMedia -=-=-=-=- */
860
861/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIA. */
862#define PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_UOFFSETOF(DRVDISKINTEGRITY, IMedia)) )
863
864
865/*********************************************************************************************************************************
866* Media interface methods *
867*********************************************************************************************************************************/
868
869
870/** @interface_method_impl{PDMIMEDIA,pfnRead} */
871static DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
872 uint64_t off, void *pvBuf, size_t cbRead)
873{
874 int rc = VINF_SUCCESS;
875 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
876
877 drvdiskintTraceLogFireEvtRead(pThis, (uintptr_t)pvBuf, false /* fAsync */, off, cbRead);
878 rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
879
880 if (pThis->hIoLogger)
881 {
882 RTSGSEG Seg;
883 RTSGBUF SgBuf;
884
885 Seg.pvSeg = pvBuf;
886 Seg.cbSeg = cbRead;
887 RTSgBufInit(&SgBuf, &Seg, 1);
888 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)pvBuf, rc, &SgBuf);
889 }
890
891 if (RT_FAILURE(rc))
892 return rc;
893
894 if (pThis->fCheckConsistency)
895 {
896 /* Verify the read. */
897 RTSGSEG Seg;
898 Seg.cbSeg = cbRead;
899 Seg.pvSeg = pvBuf;
900 rc = drvdiskintReadVerify(pThis, &Seg, 1, off, cbRead);
901 }
902
903 return rc;
904}
905
906/** @interface_method_impl{PDMIMEDIA,pfnWrite} */
907static DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
908 uint64_t off, const void *pvBuf,
909 size_t cbWrite)
910{
911 int rc = VINF_SUCCESS;
912 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
913
914 drvdiskintTraceLogFireEvtWrite(pThis, (uintptr_t)pvBuf, false /* fAsync */, off, cbWrite);
915
916 if (pThis->fRecordWriteBeforeCompletion)
917 {
918 RTSGSEG Seg;
919 Seg.cbSeg = cbWrite;
920 Seg.pvSeg = (void *)pvBuf;
921
922 rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
923 if (RT_FAILURE(rc))
924 return rc;
925 }
926
927 rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
928
929 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)pvBuf, rc, NULL);
930 if (RT_FAILURE(rc))
931 return rc;
932
933 if ( pThis->fCheckConsistency
934 && !pThis->fRecordWriteBeforeCompletion)
935 {
936 /* Record the write. */
937 RTSGSEG Seg;
938 Seg.cbSeg = cbWrite;
939 Seg.pvSeg = (void *)pvBuf;
940 rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
941 }
942
943 return rc;
944}
945
946/** @interface_method_impl{PDMIMEDIA,pfnFlush} */
947static DECLCALLBACK(int) drvdiskintFlush(PPDMIMEDIA pInterface)
948{
949 int rc = VINF_SUCCESS;
950 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
951
952 drvdiskintTraceLogFireEvtFlush(pThis, 1, false /* fAsync */);
953 rc = pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
954 drvdiskintTraceLogFireEvtComplete(pThis, 1, rc, NULL);
955
956 return rc;
957}
958
959/** @interface_method_impl{PDMIMEDIA,pfnGetSize} */
960static DECLCALLBACK(uint64_t) drvdiskintGetSize(PPDMIMEDIA pInterface)
961{
962 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
963 return pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
964}
965
966/** @interface_method_impl{PDMIMEDIA,pfnIsReadOnly} */
967static DECLCALLBACK(bool) drvdiskintIsReadOnly(PPDMIMEDIA pInterface)
968{
969 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
970 return pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
971}
972
973/** @interface_method_impl{PDMIMEDIA,pfnBiosIsVisible} */
974static DECLCALLBACK(bool) drvdiskintBiosIsVisible(PPDMIMEDIA pInterface)
975{
976 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
977 return pThis->pDrvMedia->pfnBiosIsVisible(pThis->pDrvMedia);
978}
979
980/** @interface_method_impl{PDMIMEDIA,pfnGetType} */
981static DECLCALLBACK(PDMMEDIATYPE) drvdiskintGetType(PPDMIMEDIA pInterface)
982{
983 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
984 return pThis->pDrvMedia->pfnGetType(pThis->pDrvMedia);
985}
986
987/** @interface_method_impl{PDMIMEDIA,pfnBiosGetPCHSGeometry} */
988static DECLCALLBACK(int) drvdiskintBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
989 PPDMMEDIAGEOMETRY pPCHSGeometry)
990{
991 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
992 return pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
993}
994
995/** @interface_method_impl{PDMIMEDIA,pfnBiosSetPCHSGeometry} */
996static DECLCALLBACK(int) drvdiskintBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
997 PCPDMMEDIAGEOMETRY pPCHSGeometry)
998{
999 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1000 return pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
1001}
1002
1003/** @interface_method_impl{PDMIMEDIA,pfnBiosGetLCHSGeometry} */
1004static DECLCALLBACK(int) drvdiskintBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
1005 PPDMMEDIAGEOMETRY pLCHSGeometry)
1006{
1007 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1008 return pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
1009}
1010
1011/** @interface_method_impl{PDMIMEDIA,pfnBiosSetLCHSGeometry} */
1012static DECLCALLBACK(int) drvdiskintBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
1013 PCPDMMEDIAGEOMETRY pLCHSGeometry)
1014{
1015 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1016 return pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
1017}
1018
1019/** @interface_method_impl{PDMIMEDIA,pfnGetUuid} */
1020static DECLCALLBACK(int) drvdiskintGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
1021{
1022 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1023 return pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, pUuid);
1024}
1025
1026/** @interface_method_impl{PDMIMEDIA,pfnGetSectorSize} */
1027static DECLCALLBACK(uint32_t) drvdiskintGetSectorSize(PPDMIMEDIA pInterface)
1028{
1029 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1030 return pThis->pDrvMedia->pfnGetSectorSize(pThis->pDrvMedia);
1031}
1032
1033/** @interface_method_impl{PDMIMEDIA,pfnDiscard} */
1034static DECLCALLBACK(int) drvdiskintDiscard(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges)
1035{
1036 int rc = VINF_SUCCESS;
1037 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1038
1039 rc = pThis->pDrvMedia->pfnDiscard(pThis->pDrvMedia, paRanges, cRanges);
1040 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)paRanges, rc, NULL);
1041
1042 if (pThis->fCheckConsistency)
1043 rc = drvdiskintDiscardRecords(pThis, paRanges, cRanges);
1044
1045 return rc;
1046}
1047
1048/** @interface_method_impl{PDMIMEDIA,pfnReadPcBios} */
1049static DECLCALLBACK(int) drvdiskintReadPcBios(PPDMIMEDIA pInterface,
1050 uint64_t off, void *pvBuf, size_t cbRead)
1051{
1052 LogFlowFunc(("\n"));
1053 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1054
1055 return pThis->pDrvMedia->pfnReadPcBios(pThis->pDrvMedia, off, pvBuf, cbRead);
1056}
1057
1058/** @interface_method_impl{PDMIMEDIA,pfnIsNonRotational} */
1059static DECLCALLBACK(bool) drvdiskintIsNonRotational(PPDMIMEDIA pInterface)
1060{
1061 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1062 return pThis->pDrvMedia->pfnIsNonRotational(pThis->pDrvMedia);
1063}
1064
1065/* -=-=-=-=- IMediaPort -=-=-=-=- */
1066
1067/** Makes a PDRVBLOCK out of a PPDMIMEDIAPORT. */
1068#define PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_UOFFSETOF(DRVDISKINTEGRITY, IMediaPort))) )
1069
1070/**
1071 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
1072 */
1073static DECLCALLBACK(int) drvdiskintQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
1074 uint32_t *piInstance, uint32_t *piLUN)
1075{
1076 PDRVDISKINTEGRITY pThis = PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface);
1077
1078 return pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, ppcszController,
1079 piInstance, piLUN);
1080}
1081
1082/* -=-=-=-=- IMediaExPort -=-=-=-=- */
1083
1084/**
1085 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
1086 */
1087static DECLCALLBACK(int) drvdiskintIoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1088 void *pvIoReqAlloc, int rcReq)
1089{
1090 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1091 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_ALLOC_2_DRVDISKAIOREQ(pvIoReqAlloc);
1092 int rc = VINF_SUCCESS;
1093
1094 LogFlowFunc(("pIoReq=%#p\n", pIoReq));
1095
1096 /* Remove from the active list. */
1097 if (pThis->fTraceRequests)
1098 drvdiskintIoReqRemove(pThis, pIoReq);
1099
1100 if (RT_SUCCESS(rcReq) && pThis->fCheckConsistency)
1101 {
1102 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1103 rc = drvdiskintReadVerify(pThis, &pIoReq->IoSeg, 1, pIoReq->off, pIoReq->cbTransfer);
1104 else if ( pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE
1105 && !pThis->fRecordWriteBeforeCompletion)
1106 rc = drvdiskintWriteRecord(pThis, &pIoReq->IoSeg, 1, pIoReq->off, pIoReq->cbTransfer);
1107 else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_DISCARD)
1108 rc = drvdiskintDiscardRecords(pThis, pIoReq->paRanges, pIoReq->cRanges);
1109 else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ_AFTER_WRITE)
1110 rc = drvdiskintReadAfterWriteVerify(pThis, pIoReq);
1111 else
1112 AssertMsg( pIoReq->enmTxDir == DRVDISKAIOTXDIR_FLUSH
1113 || ( pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE
1114 && pThis->fRecordWriteBeforeCompletion), ("Huh?\n"));
1115
1116 AssertRC(rc);
1117 }
1118
1119 if ( RT_SUCCESS(rcReq)
1120 && pThis->fValidateMemBufs
1121 && pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1122 {
1123 /* Check that the guest memory buffer matches what was written. */
1124 RTSGSEG SegCmp;
1125 SegCmp.pvSeg = RTMemAlloc(pIoReq->cbTransfer);
1126 SegCmp.cbSeg = pIoReq->cbTransfer;
1127
1128 RTSGBUF SgBufCmp;
1129 RTSgBufInit(&SgBufCmp, &SegCmp, 1);
1130 rc = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, hIoReq,
1131 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1132 0, &SgBufCmp, pIoReq->cbTransfer);
1133 AssertRC(rc);
1134
1135 RTSGBUF SgBuf;
1136 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1137 if (RTSgBufCmp(&SgBuf, &SgBufCmp, pIoReq->cbTransfer))
1138 {
1139 RTMsgError("Corrupted memory buffer at offset %llu!\n", 0);
1140 RTAssertDebugBreak();
1141 }
1142
1143 RTMemFree(SegCmp.pvSeg);
1144 }
1145
1146 if (pThis->hIoLogger)
1147 {
1148 RTSGBUF SgBuf;
1149
1150 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1151 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1152 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rcReq, &SgBuf);
1153 }
1154
1155 if ( pThis->fReadAfterWrite
1156 && pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE)
1157 {
1158#if 0 /** @todo */
1159 pIoReq->enmTxDir = DRVDISKAIOTXDIR_READ_AFTER_WRITE;
1160
1161 /* Add again because it was removed above. */
1162 if (pThis->fTraceRequests)
1163 drvdiskintIoReqAdd(pThis, pIoReq);
1164
1165 rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, pIoReq->off, pIoReq->paSeg, pIoReq->cSeg,
1166 pIoReq->cbTransfer, pIoReq);
1167 if (rc == VINF_VD_ASYNC_IO_FINISHED)
1168 {
1169 rc = drvdiskintReadAfterWriteVerify(pThis, pIoReq);
1170
1171 if (pThis->fTraceRequests)
1172 drvdiskintIoReqRemove(pThis, pIoReq);
1173 RTMemFree(pIoReq);
1174 }
1175 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
1176 rc = VINF_SUCCESS;
1177 else if (RT_FAILURE(rc))
1178 RTMemFree(pIoReq);
1179#endif
1180 }
1181 else
1182 {
1183 rc = pThis->pDrvMediaExPort->pfnIoReqCompleteNotify(pThis->pDrvMediaExPort, hIoReq,
1184 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1185 rcReq);
1186 /* Put on the watch list. */
1187 if (pThis->fCheckDoubleCompletion)
1188 drvdiskintIoReqCheckForDoubleCompletion(pThis, pIoReq, true /* fMediaEx */);
1189 }
1190
1191 return rc;
1192}
1193
1194/**
1195 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
1196 */
1197static DECLCALLBACK(int) drvdiskintIoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1198 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
1199 size_t cbCopy)
1200{
1201 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1202 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_ALLOC_2_DRVDISKAIOREQ(pvIoReqAlloc);
1203 RTSGBUF SgBuf;
1204
1205 RTSgBufClone(&SgBuf, pSgBuf);
1206
1207 int rc = pThis->pDrvMediaExPort->pfnIoReqCopyFromBuf(pThis->pDrvMediaExPort, hIoReq,
1208 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1209 offDst, pSgBuf, cbCopy);
1210 if ( RT_SUCCESS(rc)
1211 && pIoReq->IoSeg.pvSeg)
1212 {
1213 /* Update our copy. */
1214 RTSgBufCopyToBuf(&SgBuf, (uint8_t *)pIoReq->IoSeg.pvSeg + offDst, cbCopy);
1215
1216 /* Validate the just read data against our copy if possible. */
1217 if ( pThis->fValidateMemBufs
1218 && pThis->fCheckConsistency
1219 && pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1220 {
1221 RTSGSEG Seg;
1222
1223 Seg.pvSeg = (uint8_t *)pIoReq->IoSeg.pvSeg + offDst;
1224 Seg.cbSeg = cbCopy;
1225
1226 rc = drvdiskintReadVerify(pThis, &Seg, 1, pIoReq->off + offDst,
1227 cbCopy);
1228 }
1229 }
1230
1231 return rc;
1232}
1233
1234/**
1235 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
1236 */
1237static DECLCALLBACK(int) drvdiskintIoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1238 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
1239 size_t cbCopy)
1240{
1241 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1242 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_ALLOC_2_DRVDISKAIOREQ(pvIoReqAlloc);
1243 RTSGBUF SgBuf;
1244
1245 RTSgBufClone(&SgBuf, pSgBuf);
1246
1247 int rc = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, hIoReq,
1248 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1249 offSrc, pSgBuf, cbCopy);
1250 if ( RT_SUCCESS(rc)
1251 && pIoReq->IoSeg.pvSeg)
1252 {
1253 if (pThis->fValidateMemBufs)
1254 {
1255 /* Make sure what the caller requested matches what we got earlier. */
1256 RTSGBUF SgBufCmp;
1257 RTSgBufInit(&SgBufCmp, &pIoReq->IoSeg, 1);
1258 RTSgBufAdvance(&SgBufCmp, offSrc);
1259
1260 if (RTSgBufCmp(&SgBuf, &SgBufCmp, cbCopy))
1261 {
1262 RTMsgError("Corrupted memory buffer at offset %llu!\n", offSrc);
1263 RTAssertDebugBreak();
1264 }
1265 }
1266 else
1267 {
1268 /* Update our copy. */
1269 RTSgBufCopyToBuf(&SgBuf, (uint8_t *)pIoReq->IoSeg.pvSeg + offSrc, cbCopy);
1270 }
1271 }
1272
1273 return rc;
1274}
1275
1276/**
1277 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqQueryDiscardRanges}
1278 */
1279static DECLCALLBACK(int) drvdiskintIoReqQueryDiscardRanges(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1280 void *pvIoReqAlloc, uint32_t idxRangeStart,
1281 uint32_t cRanges, PRTRANGE paRanges,
1282 uint32_t *pcRanges)
1283{
1284 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1285 return pThis->pDrvMediaExPort->pfnIoReqQueryDiscardRanges(pThis->pDrvMediaExPort, hIoReq,
1286 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1287 idxRangeStart, cRanges, paRanges, pcRanges);
1288}
1289
1290/**
1291 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
1292 */
1293static DECLCALLBACK(void) drvdiskintIoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1294 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
1295{
1296 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1297 pThis->pDrvMediaExPort->pfnIoReqStateChanged(pThis->pDrvMediaExPort, hIoReq,
1298 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1299 enmState);
1300}
1301
1302/* -=-=-=-=- IMediaEx -=-=-=-=- */
1303
1304/**
1305 * @interface_method_impl{PDMIMEDIAEX,pfnQueryFeatures}
1306 */
1307static DECLCALLBACK(int) drvdiskintQueryFeatures(PPDMIMEDIAEX pInterface, uint32_t *pfFeatures)
1308{
1309 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1310 return pThis->pDrvMediaEx->pfnQueryFeatures(pThis->pDrvMediaEx, pfFeatures);
1311}
1312
1313/**
1314 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqAllocSizeSet}
1315 */
1316static DECLCALLBACK(int) drvdiskintIoReqAllocSizeSet(PPDMIMEDIAEX pInterface, size_t cbIoReqAlloc)
1317{
1318 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1319
1320 /* Increase the amount by the size of a pointer to our private tracking structure. */
1321 cbIoReqAlloc += sizeof(PDRVDISKAIOREQ);
1322
1323 pThis->fCheckDoubleCompletion = false;
1324
1325 return pThis->pDrvMediaEx->pfnIoReqAllocSizeSet(pThis->pDrvMediaEx, cbIoReqAlloc);
1326}
1327
1328/**
1329 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqAlloc}
1330 */
1331static DECLCALLBACK(int) drvdiskintIoReqAlloc(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc,
1332 PDMMEDIAEXIOREQID uIoReqId, uint32_t fFlags)
1333{
1334 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1335 int rc = VINF_SUCCESS;
1336 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)RTMemCacheAlloc(pThis->hReqCache);
1337 if (RT_LIKELY(pIoReq))
1338 {
1339 pIoReq->enmTxDir = DRVDISKAIOTXDIR_INVALID;
1340 pIoReq->off = 0;
1341 pIoReq->cbTransfer = 0;
1342 pIoReq->paSeg = NULL;
1343 pIoReq->cSeg = 0;
1344 pIoReq->pvUser = NULL;
1345 pIoReq->iSlot = 0;
1346 pIoReq->tsStart = 0;
1347 pIoReq->tsComplete = 0;
1348 pIoReq->IoSeg.pvSeg = NULL;
1349 pIoReq->IoSeg.cbSeg = 0;
1350
1351 PDRVDISKAIOREQ *ppIoReq = NULL;
1352 rc = pThis->pDrvMediaEx->pfnIoReqAlloc(pThis->pDrvMediaEx, phIoReq, (void **)&ppIoReq, uIoReqId, fFlags);
1353 if RT_SUCCESS(rc)
1354 {
1355 /*
1356 * Store the size off the start of our tracking structure because it is
1357 * required to access it for the read/write callbacks.
1358 *
1359 * ASSUMPTION that the offset is constant.
1360 */
1361 if (!pThis->cbIoReqOpaque)
1362 pThis->cbIoReqOpaque = (uintptr_t)ppIoReq - (uintptr_t)*phIoReq;
1363 else
1364 Assert(pThis->cbIoReqOpaque == (uintptr_t)ppIoReq - (uintptr_t)*phIoReq);
1365
1366 *ppIoReq = pIoReq;
1367 *ppvIoReqAlloc = ((uint8_t *)ppIoReq) + sizeof(PDRVDISKAIOREQ);
1368 }
1369 else
1370 RTMemCacheFree(pThis->hReqCache, pIoReq);
1371 }
1372 else
1373 rc = VERR_NO_MEMORY;
1374
1375 return rc;
1376}
1377
1378/**
1379 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqFree}
1380 */
1381static DECLCALLBACK(int) drvdiskintIoReqFree(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
1382{
1383 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1384 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1385
1386 if (pIoReq->IoSeg.pvSeg)
1387 RTMemFree(pIoReq->IoSeg.pvSeg);
1388
1389 return pThis->pDrvMediaEx->pfnIoReqFree(pThis->pDrvMediaEx, hIoReq);
1390}
1391
1392/**
1393 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryResidual}
1394 */
1395static DECLCALLBACK(int) drvdiskintIoReqQueryResidual(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbResidual)
1396{
1397 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1398 return pThis->pDrvMediaEx->pfnIoReqQueryResidual(pThis->pDrvMediaEx, hIoReq, pcbResidual);
1399}
1400
1401/**
1402 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryXferSize}
1403 */
1404static DECLCALLBACK(int) drvdiskintIoReqQueryXferSize(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbXfer)
1405{
1406 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1407 return pThis->pDrvMediaEx->pfnIoReqQueryXferSize(pThis->pDrvMediaEx, hIoReq, pcbXfer);
1408}
1409
1410/**
1411 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancelAll}
1412 */
1413static DECLCALLBACK(int) drvdiskintIoReqCancelAll(PPDMIMEDIAEX pInterface)
1414{
1415 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1416 return pThis->pDrvMediaEx->pfnIoReqCancelAll(pThis->pDrvMediaEx);
1417}
1418
1419/**
1420 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancel}
1421 */
1422static DECLCALLBACK(int) drvdiskintIoReqCancel(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQID uIoReqId)
1423{
1424 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1425 return pThis->pDrvMediaEx->pfnIoReqCancel(pThis->pDrvMediaEx, uIoReqId);
1426}
1427
1428/**
1429 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqRead}
1430 */
1431static DECLCALLBACK(int) drvdiskintIoReqRead(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbRead)
1432{
1433 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1434 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1435
1436 pIoReq->enmTxDir = DRVDISKAIOTXDIR_READ;
1437 pIoReq->off = off;
1438 pIoReq->cbTransfer = cbRead;
1439
1440 /* Allocate a I/O buffer if the I/O is verified.*/
1441 if (pThis->fCheckConsistency)
1442 {
1443 pIoReq->IoSeg.pvSeg = RTMemAlloc(cbRead);
1444 pIoReq->IoSeg.cbSeg = cbRead;
1445 }
1446
1447 if (pThis->fTraceRequests)
1448 drvdiskintIoReqAdd(pThis, pIoReq);
1449
1450 drvdiskintTraceLogFireEvtRead(pThis, (uintptr_t)hIoReq, true /* fAsync */, off, cbRead);
1451 int rc = pThis->pDrvMediaEx->pfnIoReqRead(pThis->pDrvMediaEx, hIoReq, off, cbRead);
1452 if (rc == VINF_SUCCESS)
1453 {
1454 /* Verify the read now. */
1455 if (pThis->fCheckConsistency)
1456 {
1457 int rc2 = drvdiskintReadVerify(pThis, &pIoReq->IoSeg, 1, off, cbRead);
1458 AssertRC(rc2);
1459 }
1460
1461 if (pThis->hIoLogger)
1462 {
1463 RTSGBUF SgBuf;
1464
1465 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1466 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, &SgBuf);
1467 }
1468
1469 if (pThis->fTraceRequests)
1470 drvdiskintIoReqRemove(pThis, pIoReq);
1471 }
1472 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1473 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, NULL);
1474
1475 LogFlowFunc(("returns %Rrc\n", rc));
1476 return rc;
1477}
1478
1479/**
1480 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqWrite}
1481 */
1482static DECLCALLBACK(int) drvdiskintIoReqWrite(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbWrite)
1483{
1484 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1485 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1486
1487 pIoReq->enmTxDir = DRVDISKAIOTXDIR_WRITE;
1488 pIoReq->off = off;
1489 pIoReq->cbTransfer = cbWrite;
1490
1491 /* Allocate a I/O buffer if the I/O is verified.*/
1492 if ( pThis->fCheckConsistency
1493 || pThis->fValidateMemBufs
1494 || pThis->hIoLogger
1495 || pThis->fRecordWriteBeforeCompletion)
1496 {
1497 pIoReq->IoSeg.pvSeg = RTMemAlloc(cbWrite);
1498 pIoReq->IoSeg.cbSeg = cbWrite;
1499
1500 /* Sync the memory buffer over if we should validate it. */
1501 if ( pThis->fValidateMemBufs
1502 || pThis->hIoLogger
1503 || pThis->fRecordWriteBeforeCompletion)
1504 {
1505 RTSGBUF SgBuf;
1506
1507 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1508 int rc2 = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, hIoReq,
1509 DISKINTEGRITY_IOREQ_HANDLE_2_UPPER_OPAQUE(pThis, hIoReq),
1510 0, &SgBuf, cbWrite);
1511 AssertRC(rc2);
1512 }
1513 }
1514
1515 if (pThis->fTraceRequests)
1516 drvdiskintIoReqAdd(pThis, pIoReq);
1517
1518 drvdiskintTraceLogFireEvtWrite(pThis, (uintptr_t)hIoReq, true /* fAsync */, off, cbWrite);
1519 if (pThis->fRecordWriteBeforeCompletion)
1520 {
1521
1522 int rc2 = drvdiskintWriteRecord(pThis, &pIoReq->IoSeg, 1, off, cbWrite);
1523 AssertRC(rc2);
1524 }
1525
1526 int rc = pThis->pDrvMediaEx->pfnIoReqWrite(pThis->pDrvMediaEx, hIoReq, off, cbWrite);
1527 if (rc == VINF_SUCCESS)
1528 {
1529 /* Record the write. */
1530 if ( pThis->fCheckConsistency
1531 && !pThis->fRecordWriteBeforeCompletion)
1532 {
1533 int rc2 = drvdiskintWriteRecord(pThis, &pIoReq->IoSeg, 1, off, cbWrite);
1534 AssertRC(rc2);
1535 }
1536
1537 RTSGBUF SgBuf;
1538 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1539 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, &SgBuf);
1540 if (pThis->fTraceRequests)
1541 drvdiskintIoReqRemove(pThis, pIoReq);
1542 }
1543 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1544 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, NULL);
1545
1546 LogFlowFunc(("returns %Rrc\n", rc));
1547 return rc;
1548}
1549
1550/**
1551 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqFlush}
1552 */
1553static DECLCALLBACK(int) drvdiskintIoReqFlush(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
1554{
1555 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1556 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1557
1558 pIoReq->enmTxDir = DRVDISKAIOTXDIR_FLUSH;
1559 pIoReq->off = 0;
1560 pIoReq->cbTransfer = 0;
1561
1562 if (pThis->fTraceRequests)
1563 drvdiskintIoReqAdd(pThis, pIoReq);
1564
1565 drvdiskintTraceLogFireEvtFlush(pThis, (uintptr_t)hIoReq, true /* fAsync */);
1566 int rc = pThis->pDrvMediaEx->pfnIoReqFlush(pThis->pDrvMediaEx, hIoReq);
1567 if (rc == VINF_SUCCESS)
1568 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, NULL);
1569 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1570 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, NULL);
1571
1572 LogFlowFunc(("returns %Rrc\n", rc));
1573 return rc;
1574}
1575
1576/**
1577 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqDiscard}
1578 */
1579static DECLCALLBACK(int) drvdiskintIoReqDiscard(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, unsigned cRangesMax)
1580{
1581 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1582 return pThis->pDrvMediaEx->pfnIoReqDiscard(pThis->pDrvMediaEx, hIoReq, cRangesMax);
1583}
1584
1585/**
1586 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetActiveCount}
1587 */
1588static DECLCALLBACK(uint32_t) drvdiskintIoReqGetActiveCount(PPDMIMEDIAEX pInterface)
1589{
1590 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1591 return pThis->pDrvMediaEx->pfnIoReqGetActiveCount(pThis->pDrvMediaEx);
1592}
1593
1594/**
1595 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetSuspendedCount}
1596 */
1597static DECLCALLBACK(uint32_t) drvdiskintIoReqGetSuspendedCount(PPDMIMEDIAEX pInterface)
1598{
1599 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1600 return pThis->pDrvMediaEx->pfnIoReqGetSuspendedCount(pThis->pDrvMediaEx);
1601}
1602
1603/**
1604 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedStart}
1605 */
1606static DECLCALLBACK(int) drvdiskintIoReqQuerySuspendedStart(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc)
1607{
1608 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1609 return pThis->pDrvMediaEx->pfnIoReqQuerySuspendedStart(pThis->pDrvMediaEx, phIoReq, ppvIoReqAlloc);
1610}
1611
1612/**
1613 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedNext}
1614 */
1615static DECLCALLBACK(int) drvdiskintIoReqQuerySuspendedNext(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq,
1616 PPDMMEDIAEXIOREQ phIoReqNext, void **ppvIoReqAllocNext)
1617{
1618 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1619 return pThis->pDrvMediaEx->pfnIoReqQuerySuspendedNext(pThis->pDrvMediaEx, hIoReq, phIoReqNext, ppvIoReqAllocNext);
1620}
1621
1622/**
1623 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedSave}
1624 */
1625static DECLCALLBACK(int) drvdiskintIoReqSuspendedSave(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
1626{
1627 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1628 return pThis->pDrvMediaEx->pfnIoReqSuspendedSave(pThis->pDrvMediaEx, pSSM, hIoReq);
1629}
1630
1631/**
1632 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedLoad}
1633 */
1634static DECLCALLBACK(int) drvdiskintIoReqSuspendedLoad(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
1635{
1636 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1637 return pThis->pDrvMediaEx->pfnIoReqSuspendedLoad(pThis->pDrvMediaEx, pSSM, hIoReq);
1638}
1639
1640/* -=-=-=-=- IMount -=-=-=-=- */
1641
1642/** @interface_method_impl{PDMIMOUNT,pfnUnmount} */
1643static DECLCALLBACK(int) drvdiskintUnmount(PPDMIMOUNT pInterface, bool fForce, bool fEject)
1644{
1645 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMount);
1646 return pThis->pDrvMount->pfnUnmount(pThis->pDrvMount, fForce, fEject);
1647}
1648
1649/** @interface_method_impl{PDMIMOUNT,pfnIsMounted} */
1650static DECLCALLBACK(bool) drvdiskintIsMounted(PPDMIMOUNT pInterface)
1651{
1652 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMount);
1653 return pThis->pDrvMount->pfnIsMounted(pThis->pDrvMount);
1654}
1655
1656/** @interface_method_impl{PDMIMOUNT,pfnLock} */
1657static DECLCALLBACK(int) drvdiskintLock(PPDMIMOUNT pInterface)
1658{
1659 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMount);
1660 return pThis->pDrvMount->pfnLock(pThis->pDrvMount);
1661}
1662
1663/** @interface_method_impl{PDMIMOUNT,pfnUnlock} */
1664static DECLCALLBACK(int) drvdiskintUnlock(PPDMIMOUNT pInterface)
1665{
1666 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMount);
1667 return pThis->pDrvMount->pfnUnlock(pThis->pDrvMount);
1668}
1669
1670/** @interface_method_impl{PDMIMOUNT,pfnIsLocked} */
1671static DECLCALLBACK(bool) drvdiskintIsLocked(PPDMIMOUNT pInterface)
1672{
1673 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMount);
1674 return pThis->pDrvMount->pfnIsLocked(pThis->pDrvMount);
1675}
1676
1677/* -=-=-=-=- IMountNotify -=-=-=-=- */
1678
1679/** @interface_method_impl{PDMIMOUNTNOTIFY,pfnMountNotify} */
1680static DECLCALLBACK(void) drvdiskintMountNotify(PPDMIMOUNTNOTIFY pInterface)
1681{
1682 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMountNotify);
1683 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
1684}
1685
1686/** @interface_method_impl{PDMIMOUNTNOTIFY,pfnUnmountNotify} */
1687static DECLCALLBACK(void) drvdiskintUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
1688{
1689 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMountNotify);
1690 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
1691}
1692
1693/* -=-=-=-=- IBase -=-=-=-=- */
1694
1695/**
1696 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1697 */
1698static DECLCALLBACK(void *) drvdiskintQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1699{
1700 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1701 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1702
1703 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1704 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
1705 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->IMediaPort);
1706 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pThis->IMediaExPort);
1707 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEX, pThis->pDrvMediaEx ? &pThis->IMediaEx : NULL);
1708 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNT, pThis->pDrvMount ? &pThis->IMount : NULL);
1709 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNTNOTIFY, &pThis->IMountNotify);
1710 return NULL;
1711}
1712
1713
1714/* -=-=-=-=- driver interface -=-=-=-=- */
1715
1716static DECLCALLBACK(int) drvdiskintTreeDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
1717{
1718 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)pNode;
1719
1720 RT_NOREF(pvUser);
1721
1722 RTMemFree(pSeg->pbSeg);
1723 RTMemFree(pSeg);
1724 return VINF_SUCCESS;
1725}
1726
1727/**
1728 * @copydoc FNPDMDRVDESTRUCT
1729 */
1730static DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
1731{
1732 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1733
1734 if (pThis->pTreeSegments)
1735 {
1736 RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
1737 RTMemFree(pThis->pTreeSegments);
1738 }
1739
1740 if (pThis->fTraceRequests)
1741 {
1742 pThis->fRunning = false;
1743 RTSemEventSignal(pThis->SemEvent);
1744 RTSemEventDestroy(pThis->SemEvent);
1745 }
1746
1747 if (pThis->fCheckDoubleCompletion)
1748 {
1749 /* Free all requests */
1750 while (pThis->papIoReq[pThis->iEntry])
1751 {
1752 RTMemFree(pThis->papIoReq[pThis->iEntry]);
1753 pThis->papIoReq[pThis->iEntry] = NULL;
1754 pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
1755 }
1756 }
1757
1758 if (pThis->hIoLogger)
1759 RTTraceLogWrDestroy(pThis->hIoLogger);
1760
1761 if (pThis->hReqCache != NIL_RTMEMCACHE)
1762 {
1763 RTMemCacheDestroy(pThis->hReqCache);
1764 pThis->hReqCache = NIL_RTMEMCACHE;
1765 }
1766}
1767
1768/**
1769 * Construct a disk integrity driver instance.
1770 *
1771 * @copydoc FNPDMDRVCONSTRUCT
1772 */
1773static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1774{
1775 int rc = VINF_SUCCESS;
1776 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1777 LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
1778 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1779
1780 /*
1781 * Validate configuration.
1782 */
1783 if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
1784 "TraceRequests\0"
1785 "CheckIntervalMs\0"
1786 "ExpireIntervalMs\0"
1787 "CheckDoubleCompletions\0"
1788 "HistorySize\0"
1789 "IoLogType\0"
1790 "IoLogFile\0"
1791 "IoLogAddress\0"
1792 "IoLogPort\0"
1793 "IoLogData\0"
1794 "PrepopulateRamDisk\0"
1795 "ReadAfterWrite\0"
1796 "RecordWriteBeforeCompletion\0"
1797 "ValidateMemoryBuffers\0"))
1798 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1799
1800 rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
1801 AssertRC(rc);
1802 rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
1803 AssertRC(rc);
1804 rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
1805 AssertRC(rc);
1806 rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
1807 AssertRC(rc);
1808 rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
1809 AssertRC(rc);
1810 rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
1811 AssertRC(rc);
1812 rc = CFGMR3QueryBoolDef(pCfg, "PrepopulateRamDisk", &pThis->fPrepopulateRamDisk, false);
1813 AssertRC(rc);
1814 rc = CFGMR3QueryBoolDef(pCfg, "ReadAfterWrite", &pThis->fReadAfterWrite, false);
1815 AssertRC(rc);
1816 rc = CFGMR3QueryBoolDef(pCfg, "RecordWriteBeforeCompletion", &pThis->fRecordWriteBeforeCompletion, false);
1817 AssertRC(rc);
1818 rc = CFGMR3QueryBoolDef(pCfg, "ValidateMemoryBuffers", &pThis->fValidateMemBufs, false);
1819 AssertRC(rc);
1820
1821 bool fIoLogData = false;
1822 rc = CFGMR3QueryBoolDef(pCfg, "IoLogData", &fIoLogData, false);
1823 AssertRC(rc);
1824
1825 char *pszIoLogType = NULL;
1826 char *pszIoLogFilename = NULL;
1827 char *pszAddress = NULL;
1828 uint32_t uPort = 0;
1829 rc = CFGMR3QueryStringAlloc(pCfg, "IoLogType", &pszIoLogType);
1830 if (RT_SUCCESS(rc))
1831 {
1832 if (!RTStrICmp(pszIoLogType, "File"))
1833 {
1834 rc = CFGMR3QueryStringAlloc(pCfg, "IoLogFile", &pszIoLogFilename);
1835 AssertRC(rc);
1836 }
1837 else if (!RTStrICmp(pszIoLogType, "Server"))
1838 {
1839 rc = CFGMR3QueryStringAllocDef(pCfg, "IoLogAddress", &pszAddress, NULL);
1840 AssertRC(rc);
1841 rc = CFGMR3QueryU32Def(pCfg, "IoLogPort", &uPort, 4000);
1842 AssertRC(rc);
1843 }
1844 else if (!RTStrICmp(pszIoLogType, "Client"))
1845 {
1846 rc = CFGMR3QueryStringAlloc(pCfg, "IoLogAddress", &pszAddress);
1847 AssertRC(rc);
1848 rc = CFGMR3QueryU32Def(pCfg, "IoLogPort", &uPort, 4000);
1849 AssertRC(rc);
1850 }
1851 else
1852 AssertMsgFailed(("Invalid I/O log type given: %s\n", pszIoLogType));
1853 }
1854 else
1855 Assert(rc == VERR_CFGM_VALUE_NOT_FOUND);
1856
1857 /*
1858 * Initialize most of the data members.
1859 */
1860 pThis->pDrvIns = pDrvIns;
1861 pThis->hReqCache = NIL_RTMEMCACHE;
1862
1863 /* IBase. */
1864 pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
1865
1866 /* IMedia */
1867 pThis->IMedia.pfnRead = drvdiskintRead;
1868 pThis->IMedia.pfnWrite = drvdiskintWrite;
1869 pThis->IMedia.pfnFlush = drvdiskintFlush;
1870 pThis->IMedia.pfnGetSize = drvdiskintGetSize;
1871 pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
1872 pThis->IMedia.pfnBiosIsVisible = drvdiskintBiosIsVisible;
1873 pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
1874 pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
1875 pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
1876 pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
1877 pThis->IMedia.pfnGetUuid = drvdiskintGetUuid;
1878 pThis->IMedia.pfnGetSectorSize = drvdiskintGetSectorSize;
1879 pThis->IMedia.pfnGetType = drvdiskintGetType;
1880 pThis->IMedia.pfnReadPcBios = drvdiskintReadPcBios;
1881 pThis->IMedia.pfnIsNonRotational = drvdiskintIsNonRotational;
1882
1883 /* IMediaEx. */
1884 pThis->IMediaEx.pfnQueryFeatures = drvdiskintQueryFeatures;
1885 pThis->IMediaEx.pfnIoReqAllocSizeSet = drvdiskintIoReqAllocSizeSet;
1886 pThis->IMediaEx.pfnIoReqAlloc = drvdiskintIoReqAlloc;
1887 pThis->IMediaEx.pfnIoReqFree = drvdiskintIoReqFree;
1888 pThis->IMediaEx.pfnIoReqQueryResidual = drvdiskintIoReqQueryResidual;
1889 pThis->IMediaEx.pfnIoReqQueryXferSize = drvdiskintIoReqQueryXferSize;
1890 pThis->IMediaEx.pfnIoReqCancelAll = drvdiskintIoReqCancelAll;
1891 pThis->IMediaEx.pfnIoReqCancel = drvdiskintIoReqCancel;
1892 pThis->IMediaEx.pfnIoReqRead = drvdiskintIoReqRead;
1893 pThis->IMediaEx.pfnIoReqWrite = drvdiskintIoReqWrite;
1894 pThis->IMediaEx.pfnIoReqFlush = drvdiskintIoReqFlush;
1895 pThis->IMediaEx.pfnIoReqDiscard = drvdiskintIoReqDiscard;
1896 pThis->IMediaEx.pfnIoReqGetActiveCount = drvdiskintIoReqGetActiveCount;
1897 pThis->IMediaEx.pfnIoReqGetSuspendedCount = drvdiskintIoReqGetSuspendedCount;
1898 pThis->IMediaEx.pfnIoReqQuerySuspendedStart = drvdiskintIoReqQuerySuspendedStart;
1899 pThis->IMediaEx.pfnIoReqQuerySuspendedNext = drvdiskintIoReqQuerySuspendedNext;
1900 pThis->IMediaEx.pfnIoReqSuspendedSave = drvdiskintIoReqSuspendedSave;
1901 pThis->IMediaEx.pfnIoReqSuspendedLoad = drvdiskintIoReqSuspendedLoad;
1902
1903 /* IMediaPort. */
1904 pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation;
1905
1906 /* IMediaExPort. */
1907 pThis->IMediaExPort.pfnIoReqCompleteNotify = drvdiskintIoReqCompleteNotify;
1908 pThis->IMediaExPort.pfnIoReqCopyFromBuf = drvdiskintIoReqCopyFromBuf;
1909 pThis->IMediaExPort.pfnIoReqCopyToBuf = drvdiskintIoReqCopyToBuf;
1910 pThis->IMediaExPort.pfnIoReqQueryDiscardRanges = drvdiskintIoReqQueryDiscardRanges;
1911 pThis->IMediaExPort.pfnIoReqStateChanged = drvdiskintIoReqStateChanged;
1912
1913 /* IMount */
1914 pThis->IMount.pfnUnmount = drvdiskintUnmount;
1915 pThis->IMount.pfnIsMounted = drvdiskintIsMounted;
1916 pThis->IMount.pfnLock = drvdiskintLock;
1917 pThis->IMount.pfnUnlock = drvdiskintUnlock;
1918 pThis->IMount.pfnIsLocked = drvdiskintIsLocked;
1919
1920 /* IMountNotify */
1921 pThis->IMountNotify.pfnMountNotify = drvdiskintMountNotify;
1922 pThis->IMountNotify.pfnUnmountNotify = drvdiskintUnmountNotify;
1923
1924 /* Query the media port interface above us. */
1925 pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
1926 if (!pThis->pDrvMediaPort)
1927 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1928 N_("No media port interface above"));
1929
1930 /* Try to attach extended media port interface above.*/
1931 pThis->pDrvMediaExPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAEXPORT);
1932
1933 rc = RTMemCacheCreate(&pThis->hReqCache, sizeof(DRVDISKAIOREQ), 0, UINT32_MAX,
1934 NULL, NULL, NULL, 0);
1935 if (RT_FAILURE(rc))
1936 return PDMDRV_SET_ERROR(pDrvIns, rc,
1937 N_("Failed to create request tracking structure cache"));
1938
1939 /*
1940 * Try attach driver below and query it's media interface.
1941 */
1942 PPDMIBASE pBase;
1943 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
1944 if (RT_FAILURE(rc))
1945 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1946 N_("Failed to attach driver below us! %Rrc"), rc);
1947
1948 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
1949 if (!pThis->pDrvMedia)
1950 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1951 N_("No media or async media interface below"));
1952
1953 pThis->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAEX);
1954 pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
1955
1956 if (pThis->pDrvMedia->pfnDiscard)
1957 pThis->IMedia.pfnDiscard = drvdiskintDiscard;
1958
1959 if (pThis->fCheckConsistency)
1960 {
1961 /* Create the AVL tree. */
1962 pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
1963 if (!pThis->pTreeSegments)
1964 rc = VERR_NO_MEMORY;
1965 }
1966
1967 if (pThis->fTraceRequests)
1968 {
1969 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
1970 {
1971 pThis->apReqActive[i].pIoReq = NULL;
1972 pThis->apReqActive[i].tsStart = 0;
1973 }
1974
1975 pThis->iNextFreeSlot = 0;
1976
1977 /* Init event semaphore. */
1978 rc = RTSemEventCreate(&pThis->SemEvent);
1979 AssertRC(rc);
1980 pThis->fRunning = true;
1981 rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
1982 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
1983 AssertRC(rc);
1984 }
1985
1986 if (pThis->fCheckDoubleCompletion)
1987 {
1988 pThis->iEntry = 0;
1989 pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
1990 AssertPtr(pThis->papIoReq);
1991 }
1992
1993 if (pszIoLogType)
1994 {
1995 if (!RTStrICmp(pszIoLogType, "File"))
1996 {
1997 rc = RTTraceLogWrCreateFile(&pThis->hIoLogger, NULL, pszIoLogFilename);
1998 MMR3HeapFree(pszIoLogFilename);
1999 }
2000 else if (!RTStrICmp(pszIoLogType, "Server"))
2001 {
2002 rc = RTTraceLogWrCreateTcpServer(&pThis->hIoLogger, NULL, pszAddress, uPort);
2003 if (pszAddress)
2004 MMR3HeapFree(pszAddress);
2005 }
2006 else if (!RTStrICmp(pszIoLogType, "Client"))
2007 {
2008 rc = RTTraceLogWrCreateTcpClient(&pThis->hIoLogger, NULL, pszAddress, uPort);
2009 MMR3HeapFree(pszAddress);
2010 }
2011 else
2012 AssertMsgFailed(("Invalid I/O log type given: %s\n", pszIoLogType));
2013
2014 MMR3HeapFree(pszIoLogType);
2015 }
2016
2017 /* Read in all data before the start if requested. */
2018 if (pThis->fPrepopulateRamDisk)
2019 {
2020 uint64_t cbDisk = 0;
2021
2022 LogRel(("DiskIntegrity: Prepopulating RAM disk, this will take some time...\n"));
2023
2024 cbDisk = pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
2025 if (cbDisk)
2026 {
2027 uint64_t off = 0;
2028 uint8_t abBuffer[_64K];
2029 RTSGSEG Seg;
2030
2031 Seg.pvSeg = abBuffer;
2032
2033 while (cbDisk)
2034 {
2035 size_t cbThisRead = RT_MIN(cbDisk, sizeof(abBuffer));
2036
2037 rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, abBuffer, cbThisRead);
2038 if (RT_FAILURE(rc))
2039 break;
2040
2041 if (ASMBitFirstSet(abBuffer, sizeof(abBuffer) * 8) != -1)
2042 {
2043 Seg.cbSeg = cbThisRead;
2044 rc = drvdiskintWriteRecord(pThis, &Seg, 1,
2045 off, cbThisRead);
2046 if (RT_FAILURE(rc))
2047 break;
2048 }
2049
2050 cbDisk -= cbThisRead;
2051 off += cbThisRead;
2052 }
2053
2054 LogRel(("DiskIntegrity: Prepopulating RAM disk finished with %Rrc\n", rc));
2055 }
2056 else
2057 return PDMDRV_SET_ERROR(pDrvIns, VERR_INTERNAL_ERROR,
2058 N_("DiskIntegrity: Error querying the media size below"));
2059 }
2060
2061 return rc;
2062}
2063
2064
2065/**
2066 * Block driver registration record.
2067 */
2068const PDMDRVREG g_DrvDiskIntegrity =
2069{
2070 /* u32Version */
2071 PDM_DRVREG_VERSION,
2072 /* szName */
2073 "DiskIntegrity",
2074 /* szRCMod */
2075 "",
2076 /* szR0Mod */
2077 "",
2078 /* pszDescription */
2079 "Disk integrity driver.",
2080 /* fFlags */
2081 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
2082 /* fClass. */
2083 PDM_DRVREG_CLASS_BLOCK,
2084 /* cMaxInstances */
2085 ~0U,
2086 /* cbInstance */
2087 sizeof(DRVDISKINTEGRITY),
2088 /* pfnConstruct */
2089 drvdiskintConstruct,
2090 /* pfnDestruct */
2091 drvdiskintDestruct,
2092 /* pfnRelocate */
2093 NULL,
2094 /* pfnIOCtl */
2095 NULL,
2096 /* pfnPowerOn */
2097 NULL,
2098 /* pfnReset */
2099 NULL,
2100 /* pfnSuspend */
2101 NULL,
2102 /* pfnResume */
2103 NULL,
2104 /* pfnAttach */
2105 NULL,
2106 /* pfnDetach */
2107 NULL,
2108 /* pfnPowerOff */
2109 NULL,
2110 /* pfnSoftReset */
2111 NULL,
2112 /* u32EndVersion */
2113 PDM_DRVREG_VERSION
2114};
2115
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