VirtualBox

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

Last change on this file since 86075 was 83042, checked in by vboxsync, 5 years ago

Devices/Storage/DrvDiskIntegrity: Implement some additional interface callbacks to make the driver work again

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.3 KB
Line 
1/* $Id: DrvDiskIntegrity.cpp 83042 2020-02-10 17:28:23Z 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 int rc = VINF_SUCCESS;
1810 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1811 LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
1812 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1813
1814 /*
1815 * Validate configuration.
1816 */
1817 if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
1818 "TraceRequests\0"
1819 "CheckIntervalMs\0"
1820 "ExpireIntervalMs\0"
1821 "CheckDoubleCompletions\0"
1822 "HistorySize\0"
1823 "IoLogType\0"
1824 "IoLogFile\0"
1825 "IoLogAddress\0"
1826 "IoLogPort\0"
1827 "IoLogData\0"
1828 "PrepopulateRamDisk\0"
1829 "ReadAfterWrite\0"
1830 "RecordWriteBeforeCompletion\0"
1831 "ValidateMemoryBuffers\0"))
1832 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1833
1834 rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
1835 AssertRC(rc);
1836 rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
1837 AssertRC(rc);
1838 rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
1839 AssertRC(rc);
1840 rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
1841 AssertRC(rc);
1842 rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
1843 AssertRC(rc);
1844 rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
1845 AssertRC(rc);
1846 rc = CFGMR3QueryBoolDef(pCfg, "PrepopulateRamDisk", &pThis->fPrepopulateRamDisk, false);
1847 AssertRC(rc);
1848 rc = CFGMR3QueryBoolDef(pCfg, "ReadAfterWrite", &pThis->fReadAfterWrite, false);
1849 AssertRC(rc);
1850 rc = CFGMR3QueryBoolDef(pCfg, "RecordWriteBeforeCompletion", &pThis->fRecordWriteBeforeCompletion, false);
1851 AssertRC(rc);
1852 rc = CFGMR3QueryBoolDef(pCfg, "ValidateMemoryBuffers", &pThis->fValidateMemBufs, false);
1853 AssertRC(rc);
1854
1855 bool fIoLogData = false;
1856 rc = CFGMR3QueryBoolDef(pCfg, "IoLogData", &fIoLogData, false);
1857 AssertRC(rc);
1858
1859 char *pszIoLogType = NULL;
1860 char *pszIoLogFilename = NULL;
1861 char *pszAddress = NULL;
1862 uint32_t uPort = 0;
1863 rc = CFGMR3QueryStringAlloc(pCfg, "IoLogType", &pszIoLogType);
1864 if (RT_SUCCESS(rc))
1865 {
1866 if (!RTStrICmp(pszIoLogType, "File"))
1867 {
1868 rc = CFGMR3QueryStringAlloc(pCfg, "IoLogFile", &pszIoLogFilename);
1869 AssertRC(rc);
1870 }
1871 else if (!RTStrICmp(pszIoLogType, "Server"))
1872 {
1873 rc = CFGMR3QueryStringAllocDef(pCfg, "IoLogAddress", &pszAddress, NULL);
1874 AssertRC(rc);
1875 rc = CFGMR3QueryU32Def(pCfg, "IoLogPort", &uPort, 4000);
1876 AssertRC(rc);
1877 }
1878 else if (!RTStrICmp(pszIoLogType, "Client"))
1879 {
1880 rc = CFGMR3QueryStringAlloc(pCfg, "IoLogAddress", &pszAddress);
1881 AssertRC(rc);
1882 rc = CFGMR3QueryU32Def(pCfg, "IoLogPort", &uPort, 4000);
1883 AssertRC(rc);
1884 }
1885 else
1886 AssertMsgFailed(("Invalid I/O log type given: %s\n", pszIoLogType));
1887 }
1888 else
1889 Assert(rc == VERR_CFGM_VALUE_NOT_FOUND);
1890
1891 /*
1892 * Initialize most of the data members.
1893 */
1894 pThis->pDrvIns = pDrvIns;
1895 pThis->hReqCache = NIL_RTMEMCACHE;
1896
1897 /* IBase. */
1898 pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
1899
1900 /* IMedia */
1901 pThis->IMedia.pfnRead = drvdiskintRead;
1902 pThis->IMedia.pfnWrite = drvdiskintWrite;
1903 pThis->IMedia.pfnFlush = drvdiskintFlush;
1904 pThis->IMedia.pfnGetSize = drvdiskintGetSize;
1905 pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
1906 pThis->IMedia.pfnBiosIsVisible = drvdiskintBiosIsVisible;
1907 pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
1908 pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
1909 pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
1910 pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
1911 pThis->IMedia.pfnGetUuid = drvdiskintGetUuid;
1912 pThis->IMedia.pfnGetSectorSize = drvdiskintGetSectorSize;
1913 pThis->IMedia.pfnGetType = drvdiskintGetType;
1914 pThis->IMedia.pfnReadPcBios = drvdiskintReadPcBios;
1915 pThis->IMedia.pfnIsNonRotational = drvdiskintIsNonRotational;
1916 pThis->IMedia.pfnSendCmd = NULL;
1917 pThis->IMedia.pfnGetRegionCount = drvdiskintGetRegionCount;
1918 pThis->IMedia.pfnQueryRegionProperties = drvdiskintQueryRegionProperties;
1919 pThis->IMedia.pfnQueryRegionPropertiesForLba = drvdiskintQueryRegionPropertiesForLba;
1920
1921
1922 /* IMediaEx. */
1923 pThis->IMediaEx.pfnQueryFeatures = drvdiskintQueryFeatures;
1924 pThis->IMediaEx.pfnNotifySuspend = drvdiskintNotifySuspend;
1925 pThis->IMediaEx.pfnIoReqAllocSizeSet = drvdiskintIoReqAllocSizeSet;
1926 pThis->IMediaEx.pfnIoReqAlloc = drvdiskintIoReqAlloc;
1927 pThis->IMediaEx.pfnIoReqFree = drvdiskintIoReqFree;
1928 pThis->IMediaEx.pfnIoReqQueryResidual = drvdiskintIoReqQueryResidual;
1929 pThis->IMediaEx.pfnIoReqQueryXferSize = drvdiskintIoReqQueryXferSize;
1930 pThis->IMediaEx.pfnIoReqCancelAll = drvdiskintIoReqCancelAll;
1931 pThis->IMediaEx.pfnIoReqCancel = drvdiskintIoReqCancel;
1932 pThis->IMediaEx.pfnIoReqRead = drvdiskintIoReqRead;
1933 pThis->IMediaEx.pfnIoReqWrite = drvdiskintIoReqWrite;
1934 pThis->IMediaEx.pfnIoReqFlush = drvdiskintIoReqFlush;
1935 pThis->IMediaEx.pfnIoReqDiscard = drvdiskintIoReqDiscard;
1936 pThis->IMediaEx.pfnIoReqGetActiveCount = drvdiskintIoReqGetActiveCount;
1937 pThis->IMediaEx.pfnIoReqGetSuspendedCount = drvdiskintIoReqGetSuspendedCount;
1938 pThis->IMediaEx.pfnIoReqQuerySuspendedStart = drvdiskintIoReqQuerySuspendedStart;
1939 pThis->IMediaEx.pfnIoReqQuerySuspendedNext = drvdiskintIoReqQuerySuspendedNext;
1940 pThis->IMediaEx.pfnIoReqSuspendedSave = drvdiskintIoReqSuspendedSave;
1941 pThis->IMediaEx.pfnIoReqSuspendedLoad = drvdiskintIoReqSuspendedLoad;
1942
1943 /* IMediaPort. */
1944 pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation;
1945
1946 /* IMediaExPort. */
1947 pThis->IMediaExPort.pfnIoReqCompleteNotify = drvdiskintIoReqCompleteNotify;
1948 pThis->IMediaExPort.pfnIoReqCopyFromBuf = drvdiskintIoReqCopyFromBuf;
1949 pThis->IMediaExPort.pfnIoReqCopyToBuf = drvdiskintIoReqCopyToBuf;
1950 pThis->IMediaExPort.pfnIoReqQueryDiscardRanges = drvdiskintIoReqQueryDiscardRanges;
1951 pThis->IMediaExPort.pfnIoReqStateChanged = drvdiskintIoReqStateChanged;
1952
1953 /* IMount */
1954 pThis->IMount.pfnUnmount = drvdiskintUnmount;
1955 pThis->IMount.pfnIsMounted = drvdiskintIsMounted;
1956 pThis->IMount.pfnLock = drvdiskintLock;
1957 pThis->IMount.pfnUnlock = drvdiskintUnlock;
1958 pThis->IMount.pfnIsLocked = drvdiskintIsLocked;
1959
1960 /* IMountNotify */
1961 pThis->IMountNotify.pfnMountNotify = drvdiskintMountNotify;
1962 pThis->IMountNotify.pfnUnmountNotify = drvdiskintUnmountNotify;
1963
1964 /* Query the media port interface above us. */
1965 pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
1966 if (!pThis->pDrvMediaPort)
1967 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1968 N_("No media port interface above"));
1969
1970 /* Try to attach extended media port interface above.*/
1971 pThis->pDrvMediaExPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAEXPORT);
1972
1973 rc = RTMemCacheCreate(&pThis->hReqCache, sizeof(DRVDISKAIOREQ), 0, UINT32_MAX,
1974 NULL, NULL, NULL, 0);
1975 if (RT_FAILURE(rc))
1976 return PDMDRV_SET_ERROR(pDrvIns, rc,
1977 N_("Failed to create request tracking structure cache"));
1978
1979 /*
1980 * Try attach driver below and query it's media interface.
1981 */
1982 PPDMIBASE pBase;
1983 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
1984 if (RT_FAILURE(rc))
1985 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1986 N_("Failed to attach driver below us! %Rrc"), rc);
1987
1988 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
1989 if (!pThis->pDrvMedia)
1990 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1991 N_("No media or async media interface below"));
1992
1993 pThis->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAEX);
1994 pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMOUNT);
1995
1996 if (pThis->pDrvMedia->pfnDiscard)
1997 pThis->IMedia.pfnDiscard = drvdiskintDiscard;
1998
1999 if (pThis->fCheckConsistency)
2000 {
2001 /* Create the AVL tree. */
2002 pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
2003 if (!pThis->pTreeSegments)
2004 rc = VERR_NO_MEMORY;
2005 }
2006
2007 if (pThis->fTraceRequests)
2008 {
2009 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
2010 {
2011 pThis->apReqActive[i].pIoReq = NULL;
2012 pThis->apReqActive[i].tsStart = 0;
2013 }
2014
2015 pThis->iNextFreeSlot = 0;
2016
2017 /* Init event semaphore. */
2018 rc = RTSemEventCreate(&pThis->SemEvent);
2019 AssertRC(rc);
2020 pThis->fRunning = true;
2021 rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
2022 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
2023 AssertRC(rc);
2024 }
2025
2026 if (pThis->fCheckDoubleCompletion)
2027 {
2028 pThis->iEntry = 0;
2029 pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
2030 AssertPtr(pThis->papIoReq);
2031 }
2032
2033 if (pszIoLogType)
2034 {
2035 if (!RTStrICmp(pszIoLogType, "File"))
2036 {
2037 rc = RTTraceLogWrCreateFile(&pThis->hIoLogger, NULL, pszIoLogFilename);
2038 MMR3HeapFree(pszIoLogFilename);
2039 }
2040 else if (!RTStrICmp(pszIoLogType, "Server"))
2041 {
2042 rc = RTTraceLogWrCreateTcpServer(&pThis->hIoLogger, NULL, pszAddress, uPort);
2043 if (pszAddress)
2044 MMR3HeapFree(pszAddress);
2045 }
2046 else if (!RTStrICmp(pszIoLogType, "Client"))
2047 {
2048 rc = RTTraceLogWrCreateTcpClient(&pThis->hIoLogger, NULL, pszAddress, uPort);
2049 MMR3HeapFree(pszAddress);
2050 }
2051 else
2052 AssertMsgFailed(("Invalid I/O log type given: %s\n", pszIoLogType));
2053
2054 MMR3HeapFree(pszIoLogType);
2055 }
2056
2057 /* Read in all data before the start if requested. */
2058 if (pThis->fPrepopulateRamDisk)
2059 {
2060 uint64_t cbDisk = 0;
2061
2062 LogRel(("DiskIntegrity: Prepopulating RAM disk, this will take some time...\n"));
2063
2064 cbDisk = pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
2065 if (cbDisk)
2066 {
2067 uint64_t off = 0;
2068 uint8_t abBuffer[_64K];
2069 RTSGSEG Seg;
2070
2071 Seg.pvSeg = abBuffer;
2072
2073 while (cbDisk)
2074 {
2075 size_t cbThisRead = RT_MIN(cbDisk, sizeof(abBuffer));
2076
2077 rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, abBuffer, cbThisRead);
2078 if (RT_FAILURE(rc))
2079 break;
2080
2081 if (ASMBitFirstSet(abBuffer, sizeof(abBuffer) * 8) != -1)
2082 {
2083 Seg.cbSeg = cbThisRead;
2084 rc = drvdiskintWriteRecord(pThis, &Seg, 1,
2085 off, cbThisRead);
2086 if (RT_FAILURE(rc))
2087 break;
2088 }
2089
2090 cbDisk -= cbThisRead;
2091 off += cbThisRead;
2092 }
2093
2094 LogRel(("DiskIntegrity: Prepopulating RAM disk finished with %Rrc\n", rc));
2095 }
2096 else
2097 return PDMDRV_SET_ERROR(pDrvIns, VERR_INTERNAL_ERROR,
2098 N_("DiskIntegrity: Error querying the media size below"));
2099 }
2100
2101 return rc;
2102}
2103
2104
2105/**
2106 * Block driver registration record.
2107 */
2108const PDMDRVREG g_DrvDiskIntegrity =
2109{
2110 /* u32Version */
2111 PDM_DRVREG_VERSION,
2112 /* szName */
2113 "DiskIntegrity",
2114 /* szRCMod */
2115 "",
2116 /* szR0Mod */
2117 "",
2118 /* pszDescription */
2119 "Disk integrity driver.",
2120 /* fFlags */
2121 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
2122 /* fClass. */
2123 PDM_DRVREG_CLASS_BLOCK,
2124 /* cMaxInstances */
2125 ~0U,
2126 /* cbInstance */
2127 sizeof(DRVDISKINTEGRITY),
2128 /* pfnConstruct */
2129 drvdiskintConstruct,
2130 /* pfnDestruct */
2131 drvdiskintDestruct,
2132 /* pfnRelocate */
2133 NULL,
2134 /* pfnIOCtl */
2135 NULL,
2136 /* pfnPowerOn */
2137 NULL,
2138 /* pfnReset */
2139 NULL,
2140 /* pfnSuspend */
2141 NULL,
2142 /* pfnResume */
2143 NULL,
2144 /* pfnAttach */
2145 NULL,
2146 /* pfnDetach */
2147 NULL,
2148 /* pfnPowerOff */
2149 NULL,
2150 /* pfnSoftReset */
2151 NULL,
2152 /* u32EndVersion */
2153 PDM_DRVREG_VERSION
2154};
2155
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