VirtualBox

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

Last change on this file since 38644 was 38644, checked in by vboxsync, 13 years ago

VDDbg+DrvDiskIntegrity+tstVDIo: Bugfixes and add a I/O log replay action for the scripted I/O testcase

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.4 KB
Line 
1/* $Id: DrvDiskIntegrity.cpp 38644 2011-09-05 16:45:44Z vboxsync $ */
2/** @file
3 * VBox storage devices: Disk integrity check.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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/vddbg.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/message.h>
31#include <iprt/sg.h>
32#include <iprt/time.h>
33#include <iprt/semaphore.h>
34#include <iprt/asm.h>
35
36#include "VBoxDD.h"
37
38
39/*******************************************************************************
40* Structures and Typedefs *
41*******************************************************************************/
42
43/**
44 * Transfer direction.
45 */
46typedef enum DRVDISKAIOTXDIR
47{
48 /** Read */
49 DRVDISKAIOTXDIR_READ = 0,
50 /** Write */
51 DRVDISKAIOTXDIR_WRITE,
52 /** Flush */
53 DRVDISKAIOTXDIR_FLUSH
54} DRVDISKAIOTXDIR;
55
56/**
57 * async I/O request.
58 */
59typedef struct DRVDISKAIOREQ
60{
61 /** Transfer direction. */
62 DRVDISKAIOTXDIR enmTxDir;
63 /** Start offset. */
64 uint64_t off;
65 /** Transfer size. */
66 size_t cbTransfer;
67 /** Segment array. */
68 PCRTSGSEG paSeg;
69 /** Number of array entries. */
70 unsigned cSeg;
71 /** User argument */
72 void *pvUser;
73 /** Slot in the array. */
74 unsigned iSlot;
75 /** Start timestamp */
76 uint64_t tsStart;
77 /** Completion timestamp. */
78 uint64_t tsComplete;
79 /** I/O log entry if configured. */
80 VDIOLOGENT hIoLogEntry;
81} DRVDISKAIOREQ, *PDRVDISKAIOREQ;
82
83/**
84 * I/O log entry.
85 */
86typedef struct IOLOGENT
87{
88 /** Start offset */
89 uint64_t off;
90 /** Write size */
91 size_t cbWrite;
92 /** Number of references to this entry. */
93 unsigned cRefs;
94} IOLOGENT, *PIOLOGENT;
95
96/**
97 * Disk segment.
98 */
99typedef struct DRVDISKSEGMENT
100{
101 /** AVL core. */
102 AVLRFOFFNODECORE Core;
103 /** Size of the segment */
104 size_t cbSeg;
105 /** Data for this segment */
106 uint8_t *pbSeg;
107 /** Number of entries in the I/O array. */
108 unsigned cIoLogEntries;
109 /** Array of I/O log references. */
110 PIOLOGENT apIoLog[1];
111} DRVDISKSEGMENT, *PDRVDISKSEGMENT;
112
113/**
114 * Active requests list entry.
115 */
116typedef struct DRVDISKAIOREQACTIVE
117{
118 /** Pointer to the request. */
119 volatile PDRVDISKAIOREQ pIoReq;
120 /** Start timestamp. */
121 uint64_t tsStart;
122} DRVDISKAIOREQACTIVE, *PDRVDISKAIOREQACTIVE;
123
124/**
125 * Disk integrity driver instance data.
126 *
127 * @implements PDMIMEDIA
128 */
129typedef struct DRVDISKINTEGRITY
130{
131 /** Pointer driver instance. */
132 PPDMDRVINS pDrvIns;
133 /** Pointer to the media driver below us.
134 * This is NULL if the media is not mounted. */
135 PPDMIMEDIA pDrvMedia;
136 /** Our media interface */
137 PDMIMEDIA IMedia;
138
139 /** The media port interface above. */
140 PPDMIMEDIAPORT pDrvMediaPort;
141 /** Media port interface */
142 PDMIMEDIAPORT IMediaPort;
143
144 /** Pointer to the media async driver below us.
145 * This is NULL if the media is not mounted. */
146 PPDMIMEDIAASYNC pDrvMediaAsync;
147 /** Our media async interface */
148 PDMIMEDIAASYNC IMediaAsync;
149
150 /** The async media port interface above. */
151 PPDMIMEDIAASYNCPORT pDrvMediaAsyncPort;
152 /** Our media async port interface */
153 PDMIMEDIAASYNCPORT IMediaAsyncPort;
154
155 /** Flag whether consistency checks are enabled. */
156 bool fCheckConsistency;
157 /** AVL tree containing the disk blocks to check. */
158 PAVLRFOFFTREE pTreeSegments;
159
160 /** Flag whether async request tracing is enabled. */
161 bool fTraceRequests;
162 /** Interval the thread should check for expired requests (milliseconds). */
163 uint32_t uCheckIntervalMs;
164 /** Expire timeout for a request (milliseconds). */
165 uint32_t uExpireIntervalMs;
166 /** Thread which checks for lost requests. */
167 RTTHREAD hThread;
168 /** Event semaphore */
169 RTSEMEVENT SemEvent;
170 /** Flag whether the thread should run. */
171 bool fRunning;
172 /** Array containing active requests. */
173 DRVDISKAIOREQACTIVE apReqActive[128];
174 /** Next free slot in the array */
175 volatile unsigned iNextFreeSlot;
176
177 /** Flag whether we check for requests completing twice. */
178 bool fCheckDoubleCompletion;
179 /** Number of requests we go back. */
180 unsigned cEntries;
181 /** Array of completed but still observed requests. */
182 PDRVDISKAIOREQ *papIoReq;
183 /** Current entry in the array. */
184 unsigned iEntry;
185
186 /** I/O logger to use if enabled. */
187 VDIOLOGGER hIoLogger;
188} DRVDISKINTEGRITY, *PDRVDISKINTEGRITY;
189
190
191/**
192 * Allocate a new I/O request.
193 *
194 * @returns New I/O request.
195 * @param enmTxDir Transfer direction.
196 * @param off Start offset.
197 * @param paSeg Segment array.
198 * @param cSeg Number of segments.
199 * @param cbTransfer Number of bytes to transfer.
200 * @param pvUser User argument.
201 */
202static PDRVDISKAIOREQ drvdiskintIoReqAlloc(DRVDISKAIOTXDIR enmTxDir, uint64_t off, PCRTSGSEG paSeg,
203 unsigned cSeg, size_t cbTransfer, void *pvUser)
204{
205 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)RTMemAlloc(sizeof(DRVDISKAIOREQ));
206
207 if (RT_LIKELY(pIoReq))
208 {
209 pIoReq->enmTxDir = enmTxDir;
210 pIoReq->off = off;
211 pIoReq->cbTransfer = cbTransfer;
212 pIoReq->paSeg = paSeg;
213 pIoReq->cSeg = cSeg;
214 pIoReq->pvUser = pvUser;
215 pIoReq->iSlot = 0;
216 pIoReq->tsStart = RTTimeSystemMilliTS();
217 pIoReq->tsComplete = 0;
218 pIoReq->hIoLogEntry = NULL;
219 }
220
221 return pIoReq;
222}
223
224/**
225 * Free a async I/O request.
226 *
227 * @returns nothing.
228 * @param pThis Disk driver.
229 * @param pIoReq The I/O request to free.
230 */
231static void drvdiskintIoReqFree(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
232{
233 if (pThis->fCheckDoubleCompletion)
234 {
235 /* Search if the I/O request completed already. */
236 for (unsigned i = 0; i < pThis->cEntries; i++)
237 {
238 if (RT_UNLIKELY(pThis->papIoReq[i] == pIoReq))
239 {
240 RTMsgError("Request %#p completed already!\n", pIoReq);
241 RTMsgError("Start timestamp %llu Completion timestamp %llu (completed after %llu ms)\n",
242 pIoReq->tsStart, pIoReq->tsComplete, pIoReq->tsComplete - pIoReq->tsStart);
243 RTAssertDebugBreak();
244 }
245 }
246
247 pIoReq->tsComplete = RTTimeSystemMilliTS();
248 Assert(!pThis->papIoReq[pThis->iEntry]);
249 pThis->papIoReq[pThis->iEntry] = pIoReq;
250
251 pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
252 if (pThis->papIoReq[pThis->iEntry])
253 {
254 RTMemFree(pThis->papIoReq[pThis->iEntry]);
255 pThis->papIoReq[pThis->iEntry] = NULL;
256 }
257 }
258 else
259 RTMemFree(pIoReq);
260}
261
262/**
263 * Record a successful write to the virtual disk.
264 *
265 * @returns VBox status code.
266 * @param pThis Disk integrity driver instance data.
267 * @param paSeg Segment array of the write to record.
268 * @param cSeg Number of segments.
269 * @param off Start offset.
270 * @param cbWrite Number of bytes to record.
271 */
272static int drvdiskintWriteRecord(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
273 uint64_t off, size_t cbWrite)
274{
275 int rc = VINF_SUCCESS;
276
277 LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbWrite=%u\n",
278 pThis, paSeg, cSeg, off, cbWrite));
279
280 /* Update the segments */
281 size_t cbLeft = cbWrite;
282 RTFOFF offCurr = (RTFOFF)off;
283 RTSGBUF SgBuf;
284 PIOLOGENT pIoLogEnt = (PIOLOGENT)RTMemAllocZ(sizeof(IOLOGENT));
285 if (!pIoLogEnt)
286 return VERR_NO_MEMORY;
287
288 pIoLogEnt->off = off;
289 pIoLogEnt->cbWrite = cbWrite;
290 pIoLogEnt->cRefs = 0;
291
292 RTSgBufInit(&SgBuf, paSeg, cSeg);
293
294 while (cbLeft)
295 {
296 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
297 size_t cbRange = 0;
298 bool fSet = false;
299 unsigned offSeg = 0;
300
301 if (!pSeg)
302 {
303 /* Get next segment */
304 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
305 if ( !pSeg
306 || offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
307 cbRange = cbLeft;
308 else
309 cbRange = pSeg->Core.Key - offCurr;
310
311 Assert(cbRange % 512 == 0);
312
313 /* Create new segment */
314 pSeg = (PDRVDISKSEGMENT)RTMemAllocZ(RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbRange / 512]));
315 if (pSeg)
316 {
317 pSeg->Core.Key = offCurr;
318 pSeg->Core.KeyLast = offCurr + (RTFOFF)cbRange - 1;
319 pSeg->cbSeg = cbRange;
320 pSeg->pbSeg = (uint8_t *)RTMemAllocZ(cbRange);
321 pSeg->cIoLogEntries = cbRange / 512;
322 if (!pSeg->pbSeg)
323 RTMemFree(pSeg);
324 else
325 {
326 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
327 AssertMsg(fInserted, ("Bug!\n"));
328 fSet = true;
329 }
330 }
331 }
332 else
333 {
334 fSet = true;
335 offSeg = offCurr - pSeg->Core.Key;
336 cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
337 }
338
339 if (fSet)
340 {
341 AssertPtr(pSeg);
342 size_t cbCopied = RTSgBufCopyToBuf(&SgBuf, pSeg->pbSeg + offSeg, cbRange);
343 Assert(cbCopied == cbRange);
344
345 /* Update the I/O log pointers */
346 Assert(offSeg % 512 == 0);
347 Assert(cbRange % 512 == 0);
348 while (offSeg < cbRange)
349 {
350 uint32_t uSector = offSeg / 512;
351 PIOLOGENT pIoLogOld = NULL;
352
353 AssertMsg(uSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
354
355 pIoLogOld = pSeg->apIoLog[uSector];
356 if (pIoLogOld)
357 {
358 pIoLogOld->cRefs--;
359 if (!pIoLogOld->cRefs)
360 RTMemFree(pIoLogOld);
361 }
362
363 pSeg->apIoLog[uSector] = pIoLogEnt;
364 pIoLogEnt->cRefs++;
365
366 offSeg += 512;
367 }
368 }
369 else
370 RTSgBufAdvance(&SgBuf, cbRange);
371
372 offCurr += cbRange;
373 cbLeft -= cbRange;
374 }
375
376 return rc;
377}
378
379/**
380 * Verifies a read request.
381 *
382 * @returns VBox status code.
383 * @param pThis Disk integrity driver instance data.
384 * @param paSeg Segment array of the containing the data buffers to verify.
385 * @param cSeg Number of segments.
386 * @param off Start offset.
387 * @param cbWrite Number of bytes to verify.
388 */
389static int drvdiskintReadVerify(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
390 uint64_t off, size_t cbRead)
391{
392 int rc = VINF_SUCCESS;
393
394 LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbRead=%u\n",
395 pThis, paSeg, cSeg, off, cbRead));
396
397 Assert(off % 512 == 0);
398 Assert(cbRead % 512 == 0);
399
400 /* Compare read data */
401 size_t cbLeft = cbRead;
402 RTFOFF offCurr = (RTFOFF)off;
403 RTSGBUF SgBuf;
404
405 RTSgBufInit(&SgBuf, paSeg, cSeg);
406
407 while (cbLeft)
408 {
409 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
410 size_t cbRange = 0;
411 bool fCmp = false;
412 unsigned offSeg = 0;
413
414 if (!pSeg)
415 {
416 /* Get next segment */
417 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
418 if (!pSeg)
419 {
420 /* No data in the tree for this read. Assume everything is ok. */
421 cbRange = cbLeft;
422 }
423 else if (offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
424 cbRange = cbLeft;
425 else
426 cbRange = pSeg->Core.Key - offCurr;
427 }
428 else
429 {
430 fCmp = true;
431 offSeg = offCurr - pSeg->Core.Key;
432 cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
433 }
434
435 if (fCmp)
436 {
437 RTSGSEG Seg;
438 RTSGBUF SgBufCmp;
439 size_t cbOff = 0;
440
441 Seg.cbSeg = cbRange;
442 Seg.pvSeg = pSeg->pbSeg + offSeg;
443
444 RTSgBufInit(&SgBufCmp, &Seg, 1);
445 if (RTSgBufCmpEx(&SgBuf, &SgBufCmp, cbRange, &cbOff, true))
446 {
447 /* Corrupted disk, print I/O log entry of the last write which accessed this range. */
448 uint32_t cSector = (offSeg + cbOff) / 512;
449 AssertMsg(cSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
450
451 RTMsgError("Corrupted disk at offset %llu (%u bytes in the current read buffer)!\n",
452 offCurr + cbOff, cbOff);
453 RTMsgError("Last write to this sector started at offset %llu with %u bytes (%u references to this log entry)\n",
454 pSeg->apIoLog[cSector]->off,
455 pSeg->apIoLog[cSector]->cbWrite,
456 pSeg->apIoLog[cSector]->cRefs);
457 RTAssertDebugBreak();
458 }
459 }
460 else
461 RTSgBufAdvance(&SgBuf, cbRange);
462
463 offCurr += cbRange;
464 cbLeft -= cbRange;
465 }
466
467 return rc;
468}
469
470/**
471 * Adds a request to the active list.
472 *
473 * @returns nothing.
474 * @param pThis The driver instance data.
475 * @param pIoReq The request to add.
476 */
477static void drvdiskintIoReqAdd(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
478{
479 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pThis->iNextFreeSlot];
480
481 Assert(!pReqActive->pIoReq);
482 pReqActive->tsStart = pIoReq->tsStart;
483 pReqActive->pIoReq = pIoReq;
484 pIoReq->iSlot = pThis->iNextFreeSlot;
485
486 /* Search for the next one. */
487 while (pThis->apReqActive[pThis->iNextFreeSlot].pIoReq)
488 pThis->iNextFreeSlot = (pThis->iNextFreeSlot+1) % RT_ELEMENTS(pThis->apReqActive);
489}
490
491/**
492 * Removes a request from the active list.
493 *
494 * @returns nothing.
495 * @param pThis The driver instance data.
496 * @param pIoReq The request to remove.
497 */
498static void drvdiskintIoReqRemove(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
499{
500 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pIoReq->iSlot];
501
502 Assert(pReqActive->pIoReq == pIoReq);
503
504 ASMAtomicWriteNullPtr(&pReqActive->pIoReq);
505}
506
507/**
508 * Thread checking for expired requests.
509 *
510 * @returns IPRT status code.
511 * @param pThread Thread handle.
512 * @param pvUser Opaque user data.
513 */
514static int drvdiskIntIoReqExpiredCheck(RTTHREAD pThread, void *pvUser)
515{
516 PDRVDISKINTEGRITY pThis = (PDRVDISKINTEGRITY)pvUser;
517
518 while (pThis->fRunning)
519 {
520 int rc = RTSemEventWait(pThis->SemEvent, pThis->uCheckIntervalMs);
521
522 if (!pThis->fRunning)
523 break;
524
525 Assert(rc == VERR_TIMEOUT);
526
527 /* Get current timestamp for comparison. */
528 uint64_t tsCurr = RTTimeSystemMilliTS();
529
530 /* Go through the array and check for expired requests. */
531 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
532 {
533 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[i];
534 PDRVDISKAIOREQ pIoReq = ASMAtomicReadPtrT(&pReqActive->pIoReq, PDRVDISKAIOREQ);
535
536 if ( pIoReq
537 && (tsCurr > pReqActive->tsStart)
538 && (tsCurr - pReqActive->tsStart) >= pThis->uExpireIntervalMs)
539 {
540 RTMsgError("Request %#p expired (active for %llu ms already)\n",
541 pIoReq, tsCurr - pReqActive->tsStart);
542 RTAssertDebugBreak();
543 }
544 }
545 }
546
547 return VINF_SUCCESS;
548}
549
550/* -=-=-=-=- IMedia -=-=-=-=- */
551
552/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIA. */
553#define PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMedia)) )
554/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIAASYNC. */
555#define PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsync)) )
556
557/*******************************************************************************
558* Media interface methods *
559*******************************************************************************/
560
561/** @copydoc PDMIMEDIA::pfnRead */
562static DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
563 uint64_t off, void *pvBuf, size_t cbRead)
564{
565 int rc = VINF_SUCCESS;
566 VDIOLOGENT hIoLogEntry;
567 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
568
569 if (pThis->hIoLogger)
570 {
571 rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_READ, off,
572 cbRead, NULL, &hIoLogEntry);
573 AssertRC(rc);
574 }
575
576 rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
577
578 if (pThis->hIoLogger)
579 {
580 RTSGSEG Seg;
581 RTSGBUF SgBuf;
582
583 Seg.pvSeg = pvBuf;
584 Seg.cbSeg = cbRead;
585 RTSgBufInit(&SgBuf, &Seg, 1);
586
587 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, &SgBuf);
588 AssertRC(rc2);
589 }
590
591 if (RT_FAILURE(rc))
592 return rc;
593
594 if (pThis->fCheckConsistency)
595 {
596 /* Verify the read. */
597 RTSGSEG Seg;
598 Seg.cbSeg = cbRead;
599 Seg.pvSeg = pvBuf;
600 rc = drvdiskintReadVerify(pThis, &Seg, 1, off, cbRead);
601 }
602
603 return rc;
604}
605
606/** @copydoc PDMIMEDIA::pfnWrite */
607static DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
608 uint64_t off, const void *pvBuf,
609 size_t cbWrite)
610{
611 int rc = VINF_SUCCESS;
612 VDIOLOGENT hIoLogEntry;
613 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
614
615 if (pThis->hIoLogger)
616 {
617 RTSGSEG Seg;
618 RTSGBUF SgBuf;
619
620 Seg.pvSeg = (void *)pvBuf;
621 Seg.cbSeg = cbWrite;
622 RTSgBufInit(&SgBuf, &Seg, 1);
623
624 rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_WRITE, off,
625 cbWrite, &SgBuf, &hIoLogEntry);
626 AssertRC(rc);
627 }
628
629 rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
630
631 if (pThis->hIoLogger)
632 {
633 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, NULL);
634 AssertRC(rc2);
635 }
636
637 if (RT_FAILURE(rc))
638 return rc;
639
640 if (pThis->fCheckConsistency)
641 {
642 /* Record the write. */
643 RTSGSEG Seg;
644 Seg.cbSeg = cbWrite;
645 Seg.pvSeg = (void *)pvBuf;
646 rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
647 }
648
649 return rc;
650}
651
652static DECLCALLBACK(int) drvdiskintStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
653 PCRTSGSEG paSeg, unsigned cSeg,
654 size_t cbRead, void *pvUser)
655{
656 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d pvUser=%#p\n", __FUNCTION__,
657 uOffset, paSeg, cSeg, cbRead, pvUser));
658 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
659 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_READ, uOffset, paSeg, cSeg, cbRead, pvUser);
660 AssertPtr(pIoReq);
661
662 if (pThis->fTraceRequests)
663 drvdiskintIoReqAdd(pThis, pIoReq);
664
665 if (pThis->hIoLogger)
666 {
667 int rc2 = VDDbgIoLogStart(pThis->hIoLogger, true, VDDBGIOLOGREQ_READ, uOffset,
668 cbRead, NULL, &pIoReq->hIoLogEntry);
669 AssertRC(rc2);
670 }
671
672 int rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
673 cbRead, pIoReq);
674 if (rc == VINF_VD_ASYNC_IO_FINISHED)
675 {
676 /* Verify the read now. */
677 if (pThis->fCheckConsistency)
678 {
679 int rc2 = drvdiskintReadVerify(pThis, paSeg, cSeg, uOffset, cbRead);
680 AssertRC(rc2);
681 }
682
683 if (pThis->hIoLogger)
684 {
685 RTSGBUF SgBuf;
686
687 RTSgBufInit(&SgBuf, paSeg, cSeg);
688
689 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, &SgBuf);
690 AssertRC(rc2);
691 }
692
693 if (pThis->fTraceRequests)
694 drvdiskintIoReqRemove(pThis, pIoReq);
695 RTMemFree(pIoReq);
696 }
697 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
698 RTMemFree(pIoReq);
699
700 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
701 return rc;
702}
703
704static DECLCALLBACK(int) drvdiskintStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
705 PCRTSGSEG paSeg, unsigned cSeg,
706 size_t cbWrite, void *pvUser)
707{
708 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d pvUser=%#p\n", __FUNCTION__,
709 uOffset, paSeg, cSeg, cbWrite, pvUser));
710 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
711 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_WRITE, uOffset, paSeg, cSeg, cbWrite, pvUser);
712 AssertPtr(pIoReq);
713
714 if (pThis->fTraceRequests)
715 drvdiskintIoReqAdd(pThis, pIoReq);
716
717 if (pThis->hIoLogger)
718 {
719 RTSGBUF SgBuf;
720
721 RTSgBufInit(&SgBuf, paSeg, cSeg);
722
723 int rc2 = VDDbgIoLogStart(pThis->hIoLogger, true, VDDBGIOLOGREQ_WRITE, uOffset,
724 cbWrite, &SgBuf, &pIoReq->hIoLogEntry);
725 AssertRC(rc2);
726 }
727
728 int rc = pThis->pDrvMediaAsync->pfnStartWrite(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
729 cbWrite, pIoReq);
730 if (rc == VINF_VD_ASYNC_IO_FINISHED)
731 {
732 /* Record the write. */
733 if (pThis->fCheckConsistency)
734 {
735 int rc2 = drvdiskintWriteRecord(pThis, paSeg, cSeg, uOffset, cbWrite);
736 AssertRC(rc2);
737 }
738
739 if (pThis->hIoLogger)
740 {
741 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, NULL);
742 AssertRC(rc2);
743 }
744
745 if (pThis->fTraceRequests)
746 drvdiskintIoReqRemove(pThis, pIoReq);
747
748 RTMemFree(pIoReq);
749 }
750 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
751 RTMemFree(pIoReq);
752
753 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
754 return rc;
755}
756
757/** @copydoc PDMIMEDIAASYNC::pfnStartFlush */
758static DECLCALLBACK(int) drvdiskintStartFlush(PPDMIMEDIAASYNC pInterface, void *pvUser)
759{
760 int rc = VINF_SUCCESS;
761 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
762 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_FLUSH, 0, NULL, 0, 0, pvUser);
763 AssertPtr(pIoReq);
764
765 if (pThis->fTraceRequests)
766 drvdiskintIoReqAdd(pThis, pIoReq);
767
768 if (pThis->hIoLogger)
769 {
770 rc = VDDbgIoLogStart(pThis->hIoLogger, true, VDDBGIOLOGREQ_FLUSH, 0,
771 0, NULL, &pIoReq->hIoLogEntry);
772 AssertRC(rc);
773 }
774
775 rc = pThis->pDrvMediaAsync->pfnStartFlush(pThis->pDrvMediaAsync, pIoReq);
776
777 if (rc == VINF_VD_ASYNC_IO_FINISHED)
778 {
779 if (pThis->hIoLogger)
780 {
781 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, NULL);
782 AssertRC(rc2);
783 }
784
785 RTMemFree(pIoReq);
786 }
787 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
788 RTMemFree(pIoReq);
789
790 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
791 return rc;
792}
793
794/** @copydoc PDMIMEDIA::pfnFlush */
795static DECLCALLBACK(int) drvdiskintFlush(PPDMIMEDIA pInterface)
796{
797 int rc = VINF_SUCCESS;
798 VDIOLOGENT hIoLogEntry;
799 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
800
801 if (pThis->hIoLogger)
802 {
803 rc = VDDbgIoLogStart(pThis->hIoLogger, false, VDDBGIOLOGREQ_FLUSH, 0,
804 0, NULL, &hIoLogEntry);
805 AssertRC(rc);
806 }
807
808 rc = pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
809
810 if (pThis->hIoLogger)
811 {
812 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, NULL);
813 AssertRC(rc2);
814 }
815
816 return rc;
817}
818
819/** @copydoc PDMIMEDIA::pfnGetSize */
820static DECLCALLBACK(uint64_t) drvdiskintGetSize(PPDMIMEDIA pInterface)
821{
822 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
823 return pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
824}
825
826/** @copydoc PDMIMEDIA::pfnIsReadOnly */
827static DECLCALLBACK(bool) drvdiskintIsReadOnly(PPDMIMEDIA pInterface)
828{
829 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
830 return pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
831}
832
833/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
834static DECLCALLBACK(int) drvdiskintBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
835 PPDMMEDIAGEOMETRY pPCHSGeometry)
836{
837 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
838 return pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
839}
840
841/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
842static DECLCALLBACK(int) drvdiskintBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
843 PCPDMMEDIAGEOMETRY pPCHSGeometry)
844{
845 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
846 return pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
847}
848
849/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
850static DECLCALLBACK(int) drvdiskintBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
851 PPDMMEDIAGEOMETRY pLCHSGeometry)
852{
853 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
854 return pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
855}
856
857/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
858static DECLCALLBACK(int) drvdiskintBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
859 PCPDMMEDIAGEOMETRY pLCHSGeometry)
860{
861 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
862 return pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
863}
864
865/** @copydoc PDMIMEDIA::pfnGetUuid */
866static DECLCALLBACK(int) drvdiskintGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
867{
868 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
869 return pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, pUuid);
870}
871
872/** @copydoc PDMIMEDIA::pfnDiscard */
873static DECLCALLBACK(int) drvdiskintDiscard(PPDMIMEDIA pInterface, PPDMRANGE paRanges, unsigned cRanges)
874{
875 int rc = VINF_SUCCESS;
876 VDIOLOGENT hIoLogEntry;
877 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
878
879 if (pThis->hIoLogger)
880 {
881 rc = VDDbgIoLogStartDiscard(pThis->hIoLogger, false, (PVDRANGE)paRanges, cRanges, &hIoLogEntry);
882 AssertRC(rc);
883 }
884
885 rc = pThis->pDrvMedia->pfnDiscard(pThis->pDrvMedia, paRanges, cRanges);
886
887 if (pThis->hIoLogger)
888 {
889 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, hIoLogEntry, rc, NULL);
890 AssertRC(rc2);
891 }
892
893 return rc;
894}
895
896/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
897
898/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
899#define PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsyncPort))) )
900
901static DECLCALLBACK(int) drvdiskintAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
902{
903 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface);
904 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)pvUser;
905 int rc = VINF_SUCCESS;
906
907 LogFlowFunc(("pIoReq=%#p\n", pIoReq));
908
909 /* Remove from the active list. */
910 if (pThis->fTraceRequests)
911 drvdiskintIoReqRemove(pThis, pIoReq);
912
913 if (RT_SUCCESS(rcReq) && pThis->fCheckConsistency)
914 {
915 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
916 rc = drvdiskintReadVerify(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
917 else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE)
918 rc = drvdiskintWriteRecord(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
919 else
920 AssertMsg(pIoReq->enmTxDir == DRVDISKAIOTXDIR_FLUSH, ("Huh?\n"));
921
922 AssertRC(rc);
923 }
924
925 if (pThis->hIoLogger)
926 {
927 RTSGBUF SgBuf;
928
929 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
930 RTSgBufInit(&SgBuf, pIoReq->paSeg, pIoReq->cSeg);
931
932 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, rc, &SgBuf);
933 AssertRC(rc2);
934 }
935
936 void *pvUserComplete = pIoReq->pvUser;
937
938 drvdiskintIoReqFree(pThis, pIoReq);
939
940 rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvUserComplete, rcReq);
941
942 return rc;
943}
944
945/* -=-=-=-=- IMediaPort -=-=-=-=- */
946
947/** Makes a PDRVBLOCK out of a PPDMIMEDIAPORT. */
948#define PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaPort))) )
949
950/**
951 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
952 */
953static DECLCALLBACK(int) drvdiskintQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
954 uint32_t *piInstance, uint32_t *piLUN)
955{
956 PDRVDISKINTEGRITY pThis = PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface);
957
958 return pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, ppcszController,
959 piInstance, piLUN);
960}
961
962/* -=-=-=-=- IBase -=-=-=-=- */
963
964/**
965 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
966 */
967static DECLCALLBACK(void *) drvdiskintQueryInterface(PPDMIBASE pInterface, const char *pszIID)
968{
969 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
970 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
971
972 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
973 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
974 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->pDrvMediaAsync ? &pThis->IMediaAsync : NULL);
975 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, &pThis->IMediaAsyncPort);
976 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->IMediaPort);
977 return NULL;
978}
979
980
981/* -=-=-=-=- driver interface -=-=-=-=- */
982
983static int drvdiskintTreeDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
984{
985 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)pNode;
986
987 RTMemFree(pSeg->pbSeg);
988 RTMemFree(pSeg);
989 return VINF_SUCCESS;
990}
991
992/**
993 * @copydoc FNPDMDRVDESTRUCT
994 */
995static DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
996{
997 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
998
999 if (pThis->pTreeSegments)
1000 {
1001 RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
1002 RTMemFree(pThis->pTreeSegments);
1003 }
1004
1005 if (pThis->fTraceRequests)
1006 {
1007 pThis->fRunning = false;
1008 RTSemEventSignal(pThis->SemEvent);
1009 RTSemEventDestroy(pThis->SemEvent);
1010 }
1011
1012 if (pThis->fCheckDoubleCompletion)
1013 {
1014 /* Free all requests */
1015 while (pThis->papIoReq[pThis->iEntry])
1016 {
1017 RTMemFree(pThis->papIoReq[pThis->iEntry]);
1018 pThis->papIoReq[pThis->iEntry] = NULL;
1019 pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
1020 }
1021 }
1022
1023 if (pThis->hIoLogger)
1024 VDDbgIoLogDestroy(pThis->hIoLogger);
1025}
1026
1027/**
1028 * Construct a disk integrity driver instance.
1029 *
1030 * @copydoc FNPDMDRVCONSTRUCT
1031 */
1032static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1033{
1034 int rc = VINF_SUCCESS;
1035 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1036 LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
1037 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1038
1039 /*
1040 * Validate configuration.
1041 */
1042 if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
1043 "TraceRequests\0"
1044 "CheckIntervalMs\0"
1045 "ExpireIntervalMs\0"
1046 "CheckDoubleCompletions\0"
1047 "HistorySize\0"
1048 "IoLog\0"))
1049 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1050
1051 rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
1052 AssertRC(rc);
1053 rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
1054 AssertRC(rc);
1055 rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
1056 AssertRC(rc);
1057 rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
1058 AssertRC(rc);
1059 rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
1060 AssertRC(rc);
1061 rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
1062 AssertRC(rc);
1063
1064 char *pszIoLogFilename = NULL;
1065 rc = CFGMR3QueryStringAlloc(pCfg, "IoLog", &pszIoLogFilename);
1066 Assert(RT_SUCCESS(rc) || rc == VERR_CFGM_VALUE_NOT_FOUND);
1067
1068 /*
1069 * Initialize most of the data members.
1070 */
1071 pThis->pDrvIns = pDrvIns;
1072
1073 /* IBase. */
1074 pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
1075
1076 /* IMedia */
1077 pThis->IMedia.pfnRead = drvdiskintRead;
1078 pThis->IMedia.pfnWrite = drvdiskintWrite;
1079 pThis->IMedia.pfnFlush = drvdiskintFlush;
1080 pThis->IMedia.pfnGetSize = drvdiskintGetSize;
1081 pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
1082 pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
1083 pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
1084 pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
1085 pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
1086 pThis->IMedia.pfnGetUuid = drvdiskintGetUuid;
1087
1088 /* IMediaAsync */
1089 pThis->IMediaAsync.pfnStartRead = drvdiskintStartRead;
1090 pThis->IMediaAsync.pfnStartWrite = drvdiskintStartWrite;
1091 pThis->IMediaAsync.pfnStartFlush = drvdiskintStartFlush;
1092
1093 /* IMediaAsyncPort. */
1094 pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvdiskintAsyncTransferCompleteNotify;
1095
1096 /* IMediaPort. */
1097 pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation;
1098
1099 /* Query the media port interface above us. */
1100 pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
1101 if (!pThis->pDrvMediaPort)
1102 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1103 N_("No media port inrerface above"));
1104
1105 /* Try to attach async media port interface above.*/
1106 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1107
1108 /*
1109 * Try attach driver below and query it's media interface.
1110 */
1111 PPDMIBASE pBase;
1112 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
1113 if (RT_FAILURE(rc))
1114 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1115 N_("Failed to attach driver below us! %Rrc"), rc);
1116
1117 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
1118 if (!pThis->pDrvMedia)
1119 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1120 N_("No media or async media interface below"));
1121
1122 pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
1123
1124 if (pThis->pDrvMedia->pfnDiscard)
1125 pThis->IMedia.pfnDiscard = drvdiskintDiscard;
1126
1127 if (pThis->fCheckConsistency)
1128 {
1129 /* Create the AVL tree. */
1130 pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
1131 if (!pThis->pTreeSegments)
1132 rc = VERR_NO_MEMORY;
1133 }
1134
1135 if (pThis->fTraceRequests)
1136 {
1137 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
1138 {
1139 pThis->apReqActive[i].pIoReq = NULL;
1140 pThis->apReqActive[i].tsStart = 0;
1141 }
1142
1143 pThis->iNextFreeSlot = 0;
1144
1145 /* Init event semaphore. */
1146 rc = RTSemEventCreate(&pThis->SemEvent);
1147 AssertRC(rc);
1148 pThis->fRunning = true;
1149 rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
1150 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
1151 AssertRC(rc);
1152 }
1153
1154 if (pThis->fCheckDoubleCompletion)
1155 {
1156 pThis->iEntry = 0;
1157 pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
1158 AssertPtr(pThis->papIoReq);
1159 }
1160
1161 if (pszIoLogFilename)
1162 {
1163 rc = VDDbgIoLogCreate(&pThis->hIoLogger, pszIoLogFilename, VDDBG_IOLOG_LOG_DATA);
1164 MMR3HeapFree(pszIoLogFilename);
1165 }
1166
1167 return rc;
1168}
1169
1170
1171/**
1172 * Block driver registration record.
1173 */
1174const PDMDRVREG g_DrvDiskIntegrity =
1175{
1176 /* u32Version */
1177 PDM_DRVREG_VERSION,
1178 /* szName */
1179 "DiskIntegrity",
1180 /* szRCMod */
1181 "",
1182 /* szR0Mod */
1183 "",
1184 /* pszDescription */
1185 "Disk integrity driver.",
1186 /* fFlags */
1187 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1188 /* fClass. */
1189 PDM_DRVREG_CLASS_BLOCK,
1190 /* cMaxInstances */
1191 ~0,
1192 /* cbInstance */
1193 sizeof(DRVDISKINTEGRITY),
1194 /* pfnConstruct */
1195 drvdiskintConstruct,
1196 /* pfnDestruct */
1197 drvdiskintDestruct,
1198 /* pfnRelocate */
1199 NULL,
1200 /* pfnIOCtl */
1201 NULL,
1202 /* pfnPowerOn */
1203 NULL,
1204 /* pfnReset */
1205 NULL,
1206 /* pfnSuspend */
1207 NULL,
1208 /* pfnResume */
1209 NULL,
1210 /* pfnAttach */
1211 NULL,
1212 /* pfnDetach */
1213 NULL,
1214 /* pfnPowerOff */
1215 NULL,
1216 /* pfnSoftReset */
1217 NULL,
1218 /* u32EndVersion */
1219 PDM_DRVREG_VERSION
1220};
1221
Note: See TracBrowser for help on using the repository browser.

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