VirtualBox

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

最後變更 在這個檔案從72310是 72310,由 vboxsync 提交於 7 年 前

Devices/Storage: Convert DrvDiskIntegrity to use the new trace log file format and remove use of VDDbg

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 72.0 KB
 
1/* $Id: DrvDiskIntegrity.cpp 72310 2018-05-24 07:29:35Z 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.alldomusa.eu.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 { "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, RTTRACELOGEVTGRPID 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, uGrp, 0, off, cbRead);
766 AssertRC(rc);
767 }
768}
769
770
771/**
772 * Fires a write event if enabled.
773 *
774 * @returns nothing.
775 * @param pThis The driver instance data.
776 * @param uGrp The group ID.
777 * @param off The offset to put into the event log.
778 * @param cbWrite Amount of bytes to write.
779 */
780DECLINLINE(void) drvdiskintTraceLogFireEvtWrite(PDRVDISKINTEGRITY pThis, RTTRACELOGEVTGRPID uGrp, uint64_t off, size_t cbWrite)
781{
782 if (pThis->hIoLogger)
783 {
784 int rc = RTTraceLogWrEvtAddL(pThis->hIoLogger, &g_EvtWrite, RTTRACELOG_WR_ADD_EVT_F_GRP_START, uGrp, 0, off, cbWrite);
785 AssertRC(rc);
786 }
787}
788
789
790/**
791 * Fires a flush event if enabled.
792 *
793 * @returns nothing.
794 * @param pThis The driver instance data.
795 * @param uGrp The group ID.
796 */
797DECLINLINE(void) drvdiskintTraceLogFireEvtFlush(PDRVDISKINTEGRITY pThis, RTTRACELOGEVTGRPID uGrp)
798{
799 if (pThis->hIoLogger)
800 {
801 int rc = RTTraceLogWrEvtAddL(pThis->hIoLogger, &g_EvtFlush, RTTRACELOG_WR_ADD_EVT_F_GRP_START, uGrp, 0);
802 AssertRC(rc);
803 }
804}
805
806
807/**
808 * Fires a request complete event if enabled.
809 *
810 * @returns nothing.
811 * @param pThis The driver instance data.
812 * @param uGrp The group ID.
813 * @param pSgBuf The S/G buffer holding the data.
814 */
815DECLINLINE(void) drvdiskintTraceLogFireEvtComplete(PDRVDISKINTEGRITY pThis, RTTRACELOGEVTGRPID uGrp, int rcReq, PRTSGBUF pSgBuf)
816{
817 RT_NOREF(pSgBuf);
818
819 if (pThis->hIoLogger)
820 {
821 int rc = RTTraceLogWrEvtAddL(pThis->hIoLogger, &g_EvtComplete, RTTRACELOG_WR_ADD_EVT_F_GRP_FINISH, uGrp, 0, rcReq);
822 AssertRC(rc);
823 }
824}
825
826
827/* -=-=-=-=- IMedia -=-=-=-=- */
828
829/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIA. */
830#define PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMedia)) )
831
832
833/*********************************************************************************************************************************
834* Media interface methods *
835*********************************************************************************************************************************/
836
837
838/** @interface_method_impl{PDMIMEDIA,pfnRead} */
839static DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
840 uint64_t off, void *pvBuf, size_t cbRead)
841{
842 int rc = VINF_SUCCESS;
843 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
844
845 drvdiskintTraceLogFireEvtRead(pThis, (RTTRACELOGEVTGRPID)pvBuf, off, cbRead);
846 rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
847
848 if (pThis->hIoLogger)
849 {
850 RTSGSEG Seg;
851 RTSGBUF SgBuf;
852
853 Seg.pvSeg = pvBuf;
854 Seg.cbSeg = cbRead;
855 RTSgBufInit(&SgBuf, &Seg, 1);
856 drvdiskintTraceLogFireEvtComplete(pThis, (RTTRACELOGEVTGRPID)pvBuf, rc, &SgBuf);
857 }
858
859 if (RT_FAILURE(rc))
860 return rc;
861
862 if (pThis->fCheckConsistency)
863 {
864 /* Verify the read. */
865 RTSGSEG Seg;
866 Seg.cbSeg = cbRead;
867 Seg.pvSeg = pvBuf;
868 rc = drvdiskintReadVerify(pThis, &Seg, 1, off, cbRead);
869 }
870
871 return rc;
872}
873
874/** @interface_method_impl{PDMIMEDIA,pfnWrite} */
875static DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
876 uint64_t off, const void *pvBuf,
877 size_t cbWrite)
878{
879 int rc = VINF_SUCCESS;
880 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
881
882 drvdiskintTraceLogFireEvtWrite(pThis, (RTTRACELOGEVTGRPID)pvBuf, off, cbWrite);
883
884 if (pThis->fRecordWriteBeforeCompletion)
885 {
886 RTSGSEG Seg;
887 Seg.cbSeg = cbWrite;
888 Seg.pvSeg = (void *)pvBuf;
889
890 rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
891 if (RT_FAILURE(rc))
892 return rc;
893 }
894
895 rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
896
897 drvdiskintTraceLogFireEvtComplete(pThis, (RTTRACELOGEVTGRPID)pvBuf, rc, NULL);
898 if (RT_FAILURE(rc))
899 return rc;
900
901 if ( pThis->fCheckConsistency
902 && !pThis->fRecordWriteBeforeCompletion)
903 {
904 /* Record the write. */
905 RTSGSEG Seg;
906 Seg.cbSeg = cbWrite;
907 Seg.pvSeg = (void *)pvBuf;
908 rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
909 }
910
911 return rc;
912}
913
914/** @interface_method_impl{PDMIMEDIA,pfnFlush} */
915static DECLCALLBACK(int) drvdiskintFlush(PPDMIMEDIA pInterface)
916{
917 int rc = VINF_SUCCESS;
918 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
919
920 drvdiskintTraceLogFireEvtFlush(pThis, 1);
921 rc = pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
922 drvdiskintTraceLogFireEvtComplete(pThis, 1, rc, NULL);
923
924 return rc;
925}
926
927/** @interface_method_impl{PDMIMEDIA,pfnGetSize} */
928static DECLCALLBACK(uint64_t) drvdiskintGetSize(PPDMIMEDIA pInterface)
929{
930 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
931 return pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
932}
933
934/** @interface_method_impl{PDMIMEDIA,pfnIsReadOnly} */
935static DECLCALLBACK(bool) drvdiskintIsReadOnly(PPDMIMEDIA pInterface)
936{
937 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
938 return pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
939}
940
941/** @interface_method_impl{PDMIMEDIA,pfnBiosIsVisible} */
942static DECLCALLBACK(bool) drvdiskintBiosIsVisible(PPDMIMEDIA pInterface)
943{
944 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
945 return pThis->pDrvMedia->pfnBiosIsVisible(pThis->pDrvMedia);
946}
947
948/** @interface_method_impl{PDMIMEDIA,pfnGetType} */
949static DECLCALLBACK(PDMMEDIATYPE) drvdiskintGetType(PPDMIMEDIA pInterface)
950{
951 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
952 return pThis->pDrvMedia->pfnGetType(pThis->pDrvMedia);
953}
954
955/** @interface_method_impl{PDMIMEDIA,pfnBiosGetPCHSGeometry} */
956static DECLCALLBACK(int) drvdiskintBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
957 PPDMMEDIAGEOMETRY pPCHSGeometry)
958{
959 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
960 return pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
961}
962
963/** @interface_method_impl{PDMIMEDIA,pfnBiosSetPCHSGeometry} */
964static DECLCALLBACK(int) drvdiskintBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
965 PCPDMMEDIAGEOMETRY pPCHSGeometry)
966{
967 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
968 return pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
969}
970
971/** @interface_method_impl{PDMIMEDIA,pfnBiosGetLCHSGeometry} */
972static DECLCALLBACK(int) drvdiskintBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
973 PPDMMEDIAGEOMETRY pLCHSGeometry)
974{
975 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
976 return pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
977}
978
979/** @interface_method_impl{PDMIMEDIA,pfnBiosSetLCHSGeometry} */
980static DECLCALLBACK(int) drvdiskintBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
981 PCPDMMEDIAGEOMETRY pLCHSGeometry)
982{
983 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
984 return pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
985}
986
987/** @interface_method_impl{PDMIMEDIA,pfnGetUuid} */
988static DECLCALLBACK(int) drvdiskintGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
989{
990 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
991 return pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, pUuid);
992}
993
994/** @interface_method_impl{PDMIMEDIA,pfnGetSectorSize} */
995static DECLCALLBACK(uint32_t) drvdiskintGetSectorSize(PPDMIMEDIA pInterface)
996{
997 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
998 return pThis->pDrvMedia->pfnGetSectorSize(pThis->pDrvMedia);
999}
1000
1001/** @interface_method_impl{PDMIMEDIA,pfnDiscard} */
1002static DECLCALLBACK(int) drvdiskintDiscard(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges)
1003{
1004 int rc = VINF_SUCCESS;
1005 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1006
1007 rc = pThis->pDrvMedia->pfnDiscard(pThis->pDrvMedia, paRanges, cRanges);
1008 drvdiskintTraceLogFireEvtComplete(pThis, (RTTRACELOGEVTGRPID)paRanges, rc, NULL);
1009
1010 if (pThis->fCheckConsistency)
1011 rc = drvdiskintDiscardRecords(pThis, paRanges, cRanges);
1012
1013 return rc;
1014}
1015
1016/** @interface_method_impl{PDMIMEDIA,pfnReadPcBios} */
1017static DECLCALLBACK(int) drvdiskintReadPcBios(PPDMIMEDIA pInterface,
1018 uint64_t off, void *pvBuf, size_t cbRead)
1019{
1020 LogFlowFunc(("\n"));
1021 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1022
1023 return pThis->pDrvMedia->pfnReadPcBios(pThis->pDrvMedia, off, pvBuf, cbRead);
1024}
1025
1026/** @interface_method_impl{PDMIMEDIA,pfnIsNonRotational} */
1027static DECLCALLBACK(bool) drvdiskintIsNonRotational(PPDMIMEDIA pInterface)
1028{
1029 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
1030 return pThis->pDrvMedia->pfnIsNonRotational(pThis->pDrvMedia);
1031}
1032
1033/* -=-=-=-=- IMediaPort -=-=-=-=- */
1034
1035/** Makes a PDRVBLOCK out of a PPDMIMEDIAPORT. */
1036#define PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaPort))) )
1037
1038/**
1039 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
1040 */
1041static DECLCALLBACK(int) drvdiskintQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
1042 uint32_t *piInstance, uint32_t *piLUN)
1043{
1044 PDRVDISKINTEGRITY pThis = PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface);
1045
1046 return pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, ppcszController,
1047 piInstance, piLUN);
1048}
1049
1050/* -=-=-=-=- IMediaExPort -=-=-=-=- */
1051
1052/**
1053 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
1054 */
1055static DECLCALLBACK(int) drvdiskintIoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1056 void *pvIoReqAlloc, int rcReq)
1057{
1058 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1059 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_ALLOC_2_DRVDISKAIOREQ(pvIoReqAlloc);
1060 int rc = VINF_SUCCESS;
1061
1062 LogFlowFunc(("pIoReq=%#p\n", pIoReq));
1063
1064 /* Remove from the active list. */
1065 if (pThis->fTraceRequests)
1066 drvdiskintIoReqRemove(pThis, pIoReq);
1067
1068 if (RT_SUCCESS(rcReq) && pThis->fCheckConsistency)
1069 {
1070 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1071 rc = drvdiskintReadVerify(pThis, &pIoReq->IoSeg, 1, pIoReq->off, pIoReq->cbTransfer);
1072 else if ( pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE
1073 && !pThis->fRecordWriteBeforeCompletion)
1074 rc = drvdiskintWriteRecord(pThis, &pIoReq->IoSeg, 1, pIoReq->off, pIoReq->cbTransfer);
1075 else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_DISCARD)
1076 rc = drvdiskintDiscardRecords(pThis, pIoReq->paRanges, pIoReq->cRanges);
1077 else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ_AFTER_WRITE)
1078 rc = drvdiskintReadAfterWriteVerify(pThis, pIoReq);
1079 else
1080 AssertMsg( pIoReq->enmTxDir == DRVDISKAIOTXDIR_FLUSH
1081 || ( pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE
1082 && pThis->fRecordWriteBeforeCompletion), ("Huh?\n"));
1083
1084 AssertRC(rc);
1085 }
1086
1087 if ( RT_SUCCESS(rcReq)
1088 && pThis->fValidateMemBufs
1089 && pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1090 {
1091 /* Check that the guest memory buffer matches what was written. */
1092 RTSGSEG SegCmp;
1093 SegCmp.pvSeg = RTMemAlloc(pIoReq->cbTransfer);
1094 SegCmp.cbSeg = pIoReq->cbTransfer;
1095
1096 RTSGBUF SgBufCmp;
1097 RTSgBufInit(&SgBufCmp, &SegCmp, 1);
1098 rc = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, hIoReq,
1099 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1100 0, &SgBufCmp, pIoReq->cbTransfer);
1101 AssertRC(rc);
1102
1103 RTSGBUF SgBuf;
1104 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1105 if (RTSgBufCmp(&SgBuf, &SgBufCmp, pIoReq->cbTransfer))
1106 {
1107 RTMsgError("Corrupted memory buffer at offset %llu!\n", 0);
1108 RTAssertDebugBreak();
1109 }
1110
1111 RTMemFree(SegCmp.pvSeg);
1112 }
1113
1114 if (pThis->hIoLogger)
1115 {
1116 RTSGBUF SgBuf;
1117
1118 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1119 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1120 drvdiskintTraceLogFireEvtComplete(pThis, (RTTRACELOGEVTGRPID)hIoReq, rcReq, &SgBuf);
1121 }
1122
1123 if ( pThis->fReadAfterWrite
1124 && pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE)
1125 {
1126#if 0 /** @todo */
1127 pIoReq->enmTxDir = DRVDISKAIOTXDIR_READ_AFTER_WRITE;
1128
1129 /* Add again because it was removed above. */
1130 if (pThis->fTraceRequests)
1131 drvdiskintIoReqAdd(pThis, pIoReq);
1132
1133 rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, pIoReq->off, pIoReq->paSeg, pIoReq->cSeg,
1134 pIoReq->cbTransfer, pIoReq);
1135 if (rc == VINF_VD_ASYNC_IO_FINISHED)
1136 {
1137 rc = drvdiskintReadAfterWriteVerify(pThis, pIoReq);
1138
1139 if (pThis->fTraceRequests)
1140 drvdiskintIoReqRemove(pThis, pIoReq);
1141 RTMemFree(pIoReq);
1142 }
1143 else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
1144 rc = VINF_SUCCESS;
1145 else if (RT_FAILURE(rc))
1146 RTMemFree(pIoReq);
1147#endif
1148 }
1149 else
1150 {
1151 rc = pThis->pDrvMediaExPort->pfnIoReqCompleteNotify(pThis->pDrvMediaExPort, hIoReq,
1152 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1153 rcReq);
1154 /* Put on the watch list. */
1155 if (pThis->fCheckDoubleCompletion)
1156 drvdiskintIoReqCheckForDoubleCompletion(pThis, pIoReq, true /* fMediaEx */);
1157 }
1158
1159 return rc;
1160}
1161
1162/**
1163 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
1164 */
1165static DECLCALLBACK(int) drvdiskintIoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1166 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
1167 size_t cbCopy)
1168{
1169 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1170 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_ALLOC_2_DRVDISKAIOREQ(pvIoReqAlloc);
1171 RTSGBUF SgBuf;
1172
1173 RTSgBufClone(&SgBuf, pSgBuf);
1174
1175 int rc = pThis->pDrvMediaExPort->pfnIoReqCopyFromBuf(pThis->pDrvMediaExPort, hIoReq,
1176 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1177 offDst, pSgBuf, cbCopy);
1178 if ( RT_SUCCESS(rc)
1179 && pIoReq->IoSeg.pvSeg)
1180 {
1181 /* Update our copy. */
1182 RTSgBufCopyToBuf(&SgBuf, (uint8_t *)pIoReq->IoSeg.pvSeg + offDst, cbCopy);
1183
1184 /* Validate the just read data against our copy if possible. */
1185 if ( pThis->fValidateMemBufs
1186 && pThis->fCheckConsistency
1187 && pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
1188 {
1189 RTSGSEG Seg;
1190
1191 Seg.pvSeg = (uint8_t *)pIoReq->IoSeg.pvSeg + offDst;
1192 Seg.cbSeg = cbCopy;
1193
1194 rc = drvdiskintReadVerify(pThis, &Seg, 1, pIoReq->off + offDst,
1195 cbCopy);
1196 }
1197 }
1198
1199 return rc;
1200}
1201
1202/**
1203 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
1204 */
1205static DECLCALLBACK(int) drvdiskintIoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1206 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
1207 size_t cbCopy)
1208{
1209 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1210 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_ALLOC_2_DRVDISKAIOREQ(pvIoReqAlloc);
1211 RTSGBUF SgBuf;
1212
1213 RTSgBufClone(&SgBuf, pSgBuf);
1214
1215 int rc = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, hIoReq,
1216 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1217 offSrc, pSgBuf, cbCopy);
1218 if ( RT_SUCCESS(rc)
1219 && pIoReq->IoSeg.pvSeg)
1220 {
1221 if (pThis->fValidateMemBufs)
1222 {
1223 /* Make sure what the caller requested matches what we got earlier. */
1224 RTSGBUF SgBufCmp;
1225 RTSgBufInit(&SgBufCmp, &pIoReq->IoSeg, 1);
1226 RTSgBufAdvance(&SgBufCmp, offSrc);
1227
1228 if (RTSgBufCmp(&SgBuf, &SgBufCmp, cbCopy))
1229 {
1230 RTMsgError("Corrupted memory buffer at offset %llu!\n", offSrc);
1231 RTAssertDebugBreak();
1232 }
1233 }
1234 else
1235 {
1236 /* Update our copy. */
1237 RTSgBufCopyToBuf(&SgBuf, (uint8_t *)pIoReq->IoSeg.pvSeg + offSrc, cbCopy);
1238 }
1239 }
1240
1241 return rc;
1242}
1243
1244/**
1245 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqQueryDiscardRanges}
1246 */
1247static DECLCALLBACK(int) drvdiskintIoReqQueryDiscardRanges(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1248 void *pvIoReqAlloc, uint32_t idxRangeStart,
1249 uint32_t cRanges, PRTRANGE paRanges,
1250 uint32_t *pcRanges)
1251{
1252 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1253 return pThis->pDrvMediaExPort->pfnIoReqQueryDiscardRanges(pThis->pDrvMediaExPort, hIoReq,
1254 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1255 idxRangeStart, cRanges, paRanges, pcRanges);
1256}
1257
1258/**
1259 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
1260 */
1261static DECLCALLBACK(void) drvdiskintIoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
1262 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
1263{
1264 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaExPort);
1265 pThis->pDrvMediaExPort->pfnIoReqStateChanged(pThis->pDrvMediaExPort, hIoReq,
1266 DISKINTEGRITY_IOREQ_ALLOC_2_UPPER(pvIoReqAlloc),
1267 enmState);
1268}
1269
1270/* -=-=-=-=- IMediaEx -=-=-=-=- */
1271
1272/**
1273 * @interface_method_impl{PDMIMEDIAEX,pfnQueryFeatures}
1274 */
1275static DECLCALLBACK(int) drvdiskintQueryFeatures(PPDMIMEDIAEX pInterface, uint32_t *pfFeatures)
1276{
1277 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1278 return pThis->pDrvMediaEx->pfnQueryFeatures(pThis->pDrvMediaEx, pfFeatures);
1279}
1280
1281/**
1282 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqAllocSizeSet}
1283 */
1284static DECLCALLBACK(int) drvdiskintIoReqAllocSizeSet(PPDMIMEDIAEX pInterface, size_t cbIoReqAlloc)
1285{
1286 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1287
1288 /* Increase the amount by the size of a pointer to our private tracking structure. */
1289 cbIoReqAlloc += sizeof(PDRVDISKAIOREQ);
1290
1291 pThis->fCheckDoubleCompletion = false;
1292
1293 return pThis->pDrvMediaEx->pfnIoReqAllocSizeSet(pThis->pDrvMediaEx, cbIoReqAlloc);
1294}
1295
1296/**
1297 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqAlloc}
1298 */
1299static DECLCALLBACK(int) drvdiskintIoReqAlloc(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc,
1300 PDMMEDIAEXIOREQID uIoReqId, uint32_t fFlags)
1301{
1302 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1303 int rc = VINF_SUCCESS;
1304 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)RTMemCacheAlloc(pThis->hReqCache);
1305 if (RT_LIKELY(pIoReq))
1306 {
1307 pIoReq->enmTxDir = DRVDISKAIOTXDIR_INVALID;
1308 pIoReq->off = 0;
1309 pIoReq->cbTransfer = 0;
1310 pIoReq->paSeg = NULL;
1311 pIoReq->cSeg = 0;
1312 pIoReq->pvUser = NULL;
1313 pIoReq->iSlot = 0;
1314 pIoReq->tsStart = 0;
1315 pIoReq->tsComplete = 0;
1316 pIoReq->IoSeg.pvSeg = NULL;
1317 pIoReq->IoSeg.cbSeg = 0;
1318
1319 PDRVDISKAIOREQ *ppIoReq = NULL;
1320 rc = pThis->pDrvMediaEx->pfnIoReqAlloc(pThis->pDrvMediaEx, phIoReq, (void **)&ppIoReq, uIoReqId, fFlags);
1321 if RT_SUCCESS(rc)
1322 {
1323 /*
1324 * Store the size off the start of our tracking structure because it is
1325 * required to access it for the read/write callbacks.
1326 *
1327 * ASSUMPTION that the offset is constant.
1328 */
1329 if (!pThis->cbIoReqOpaque)
1330 pThis->cbIoReqOpaque = (uintptr_t)ppIoReq - (uintptr_t)*phIoReq;
1331 else
1332 Assert(pThis->cbIoReqOpaque == (uintptr_t)ppIoReq - (uintptr_t)*phIoReq);
1333
1334 *ppIoReq = pIoReq;
1335 *ppvIoReqAlloc = ((uint8_t *)ppIoReq) + sizeof(PDRVDISKAIOREQ);
1336 }
1337 else
1338 RTMemCacheFree(pThis->hReqCache, pIoReq);
1339 }
1340 else
1341 rc = VERR_NO_MEMORY;
1342
1343 return rc;
1344}
1345
1346/**
1347 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqFree}
1348 */
1349static DECLCALLBACK(int) drvdiskintIoReqFree(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
1350{
1351 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1352 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1353
1354 if (pIoReq->IoSeg.pvSeg)
1355 RTMemFree(pIoReq->IoSeg.pvSeg);
1356
1357 return pThis->pDrvMediaEx->pfnIoReqFree(pThis->pDrvMediaEx, hIoReq);
1358}
1359
1360/**
1361 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryResidual}
1362 */
1363static DECLCALLBACK(int) drvdiskintIoReqQueryResidual(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbResidual)
1364{
1365 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1366 return pThis->pDrvMediaEx->pfnIoReqQueryResidual(pThis->pDrvMediaEx, hIoReq, pcbResidual);
1367}
1368
1369/**
1370 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryXferSize}
1371 */
1372static DECLCALLBACK(int) drvdiskintIoReqQueryXferSize(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbXfer)
1373{
1374 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1375 return pThis->pDrvMediaEx->pfnIoReqQueryXferSize(pThis->pDrvMediaEx, hIoReq, pcbXfer);
1376}
1377
1378/**
1379 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancelAll}
1380 */
1381static DECLCALLBACK(int) drvdiskintIoReqCancelAll(PPDMIMEDIAEX pInterface)
1382{
1383 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1384 return pThis->pDrvMediaEx->pfnIoReqCancelAll(pThis->pDrvMediaEx);
1385}
1386
1387/**
1388 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancel}
1389 */
1390static DECLCALLBACK(int) drvdiskintIoReqCancel(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQID uIoReqId)
1391{
1392 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1393 return pThis->pDrvMediaEx->pfnIoReqCancel(pThis->pDrvMediaEx, uIoReqId);
1394}
1395
1396/**
1397 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqRead}
1398 */
1399static DECLCALLBACK(int) drvdiskintIoReqRead(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbRead)
1400{
1401 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1402 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1403
1404 pIoReq->enmTxDir = DRVDISKAIOTXDIR_READ;
1405 pIoReq->off = off;
1406 pIoReq->cbTransfer = cbRead;
1407
1408 /* Allocate a I/O buffer if the I/O is verified.*/
1409 if (pThis->fCheckConsistency)
1410 {
1411 pIoReq->IoSeg.pvSeg = RTMemAlloc(cbRead);
1412 pIoReq->IoSeg.cbSeg = cbRead;
1413 }
1414
1415 if (pThis->fTraceRequests)
1416 drvdiskintIoReqAdd(pThis, pIoReq);
1417
1418 drvdiskintTraceLogFireEvtRead(pThis, (RTTRACELOGEVTGRPID)hIoReq, off, cbRead);
1419 int rc = pThis->pDrvMediaEx->pfnIoReqRead(pThis->pDrvMediaEx, hIoReq, off, cbRead);
1420 if (rc == VINF_SUCCESS)
1421 {
1422 /* Verify the read now. */
1423 if (pThis->fCheckConsistency)
1424 {
1425 int rc2 = drvdiskintReadVerify(pThis, &pIoReq->IoSeg, 1, off, cbRead);
1426 AssertRC(rc2);
1427 }
1428
1429 if (pThis->hIoLogger)
1430 {
1431 RTSGBUF SgBuf;
1432
1433 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1434 drvdiskintTraceLogFireEvtComplete(pThis, (RTTRACELOGEVTGRPID)hIoReq, rc, &SgBuf);
1435 }
1436
1437 if (pThis->fTraceRequests)
1438 drvdiskintIoReqRemove(pThis, pIoReq);
1439 }
1440 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1441 drvdiskintTraceLogFireEvtComplete(pThis, (RTTRACELOGEVTGRPID)hIoReq, rc, NULL);
1442
1443 LogFlowFunc(("returns %Rrc\n", rc));
1444 return rc;
1445}
1446
1447/**
1448 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqWrite}
1449 */
1450static DECLCALLBACK(int) drvdiskintIoReqWrite(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbWrite)
1451{
1452 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1453 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1454
1455 pIoReq->enmTxDir = DRVDISKAIOTXDIR_WRITE;
1456 pIoReq->off = off;
1457 pIoReq->cbTransfer = cbWrite;
1458
1459 /* Allocate a I/O buffer if the I/O is verified.*/
1460 if ( pThis->fCheckConsistency
1461 || pThis->fValidateMemBufs
1462 || pThis->hIoLogger
1463 || pThis->fRecordWriteBeforeCompletion)
1464 {
1465 pIoReq->IoSeg.pvSeg = RTMemAlloc(cbWrite);
1466 pIoReq->IoSeg.cbSeg = cbWrite;
1467
1468 /* Sync the memory buffer over if we should validate it. */
1469 if ( pThis->fValidateMemBufs
1470 || pThis->hIoLogger
1471 || pThis->fRecordWriteBeforeCompletion)
1472 {
1473 RTSGBUF SgBuf;
1474
1475 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1476 int rc2 = pThis->pDrvMediaExPort->pfnIoReqCopyToBuf(pThis->pDrvMediaExPort, hIoReq,
1477 DISKINTEGRITY_IOREQ_HANDLE_2_UPPER_OPAQUE(pThis, hIoReq),
1478 0, &SgBuf, cbWrite);
1479 AssertRC(rc2);
1480 }
1481 }
1482
1483 if (pThis->fTraceRequests)
1484 drvdiskintIoReqAdd(pThis, pIoReq);
1485
1486 drvdiskintTraceLogFireEvtWrite(pThis, (RTTRACELOGEVTGRPID)hIoReq, off, cbWrite);
1487 if (pThis->fRecordWriteBeforeCompletion)
1488 {
1489
1490 int rc2 = drvdiskintWriteRecord(pThis, &pIoReq->IoSeg, 1, off, cbWrite);
1491 AssertRC(rc2);
1492 }
1493
1494 int rc = pThis->pDrvMediaEx->pfnIoReqWrite(pThis->pDrvMediaEx, hIoReq, off, cbWrite);
1495 if (rc == VINF_SUCCESS)
1496 {
1497 /* Record the write. */
1498 if ( pThis->fCheckConsistency
1499 && !pThis->fRecordWriteBeforeCompletion)
1500 {
1501 int rc2 = drvdiskintWriteRecord(pThis, &pIoReq->IoSeg, 1, off, cbWrite);
1502 AssertRC(rc2);
1503 }
1504
1505 RTSGBUF SgBuf;
1506 RTSgBufInit(&SgBuf, &pIoReq->IoSeg, 1);
1507 drvdiskintTraceLogFireEvtComplete(pThis, (RTTRACELOGEVTGRPID)hIoReq, rc, &SgBuf);
1508 if (pThis->fTraceRequests)
1509 drvdiskintIoReqRemove(pThis, pIoReq);
1510 }
1511 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1512 drvdiskintTraceLogFireEvtComplete(pThis, (RTTRACELOGEVTGRPID)hIoReq, rc, NULL);
1513
1514 LogFlowFunc(("returns %Rrc\n", rc));
1515 return rc;
1516}
1517
1518/**
1519 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqFlush}
1520 */
1521static DECLCALLBACK(int) drvdiskintIoReqFlush(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
1522{
1523 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1524 PDRVDISKAIOREQ pIoReq = DISKINTEGRITY_IOREQ_HANDLE_2_DRVDISKAIOREQ(pThis, hIoReq);
1525
1526 pIoReq->enmTxDir = DRVDISKAIOTXDIR_FLUSH;
1527 pIoReq->off = 0;
1528 pIoReq->cbTransfer = 0;
1529
1530 if (pThis->fTraceRequests)
1531 drvdiskintIoReqAdd(pThis, pIoReq);
1532
1533 drvdiskintTraceLogFireEvtFlush(pThis, (RTTRACELOGEVTGRPID)hIoReq);
1534 int rc = pThis->pDrvMediaEx->pfnIoReqFlush(pThis->pDrvMediaEx, hIoReq);
1535 if (rc == VINF_SUCCESS)
1536 drvdiskintTraceLogFireEvtComplete(pThis, (RTTRACELOGEVTGRPID)hIoReq, rc, NULL);
1537 else if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
1538 drvdiskintTraceLogFireEvtComplete(pThis, (RTTRACELOGEVTGRPID)hIoReq, rc, NULL);
1539
1540 LogFlowFunc(("returns %Rrc\n", rc));
1541 return rc;
1542}
1543
1544/**
1545 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqDiscard}
1546 */
1547static DECLCALLBACK(int) drvdiskintIoReqDiscard(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, unsigned cRangesMax)
1548{
1549 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1550 return pThis->pDrvMediaEx->pfnIoReqDiscard(pThis->pDrvMediaEx, hIoReq, cRangesMax);
1551}
1552
1553/**
1554 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetActiveCount}
1555 */
1556static DECLCALLBACK(uint32_t) drvdiskintIoReqGetActiveCount(PPDMIMEDIAEX pInterface)
1557{
1558 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1559 return pThis->pDrvMediaEx->pfnIoReqGetActiveCount(pThis->pDrvMediaEx);
1560}
1561
1562/**
1563 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetSuspendedCount}
1564 */
1565static DECLCALLBACK(uint32_t) drvdiskintIoReqGetSuspendedCount(PPDMIMEDIAEX pInterface)
1566{
1567 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1568 return pThis->pDrvMediaEx->pfnIoReqGetSuspendedCount(pThis->pDrvMediaEx);
1569}
1570
1571/**
1572 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedStart}
1573 */
1574static DECLCALLBACK(int) drvdiskintIoReqQuerySuspendedStart(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc)
1575{
1576 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1577 return pThis->pDrvMediaEx->pfnIoReqQuerySuspendedStart(pThis->pDrvMediaEx, phIoReq, ppvIoReqAlloc);
1578}
1579
1580/**
1581 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedNext}
1582 */
1583static DECLCALLBACK(int) drvdiskintIoReqQuerySuspendedNext(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq,
1584 PPDMMEDIAEXIOREQ phIoReqNext, void **ppvIoReqAllocNext)
1585{
1586 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1587 return pThis->pDrvMediaEx->pfnIoReqQuerySuspendedNext(pThis->pDrvMediaEx, hIoReq, phIoReqNext, ppvIoReqAllocNext);
1588}
1589
1590/**
1591 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedSave}
1592 */
1593static DECLCALLBACK(int) drvdiskintIoReqSuspendedSave(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
1594{
1595 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1596 return pThis->pDrvMediaEx->pfnIoReqSuspendedSave(pThis->pDrvMediaEx, pSSM, hIoReq);
1597}
1598
1599/**
1600 * @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedLoad}
1601 */
1602static DECLCALLBACK(int) drvdiskintIoReqSuspendedLoad(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
1603{
1604 PDRVDISKINTEGRITY pThis = RT_FROM_MEMBER(pInterface, DRVDISKINTEGRITY, IMediaEx);
1605 return pThis->pDrvMediaEx->pfnIoReqSuspendedLoad(pThis->pDrvMediaEx, pSSM, hIoReq);
1606}
1607
1608/* -=-=-=-=- IBase -=-=-=-=- */
1609
1610/**
1611 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1612 */
1613static DECLCALLBACK(void *) drvdiskintQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1614{
1615 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1616 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1617
1618 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1619 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
1620 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->IMediaPort);
1621 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pThis->IMediaExPort);
1622 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEX, pThis->pDrvMediaEx ? &pThis->IMediaEx : NULL);
1623 return NULL;
1624}
1625
1626
1627/* -=-=-=-=- driver interface -=-=-=-=- */
1628
1629static DECLCALLBACK(int) drvdiskintTreeDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
1630{
1631 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)pNode;
1632
1633 RT_NOREF(pvUser);
1634
1635 RTMemFree(pSeg->pbSeg);
1636 RTMemFree(pSeg);
1637 return VINF_SUCCESS;
1638}
1639
1640/**
1641 * @copydoc FNPDMDRVDESTRUCT
1642 */
1643static DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
1644{
1645 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1646
1647 if (pThis->pTreeSegments)
1648 {
1649 RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
1650 RTMemFree(pThis->pTreeSegments);
1651 }
1652
1653 if (pThis->fTraceRequests)
1654 {
1655 pThis->fRunning = false;
1656 RTSemEventSignal(pThis->SemEvent);
1657 RTSemEventDestroy(pThis->SemEvent);
1658 }
1659
1660 if (pThis->fCheckDoubleCompletion)
1661 {
1662 /* Free all requests */
1663 while (pThis->papIoReq[pThis->iEntry])
1664 {
1665 RTMemFree(pThis->papIoReq[pThis->iEntry]);
1666 pThis->papIoReq[pThis->iEntry] = NULL;
1667 pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
1668 }
1669 }
1670
1671 if (pThis->hIoLogger)
1672 RTTraceLogWrDestroy(pThis->hIoLogger);
1673
1674 if (pThis->hReqCache != NIL_RTMEMCACHE)
1675 {
1676 RTMemCacheDestroy(pThis->hReqCache);
1677 pThis->hReqCache = NIL_RTMEMCACHE;
1678 }
1679}
1680
1681/**
1682 * Construct a disk integrity driver instance.
1683 *
1684 * @copydoc FNPDMDRVCONSTRUCT
1685 */
1686static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1687{
1688 int rc = VINF_SUCCESS;
1689 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1690 LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
1691 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1692
1693 /*
1694 * Validate configuration.
1695 */
1696 if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
1697 "TraceRequests\0"
1698 "CheckIntervalMs\0"
1699 "ExpireIntervalMs\0"
1700 "CheckDoubleCompletions\0"
1701 "HistorySize\0"
1702 "IoLogType\0"
1703 "IoLogFile\0"
1704 "IoLogAddress\0"
1705 "IoLogPort\0"
1706 "IoLogData\0"
1707 "PrepopulateRamDisk\0"
1708 "ReadAfterWrite\0"
1709 "RecordWriteBeforeCompletion\0"
1710 "ValidateMemoryBuffers\0"))
1711 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1712
1713 rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
1714 AssertRC(rc);
1715 rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
1716 AssertRC(rc);
1717 rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
1718 AssertRC(rc);
1719 rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
1720 AssertRC(rc);
1721 rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
1722 AssertRC(rc);
1723 rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
1724 AssertRC(rc);
1725 rc = CFGMR3QueryBoolDef(pCfg, "PrepopulateRamDisk", &pThis->fPrepopulateRamDisk, false);
1726 AssertRC(rc);
1727 rc = CFGMR3QueryBoolDef(pCfg, "ReadAfterWrite", &pThis->fReadAfterWrite, false);
1728 AssertRC(rc);
1729 rc = CFGMR3QueryBoolDef(pCfg, "RecordWriteBeforeCompletion", &pThis->fRecordWriteBeforeCompletion, false);
1730 AssertRC(rc);
1731 rc = CFGMR3QueryBoolDef(pCfg, "ValidateMemoryBuffers", &pThis->fValidateMemBufs, false);
1732 AssertRC(rc);
1733
1734 bool fIoLogData = false;
1735 rc = CFGMR3QueryBoolDef(pCfg, "IoLogData", &fIoLogData, false);
1736 AssertRC(rc);
1737
1738 char *pszIoLogType = NULL;
1739 char *pszIoLogFilename = NULL;
1740 char *pszAddress = NULL;
1741 uint32_t uPort = 0;
1742 rc = CFGMR3QueryStringAlloc(pCfg, "IoLogType", &pszIoLogType);
1743 if (RT_SUCCESS(rc))
1744 {
1745 if (!RTStrICmp(pszIoLogType, "File"))
1746 {
1747 rc = CFGMR3QueryStringAlloc(pCfg, "IoLogFile", &pszIoLogFilename);
1748 AssertRC(rc);
1749 }
1750 else if (!RTStrICmp(pszIoLogType, "Server"))
1751 {
1752 rc = CFGMR3QueryStringAllocDef(pCfg, "IoLogAddress", &pszAddress, NULL);
1753 AssertRC(rc);
1754 rc = CFGMR3QueryU32Def(pCfg, "IoLogPort", &uPort, 4000);
1755 AssertRC(rc);
1756 }
1757 else if (!RTStrICmp(pszIoLogType, "Client"))
1758 {
1759 rc = CFGMR3QueryStringAlloc(pCfg, "IoLogAddress", &pszAddress);
1760 AssertRC(rc);
1761 rc = CFGMR3QueryU32Def(pCfg, "IoLogPort", &uPort, 4000);
1762 AssertRC(rc);
1763 }
1764 else
1765 AssertMsgFailed(("Invalid I/O log type given: %s\n", pszIoLogType));
1766 }
1767 else
1768 Assert(rc == VERR_CFGM_VALUE_NOT_FOUND);
1769
1770 /*
1771 * Initialize most of the data members.
1772 */
1773 pThis->pDrvIns = pDrvIns;
1774 pThis->hReqCache = NIL_RTMEMCACHE;
1775
1776 /* IBase. */
1777 pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
1778
1779 /* IMedia */
1780 pThis->IMedia.pfnRead = drvdiskintRead;
1781 pThis->IMedia.pfnWrite = drvdiskintWrite;
1782 pThis->IMedia.pfnFlush = drvdiskintFlush;
1783 pThis->IMedia.pfnGetSize = drvdiskintGetSize;
1784 pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
1785 pThis->IMedia.pfnBiosIsVisible = drvdiskintBiosIsVisible;
1786 pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
1787 pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
1788 pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
1789 pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
1790 pThis->IMedia.pfnGetUuid = drvdiskintGetUuid;
1791 pThis->IMedia.pfnGetSectorSize = drvdiskintGetSectorSize;
1792 pThis->IMedia.pfnGetType = drvdiskintGetType;
1793 pThis->IMedia.pfnReadPcBios = drvdiskintReadPcBios;
1794 pThis->IMedia.pfnIsNonRotational = drvdiskintIsNonRotational;
1795
1796 /* IMediaEx. */
1797 pThis->IMediaEx.pfnQueryFeatures = drvdiskintQueryFeatures;
1798 pThis->IMediaEx.pfnIoReqAllocSizeSet = drvdiskintIoReqAllocSizeSet;
1799 pThis->IMediaEx.pfnIoReqAlloc = drvdiskintIoReqAlloc;
1800 pThis->IMediaEx.pfnIoReqFree = drvdiskintIoReqFree;
1801 pThis->IMediaEx.pfnIoReqQueryResidual = drvdiskintIoReqQueryResidual;
1802 pThis->IMediaEx.pfnIoReqQueryXferSize = drvdiskintIoReqQueryXferSize;
1803 pThis->IMediaEx.pfnIoReqCancelAll = drvdiskintIoReqCancelAll;
1804 pThis->IMediaEx.pfnIoReqCancel = drvdiskintIoReqCancel;
1805 pThis->IMediaEx.pfnIoReqRead = drvdiskintIoReqRead;
1806 pThis->IMediaEx.pfnIoReqWrite = drvdiskintIoReqWrite;
1807 pThis->IMediaEx.pfnIoReqFlush = drvdiskintIoReqFlush;
1808 pThis->IMediaEx.pfnIoReqDiscard = drvdiskintIoReqDiscard;
1809 pThis->IMediaEx.pfnIoReqGetActiveCount = drvdiskintIoReqGetActiveCount;
1810 pThis->IMediaEx.pfnIoReqGetSuspendedCount = drvdiskintIoReqGetSuspendedCount;
1811 pThis->IMediaEx.pfnIoReqQuerySuspendedStart = drvdiskintIoReqQuerySuspendedStart;
1812 pThis->IMediaEx.pfnIoReqQuerySuspendedNext = drvdiskintIoReqQuerySuspendedNext;
1813 pThis->IMediaEx.pfnIoReqSuspendedSave = drvdiskintIoReqSuspendedSave;
1814 pThis->IMediaEx.pfnIoReqSuspendedLoad = drvdiskintIoReqSuspendedLoad;
1815
1816 /* IMediaPort. */
1817 pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation;
1818
1819 /* IMediaExPort. */
1820 pThis->IMediaExPort.pfnIoReqCompleteNotify = drvdiskintIoReqCompleteNotify;
1821 pThis->IMediaExPort.pfnIoReqCopyFromBuf = drvdiskintIoReqCopyFromBuf;
1822 pThis->IMediaExPort.pfnIoReqCopyToBuf = drvdiskintIoReqCopyToBuf;
1823 pThis->IMediaExPort.pfnIoReqQueryDiscardRanges = drvdiskintIoReqQueryDiscardRanges;
1824 pThis->IMediaExPort.pfnIoReqStateChanged = drvdiskintIoReqStateChanged;
1825
1826 /* Query the media port interface above us. */
1827 pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
1828 if (!pThis->pDrvMediaPort)
1829 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1830 N_("No media port interface above"));
1831
1832 /* Try to attach extended media port interface above.*/
1833 pThis->pDrvMediaExPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAEXPORT);
1834
1835 rc = RTMemCacheCreate(&pThis->hReqCache, sizeof(DRVDISKAIOREQ), 0, UINT32_MAX,
1836 NULL, NULL, NULL, 0);
1837 if (RT_FAILURE(rc))
1838 return PDMDRV_SET_ERROR(pDrvIns, rc,
1839 N_("Failed to create request tracking structure cache"));
1840
1841 /*
1842 * Try attach driver below and query it's media interface.
1843 */
1844 PPDMIBASE pBase;
1845 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
1846 if (RT_FAILURE(rc))
1847 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1848 N_("Failed to attach driver below us! %Rrc"), rc);
1849
1850 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
1851 if (!pThis->pDrvMedia)
1852 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1853 N_("No media or async media interface below"));
1854
1855 pThis->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAEX);
1856
1857 if (pThis->pDrvMedia->pfnDiscard)
1858 pThis->IMedia.pfnDiscard = drvdiskintDiscard;
1859
1860 if (pThis->fCheckConsistency)
1861 {
1862 /* Create the AVL tree. */
1863 pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
1864 if (!pThis->pTreeSegments)
1865 rc = VERR_NO_MEMORY;
1866 }
1867
1868 if (pThis->fTraceRequests)
1869 {
1870 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
1871 {
1872 pThis->apReqActive[i].pIoReq = NULL;
1873 pThis->apReqActive[i].tsStart = 0;
1874 }
1875
1876 pThis->iNextFreeSlot = 0;
1877
1878 /* Init event semaphore. */
1879 rc = RTSemEventCreate(&pThis->SemEvent);
1880 AssertRC(rc);
1881 pThis->fRunning = true;
1882 rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
1883 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
1884 AssertRC(rc);
1885 }
1886
1887 if (pThis->fCheckDoubleCompletion)
1888 {
1889 pThis->iEntry = 0;
1890 pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
1891 AssertPtr(pThis->papIoReq);
1892 }
1893
1894 if (pszIoLogType)
1895 {
1896 if (!RTStrICmp(pszIoLogType, "File"))
1897 {
1898 rc = RTTraceLogWrCreateFile(&pThis->hIoLogger, NULL, pszIoLogFilename);
1899 MMR3HeapFree(pszIoLogFilename);
1900 }
1901 else if (!RTStrICmp(pszIoLogType, "Server"))
1902 {
1903 rc = RTTraceLogWrCreateTcpServer(&pThis->hIoLogger, NULL, pszAddress, uPort);
1904 if (pszAddress)
1905 MMR3HeapFree(pszAddress);
1906 }
1907 else if (!RTStrICmp(pszIoLogType, "Client"))
1908 {
1909 rc = RTTraceLogWrCreateTcpClient(&pThis->hIoLogger, NULL, pszAddress, uPort);
1910 MMR3HeapFree(pszAddress);
1911 }
1912 else
1913 AssertMsgFailed(("Invalid I/O log type given: %s\n", pszIoLogType));
1914
1915 MMR3HeapFree(pszIoLogType);
1916 }
1917
1918 /* Read in all data before the start if requested. */
1919 if (pThis->fPrepopulateRamDisk)
1920 {
1921 uint64_t cbDisk = 0;
1922
1923 LogRel(("DiskIntegrity: Prepopulating RAM disk, this will take some time...\n"));
1924
1925 cbDisk = pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
1926 if (cbDisk)
1927 {
1928 uint64_t off = 0;
1929 uint8_t abBuffer[_64K];
1930 RTSGSEG Seg;
1931
1932 Seg.pvSeg = abBuffer;
1933
1934 while (cbDisk)
1935 {
1936 size_t cbThisRead = RT_MIN(cbDisk, sizeof(abBuffer));
1937
1938 rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, abBuffer, cbThisRead);
1939 if (RT_FAILURE(rc))
1940 break;
1941
1942 if (ASMBitFirstSet(abBuffer, sizeof(abBuffer) * 8) != -1)
1943 {
1944 Seg.cbSeg = cbThisRead;
1945 rc = drvdiskintWriteRecord(pThis, &Seg, 1,
1946 off, cbThisRead);
1947 if (RT_FAILURE(rc))
1948 break;
1949 }
1950
1951 cbDisk -= cbThisRead;
1952 off += cbThisRead;
1953 }
1954
1955 LogRel(("DiskIntegrity: Prepopulating RAM disk finished with %Rrc\n", rc));
1956 }
1957 else
1958 return PDMDRV_SET_ERROR(pDrvIns, VERR_INTERNAL_ERROR,
1959 N_("DiskIntegrity: Error querying the media size below"));
1960 }
1961
1962 return rc;
1963}
1964
1965
1966/**
1967 * Block driver registration record.
1968 */
1969const PDMDRVREG g_DrvDiskIntegrity =
1970{
1971 /* u32Version */
1972 PDM_DRVREG_VERSION,
1973 /* szName */
1974 "DiskIntegrity",
1975 /* szRCMod */
1976 "",
1977 /* szR0Mod */
1978 "",
1979 /* pszDescription */
1980 "Disk integrity driver.",
1981 /* fFlags */
1982 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1983 /* fClass. */
1984 PDM_DRVREG_CLASS_BLOCK,
1985 /* cMaxInstances */
1986 ~0U,
1987 /* cbInstance */
1988 sizeof(DRVDISKINTEGRITY),
1989 /* pfnConstruct */
1990 drvdiskintConstruct,
1991 /* pfnDestruct */
1992 drvdiskintDestruct,
1993 /* pfnRelocate */
1994 NULL,
1995 /* pfnIOCtl */
1996 NULL,
1997 /* pfnPowerOn */
1998 NULL,
1999 /* pfnReset */
2000 NULL,
2001 /* pfnSuspend */
2002 NULL,
2003 /* pfnResume */
2004 NULL,
2005 /* pfnAttach */
2006 NULL,
2007 /* pfnDetach */
2008 NULL,
2009 /* pfnPowerOff */
2010 NULL,
2011 /* pfnSoftReset */
2012 NULL,
2013 /* u32EndVersion */
2014 PDM_DRVREG_VERSION
2015};
2016
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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