VirtualBox

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

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

Storage/DrvDiskIntegrity: Start integration to work with the extended media interface

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