VirtualBox

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

Last change on this file since 91968 was 91897, checked in by vboxsync, 3 years ago

VMM,Devices: Add callbacks to required MMR3* APIs to the helper callbacks tables and convert devices and drivers to make use of those, bugref:10074

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.6 KB
Line 
1/* $Id: DrvDiskIntegrity.cpp 91897 2021-10-20 13:42:39Z vboxsync $ */
2/** @file
3 * VBox storage devices: Disk integrity check.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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/** @interface_method_impl{PDMIMEDIA,pfnGetRegionCount} */
1066static DECLCALLBACK(uint32_t) drvdiskintGetRegionCount(PPDMIMEDIA pInterface)
1067{
1068 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1069 return pThis->pDrvMedia->pfnGetRegionCount(pThis->pDrvMedia);
1070}
1071
1072/** @interface_method_impl{PDMIMEDIA,pfnQueryRegionProperties} */
1073static DECLCALLBACK(int) drvdiskintQueryRegionProperties(PPDMIMEDIA pInterface, uint32_t uRegion, uint64_t *pu64LbaStart,
1074 uint64_t *pcBlocks, uint64_t *pcbBlock,
1075 PVDREGIONDATAFORM penmDataForm)
1076{
1077 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1078 return pThis->pDrvMedia->pfnQueryRegionProperties(pThis->pDrvMedia, uRegion, pu64LbaStart, pcBlocks, pcbBlock, penmDataForm);
1079}
1080
1081/** @interface_method_impl{PDMIMEDIA,pfnQueryRegionPropertiesForLba} */
1082static DECLCALLBACK(int) drvdiskintQueryRegionPropertiesForLba(PPDMIMEDIA pInterface, uint64_t u64LbaStart,
1083 uint32_t *puRegion, uint64_t *pcBlocks,
1084 uint64_t *pcbBlock, PVDREGIONDATAFORM penmDataForm)
1085{
1086 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1087 return pThis->pDrvMedia->pfnQueryRegionPropertiesForLba(pThis->pDrvMedia, u64LbaStart, puRegion, pcBlocks, pcbBlock, penmDataForm);
1088}
1089
1090/* -=-=-=-=- IMediaPort -=-=-=-=- */
1091
1092/** Makes a PDRVBLOCK out of a PPDMIMEDIAPORT. */
1093#define PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_UOFFSETOF(DRVDISKINTEGRITY, IMediaPort))) )
1094
1095/**
1096 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
1097 */
1098static DECLCALLBACK(int) drvdiskintQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
1099 uint32_t *piInstance, uint32_t *piLUN)
1100{
1101 PDRVDISKINTEGRITY pThis = PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface);
1102
1103 return pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, ppcszController,
1104 piInstance, piLUN);
1105}
1106
1107/* -=-=-=-=- IMediaExPort -=-=-=-=- */
1108
1109/**
1110 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
1111 */
1112static DECLCALLBACK(int) drvdiskintIoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1113 void *pvIoReqAlloc, int rcReq)
1114{
1115 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1116 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_ALLOC_2_DRVDISKAIOREQ(pvIoReqAlloc);
1117 int rc = VINF_SUCCESS;
1118
1119 LogFlowFunc(("pIoReq=%#p\n", pIoReq));
1120
1121 /* Remove from the active list. */
1122 if (pThis->fTraceRequests)
1123 drvdiskintIoReqRemove(pThis, pIoReq);
1124
1125 if (RT_SUCCESS(rcReq) && pThis->fCheckConsistency)
1126 {
1127 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1128 rc = drvdiskintReadVerify(pThis, &pIoReq->IoSeg, 1, pIoReq->off, pIoReq->cbTransfer);
1129 else if ( pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE
1130 && !pThis->fRecordWriteBeforeCompletion)
1131 rc = drvdiskintWriteRecord(pThis, &pIoReq->IoSeg, 1, pIoReq->off, pIoReq->cbTransfer);
1132 else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_DISCARD)
1133 rc = drvdiskintDiscardRecords(pThis, pIoReq->paRanges, pIoReq->cRanges);
1134 else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ_AFTER_WRITE)
1135 rc = drvdiskintReadAfterWriteVerify(pThis, pIoReq);
1136 else
1137 AssertMsg( pIoReq->enmTxDir == DRVDISKAIOTXDIR_FLUSH
1138 || ( pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE
1139 && pThis->fRecordWriteBeforeCompletion), ("Huh?\n"));
1140
1141 AssertRC(rc);
1142 }
1143
1144 if ( RT_SUCCESS(rcReq)
1145 && pThis->fValidateMemBufs
1146 && pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1147 {
1148 /* Check that the guest memory buffer matches what was written. */
1149 RTSGSEG SegCmp;
1150 SegCmp.pvSeg = RTMemAlloc(pIoReq->cbTransfer);
1151 SegCmp.cbSeg = pIoReq->cbTransfer;
1152
1153 RTSGBUF SgBufCmp;
1154 RTSgBufInit(&SgBufCmp, &SegCmp, 1);
1155 rc = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, hIoReq,
1156 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1157 0, &SgBufCmp, pIoReq->cbTransfer);
1158 AssertRC(rc);
1159
1160 RTSGBUF SgBuf;
1161 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1162 if (RTSgBufCmp(&SgBuf, &SgBufCmp, pIoReq->cbTransfer))
1163 {
1164 RTMsgError("Corrupted memory buffer at offset %llu!\n", 0);
1165 RTAssertDebugBreak();
1166 }
1167
1168 RTMemFree(SegCmp.pvSeg);
1169 }
1170
1171 if (pThis->hIoLogger)
1172 {
1173 RTSGBUF SgBuf;
1174
1175 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1176 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1177 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rcReq, &SgBuf);
1178 }
1179
1180 if ( pThis->fReadAfterWrite
1181 && pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE)
1182 {
1183#if 0 /** @todo */
1184 pIoReq->enmTxDir = DRVDISKAIOTXDIR_READ_AFTER_WRITE;
1185
1186 /* Add again because it was removed above. */
1187 if (pThis->fTraceRequests)
1188 drvdiskintIoReqAdd(pThis, pIoReq);
1189
1190 rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, pIoReq->off, pIoReq->paSeg, pIoReq->cSeg,
1191 pIoReq->cbTransfer, pIoReq);
1192 if (rc == VINF_VD_ASYNC_IO_FINISHED)
1193 {
1194 rc = drvdiskintReadAfterWriteVerify(pThis, pIoReq);
1195
1196 if (pThis->fTraceRequests)
1197 drvdiskintIoReqRemove(pThis, pIoReq);
1198 RTMemFree(pIoReq);
1199 }
1200 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
1201 rc = VINF_SUCCESS;
1202 else if (RT_FAILURE(rc))
1203 RTMemFree(pIoReq);
1204#endif
1205 }
1206 else
1207 {
1208 rc = pThis->pDrvMediaExPort->pfnIoReqCompleteNotify(pThis->pDrvMediaExPort, hIoReq,
1209 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1210 rcReq);
1211 /* Put on the watch list. */
1212 if (pThis->fCheckDoubleCompletion)
1213 drvdiskintIoReqCheckForDoubleCompletion(pThis, pIoReq, true /* fMediaEx */);
1214 }
1215
1216 return rc;
1217}
1218
1219/**
1220 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
1221 */
1222static DECLCALLBACK(int) drvdiskintIoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1223 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
1224 size_t cbCopy)
1225{
1226 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1227 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_ALLOC_2_DRVDISKAIOREQ(pvIoReqAlloc);
1228 RTSGBUF SgBuf;
1229
1230 RTSgBufClone(&SgBuf, pSgBuf);
1231
1232 int rc = pThis->pDrvMediaExPort->pfnIoReqCopyFromBuf(pThis->pDrvMediaExPort, hIoReq,
1233 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1234 offDst, pSgBuf, cbCopy);
1235 if ( RT_SUCCESS(rc)
1236 && pIoReq->IoSeg.pvSeg)
1237 {
1238 /* Update our copy. */
1239 RTSgBufCopyToBuf(&SgBuf, (uint8_t *)pIoReq->IoSeg.pvSeg + offDst, cbCopy);
1240
1241 /* Validate the just read data against our copy if possible. */
1242 if ( pThis->fValidateMemBufs
1243 && pThis->fCheckConsistency
1244 && pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1245 {
1246 RTSGSEG Seg;
1247
1248 Seg.pvSeg = (uint8_t *)pIoReq->IoSeg.pvSeg + offDst;
1249 Seg.cbSeg = cbCopy;
1250
1251 rc = drvdiskintReadVerify(pThis, &Seg, 1, pIoReq->off + offDst,
1252 cbCopy);
1253 }
1254 }
1255
1256 return rc;
1257}
1258
1259/**
1260 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
1261 */
1262static DECLCALLBACK(int) drvdiskintIoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1263 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
1264 size_t cbCopy)
1265{
1266 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1267 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_ALLOC_2_DRVDISKAIOREQ(pvIoReqAlloc);
1268 RTSGBUF SgBuf;
1269
1270 RTSgBufClone(&SgBuf, pSgBuf);
1271
1272 int rc = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, hIoReq,
1273 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1274 offSrc, pSgBuf, cbCopy);
1275 if ( RT_SUCCESS(rc)
1276 && pIoReq->IoSeg.pvSeg)
1277 {
1278 if (pThis->fValidateMemBufs)
1279 {
1280 /* Make sure what the caller requested matches what we got earlier. */
1281 RTSGBUF SgBufCmp;
1282 RTSgBufInit(&SgBufCmp, &pIoReq->IoSeg, 1);
1283 RTSgBufAdvance(&SgBufCmp, offSrc);
1284
1285 if (RTSgBufCmp(&SgBuf, &SgBufCmp, cbCopy))
1286 {
1287 RTMsgError("Corrupted memory buffer at offset %llu!\n", offSrc);
1288 RTAssertDebugBreak();
1289 }
1290 }
1291 else
1292 {
1293 /* Update our copy. */
1294 RTSgBufCopyToBuf(&SgBuf, (uint8_t *)pIoReq->IoSeg.pvSeg + offSrc, cbCopy);
1295 }
1296 }
1297
1298 return rc;
1299}
1300
1301/**
1302 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqQueryDiscardRanges}
1303 */
1304static DECLCALLBACK(int) drvdiskintIoReqQueryDiscardRanges(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1305 void *pvIoReqAlloc, uint32_t idxRangeStart,
1306 uint32_t cRanges, PRTRANGE paRanges,
1307 uint32_t *pcRanges)
1308{
1309 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1310 return pThis->pDrvMediaExPort->pfnIoReqQueryDiscardRanges(pThis->pDrvMediaExPort, hIoReq,
1311 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1312 idxRangeStart, cRanges, paRanges, pcRanges);
1313}
1314
1315/**
1316 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
1317 */
1318static DECLCALLBACK(void) drvdiskintIoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1319 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
1320{
1321 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1322 pThis->pDrvMediaExPort->pfnIoReqStateChanged(pThis->pDrvMediaExPort, hIoReq,
1323 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1324 enmState);
1325}
1326
1327/* -=-=-=-=- IMediaEx -=-=-=-=- */
1328
1329/**
1330 * @interface_method_impl{PDMIMEDIAEX,pfnQueryFeatures}
1331 */
1332static DECLCALLBACK(int) drvdiskintQueryFeatures(PPDMIMEDIAEX pInterface, uint32_t *pfFeatures)
1333{
1334 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1335 return pThis->pDrvMediaEx->pfnQueryFeatures(pThis->pDrvMediaEx, pfFeatures);
1336}
1337
1338/**
1339 * @interface_method_impl{PDMIMEDIAEX,pfnNotifySuspend}
1340 */
1341static DECLCALLBACK(void) drvdiskintNotifySuspend(PPDMIMEDIAEX pInterface)
1342{
1343 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1344 return pThis->pDrvMediaEx->pfnNotifySuspend(pThis->pDrvMediaEx);
1345}
1346
1347/**
1348 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqAllocSizeSet}
1349 */
1350static DECLCALLBACK(int) drvdiskintIoReqAllocSizeSet(PPDMIMEDIAEX pInterface, size_t cbIoReqAlloc)
1351{
1352 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1353
1354 /* Increase the amount by the size of a pointer to our private tracking structure. */
1355 cbIoReqAlloc += sizeof(PDRVDISKAIOREQ);
1356
1357 pThis->fCheckDoubleCompletion = false;
1358
1359 return pThis->pDrvMediaEx->pfnIoReqAllocSizeSet(pThis->pDrvMediaEx, cbIoReqAlloc);
1360}
1361
1362/**
1363 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqAlloc}
1364 */
1365static DECLCALLBACK(int) drvdiskintIoReqAlloc(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc,
1366 PDMMEDIAEXIOREQID uIoReqId, uint32_t fFlags)
1367{
1368 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1369 int rc = VINF_SUCCESS;
1370 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)RTMemCacheAlloc(pThis->hReqCache);
1371 if (RT_LIKELY(pIoReq))
1372 {
1373 pIoReq->enmTxDir = DRVDISKAIOTXDIR_INVALID;
1374 pIoReq->off = 0;
1375 pIoReq->cbTransfer = 0;
1376 pIoReq->paSeg = NULL;
1377 pIoReq->cSeg = 0;
1378 pIoReq->pvUser = NULL;
1379 pIoReq->iSlot = 0;
1380 pIoReq->tsStart = 0;
1381 pIoReq->tsComplete = 0;
1382 pIoReq->IoSeg.pvSeg = NULL;
1383 pIoReq->IoSeg.cbSeg = 0;
1384
1385 PDRVDISKAIOREQ *ppIoReq = NULL;
1386 rc = pThis->pDrvMediaEx->pfnIoReqAlloc(pThis->pDrvMediaEx, phIoReq, (void **)&ppIoReq, uIoReqId, fFlags);
1387 if RT_SUCCESS(rc)
1388 {
1389 /*
1390 * Store the size off the start of our tracking structure because it is
1391 * required to access it for the read/write callbacks.
1392 *
1393 * ASSUMPTION that the offset is constant.
1394 */
1395 if (!pThis->cbIoReqOpaque)
1396 pThis->cbIoReqOpaque = (uintptr_t)ppIoReq - (uintptr_t)*phIoReq;
1397 else
1398 Assert(pThis->cbIoReqOpaque == (uintptr_t)ppIoReq - (uintptr_t)*phIoReq);
1399
1400 *ppIoReq = pIoReq;
1401 *ppvIoReqAlloc = ((uint8_t *)ppIoReq) + sizeof(PDRVDISKAIOREQ);
1402 }
1403 else
1404 RTMemCacheFree(pThis->hReqCache, pIoReq);
1405 }
1406 else
1407 rc = VERR_NO_MEMORY;
1408
1409 return rc;
1410}
1411
1412/**
1413 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqFree}
1414 */
1415static DECLCALLBACK(int) drvdiskintIoReqFree(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
1416{
1417 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1418 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1419
1420 if (pIoReq->IoSeg.pvSeg)
1421 RTMemFree(pIoReq->IoSeg.pvSeg);
1422
1423 return pThis->pDrvMediaEx->pfnIoReqFree(pThis->pDrvMediaEx, hIoReq);
1424}
1425
1426/**
1427 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryResidual}
1428 */
1429static DECLCALLBACK(int) drvdiskintIoReqQueryResidual(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbResidual)
1430{
1431 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1432 return pThis->pDrvMediaEx->pfnIoReqQueryResidual(pThis->pDrvMediaEx, hIoReq, pcbResidual);
1433}
1434
1435/**
1436 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryXferSize}
1437 */
1438static DECLCALLBACK(int) drvdiskintIoReqQueryXferSize(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbXfer)
1439{
1440 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1441 return pThis->pDrvMediaEx->pfnIoReqQueryXferSize(pThis->pDrvMediaEx, hIoReq, pcbXfer);
1442}
1443
1444/**
1445 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancelAll}
1446 */
1447static DECLCALLBACK(int) drvdiskintIoReqCancelAll(PPDMIMEDIAEX pInterface)
1448{
1449 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1450 return pThis->pDrvMediaEx->pfnIoReqCancelAll(pThis->pDrvMediaEx);
1451}
1452
1453/**
1454 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancel}
1455 */
1456static DECLCALLBACK(int) drvdiskintIoReqCancel(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQID uIoReqId)
1457{
1458 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1459 return pThis->pDrvMediaEx->pfnIoReqCancel(pThis->pDrvMediaEx, uIoReqId);
1460}
1461
1462/**
1463 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqRead}
1464 */
1465static DECLCALLBACK(int) drvdiskintIoReqRead(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbRead)
1466{
1467 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1468 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1469
1470 pIoReq->enmTxDir = DRVDISKAIOTXDIR_READ;
1471 pIoReq->off = off;
1472 pIoReq->cbTransfer = cbRead;
1473
1474 /* Allocate a I/O buffer if the I/O is verified.*/
1475 if (pThis->fCheckConsistency)
1476 {
1477 pIoReq->IoSeg.pvSeg = RTMemAlloc(cbRead);
1478 pIoReq->IoSeg.cbSeg = cbRead;
1479 }
1480
1481 if (pThis->fTraceRequests)
1482 drvdiskintIoReqAdd(pThis, pIoReq);
1483
1484 drvdiskintTraceLogFireEvtRead(pThis, (uintptr_t)hIoReq, true /* fAsync */, off, cbRead);
1485 int rc = pThis->pDrvMediaEx->pfnIoReqRead(pThis->pDrvMediaEx, hIoReq, off, cbRead);
1486 if (rc == VINF_SUCCESS)
1487 {
1488 /* Verify the read now. */
1489 if (pThis->fCheckConsistency)
1490 {
1491 int rc2 = drvdiskintReadVerify(pThis, &pIoReq->IoSeg, 1, off, cbRead);
1492 AssertRC(rc2);
1493 }
1494
1495 if (pThis->hIoLogger)
1496 {
1497 RTSGBUF SgBuf;
1498
1499 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1500 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, &SgBuf);
1501 }
1502
1503 if (pThis->fTraceRequests)
1504 drvdiskintIoReqRemove(pThis, pIoReq);
1505 }
1506 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1507 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, NULL);
1508
1509 LogFlowFunc(("returns %Rrc\n", rc));
1510 return rc;
1511}
1512
1513/**
1514 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqWrite}
1515 */
1516static DECLCALLBACK(int) drvdiskintIoReqWrite(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbWrite)
1517{
1518 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1519 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1520
1521 pIoReq->enmTxDir = DRVDISKAIOTXDIR_WRITE;
1522 pIoReq->off = off;
1523 pIoReq->cbTransfer = cbWrite;
1524
1525 /* Allocate a I/O buffer if the I/O is verified.*/
1526 if ( pThis->fCheckConsistency
1527 || pThis->fValidateMemBufs
1528 || pThis->hIoLogger
1529 || pThis->fRecordWriteBeforeCompletion)
1530 {
1531 pIoReq->IoSeg.pvSeg = RTMemAlloc(cbWrite);
1532 pIoReq->IoSeg.cbSeg = cbWrite;
1533
1534 /* Sync the memory buffer over if we should validate it. */
1535 if ( pThis->fValidateMemBufs
1536 || pThis->hIoLogger
1537 || pThis->fRecordWriteBeforeCompletion)
1538 {
1539 RTSGBUF SgBuf;
1540
1541 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1542 int rc2 = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, hIoReq,
1543 DISKINTEGRITY_IOREQ_HANDLE_2_UPPER_OPAQUE(pThis, hIoReq),
1544 0, &SgBuf, cbWrite);
1545 AssertRC(rc2);
1546 }
1547 }
1548
1549 if (pThis->fTraceRequests)
1550 drvdiskintIoReqAdd(pThis, pIoReq);
1551
1552 drvdiskintTraceLogFireEvtWrite(pThis, (uintptr_t)hIoReq, true /* fAsync */, off, cbWrite);
1553 if (pThis->fRecordWriteBeforeCompletion)
1554 {
1555
1556 int rc2 = drvdiskintWriteRecord(pThis, &pIoReq->IoSeg, 1, off, cbWrite);
1557 AssertRC(rc2);
1558 }
1559
1560 int rc = pThis->pDrvMediaEx->pfnIoReqWrite(pThis->pDrvMediaEx, hIoReq, off, cbWrite);
1561 if (rc == VINF_SUCCESS)
1562 {
1563 /* Record the write. */
1564 if ( pThis->fCheckConsistency
1565 && !pThis->fRecordWriteBeforeCompletion)
1566 {
1567 int rc2 = drvdiskintWriteRecord(pThis, &pIoReq->IoSeg, 1, off, cbWrite);
1568 AssertRC(rc2);
1569 }
1570
1571 RTSGBUF SgBuf;
1572 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1573 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, &SgBuf);
1574 if (pThis->fTraceRequests)
1575 drvdiskintIoReqRemove(pThis, pIoReq);
1576 }
1577 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1578 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, NULL);
1579
1580 LogFlowFunc(("returns %Rrc\n", rc));
1581 return rc;
1582}
1583
1584/**
1585 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqFlush}
1586 */
1587static DECLCALLBACK(int) drvdiskintIoReqFlush(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
1588{
1589 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1590 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1591
1592 pIoReq->enmTxDir = DRVDISKAIOTXDIR_FLUSH;
1593 pIoReq->off = 0;
1594 pIoReq->cbTransfer = 0;
1595
1596 if (pThis->fTraceRequests)
1597 drvdiskintIoReqAdd(pThis, pIoReq);
1598
1599 drvdiskintTraceLogFireEvtFlush(pThis, (uintptr_t)hIoReq, true /* fAsync */);
1600 int rc = pThis->pDrvMediaEx->pfnIoReqFlush(pThis->pDrvMediaEx, hIoReq);
1601 if (rc == VINF_SUCCESS)
1602 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, NULL);
1603 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1604 drvdiskintTraceLogFireEvtComplete(pThis, (uintptr_t)hIoReq, rc, NULL);
1605
1606 LogFlowFunc(("returns %Rrc\n", rc));
1607 return rc;
1608}
1609
1610/**
1611 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqDiscard}
1612 */
1613static DECLCALLBACK(int) drvdiskintIoReqDiscard(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, unsigned cRangesMax)
1614{
1615 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1616 return pThis->pDrvMediaEx->pfnIoReqDiscard(pThis->pDrvMediaEx, hIoReq, cRangesMax);
1617}
1618
1619/**
1620 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetActiveCount}
1621 */
1622static DECLCALLBACK(uint32_t) drvdiskintIoReqGetActiveCount(PPDMIMEDIAEX pInterface)
1623{
1624 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1625 return pThis->pDrvMediaEx->pfnIoReqGetActiveCount(pThis->pDrvMediaEx);
1626}
1627
1628/**
1629 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetSuspendedCount}
1630 */
1631static DECLCALLBACK(uint32_t) drvdiskintIoReqGetSuspendedCount(PPDMIMEDIAEX pInterface)
1632{
1633 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1634 return pThis->pDrvMediaEx->pfnIoReqGetSuspendedCount(pThis->pDrvMediaEx);
1635}
1636
1637/**
1638 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedStart}
1639 */
1640static DECLCALLBACK(int) drvdiskintIoReqQuerySuspendedStart(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc)
1641{
1642 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1643 return pThis->pDrvMediaEx->pfnIoReqQuerySuspendedStart(pThis->pDrvMediaEx, phIoReq, ppvIoReqAlloc);
1644}
1645
1646/**
1647 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedNext}
1648 */
1649static DECLCALLBACK(int) drvdiskintIoReqQuerySuspendedNext(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq,
1650 PPDMMEDIAEXIOREQ phIoReqNext, void **ppvIoReqAllocNext)
1651{
1652 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1653 return pThis->pDrvMediaEx->pfnIoReqQuerySuspendedNext(pThis->pDrvMediaEx, hIoReq, phIoReqNext, ppvIoReqAllocNext);
1654}
1655
1656/**
1657 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedSave}
1658 */
1659static DECLCALLBACK(int) drvdiskintIoReqSuspendedSave(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
1660{
1661 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1662 return pThis->pDrvMediaEx->pfnIoReqSuspendedSave(pThis->pDrvMediaEx, pSSM, hIoReq);
1663}
1664
1665/**
1666 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedLoad}
1667 */
1668static DECLCALLBACK(int) drvdiskintIoReqSuspendedLoad(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
1669{
1670 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1671 return pThis->pDrvMediaEx->pfnIoReqSuspendedLoad(pThis->pDrvMediaEx, pSSM, hIoReq);
1672}
1673
1674/* -=-=-=-=- IMount -=-=-=-=- */
1675
1676/** @interface_method_impl{PDMIMOUNT,pfnUnmount} */
1677static DECLCALLBACK(int) drvdiskintUnmount(PPDMIMOUNT pInterface, bool fForce, bool fEject)
1678{
1679 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMount);
1680 return pThis->pDrvMount->pfnUnmount(pThis->pDrvMount, fForce, fEject);
1681}
1682
1683/** @interface_method_impl{PDMIMOUNT,pfnIsMounted} */
1684static DECLCALLBACK(bool) drvdiskintIsMounted(PPDMIMOUNT pInterface)
1685{
1686 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMount);
1687 return pThis->pDrvMount->pfnIsMounted(pThis->pDrvMount);
1688}
1689
1690/** @interface_method_impl{PDMIMOUNT,pfnLock} */
1691static DECLCALLBACK(int) drvdiskintLock(PPDMIMOUNT pInterface)
1692{
1693 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMount);
1694 return pThis->pDrvMount->pfnLock(pThis->pDrvMount);
1695}
1696
1697/** @interface_method_impl{PDMIMOUNT,pfnUnlock} */
1698static DECLCALLBACK(int) drvdiskintUnlock(PPDMIMOUNT pInterface)
1699{
1700 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMount);
1701 return pThis->pDrvMount->pfnUnlock(pThis->pDrvMount);
1702}
1703
1704/** @interface_method_impl{PDMIMOUNT,pfnIsLocked} */
1705static DECLCALLBACK(bool) drvdiskintIsLocked(PPDMIMOUNT pInterface)
1706{
1707 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMount);
1708 return pThis->pDrvMount->pfnIsLocked(pThis->pDrvMount);
1709}
1710
1711/* -=-=-=-=- IMountNotify -=-=-=-=- */
1712
1713/** @interface_method_impl{PDMIMOUNTNOTIFY,pfnMountNotify} */
1714static DECLCALLBACK(void) drvdiskintMountNotify(PPDMIMOUNTNOTIFY pInterface)
1715{
1716 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMountNotify);
1717 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
1718}
1719
1720/** @interface_method_impl{PDMIMOUNTNOTIFY,pfnUnmountNotify} */
1721static DECLCALLBACK(void) drvdiskintUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
1722{
1723 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMountNotify);
1724 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
1725}
1726
1727/* -=-=-=-=- IBase -=-=-=-=- */
1728
1729/**
1730 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1731 */
1732static DECLCALLBACK(void *) drvdiskintQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1733{
1734 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1735 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1736
1737 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1738 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
1739 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->IMediaPort);
1740 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pThis->IMediaExPort);
1741 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEX, pThis->pDrvMediaEx ? &pThis->IMediaEx : NULL);
1742 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNT, pThis->pDrvMount ? &pThis->IMount : NULL);
1743 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNTNOTIFY, &pThis->IMountNotify);
1744 return NULL;
1745}
1746
1747
1748/* -=-=-=-=- driver interface -=-=-=-=- */
1749
1750static DECLCALLBACK(int) drvdiskintTreeDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
1751{
1752 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)pNode;
1753
1754 RT_NOREF(pvUser);
1755
1756 RTMemFree(pSeg->pbSeg);
1757 RTMemFree(pSeg);
1758 return VINF_SUCCESS;
1759}
1760
1761/**
1762 * @copydoc FNPDMDRVDESTRUCT
1763 */
1764static DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
1765{
1766 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1767
1768 if (pThis->pTreeSegments)
1769 {
1770 RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
1771 RTMemFree(pThis->pTreeSegments);
1772 }
1773
1774 if (pThis->fTraceRequests)
1775 {
1776 pThis->fRunning = false;
1777 RTSemEventSignal(pThis->SemEvent);
1778 RTSemEventDestroy(pThis->SemEvent);
1779 }
1780
1781 if (pThis->fCheckDoubleCompletion)
1782 {
1783 /* Free all requests */
1784 while (pThis->papIoReq[pThis->iEntry])
1785 {
1786 RTMemFree(pThis->papIoReq[pThis->iEntry]);
1787 pThis->papIoReq[pThis->iEntry] = NULL;
1788 pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
1789 }
1790 }
1791
1792 if (pThis->hIoLogger)
1793 RTTraceLogWrDestroy(pThis->hIoLogger);
1794
1795 if (pThis->hReqCache != NIL_RTMEMCACHE)
1796 {
1797 RTMemCacheDestroy(pThis->hReqCache);
1798 pThis->hReqCache = NIL_RTMEMCACHE;
1799 }
1800}
1801
1802/**
1803 * Construct a disk integrity driver instance.
1804 *
1805 * @copydoc FNPDMDRVCONSTRUCT
1806 */
1807static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1808{
1809 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1810 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1811 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
1812
1813 LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
1814
1815 /*
1816 * Validate configuration.
1817 */
1818 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "CheckConsistency"
1819 "|TraceRequests"
1820 "|CheckIntervalMs"
1821 "|ExpireIntervalMs"
1822 "|CheckDoubleCompletions"
1823 "|HistorySize"
1824 "|IoLogType"
1825 "|IoLogFile"
1826 "|IoLogAddress"
1827 "|IoLogPort"
1828 "|IoLogData"
1829 "|PrepopulateRamDisk"
1830 "|ReadAfterWrite"
1831 "|RecordWriteBeforeCompletion"
1832 "|ValidateMemoryBuffers",
1833 "");
1834
1835 int rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
1836 AssertRC(rc);
1837 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
1838 AssertRC(rc);
1839 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
1840 AssertRC(rc);
1841 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
1842 AssertRC(rc);
1843 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
1844 AssertRC(rc);
1845 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
1846 AssertRC(rc);
1847 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "PrepopulateRamDisk", &pThis->fPrepopulateRamDisk, false);
1848 AssertRC(rc);
1849 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "ReadAfterWrite", &pThis->fReadAfterWrite, false);
1850 AssertRC(rc);
1851 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "RecordWriteBeforeCompletion", &pThis->fRecordWriteBeforeCompletion, false);
1852 AssertRC(rc);
1853 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "ValidateMemoryBuffers", &pThis->fValidateMemBufs, false);
1854 AssertRC(rc);
1855
1856 bool fIoLogData = false;
1857 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "IoLogData", &fIoLogData, false);
1858 AssertRC(rc);
1859
1860 char *pszIoLogType = NULL;
1861 char *pszIoLogFilename = NULL;
1862 char *pszAddress = NULL;
1863 uint32_t uPort = 0;
1864 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "IoLogType", &pszIoLogType);
1865 if (RT_SUCCESS(rc))
1866 {
1867 if (!RTStrICmp(pszIoLogType, "File"))
1868 {
1869 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "IoLogFile", &pszIoLogFilename);
1870 AssertRC(rc);
1871 }
1872 else if (!RTStrICmp(pszIoLogType, "Server"))
1873 {
1874 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "IoLogAddress", &pszAddress, NULL);
1875 AssertRC(rc);
1876 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "IoLogPort", &uPort, 4000);
1877 AssertRC(rc);
1878 }
1879 else if (!RTStrICmp(pszIoLogType, "Client"))
1880 {
1881 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "IoLogAddress", &pszAddress);
1882 AssertRC(rc);
1883 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "IoLogPort", &uPort, 4000);
1884 AssertRC(rc);
1885 }
1886 else
1887 AssertMsgFailed(("Invalid I/O log type given: %s\n", pszIoLogType));
1888 }
1889 else
1890 Assert(rc == VERR_CFGM_VALUE_NOT_FOUND);
1891
1892 /*
1893 * Initialize most of the data members.
1894 */
1895 pThis->pDrvIns = pDrvIns;
1896 pThis->hReqCache = NIL_RTMEMCACHE;
1897
1898 /* IBase. */
1899 pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
1900
1901 /* IMedia */
1902 pThis->IMedia.pfnRead = drvdiskintRead;
1903 pThis->IMedia.pfnWrite = drvdiskintWrite;
1904 pThis->IMedia.pfnFlush = drvdiskintFlush;
1905 pThis->IMedia.pfnGetSize = drvdiskintGetSize;
1906 pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
1907 pThis->IMedia.pfnBiosIsVisible = drvdiskintBiosIsVisible;
1908 pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
1909 pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
1910 pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
1911 pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
1912 pThis->IMedia.pfnGetUuid = drvdiskintGetUuid;
1913 pThis->IMedia.pfnGetSectorSize = drvdiskintGetSectorSize;
1914 pThis->IMedia.pfnGetType = drvdiskintGetType;
1915 pThis->IMedia.pfnReadPcBios = drvdiskintReadPcBios;
1916 pThis->IMedia.pfnIsNonRotational = drvdiskintIsNonRotational;
1917 pThis->IMedia.pfnSendCmd = NULL;
1918 pThis->IMedia.pfnGetRegionCount = drvdiskintGetRegionCount;
1919 pThis->IMedia.pfnQueryRegionProperties = drvdiskintQueryRegionProperties;
1920 pThis->IMedia.pfnQueryRegionPropertiesForLba = drvdiskintQueryRegionPropertiesForLba;
1921
1922
1923 /* IMediaEx. */
1924 pThis->IMediaEx.pfnQueryFeatures = drvdiskintQueryFeatures;
1925 pThis->IMediaEx.pfnNotifySuspend = drvdiskintNotifySuspend;
1926 pThis->IMediaEx.pfnIoReqAllocSizeSet = drvdiskintIoReqAllocSizeSet;
1927 pThis->IMediaEx.pfnIoReqAlloc = drvdiskintIoReqAlloc;
1928 pThis->IMediaEx.pfnIoReqFree = drvdiskintIoReqFree;
1929 pThis->IMediaEx.pfnIoReqQueryResidual = drvdiskintIoReqQueryResidual;
1930 pThis->IMediaEx.pfnIoReqQueryXferSize = drvdiskintIoReqQueryXferSize;
1931 pThis->IMediaEx.pfnIoReqCancelAll = drvdiskintIoReqCancelAll;
1932 pThis->IMediaEx.pfnIoReqCancel = drvdiskintIoReqCancel;
1933 pThis->IMediaEx.pfnIoReqRead = drvdiskintIoReqRead;
1934 pThis->IMediaEx.pfnIoReqWrite = drvdiskintIoReqWrite;
1935 pThis->IMediaEx.pfnIoReqFlush = drvdiskintIoReqFlush;
1936 pThis->IMediaEx.pfnIoReqDiscard = drvdiskintIoReqDiscard;
1937 pThis->IMediaEx.pfnIoReqGetActiveCount = drvdiskintIoReqGetActiveCount;
1938 pThis->IMediaEx.pfnIoReqGetSuspendedCount = drvdiskintIoReqGetSuspendedCount;
1939 pThis->IMediaEx.pfnIoReqQuerySuspendedStart = drvdiskintIoReqQuerySuspendedStart;
1940 pThis->IMediaEx.pfnIoReqQuerySuspendedNext = drvdiskintIoReqQuerySuspendedNext;
1941 pThis->IMediaEx.pfnIoReqSuspendedSave = drvdiskintIoReqSuspendedSave;
1942 pThis->IMediaEx.pfnIoReqSuspendedLoad = drvdiskintIoReqSuspendedLoad;
1943
1944 /* IMediaPort. */
1945 pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation;
1946
1947 /* IMediaExPort. */
1948 pThis->IMediaExPort.pfnIoReqCompleteNotify = drvdiskintIoReqCompleteNotify;
1949 pThis->IMediaExPort.pfnIoReqCopyFromBuf = drvdiskintIoReqCopyFromBuf;
1950 pThis->IMediaExPort.pfnIoReqCopyToBuf = drvdiskintIoReqCopyToBuf;
1951 pThis->IMediaExPort.pfnIoReqQueryDiscardRanges = drvdiskintIoReqQueryDiscardRanges;
1952 pThis->IMediaExPort.pfnIoReqStateChanged = drvdiskintIoReqStateChanged;
1953
1954 /* IMount */
1955 pThis->IMount.pfnUnmount = drvdiskintUnmount;
1956 pThis->IMount.pfnIsMounted = drvdiskintIsMounted;
1957 pThis->IMount.pfnLock = drvdiskintLock;
1958 pThis->IMount.pfnUnlock = drvdiskintUnlock;
1959 pThis->IMount.pfnIsLocked = drvdiskintIsLocked;
1960
1961 /* IMountNotify */
1962 pThis->IMountNotify.pfnMountNotify = drvdiskintMountNotify;
1963 pThis->IMountNotify.pfnUnmountNotify = drvdiskintUnmountNotify;
1964
1965 /* Query the media port interface above us. */
1966 pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
1967 if (!pThis->pDrvMediaPort)
1968 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1969 N_("No media port interface above"));
1970
1971 /* Try to attach extended media port interface above.*/
1972 pThis->pDrvMediaExPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAEXPORT);
1973
1974 rc = RTMemCacheCreate(&pThis->hReqCache, sizeof(DRVDISKAIOREQ), 0, UINT32_MAX,
1975 NULL, NULL, NULL, 0);
1976 if (RT_FAILURE(rc))
1977 return PDMDRV_SET_ERROR(pDrvIns, rc,
1978 N_("Failed to create request tracking structure cache"));
1979
1980 /*
1981 * Try attach driver below and query it's media interface.
1982 */
1983 PPDMIBASE pBase;
1984 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
1985 if (RT_FAILURE(rc))
1986 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1987 N_("Failed to attach driver below us! %Rrc"), rc);
1988
1989 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
1990 if (!pThis->pDrvMedia)
1991 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1992 N_("No media or async media interface below"));
1993
1994 pThis->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAEX);
1995 pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
1996
1997 if (pThis->pDrvMedia->pfnDiscard)
1998 pThis->IMedia.pfnDiscard = drvdiskintDiscard;
1999
2000 if (pThis->fCheckConsistency)
2001 {
2002 /* Create the AVL tree. */
2003 pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
2004 if (!pThis->pTreeSegments)
2005 rc = VERR_NO_MEMORY;
2006 }
2007
2008 if (pThis->fTraceRequests)
2009 {
2010 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
2011 {
2012 pThis->apReqActive[i].pIoReq = NULL;
2013 pThis->apReqActive[i].tsStart = 0;
2014 }
2015
2016 pThis->iNextFreeSlot = 0;
2017
2018 /* Init event semaphore. */
2019 rc = RTSemEventCreate(&pThis->SemEvent);
2020 AssertRC(rc);
2021 pThis->fRunning = true;
2022 rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
2023 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
2024 AssertRC(rc);
2025 }
2026
2027 if (pThis->fCheckDoubleCompletion)
2028 {
2029 pThis->iEntry = 0;
2030 pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
2031 AssertPtr(pThis->papIoReq);
2032 }
2033
2034 if (pszIoLogType)
2035 {
2036 if (!RTStrICmp(pszIoLogType, "File"))
2037 {
2038 rc = RTTraceLogWrCreateFile(&pThis->hIoLogger, NULL, pszIoLogFilename);
2039 PDMDrvHlpMMHeapFree(pDrvIns, pszIoLogFilename);
2040 }
2041 else if (!RTStrICmp(pszIoLogType, "Server"))
2042 {
2043 rc = RTTraceLogWrCreateTcpServer(&pThis->hIoLogger, NULL, pszAddress, uPort);
2044 if (pszAddress)
2045 PDMDrvHlpMMHeapFree(pDrvIns, pszAddress);
2046 }
2047 else if (!RTStrICmp(pszIoLogType, "Client"))
2048 {
2049 rc = RTTraceLogWrCreateTcpClient(&pThis->hIoLogger, NULL, pszAddress, uPort);
2050 PDMDrvHlpMMHeapFree(pDrvIns, pszAddress);
2051 }
2052 else
2053 AssertMsgFailed(("Invalid I/O log type given: %s\n", pszIoLogType));
2054
2055 PDMDrvHlpMMHeapFree(pDrvIns, pszIoLogType);
2056 }
2057
2058 /* Read in all data before the start if requested. */
2059 if (pThis->fPrepopulateRamDisk)
2060 {
2061 uint64_t cbDisk = 0;
2062
2063 LogRel(("DiskIntegrity: Prepopulating RAM disk, this will take some time...\n"));
2064
2065 cbDisk = pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
2066 if (cbDisk)
2067 {
2068 uint64_t off = 0;
2069 uint8_t abBuffer[_64K];
2070 RTSGSEG Seg;
2071
2072 Seg.pvSeg = abBuffer;
2073
2074 while (cbDisk)
2075 {
2076 size_t cbThisRead = RT_MIN(cbDisk, sizeof(abBuffer));
2077
2078 rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, abBuffer, cbThisRead);
2079 if (RT_FAILURE(rc))
2080 break;
2081
2082 if (ASMBitFirstSet(abBuffer, sizeof(abBuffer) * 8) != -1)
2083 {
2084 Seg.cbSeg = cbThisRead;
2085 rc = drvdiskintWriteRecord(pThis, &Seg, 1,
2086 off, cbThisRead);
2087 if (RT_FAILURE(rc))
2088 break;
2089 }
2090
2091 cbDisk -= cbThisRead;
2092 off += cbThisRead;
2093 }
2094
2095 LogRel(("DiskIntegrity: Prepopulating RAM disk finished with %Rrc\n", rc));
2096 }
2097 else
2098 return PDMDRV_SET_ERROR(pDrvIns, VERR_INTERNAL_ERROR,
2099 N_("DiskIntegrity: Error querying the media size below"));
2100 }
2101
2102 return rc;
2103}
2104
2105
2106/**
2107 * Block driver registration record.
2108 */
2109const PDMDRVREG g_DrvDiskIntegrity =
2110{
2111 /* u32Version */
2112 PDM_DRVREG_VERSION,
2113 /* szName */
2114 "DiskIntegrity",
2115 /* szRCMod */
2116 "",
2117 /* szR0Mod */
2118 "",
2119 /* pszDescription */
2120 "Disk integrity driver.",
2121 /* fFlags */
2122 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
2123 /* fClass. */
2124 PDM_DRVREG_CLASS_BLOCK,
2125 /* cMaxInstances */
2126 ~0U,
2127 /* cbInstance */
2128 sizeof(DRVDISKINTEGRITY),
2129 /* pfnConstruct */
2130 drvdiskintConstruct,
2131 /* pfnDestruct */
2132 drvdiskintDestruct,
2133 /* pfnRelocate */
2134 NULL,
2135 /* pfnIOCtl */
2136 NULL,
2137 /* pfnPowerOn */
2138 NULL,
2139 /* pfnReset */
2140 NULL,
2141 /* pfnSuspend */
2142 NULL,
2143 /* pfnResume */
2144 NULL,
2145 /* pfnAttach */
2146 NULL,
2147 /* pfnDetach */
2148 NULL,
2149 /* pfnPowerOff */
2150 NULL,
2151 /* pfnSoftReset */
2152 NULL,
2153 /* u32EndVersion */
2154 PDM_DRVREG_VERSION
2155};
2156
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