VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use