VirtualBox

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

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

DrvDiskIntegrity: Add async flag to indicate whether a request used the sync or async path

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