VirtualBox

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

Last change on this file since 72312 was 72312, checked in by vboxsync, 7 years ago

Build fix attempt for 32bit Windows

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette