VirtualBox

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

Last change on this file since 28114 was 28114, checked in by vboxsync, 15 years ago

DrvDiskIntegrity: Support for async I/O

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