VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 22.9 KB
 
1/* $Id: DrvDiskIntegrity.cpp 28800 2010-04-27 08:22:32Z 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
32#include "Builtins.h"
33
34
35/*******************************************************************************
36* Structures and Typedefs *
37*******************************************************************************/
38
39/**
40 * async I/O request.
41 */
42typedef struct DRVDISKAIOREQ
43{
44 /** Flag whether this is a read or write request. */
45 bool fRead;
46 /** Start offset. */
47 uint64_t off;
48 /** Transfer size. */
49 size_t cbTransfer;
50 /** Segment array. */
51 PCRTSGSEG paSeg;
52 /** Number of array entries. */
53 unsigned cSeg;
54 /** User argument */
55 void *pvUser;
56} DRVDISKAIOREQ, *PDRVDISKAIOREQ;
57
58/**
59 * I/O log entry.
60 */
61typedef struct IOLOGENT
62{
63 /** Start offset */
64 uint64_t off;
65 /** Write size */
66 size_t cbWrite;
67 /** Number of references to this entry. */
68 unsigned cRefs;
69} IOLOGENT, *PIOLOGENT;
70
71/**
72 * Disk segment.
73 */
74typedef struct DRVDISKSEGMENT
75{
76 /** AVL core. */
77 AVLRFOFFNODECORE Core;
78 /** Size of the segment */
79 size_t cbSeg;
80 /** Data for this segment */
81 uint8_t *pbSeg;
82 /** Numbner of entries in the I/O array. */
83 unsigned cIoLogEntries;
84 /** Array of I/O log references. */
85 PIOLOGENT apIoLog[1];
86} DRVDISKSEGMENT, *PDRVDISKSEGMENT;
87
88/**
89 * Disk integrity driver instance data.
90 *
91 * @implements PDMIMEDIA
92 */
93typedef struct DRVDISKINTEGRITY
94{
95 /** Pointer driver instance. */
96 PPDMDRVINS pDrvIns;
97 /** Pointer to the media driver below us.
98 * This is NULL if the media is not mounted. */
99 PPDMIMEDIA pDrvMedia;
100 /** Our media interface */
101 PDMIMEDIA IMedia;
102
103 /** Pointer to the media async driver below us.
104 * This is NULL if the media is not mounted. */
105 PPDMIMEDIAASYNC pDrvMediaAsync;
106 /** Our media async interface */
107 PDMIMEDIAASYNC IMediaAsync;
108
109 /** The async media port interface above. */
110 PPDMIMEDIAASYNCPORT pDrvMediaAsyncPort;
111 /** Our media async port interface */
112 PDMIMEDIAASYNCPORT IMediaAsyncPort;
113
114 /** AVL tree containing the disk blocks to check. */
115 PAVLRFOFFTREE pTreeSegments;
116} DRVDISKINTEGRITY, *PDRVDISKINTEGRITY;
117
118
119/**
120 * Allocate a new I/O request.
121 *
122 * @returns New I/O request.
123 * @param fRead Flag whether this is a read or a write.
124 * @param off Start offset.
125 * @param paSeg Segment array.
126 * @param cSeg Number of segments.
127 * @param cbTransfer Number of bytes to transfer.
128 * @param pvUser User argument.
129 */
130static PDRVDISKAIOREQ drvdiskintIoReqAlloc(bool fRead, uint64_t off, PCRTSGSEG paSeg,
131 unsigned cSeg, size_t cbTransfer, void *pvUser)
132{
133 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)RTMemAlloc(sizeof(DRVDISKAIOREQ));
134
135 if (RT_LIKELY(pIoReq))
136 {
137 pIoReq->fRead = fRead;
138 pIoReq->off = off;
139 pIoReq->cbTransfer = cbTransfer;
140 pIoReq->paSeg = paSeg;
141 pIoReq->cSeg = cSeg;
142 pIoReq->pvUser = pvUser;
143 }
144
145 return pIoReq;
146}
147
148/**
149 * Record a successful write to the virtual disk.
150 *
151 * @returns VBox status code.
152 * @param pThis Disk integrity driver instance data.
153 * @param paSeg Segment array of the write to record.
154 * @param cSeg Number of segments.
155 * @param off Start offset.
156 * @param cbWrite Number of bytes to record.
157 */
158static int drvdiskintWriteRecord(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
159 uint64_t off, size_t cbWrite)
160{
161 int rc = VINF_SUCCESS;
162
163 LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbWrite=%u\n",
164 pThis, paSeg, cSeg, off, cbWrite));
165
166 /* Update the segments */
167 size_t cbLeft = cbWrite;
168 RTFOFF offCurr = (RTFOFF)off;
169 RTSGBUF SgBuf;
170 PIOLOGENT pIoLogEnt = (PIOLOGENT)RTMemAllocZ(sizeof(IOLOGENT));
171 if (!pIoLogEnt)
172 return VERR_NO_MEMORY;
173
174 pIoLogEnt->off = off;
175 pIoLogEnt->cbWrite = cbWrite;
176 pIoLogEnt->cRefs = 0;
177
178 RTSgBufInit(&SgBuf, paSeg, cSeg);
179
180 while (cbLeft)
181 {
182 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
183 size_t cbRange = 0;
184 bool fSet = false;
185 unsigned offSeg = 0;
186
187 if (!pSeg)
188 {
189 /* Get next segment */
190 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
191 if ( !pSeg
192 || offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
193 cbRange = cbLeft;
194 else
195 cbRange = pSeg->Core.Key - offCurr;
196
197 Assert(cbRange % 512 == 0);
198
199 /* Create new segment */
200 pSeg = (PDRVDISKSEGMENT)RTMemAllocZ(RT_OFFSETOF(DRVDISKSEGMENT, apIoLog[cbRange / 512]));
201 if (pSeg)
202 {
203 pSeg->Core.Key = offCurr;
204 pSeg->Core.KeyLast = offCurr + (RTFOFF)cbRange - 1;
205 pSeg->cbSeg = cbRange;
206 pSeg->pbSeg = (uint8_t *)RTMemAllocZ(cbRange);
207 pSeg->cIoLogEntries = cbRange / 512;
208 if (!pSeg->pbSeg)
209 RTMemFree(pSeg);
210 else
211 {
212 bool fInserted = RTAvlrFileOffsetInsert(pThis->pTreeSegments, &pSeg->Core);
213 AssertMsg(fInserted, ("Bug!\n"));
214 fSet = true;
215 }
216 }
217 }
218 else
219 {
220 fSet = true;
221 offSeg = offCurr - pSeg->Core.Key;
222 cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
223 }
224
225 if (fSet)
226 {
227 AssertPtr(pSeg);
228 size_t cbCopied = RTSgBufCopyToBuf(&SgBuf, pSeg->pbSeg + offSeg, cbRange);
229 Assert(cbCopied == cbRange);
230
231 /* Update the I/O log pointers */
232 Assert(offSeg % 512 == 0);
233 Assert(cbRange % 512 == 0);
234 while (offSeg < cbRange)
235 {
236 uint32_t uSector = offSeg / 512;
237 PIOLOGENT pIoLogOld = NULL;
238
239 AssertMsg(uSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
240
241 pIoLogOld = pSeg->apIoLog[uSector];
242 if (pIoLogOld)
243 {
244 pIoLogOld->cRefs--;
245 if (!pIoLogOld->cRefs)
246 RTMemFree(pIoLogOld);
247 }
248
249 pSeg->apIoLog[uSector] = pIoLogEnt;
250 pIoLogEnt->cRefs++;
251
252 offSeg += 512;
253 }
254 }
255 else
256 RTSgBufAdvance(&SgBuf, cbRange);
257
258 offCurr += cbRange;
259 cbLeft -= cbRange;
260 }
261
262 return rc;
263}
264
265/**
266 * Verifies a read request.
267 *
268 * @returns VBox status code.
269 * @param pThis Disk integrity driver instance data.
270 * @param paSeg Segment array of the containing the data buffers to verify.
271 * @param cSeg Number of segments.
272 * @param off Start offset.
273 * @param cbWrite Number of bytes to verify.
274 */
275static int drvdiskintReadVerify(PDRVDISKINTEGRITY pThis, PCRTSGSEG paSeg, unsigned cSeg,
276 uint64_t off, size_t cbRead)
277{
278 int rc = VINF_SUCCESS;
279
280 LogFlowFunc(("pThis=%#p paSeg=%#p cSeg=%u off=%llx cbRead=%u\n",
281 pThis, paSeg, cSeg, off, cbRead));
282
283 Assert(off % 512 == 0);
284 Assert(cbRead % 512 == 0);
285
286 /* Compare read data */
287 size_t cbLeft = cbRead;
288 RTFOFF offCurr = (RTFOFF)off;
289 RTSGBUF SgBuf;
290
291 RTSgBufInit(&SgBuf, paSeg, cSeg);
292
293 while (cbLeft)
294 {
295 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetRangeGet(pThis->pTreeSegments, offCurr);
296 size_t cbRange = 0;
297 bool fCmp = false;
298 unsigned offSeg = 0;
299
300 if (!pSeg)
301 {
302 /* Get next segment */
303 pSeg = (PDRVDISKSEGMENT)RTAvlrFileOffsetGetBestFit(pThis->pTreeSegments, offCurr, true);
304 if (!pSeg)
305 {
306 /* No data in the tree for this read. Assume everything is ok. */
307 cbRange = cbLeft;
308 }
309 else if (offCurr + (RTFOFF)cbLeft <= pSeg->Core.Key)
310 cbRange = cbLeft;
311 else
312 cbRange = pSeg->Core.Key - offCurr;
313 }
314 else
315 {
316 fCmp = true;
317 offSeg = offCurr - pSeg->Core.Key;
318 cbRange = RT_MIN(cbLeft, (size_t)(pSeg->Core.KeyLast + 1 - offCurr));
319 }
320
321 if (fCmp)
322 {
323 RTSGSEG Seg;
324 RTSGBUF SgBufCmp;
325 size_t cbOff = 0;
326
327 Seg.cbSeg = cbRange;
328 Seg.pvSeg = pSeg->pbSeg + offSeg;
329
330 RTSgBufInit(&SgBufCmp, &Seg, 1);
331 if (RTSgBufCmpEx(&SgBuf, &SgBufCmp, cbRange, &cbOff, true))
332 {
333 /* Corrupted disk, print I/O log entry of the last write which accessed this range. */
334 uint32_t cSector = (offSeg + cbOff) / 512;
335 AssertMsg(cSector < pSeg->cIoLogEntries, ("Internal bug!\n"));
336
337 RTMsgError("Corrupted disk at offset %llu (%u bytes in the current read buffer)!\n",
338 offCurr + cbOff, cbOff);
339 RTMsgError("Last write to this sector started at offset %llu with %u bytes (%u references to this log entry)\n",
340 pSeg->apIoLog[cSector]->off,
341 pSeg->apIoLog[cSector]->cbWrite,
342 pSeg->apIoLog[cSector]->cRefs);
343 RTAssertDebugBreak();
344 }
345 }
346 else
347 RTSgBufAdvance(&SgBuf, cbRange);
348
349 offCurr += cbRange;
350 cbLeft -= cbRange;
351 }
352
353 return rc;
354}
355
356/* -=-=-=-=- IMedia -=-=-=-=- */
357
358/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIA. */
359#define PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMedia)) )
360/** Makes a PDRVDISKINTEGRITY out of a PPDMIMEDIAASYNC. */
361#define PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY)((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsync)) )
362
363/*******************************************************************************
364* Media interface methods *
365*******************************************************************************/
366
367/** @copydoc PDMIMEDIA::pfnRead */
368static DECLCALLBACK(int) drvdiskintRead(PPDMIMEDIA pInterface,
369 uint64_t off, void *pvBuf, size_t cbRead)
370{
371 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
372 int rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
373 if (RT_FAILURE(rc))
374 return rc;
375
376 /* Verify the read. */
377 RTSGSEG Seg;
378 Seg.cbSeg = cbRead;
379 Seg.pvSeg = pvBuf;
380 return drvdiskintReadVerify(pThis, &Seg, 1, off, cbRead);
381}
382
383/** @copydoc PDMIMEDIA::pfnWrite */
384static DECLCALLBACK(int) drvdiskintWrite(PPDMIMEDIA pInterface,
385 uint64_t off, const void *pvBuf,
386 size_t cbWrite)
387{
388 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
389 int rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
390 if (RT_FAILURE(rc))
391 return rc;
392
393 /* Record the write. */
394 RTSGSEG Seg;
395 Seg.cbSeg = cbWrite;
396 Seg.pvSeg = (void *)pvBuf;
397 return drvdiskintWriteRecord(pThis, &Seg, 1, off, cbWrite);
398}
399
400static DECLCALLBACK(int) drvdiskintStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
401 PCRTSGSEG paSeg, unsigned cSeg,
402 size_t cbRead, void *pvUser)
403{
404 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d\n pvUser=%#p", __FUNCTION__,
405 uOffset, paSeg, cSeg, cbRead, pvUser));
406 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
407 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(true, uOffset, paSeg, cSeg, cbRead, pvUser);
408 AssertPtr(pIoReq);
409
410 int rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
411 cbRead, pIoReq);
412 if (rc == VINF_VD_ASYNC_IO_FINISHED)
413 {
414 /* Verify the read now. */
415 int rc2 = drvdiskintReadVerify(pThis, paSeg, cSeg, uOffset, cbRead);
416 AssertRC(rc2);
417 RTMemFree(pIoReq);
418 }
419 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
420 RTMemFree(pIoReq);
421
422 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
423 return rc;
424}
425
426static DECLCALLBACK(int) drvdiskintStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
427 PCRTSGSEG paSeg, unsigned cSeg,
428 size_t cbWrite, void *pvUser)
429{
430 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d\n pvUser=%#p", __FUNCTION__,
431 uOffset, paSeg, cSeg, cbWrite, pvUser));
432 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNC_2_DRVDISKINTEGRITY(pInterface);
433 PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(false, uOffset, paSeg, cSeg, cbWrite, pvUser);
434 AssertPtr(pIoReq);
435
436 int rc = pThis->pDrvMediaAsync->pfnStartWrite(pThis->pDrvMediaAsync, uOffset, paSeg, cSeg,
437 cbWrite, pIoReq);
438 if (rc == VINF_VD_ASYNC_IO_FINISHED)
439 {
440 /* Verify the read now. */
441 int rc2 = drvdiskintWriteRecord(pThis, paSeg, cSeg, uOffset, cbWrite);
442 AssertRC(rc2);
443 RTMemFree(pIoReq);
444 }
445 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
446 RTMemFree(pIoReq);
447
448 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
449 return rc;
450}
451
452/** @copydoc PDMIMEDIA::pfnFlush */
453static DECLCALLBACK(int) drvdiskintFlush(PPDMIMEDIA pInterface)
454{
455 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
456 return pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
457}
458
459/** @copydoc PDMIMEDIA::pfnGetSize */
460static DECLCALLBACK(uint64_t) drvdiskintGetSize(PPDMIMEDIA pInterface)
461{
462 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
463 return pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
464}
465
466/** @copydoc PDMIMEDIA::pfnIsReadOnly */
467static DECLCALLBACK(bool) drvdiskintIsReadOnly(PPDMIMEDIA pInterface)
468{
469 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
470 return pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
471}
472
473/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
474static DECLCALLBACK(int) drvdiskintBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
475 PPDMMEDIAGEOMETRY pPCHSGeometry)
476{
477 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
478 return pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
479}
480
481/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
482static DECLCALLBACK(int) drvdiskintBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
483 PCPDMMEDIAGEOMETRY pPCHSGeometry)
484{
485 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
486 return pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
487}
488
489/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
490static DECLCALLBACK(int) drvdiskintBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
491 PPDMMEDIAGEOMETRY pLCHSGeometry)
492{
493 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
494 return pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
495}
496
497/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
498static DECLCALLBACK(int) drvdiskintBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
499 PCPDMMEDIAGEOMETRY pLCHSGeometry)
500{
501 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
502 return pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
503}
504
505/** @copydoc PDMIMEDIA::pfnGetUuid */
506static DECLCALLBACK(int) drvdiskintGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
507{
508 PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
509 return pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, pUuid);
510}
511
512/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
513
514/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
515#define PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface) ( (PDRVDISKINTEGRITY((uintptr_t)pInterface - RT_OFFSETOF(DRVDISKINTEGRITY, IMediaAsyncPort))) )
516
517static DECLCALLBACK(int) drvdiskintAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
518{
519 PDRVDISKINTEGRITY pThis = PDMIMEDIAASYNCPORT_2_DRVDISKINTEGRITY(pInterface);
520 PDRVDISKAIOREQ pIoReq = (PDRVDISKAIOREQ)pvUser;
521 int rc = VINF_SUCCESS;
522
523 LogFlowFunc(("pIoReq=%#p\n", pIoReq));
524
525 if (RT_SUCCESS(rcReq))
526 {
527 if (pIoReq->fRead)
528 rc = drvdiskintReadVerify(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
529 else
530 rc = drvdiskintWriteRecord(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
531
532 AssertRC(rc);
533 }
534
535 rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pIoReq->pvUser, rcReq);
536 RTMemFree(pIoReq);
537
538 return rc;
539}
540
541/* -=-=-=-=- IBase -=-=-=-=- */
542
543/**
544 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
545 */
546static DECLCALLBACK(void *) drvdiskintQueryInterface(PPDMIBASE pInterface, const char *pszIID)
547{
548 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
549 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
550
551 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
552 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
553 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->pDrvMediaAsync ? &pThis->IMediaAsync : NULL);
554 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, &pThis->IMediaAsyncPort);
555 return NULL;
556}
557
558
559/* -=-=-=-=- driver interface -=-=-=-=- */
560
561static int drvdiskintTreeDestroy(PAVLRFOFFNODECORE pNode, void *pvUser)
562{
563 PDRVDISKSEGMENT pSeg = (PDRVDISKSEGMENT)pNode;
564
565 RTMemFree(pSeg->pbSeg);
566 RTMemFree(pSeg);
567 return VINF_SUCCESS;
568}
569
570/**
571 * @copydoc FNPDMDRVDESTRUCT
572 */
573static DECLCALLBACK(void) drvdiskintDestruct(PPDMDRVINS pDrvIns)
574{
575 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
576
577 if (pThis->pTreeSegments)
578 {
579 RTAvlrFileOffsetDestroy(pThis->pTreeSegments, drvdiskintTreeDestroy, NULL);
580 RTMemFree(pThis->pTreeSegments);
581 }
582}
583
584/**
585 * Construct a disk integrity driver instance.
586 *
587 * @copydoc FNPDMDRVCONSTRUCT
588 */
589static DECLCALLBACK(int) drvdiskintConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
590{
591 PDRVDISKINTEGRITY pThis = PDMINS_2_DATA(pDrvIns, PDRVDISKINTEGRITY);
592 LogFlow(("drvdiskintConstruct: iInstance=%d\n", pDrvIns->iInstance));
593 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
594
595 /*
596 * Validate configuration.
597 */
598 if (!CFGMR3AreValuesValid(pCfg, ""))
599 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
600
601 /*
602 * Initialize most of the data members.
603 */
604 pThis->pDrvIns = pDrvIns;
605
606 /* IBase. */
607 pDrvIns->IBase.pfnQueryInterface = drvdiskintQueryInterface;
608
609 /* IMedia */
610 pThis->IMedia.pfnRead = drvdiskintRead;
611 pThis->IMedia.pfnWrite = drvdiskintWrite;
612 pThis->IMedia.pfnFlush = drvdiskintFlush;
613 pThis->IMedia.pfnGetSize = drvdiskintGetSize;
614 pThis->IMedia.pfnIsReadOnly = drvdiskintIsReadOnly;
615 pThis->IMedia.pfnBiosGetPCHSGeometry = drvdiskintBiosGetPCHSGeometry;
616 pThis->IMedia.pfnBiosSetPCHSGeometry = drvdiskintBiosSetPCHSGeometry;
617 pThis->IMedia.pfnBiosGetLCHSGeometry = drvdiskintBiosGetLCHSGeometry;
618 pThis->IMedia.pfnBiosSetLCHSGeometry = drvdiskintBiosSetLCHSGeometry;
619 pThis->IMedia.pfnGetUuid = drvdiskintGetUuid;
620
621 /* IMediaAsync */
622 pThis->IMediaAsync.pfnStartRead = drvdiskintStartRead;
623 pThis->IMediaAsync.pfnStartWrite = drvdiskintStartWrite;
624
625 /* IMediaAsyncPort. */
626 pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvdiskintAsyncTransferCompleteNotify;
627
628 /*
629 * Try attach driver below and query it's media interface.
630 */
631 PPDMIBASE pBase;
632 int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
633 if (RT_FAILURE(rc))
634 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
635 N_("Failed to attach driver below us! %Rrf"), rc);
636
637 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
638 if (!pThis->pDrvMedia)
639 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
640 N_("No media or async media interface below"));
641
642 pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
643
644 /* Try to attach async media port interface above.*/
645 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
646
647 /* Create the AVL tree. */
648 pThis->pTreeSegments = (PAVLRFOFFTREE)RTMemAllocZ(sizeof(AVLRFOFFTREE));
649 if (!pThis->pTreeSegments)
650 rc = VERR_NO_MEMORY;
651
652 return rc;
653}
654
655
656/**
657 * Block driver registration record.
658 */
659const PDMDRVREG g_DrvDiskIntegrity =
660{
661 /* u32Version */
662 PDM_DRVREG_VERSION,
663 /* szName */
664 "DiskIntegrity",
665 /* szRCMod */
666 "",
667 /* szR0Mod */
668 "",
669 /* pszDescription */
670 "Disk integrity driver.",
671 /* fFlags */
672 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
673 /* fClass. */
674 PDM_DRVREG_CLASS_BLOCK,
675 /* cMaxInstances */
676 ~0,
677 /* cbInstance */
678 sizeof(DRVDISKINTEGRITY),
679 /* pfnConstruct */
680 drvdiskintConstruct,
681 /* pfnDestruct */
682 drvdiskintDestruct,
683 /* pfnRelocate */
684 NULL,
685 /* pfnIOCtl */
686 NULL,
687 /* pfnPowerOn */
688 NULL,
689 /* pfnReset */
690 NULL,
691 /* pfnSuspend */
692 NULL,
693 /* pfnResume */
694 NULL,
695 /* pfnAttach */
696 NULL,
697 /* pfnDetach */
698 NULL,
699 /* pfnPowerOff */
700 NULL,
701 /* pfnSoftReset */
702 NULL,
703 /* u32EndVersion */
704 PDM_DRVREG_VERSION
705};
706
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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