VirtualBox

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

最後變更 在這個檔案從29278是 28948,由 vboxsync 提交於 15 年 前

DiskIntegrity: Fix memory corruption caused by the trace option. The index for the next free slot must be clipped always or we write beyond the array

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 28.6 KB
 
1/* $Id: DrvDiskIntegrity.cpp 28948 2010-04-30 21:19:04Z 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.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_DISK_INTEGRITY
23#include <VBox/pdmdrv.h>
24#include <iprt/assert.h>
25#include <iprt/string.h>
26#include <iprt/uuid.h>
27#include <iprt/avl.h>
28#include <iprt/mem.h>
29#include <iprt/message.h>
30#include <iprt/sg.h>
31#include <iprt/time.h>
32#include <iprt/semaphore.h>
33
34#include "Builtins.h"
35
36
37/*******************************************************************************
38* Structures and Typedefs *
39*******************************************************************************/
40
41/**
42 * async I/O request.
43 */
44typedef struct DRVDISKAIOREQ
45{
46 /** Flag whether this is a read or write request. */
47 bool fRead;
48 /** Start offset. */
49 uint64_t off;
50 /** Transfer size. */
51 size_t cbTransfer;
52 /** Segment array. */
53 PCRTSGSEG paSeg;
54 /** Number of array entries. */
55 unsigned cSeg;
56 /** User argument */
57 void *pvUser;
58 /** Slot in the array. */
59 unsigned iSlot;
60} DRVDISKAIOREQ, *PDRVDISKAIOREQ;
61
62/**
63 * I/O log entry.
64 */
65typedef struct IOLOGENT
66{
67 /** Start offset */
68 uint64_t off;
69 /** Write size */
70 size_t cbWrite;
71 /** Number of references to this entry. */
72 unsigned cRefs;
73} IOLOGENT, *PIOLOGENT;
74
75/**
76 * Disk segment.
77 */
78typedef struct DRVDISKSEGMENT
79{
80 /** AVL core. */
81 AVLRFOFFNODECORE Core;
82 /** Size of the segment */
83 size_t cbSeg;
84 /** Data for this segment */
85 uint8_t *pbSeg;
86 /** Numbner of entries in the I/O array. */
87 unsigned cIoLogEntries;
88 /** Array of I/O log references. */
89 PIOLOGENT apIoLog[1];
90} DRVDISKSEGMENT, *PDRVDISKSEGMENT;
91
92/**
93 * Active requests list entry.
94 */
95typedef struct DRVDISKAIOREQACTIVE
96{
97 /** Pointer to the request. */
98 volatile PDRVDISKAIOREQ pIoReq;
99 /** Start timestamp. */
100 uint64_t tsStart;
101} DRVDISKAIOREQACTIVE, *PDRVDISKAIOREQACTIVE;
102
103/**
104 * Disk integrity driver instance data.
105 *
106 * @implements PDMIMEDIA
107 */
108typedef struct DRVDISKINTEGRITY
109{
110 /** Pointer driver instance. */
111 PPDMDRVINS pDrvIns;
112 /** Pointer to the media driver below us.
113 * This is NULL if the media is not mounted. */
114 PPDMIMEDIA pDrvMedia;
115 /** Our media interface */
116 PDMIMEDIA IMedia;
117
118 /** Pointer to the media async driver below us.
119 * This is NULL if the media is not mounted. */
120 PPDMIMEDIAASYNC pDrvMediaAsync;
121 /** Our media async interface */
122 PDMIMEDIAASYNC IMediaAsync;
123
124 /** The async media port interface above. */
125 PPDMIMEDIAASYNCPORT pDrvMediaAsyncPort;
126 /** Our media async port interface */
127 PDMIMEDIAASYNCPORT IMediaAsyncPort;
128
129 /** Flag whether consistency checks are enabled. */
130 bool fCheckConsistency;
131 /** AVL tree containing the disk blocks to check. */
132 PAVLRFOFFTREE pTreeSegments;
133
134 /** Flag whether async request tracing is enabled. */
135 bool fTraceRequests;
136 /** Interval the thread should check for expired requests (milliseconds). */
137 uint32_t uCheckIntervalMs;
138 /** Expire timeout for a request (milliseconds). */
139 uint32_t uExpireIntervalMs;
140 /** Thread which checks for lost requests. */
141 RTTHREAD hThread;
142 /** Event semaphore */
143 RTSEMEVENT SemEvent;
144 /** Flag whether the thread should run. */
145 bool fRunning;
146 /** Array containing active requests. */
147 DRVDISKAIOREQACTIVE apReqActive[128];
148 /** Next free slot in the array */
149 volatile unsigned iNextFreeSlot;
150} DRVDISKINTEGRITY, *PDRVDISKINTEGRITY;
151
152
153/**
154 * Allocate a new I/O request.
155 *
156 * @returns New I/O request.
157 * @param fRead Flag whether this is a read or a write.
158 * @param off Start offset.
159 * @param paSeg Segment array.
160 * @param cSeg Number of segments.
161 * @param cbTransfer Number of bytes to transfer.
162 * @param pvUser User argument.
163 */
164static PDRVDISKAIOREQ drvdiskintIoReqAlloc(bool fRead, uint64_t off, PCRTSGSEG paSeg,
165 unsigned cSeg, size_t cbTransfer, void *pvUser)
166{
167 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)RTMemAlloc(sizeof(DRVDISKAIOREQ));
168
169 if (RT_LIKELY(pIoReq))
170 {
171 pIoReq->fRead = fRead;
172 pIoReq->off = off;
173 pIoReq->cbTransfer = cbTransfer;
174 pIoReq->paSeg = paSeg;
175 pIoReq->cSeg = cSeg;
176 pIoReq->pvUser = pvUser;
177 }
178
179 return pIoReq;
180}
181
182/**
183 * Record a successful write to the virtual disk.
184 *
185 * @returns VBox status code.
186 * @param pThis Disk integrity driver instance data.
187 * @param paSeg Segment array of the write to record.
188 * @param cSeg Number of segments.
189 * @param off Start offset.
190 * @param cbWrite Number of bytes to record.
191 */
192static int drvdiskintWriteRecord(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
193 uint64_t off, size_t cbWrite)
194{
195 int rc = VINF_SUCCESS;
196
197 LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbWrite=%u\n",
198 pThis, paSeg, cSeg, off, cbWrite));
199
200 /* Update the segments */
201 size_t cbLeft = cbWrite;
202 RTFOFF offCurr = (RTFOFF)off;
203 RTSGBUF SgBuf;
204 PIOLOGENT pIoLogEnt = (PIOLOGENT)RTMemAllocZ(sizeof(IOLOGENT));
205 if (!pIoLogEnt)
206 return VERR_NO_MEMORY;
207
208 pIoLogEnt->off = off;
209 pIoLogEnt->cbWrite = cbWrite;
210 pIoLogEnt->cRefs = 0;
211
212 RTSgBufInit(&SgBuf, paSeg, cSeg);
213
214 while (cbLeft)
215 {
216 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
217 size_t cbRange = 0;
218 bool fSet = false;
219 unsigned offSeg = 0;
220
221 if (!pSeg)
222 {
223 /* Get next segment */
224 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
225 if ( !pSeg
226 || offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
227 cbRange = cbLeft;
228 else
229 cbRange = pSeg->Core.Key - offCurr;
230
231 Assert(cbRange % 512 == 0);
232
233 /* Create new segment */
234 pSeg = (PDRVDISKSEGMENT)RTMemAllocZ(RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbRange / 512]));
235 if (pSeg)
236 {
237 pSeg->Core.Key = offCurr;
238 pSeg->Core.KeyLast = offCurr + (RTFOFF)cbRange - 1;
239 pSeg->cbSeg = cbRange;
240 pSeg->pbSeg = (uint8_t *)RTMemAllocZ(cbRange);
241 pSeg->cIoLogEntries = cbRange / 512;
242 if (!pSeg->pbSeg)
243 RTMemFree(pSeg);
244 else
245 {
246 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
247 AssertMsg(fInserted, ("Bug!\n"));
248 fSet = true;
249 }
250 }
251 }
252 else
253 {
254 fSet = true;
255 offSeg = offCurr - pSeg->Core.Key;
256 cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
257 }
258
259 if (fSet)
260 {
261 AssertPtr(pSeg);
262 size_t cbCopied = RTSgBufCopyToBuf(&SgBuf, pSeg->pbSeg + offSeg, cbRange);
263 Assert(cbCopied == cbRange);
264
265 /* Update the I/O log pointers */
266 Assert(offSeg % 512 == 0);
267 Assert(cbRange % 512 == 0);
268 while (offSeg < cbRange)
269 {
270 uint32_t uSector = offSeg / 512;
271 PIOLOGENT pIoLogOld = NULL;
272
273 AssertMsg(uSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
274
275 pIoLogOld = pSeg->apIoLog[uSector];
276 if (pIoLogOld)
277 {
278 pIoLogOld->cRefs--;
279 if (!pIoLogOld->cRefs)
280 RTMemFree(pIoLogOld);
281 }
282
283 pSeg->apIoLog[uSector] = pIoLogEnt;
284 pIoLogEnt->cRefs++;
285
286 offSeg += 512;
287 }
288 }
289 else
290 RTSgBufAdvance(&SgBuf, cbRange);
291
292 offCurr += cbRange;
293 cbLeft -= cbRange;
294 }
295
296 return rc;
297}
298
299/**
300 * Verifies a read request.
301 *
302 * @returns VBox status code.
303 * @param pThis Disk integrity driver instance data.
304 * @param paSeg Segment array of the containing the data buffers to verify.
305 * @param cSeg Number of segments.
306 * @param off Start offset.
307 * @param cbWrite Number of bytes to verify.
308 */
309static int drvdiskintReadVerify(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
310 uint64_t off, size_t cbRead)
311{
312 int rc = VINF_SUCCESS;
313
314 LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbRead=%u\n",
315 pThis, paSeg, cSeg, off, cbRead));
316
317 Assert(off % 512 == 0);
318 Assert(cbRead % 512 == 0);
319
320 /* Compare read data */
321 size_t cbLeft = cbRead;
322 RTFOFF offCurr = (RTFOFF)off;
323 RTSGBUF SgBuf;
324
325 RTSgBufInit(&SgBuf, paSeg, cSeg);
326
327 while (cbLeft)
328 {
329 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
330 size_t cbRange = 0;
331 bool fCmp = false;
332 unsigned offSeg = 0;
333
334 if (!pSeg)
335 {
336 /* Get next segment */
337 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
338 if (!pSeg)
339 {
340 /* No data in the tree for this read. Assume everything is ok. */
341 cbRange = cbLeft;
342 }
343 else if (offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
344 cbRange = cbLeft;
345 else
346 cbRange = pSeg->Core.Key - offCurr;
347 }
348 else
349 {
350 fCmp = true;
351 offSeg = offCurr - pSeg->Core.Key;
352 cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
353 }
354
355 if (fCmp)
356 {
357 RTSGSEG Seg;
358 RTSGBUF SgBufCmp;
359 size_t cbOff = 0;
360
361 Seg.cbSeg = cbRange;
362 Seg.pvSeg = pSeg->pbSeg + offSeg;
363
364 RTSgBufInit(&SgBufCmp, &Seg, 1);
365 if (RTSgBufCmpEx(&SgBuf, &SgBufCmp, cbRange, &cbOff, true))
366 {
367 /* Corrupted disk, print I/O log entry of the last write which accessed this range. */
368 uint32_t cSector = (offSeg + cbOff) / 512;
369 AssertMsg(cSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
370
371 RTMsgError("Corrupted disk at offset %llu (%u bytes in the current read buffer)!\n",
372 offCurr + cbOff, cbOff);
373 RTMsgError("Last write to this sector started at offset %llu with %u bytes (%u references to this log entry)\n",
374 pSeg->apIoLog[cSector]->off,
375 pSeg->apIoLog[cSector]->cbWrite,
376 pSeg->apIoLog[cSector]->cRefs);
377 RTAssertDebugBreak();
378 }
379 }
380 else
381 RTSgBufAdvance(&SgBuf, cbRange);
382
383 offCurr += cbRange;
384 cbLeft -= cbRange;
385 }
386
387 return rc;
388}
389
390/**
391 * Adds a request to the active list.
392 *
393 * @returns nothing.
394 * @param pThis The driver instance data.
395 * @param pIoReq The request to add.
396 */
397static void drvdiskintIoReqAdd(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
398{
399 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pThis->iNextFreeSlot];
400
401 Assert(!pReqActive->pIoReq);
402 pReqActive->tsStart = RTTimeSystemMilliTS();
403 pReqActive->pIoReq = pIoReq;
404 pIoReq->iSlot = pThis->iNextFreeSlot;
405
406 /* Search for the next one. */
407 while (pThis->apReqActive[pThis->iNextFreeSlot].pIoReq)
408 pThis->iNextFreeSlot = (pThis->iNextFreeSlot+1) % RT_ELEMENTS(pThis->apReqActive);
409}
410
411/**
412 * Removes a request from the active list.
413 *
414 * @returns nothing.
415 * @param pThis The driver instance data.
416 * @param pIoReq The request to remove.
417 */
418static void drvdiskintIoReqRemove(PDRVDISKINTEGRITY pThis, PDRVDISKAIOREQ pIoReq)
419{
420 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[pIoReq->iSlot];
421
422 Assert(pReqActive->pIoReq == pIoReq);
423
424 ASMAtomicXchgPtr((void * volatile *)&pReqActive->pIoReq, NULL);
425}
426
427/**
428 * Thread checking for expired requests.
429 *
430 * @returns IPRT status code.
431 * @param pThread Thread handle.
432 * @param pvUser Opaque user data.
433 */
434static int drvdiskIntIoReqExpiredCheck(RTTHREAD pThread, void *pvUser)
435{
436 PDRVDISKINTEGRITY pThis = (PDRVDISKINTEGRITY)pvUser;
437
438 while (pThis->fRunning)
439 {
440 int rc = RTSemEventWait(pThis->SemEvent, pThis->uCheckIntervalMs);
441
442 if (!pThis->fRunning)
443 break;
444
445 Assert(rc == VERR_TIMEOUT);
446
447 /* Get current timestamp for comparison. */
448 uint64_t tsCurr = RTTimeSystemMilliTS();
449
450 /* Go through the array and check for expired requests. */
451 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
452 {
453 PDRVDISKAIOREQACTIVE pReqActive = &pThis->apReqActive[i];
454 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)ASMAtomicReadPtr((void * volatile *)&pReqActive->pIoReq);
455
456 if ( pIoReq
457 && (tsCurr - pReqActive->tsStart) >= pThis->uExpireIntervalMs)
458 {
459 RTMsgError("Request %#p expired (active for %llu ms already)\n",
460 pIoReq, tsCurr - pReqActive->tsStart);
461 RTAssertDebugBreak();
462 }
463 }
464 }
465
466 return VINF_SUCCESS;
467}
468
469/* -=-=-=-=- IMedia -=-=-=-=- */
470
471/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIA. */
472#define PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMedia)) )
473/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIAASYNC. */
474#define PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsync)) )
475
476/*******************************************************************************
477* Media interface methods *
478*******************************************************************************/
479
480/** @copydoc PDMIMEDIA::pfnRead */
481static DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
482 uint64_t off, void *pvBuf, size_t cbRead)
483{
484 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
485 int rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
486 if (RT_FAILURE(rc))
487 return rc;
488
489 if (pThis->fCheckConsistency)
490 {
491 /* Verify the read. */
492 RTSGSEG Seg;
493 Seg.cbSeg = cbRead;
494 Seg.pvSeg = pvBuf;
495 rc = drvdiskintReadVerify(pThis, &Seg, 1, off, cbRead);
496 }
497
498 return rc;
499}
500
501/** @copydoc PDMIMEDIA::pfnWrite */
502static DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
503 uint64_t off, const void *pvBuf,
504 size_t cbWrite)
505{
506 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
507 int rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
508 if (RT_FAILURE(rc))
509 return rc;
510
511 if (pThis->fCheckConsistency)
512 {
513 /* Record the write. */
514 RTSGSEG Seg;
515 Seg.cbSeg = cbWrite;
516 Seg.pvSeg = (void *)pvBuf;
517 rc = drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
518 }
519
520 return rc;
521}
522
523static DECLCALLBACK(int) drvdiskintStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
524 PCRTSGSEG paSeg, unsigned cSeg,
525 size_t cbRead, void *pvUser)
526{
527 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d pvUser=%#p\n", __FUNCTION__,
528 uOffset, paSeg, cSeg, cbRead, pvUser));
529 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
530 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(true, uOffset, paSeg, cSeg, cbRead, pvUser);
531 AssertPtr(pIoReq);
532
533 if (pThis->fTraceRequests)
534 drvdiskintIoReqAdd(pThis, pIoReq);
535
536 int rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
537 cbRead, pIoReq);
538 if (rc == VINF_VD_ASYNC_IO_FINISHED)
539 {
540 /* Verify the read now. */
541 if (pThis->fCheckConsistency)
542 {
543 int rc2 = drvdiskintReadVerify(pThis, paSeg, cSeg, uOffset, cbRead);
544 AssertRC(rc2);
545 }
546
547 if (pThis->fTraceRequests)
548 drvdiskintIoReqRemove(pThis, pIoReq);
549 RTMemFree(pIoReq);
550 }
551 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
552 RTMemFree(pIoReq);
553
554 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
555 return rc;
556}
557
558static DECLCALLBACK(int) drvdiskintStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
559 PCRTSGSEG paSeg, unsigned cSeg,
560 size_t cbWrite, void *pvUser)
561{
562 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d pvUser=%#p\n", __FUNCTION__,
563 uOffset, paSeg, cSeg, cbWrite, pvUser));
564 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
565 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(false, uOffset, paSeg, cSeg, cbWrite, pvUser);
566 AssertPtr(pIoReq);
567
568 if (pThis->fTraceRequests)
569 drvdiskintIoReqAdd(pThis, pIoReq);
570
571 int rc = pThis->pDrvMediaAsync->pfnStartWrite(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
572 cbWrite, pIoReq);
573 if (rc == VINF_VD_ASYNC_IO_FINISHED)
574 {
575 /* Verify the read now. */
576 if (pThis->fCheckConsistency)
577 {
578 int rc2 = drvdiskintWriteRecord(pThis, paSeg, cSeg, uOffset, cbWrite);
579 AssertRC(rc2);
580 }
581
582 if (pThis->fTraceRequests)
583 drvdiskintIoReqRemove(pThis, pIoReq);
584
585 RTMemFree(pIoReq);
586 }
587 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
588 RTMemFree(pIoReq);
589
590 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
591 return rc;
592}
593
594/** @copydoc PDMIMEDIA::pfnFlush */
595static DECLCALLBACK(int) drvdiskintFlush(PPDMIMEDIA pInterface)
596{
597 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
598 return pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
599}
600
601/** @copydoc PDMIMEDIA::pfnGetSize */
602static DECLCALLBACK(uint64_t) drvdiskintGetSize(PPDMIMEDIA pInterface)
603{
604 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
605 return pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
606}
607
608/** @copydoc PDMIMEDIA::pfnIsReadOnly */
609static DECLCALLBACK(bool) drvdiskintIsReadOnly(PPDMIMEDIA pInterface)
610{
611 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
612 return pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
613}
614
615/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
616static DECLCALLBACK(int) drvdiskintBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
617 PPDMMEDIAGEOMETRY pPCHSGeometry)
618{
619 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
620 return pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
621}
622
623/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
624static DECLCALLBACK(int) drvdiskintBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
625 PCPDMMEDIAGEOMETRY pPCHSGeometry)
626{
627 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
628 return pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
629}
630
631/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
632static DECLCALLBACK(int) drvdiskintBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
633 PPDMMEDIAGEOMETRY pLCHSGeometry)
634{
635 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
636 return pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
637}
638
639/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
640static DECLCALLBACK(int) drvdiskintBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
641 PCPDMMEDIAGEOMETRY pLCHSGeometry)
642{
643 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
644 return pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
645}
646
647/** @copydoc PDMIMEDIA::pfnGetUuid */
648static DECLCALLBACK(int) drvdiskintGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
649{
650 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
651 return pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, pUuid);
652}
653
654/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
655
656/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
657#define PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsyncPort))) )
658
659static DECLCALLBACK(int) drvdiskintAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
660{
661 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface);
662 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)pvUser;
663 int rc = VINF_SUCCESS;
664
665 LogFlowFunc(("pIoReq=%#p\n", pIoReq));
666
667 /* Remove from the active list. */
668 if (pThis->fTraceRequests)
669 drvdiskintIoReqRemove(pThis, pIoReq);
670
671 if (RT_SUCCESS(rcReq) && pThis->fCheckConsistency)
672 {
673 if (pIoReq->fRead)
674 rc = drvdiskintReadVerify(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
675 else
676 rc = drvdiskintWriteRecord(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
677
678 AssertRC(rc);
679 }
680
681 rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pIoReq->pvUser, rcReq);
682 RTMemFree(pIoReq);
683
684 return rc;
685}
686
687/* -=-=-=-=- IBase -=-=-=-=- */
688
689/**
690 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
691 */
692static DECLCALLBACK(void *) drvdiskintQueryInterface(PPDMIBASE pInterface, const char *pszIID)
693{
694 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
695 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
696
697 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
698 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
699 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->pDrvMediaAsync ? &pThis->IMediaAsync : NULL);
700 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, &pThis->IMediaAsyncPort);
701 return NULL;
702}
703
704
705/* -=-=-=-=- driver interface -=-=-=-=- */
706
707static int drvdiskintTreeDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
708{
709 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)pNode;
710
711 RTMemFree(pSeg->pbSeg);
712 RTMemFree(pSeg);
713 return VINF_SUCCESS;
714}
715
716/**
717 * @copydoc FNPDMDRVDESTRUCT
718 */
719static DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
720{
721 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
722
723 if (pThis->pTreeSegments)
724 {
725 RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
726 RTMemFree(pThis->pTreeSegments);
727 }
728
729 if (pThis->fTraceRequests)
730 {
731 pThis->fRunning = false;
732 RTSemEventSignal(pThis->SemEvent);
733 RTSemEventDestroy(pThis->SemEvent);
734 }
735}
736
737/**
738 * Construct a disk integrity driver instance.
739 *
740 * @copydoc FNPDMDRVCONSTRUCT
741 */
742static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
743{
744 int rc = VINF_SUCCESS;
745 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
746 LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
747 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
748
749 /*
750 * Validate configuration.
751 */
752 if (!CFGMR3AreValuesValid(pCfg, "CheckConsistency\0"
753 "TraceRequests\0"
754 "CheckIntervalMs\0"
755 "ExpireIntervalMs\0"))
756 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
757
758 rc = CFGMR3QueryBoolDef(pCfg, "CheckConsistency", &pThis->fCheckConsistency, false);
759 AssertRC(rc);
760 rc = CFGMR3QueryBoolDef(pCfg, "TraceRequests", &pThis->fTraceRequests, false);
761 AssertRC(rc);
762 rc = CFGMR3QueryU32Def(pCfg, "CheckIntervalMs", &pThis->uCheckIntervalMs, 5000); /* 5 seconds */
763 AssertRC(rc);
764 rc = CFGMR3QueryU32Def(pCfg, "ExpireIntervalMs", &pThis->uExpireIntervalMs, 20000); /* 20 seconds */
765 AssertRC(rc);
766
767 /*
768 * Initialize most of the data members.
769 */
770 pThis->pDrvIns = pDrvIns;
771
772 /* IBase. */
773 pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
774
775 /* IMedia */
776 pThis->IMedia.pfnRead = drvdiskintRead;
777 pThis->IMedia.pfnWrite = drvdiskintWrite;
778 pThis->IMedia.pfnFlush = drvdiskintFlush;
779 pThis->IMedia.pfnGetSize = drvdiskintGetSize;
780 pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
781 pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
782 pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
783 pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
784 pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
785 pThis->IMedia.pfnGetUuid = drvdiskintGetUuid;
786
787 /* IMediaAsync */
788 pThis->IMediaAsync.pfnStartRead = drvdiskintStartRead;
789 pThis->IMediaAsync.pfnStartWrite = drvdiskintStartWrite;
790
791 /* IMediaAsyncPort. */
792 pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvdiskintAsyncTransferCompleteNotify;
793
794 /*
795 * Try attach driver below and query it's media interface.
796 */
797 PPDMIBASE pBase;
798 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
799 if (RT_FAILURE(rc))
800 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
801 N_("Failed to attach driver below us! %Rrc"), rc);
802
803 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
804 if (!pThis->pDrvMedia)
805 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
806 N_("No media or async media interface below"));
807
808 pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
809
810 /* Try to attach async media port interface above.*/
811 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
812
813 if (pThis->fCheckConsistency)
814 {
815 /* Create the AVL tree. */
816 pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
817 if (!pThis->pTreeSegments)
818 rc = VERR_NO_MEMORY;
819 }
820
821 if (pThis->fTraceRequests)
822 {
823 for (unsigned i = 0; i < RT_ELEMENTS(pThis->apReqActive); i++)
824 {
825 pThis->apReqActive[i].pIoReq = NULL;
826 pThis->apReqActive[i].tsStart = 0;
827 }
828
829 pThis->iNextFreeSlot = 0;
830
831 /* Init event semaphore. */
832 rc = RTSemEventCreate(&pThis->SemEvent);
833 AssertRC(rc);
834 pThis->fRunning = true;
835 rc = RTThreadCreate(&pThis->hThread, drvdiskIntIoReqExpiredCheck, pThis,
836 0, RTTHREADTYPE_INFREQUENT_POLLER, 0, "DiskIntegrity");
837 AssertRC(rc);
838 }
839
840 return rc;
841}
842
843
844/**
845 * Block driver registration record.
846 */
847const PDMDRVREG g_DrvDiskIntegrity =
848{
849 /* u32Version */
850 PDM_DRVREG_VERSION,
851 /* szName */
852 "DiskIntegrity",
853 /* szRCMod */
854 "",
855 /* szR0Mod */
856 "",
857 /* pszDescription */
858 "Disk integrity driver.",
859 /* fFlags */
860 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
861 /* fClass. */
862 PDM_DRVREG_CLASS_BLOCK,
863 /* cMaxInstances */
864 ~0,
865 /* cbInstance */
866 sizeof(DRVDISKINTEGRITY),
867 /* pfnConstruct */
868 drvdiskintConstruct,
869 /* pfnDestruct */
870 drvdiskintDestruct,
871 /* pfnRelocate */
872 NULL,
873 /* pfnIOCtl */
874 NULL,
875 /* pfnPowerOn */
876 NULL,
877 /* pfnReset */
878 NULL,
879 /* pfnSuspend */
880 NULL,
881 /* pfnResume */
882 NULL,
883 /* pfnAttach */
884 NULL,
885 /* pfnDetach */
886 NULL,
887 /* pfnPowerOff */
888 NULL,
889 /* pfnSoftReset */
890 NULL,
891 /* u32EndVersion */
892 PDM_DRVREG_VERSION
893};
894
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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