VirtualBox

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

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

DrvDiskIntegrity: Bug fix

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