VirtualBox

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

Last change on this file since 63942 was 63727, checked in by vboxsync, 8 years ago

DiskIntegrity: Updates to handle the PDMIMEDIAEX interface

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