VirtualBox

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

Last change on this file since 38541 was 38541, checked in by vboxsync, 14 years ago

DrvDiskIntegrity: Add support for the I/O logger from the storage debug library

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.6 KB
Line 
1/* $Id: DrvDiskIntegrity.cpp 38541 2011-08-25 22:11:02Z 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.215389.xyz. 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, VDDBGIOLOGTXDIR_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, VDDBGIOLOGTXDIR_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, VDDBGIOLOGTXDIR_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, VDDBGIOLOGTXDIR_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, VDDBGIOLOGTXDIR_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, VDDBGIOLOGTXDIR_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/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
873
874/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
875#define PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsyncPort))) )
876
877static DECLCALLBACK(int) drvdiskintAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
878{
879 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface);
880 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)pvUser;
881 int rc = VINF_SUCCESS;
882
883 LogFlowFunc(("pIoReq=%#p\n", pIoReq));
884
885 /* Remove from the active list. */
886 if (pThis->fTraceRequests)
887 drvdiskintIoReqRemove(pThis, pIoReq);
888
889 if (RT_SUCCESS(rcReq) && pThis->fCheckConsistency)
890 {
891 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
892 rc = drvdiskintReadVerify(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
893 else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE)
894 rc = drvdiskintWriteRecord(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
895 else
896 AssertMsg(pIoReq->enmTxDir == DRVDISKAIOTXDIR_FLUSH, ("Huh?\n"));
897
898 AssertRC(rc);
899 }
900
901 if (pThis->hIoLogger)
902 {
903 RTSGBUF SgBuf;
904
905 if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_READ)
906 RTSgBufInit(&SgBuf, pIoReq->paSeg, pIoReq->cSeg);
907
908 int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, rc, &SgBuf);
909 AssertRC(rc2);
910 }
911
912 void *pvUserComplete = pIoReq->pvUser;
913
914 drvdiskintIoReqFree(pThis, pIoReq);
915
916 rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvUserComplete, rcReq);
917
918 return rc;
919}
920
921/* -=-=-=-=- IMediaPort -=-=-=-=- */
922
923/** Makes a PDRVBLOCK out of a PPDMIMEDIAPORT. */
924#define PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaPort))) )
925
926/**
927 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
928 */
929static DECLCALLBACK(int) drvdiskintQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
930 uint32_t *piInstance, uint32_t *piLUN)
931{
932 PDRVDISKINTEGRITY pThis = PDMIMEDIAPORT_2_DRVDISKINTEGRITY(pInterface);
933
934 return pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, ppcszController,
935 piInstance, piLUN);
936}
937
938/* -=-=-=-=- IBase -=-=-=-=- */
939
940/**
941 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
942 */
943static DECLCALLBACK(void *) drvdiskintQueryInterface(PPDMIBASE pInterface, const char *pszIID)
944{
945 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
946 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
947
948 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
949 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
950 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->pDrvMediaAsync ? &pThis->IMediaAsync : NULL);
951 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, &pThis->IMediaAsyncPort);
952 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->IMediaPort);
953 return NULL;
954}
955
956
957/* -=-=-=-=- driver interface -=-=-=-=- */
958
959static int drvdiskintTreeDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
960{
961 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)pNode;
962
963 RTMemFree(pSeg->pbSeg);
964 RTMemFree(pSeg);
965 return VINF_SUCCESS;
966}
967
968/**
969 * @copydoc FNPDMDRVDESTRUCT
970 */
971static DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
972{
973 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
974
975 if (pThis->pTreeSegments)
976 {
977 RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
978 RTMemFree(pThis->pTreeSegments);
979 }
980
981 if (pThis->fTraceRequests)
982 {
983 pThis->fRunning = false;
984 RTSemEventSignal(pThis->SemEvent);
985 RTSemEventDestroy(pThis->SemEvent);
986 }
987
988 if (pThis->fCheckDoubleCompletion)
989 {
990 /* Free all requests */
991 while (pThis->papIoReq[pThis->iEntry])
992 {
993 RTMemFree(pThis->papIoReq[pThis->iEntry]);
994 pThis->papIoReq[pThis->iEntry] = NULL;
995 pThis->iEntry = (pThis->iEntry+1) % pThis->cEntries;
996 }
997 }
998
999 if (pThis->hIoLogger)
1000 VDDbgIoLogDestroy(pThis->hIoLogger);
1001}
1002
1003/**
1004 * Construct a disk integrity driver instance.
1005 *
1006 * @copydoc FNPDMDRVCONSTRUCT
1007 */
1008static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1009{
1010 int rc = VINF_SUCCESS;
1011 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
1012 LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
1013 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1014
1015 /*
1016 * Validate configuration.
1017 */
1018 if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
1019 "TraceRequests\0"
1020 "CheckIntervalMs\0"
1021 "ExpireIntervalMs\0"
1022 "CheckDoubleCompletions\0"
1023 "HistorySize\0"
1024 "IoLog\0"))
1025 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1026
1027 rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
1028 AssertRC(rc);
1029 rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
1030 AssertRC(rc);
1031 rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
1032 AssertRC(rc);
1033 rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
1034 AssertRC(rc);
1035 rc = CFGMR3QueryBoolDef(pCfg, "CheckDoubleCompletions", &pThis->fCheckDoubleCompletion, false);
1036 AssertRC(rc);
1037 rc = CFGMR3QueryU32Def(pCfg, "HistorySize", &pThis->cEntries, 512);
1038 AssertRC(rc);
1039
1040 char *pszIoLogFilename = NULL;
1041 rc = CFGMR3QueryStringAlloc(pCfg, "IoLog", &pszIoLogFilename);
1042 Assert(RT_SUCCESS(rc) || rc == VERR_CFGM_VALUE_NOT_FOUND);
1043
1044 /*
1045 * Initialize most of the data members.
1046 */
1047 pThis->pDrvIns = pDrvIns;
1048
1049 /* IBase. */
1050 pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
1051
1052 /* IMedia */
1053 pThis->IMedia.pfnRead = drvdiskintRead;
1054 pThis->IMedia.pfnWrite = drvdiskintWrite;
1055 pThis->IMedia.pfnFlush = drvdiskintFlush;
1056 pThis->IMedia.pfnGetSize = drvdiskintGetSize;
1057 pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
1058 pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
1059 pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
1060 pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
1061 pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
1062 pThis->IMedia.pfnGetUuid = drvdiskintGetUuid;
1063
1064 /* IMediaAsync */
1065 pThis->IMediaAsync.pfnStartRead = drvdiskintStartRead;
1066 pThis->IMediaAsync.pfnStartWrite = drvdiskintStartWrite;
1067 pThis->IMediaAsync.pfnStartFlush = drvdiskintStartFlush;
1068
1069 /* IMediaAsyncPort. */
1070 pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvdiskintAsyncTransferCompleteNotify;
1071
1072 /* IMediaPort. */
1073 pThis->IMediaPort.pfnQueryDeviceLocation = drvdiskintQueryDeviceLocation;
1074
1075 /* Query the media port interface above us. */
1076 pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
1077 if (!pThis->pDrvMediaPort)
1078 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1079 N_("No media port inrerface above"));
1080
1081 /* Try to attach async media port interface above.*/
1082 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1083
1084 /*
1085 * Try attach driver below and query it's media interface.
1086 */
1087 PPDMIBASE pBase;
1088 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
1089 if (RT_FAILURE(rc))
1090 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1091 N_("Failed to attach driver below us! %Rrc"), rc);
1092
1093 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
1094 if (!pThis->pDrvMedia)
1095 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
1096 N_("No media or async media interface below"));
1097
1098 pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
1099
1100 if (pThis->fCheckConsistency)
1101 {
1102 /* Create the AVL tree. */
1103 pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
1104 if (!pThis->pTreeSegments)
1105 rc = VERR_NO_MEMORY;
1106 }
1107
1108 if (pThis->fTraceRequests)
1109 {
1110 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
1111 {
1112 pThis->apReqActive[i].pIoReq = NULL;
1113 pThis->apReqActive[i].tsStart = 0;
1114 }
1115
1116 pThis->iNextFreeSlot = 0;
1117
1118 /* Init event semaphore. */
1119 rc = RTSemEventCreate(&pThis->SemEvent);
1120 AssertRC(rc);
1121 pThis->fRunning = true;
1122 rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
1123 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
1124 AssertRC(rc);
1125 }
1126
1127 if (pThis->fCheckDoubleCompletion)
1128 {
1129 pThis->iEntry = 0;
1130 pThis->papIoReq = (PDRVDISKAIOREQ *)RTMemAllocZ(pThis->cEntries * sizeof(PDRVDISKAIOREQ));
1131 AssertPtr(pThis->papIoReq);
1132 }
1133
1134 if (pszIoLogFilename)
1135 {
1136 rc = VDDbgIoLogCreate(&pThis->hIoLogger, pszIoLogFilename, VDDBG_IOLOG_LOG_DATA);
1137 RTStrFree(pszIoLogFilename);
1138 }
1139
1140 return rc;
1141}
1142
1143
1144/**
1145 * Block driver registration record.
1146 */
1147const PDMDRVREG g_DrvDiskIntegrity =
1148{
1149 /* u32Version */
1150 PDM_DRVREG_VERSION,
1151 /* szName */
1152 "DiskIntegrity",
1153 /* szRCMod */
1154 "",
1155 /* szR0Mod */
1156 "",
1157 /* pszDescription */
1158 "Disk integrity driver.",
1159 /* fFlags */
1160 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1161 /* fClass. */
1162 PDM_DRVREG_CLASS_BLOCK,
1163 /* cMaxInstances */
1164 ~0,
1165 /* cbInstance */
1166 sizeof(DRVDISKINTEGRITY),
1167 /* pfnConstruct */
1168 drvdiskintConstruct,
1169 /* pfnDestruct */
1170 drvdiskintDestruct,
1171 /* pfnRelocate */
1172 NULL,
1173 /* pfnIOCtl */
1174 NULL,
1175 /* pfnPowerOn */
1176 NULL,
1177 /* pfnReset */
1178 NULL,
1179 /* pfnSuspend */
1180 NULL,
1181 /* pfnResume */
1182 NULL,
1183 /* pfnAttach */
1184 NULL,
1185 /* pfnDetach */
1186 NULL,
1187 /* pfnPowerOff */
1188 NULL,
1189 /* pfnSoftReset */
1190 NULL,
1191 /* u32EndVersion */
1192 PDM_DRVREG_VERSION
1193};
1194
Note: See TracBrowser for help on using the repository browser.

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