VirtualBox

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

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

doxygen

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

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