VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvBlock.cpp@ 6291

Last change on this file since 6291 was 6291, checked in by vboxsync, 17 years ago

Big virtual disk changeset containing several modifications

  • remove the always buggy translation setting and replace it with two sets of geometries, physical and logical
  • complete vmdk creation (fixed/dynamic variants, both split in 2G chunks and single file)
  • implemented VBoxHDD-new generic snapshot support, i.e. diff image creation and image merging (completely untested, I'm pretty sure there are bugs)
  • assorted changes which generalize the VBoxHDD-new interfaces (both externally and internally)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.0 KB
Line 
1/** @file
2 *
3 * VBox storage devices:
4 * Generic block driver
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#define LOG_GROUP LOG_GROUP_DRV_BLOCK
24#include <VBox/pdmdrv.h>
25#include <iprt/assert.h>
26#include <iprt/uuid.h>
27
28#include <string.h>
29
30#include "Builtins.h"
31
32
33/** @def VBOX_PERIODIC_FLUSH
34 * Enable support for periodically flushing the VDI to disk. This may prove
35 * useful for those nasty problems with the ultra-slow host filesystems.
36 * If this is enabled, it can be configured via the CFGM key
37 * "VBoxInternal/Devices/piix3ide/0/LUN#<x>/Config/FlushInterval". <x>
38 * must be replaced with the correct LUN number of the disk that should
39 * do the periodic flushes. The value of the key is the number of bytes
40 * written between flushes. A value of 0 (the default) denotes no flushes. */
41#define VBOX_PERIODIC_FLUSH
42
43/** @def VBOX_IGNORE_FLUSH
44 * Enable support for ignoring VDI flush requests. This can be useful for
45 * filesystems that show bad guest IDE write performance (especially with
46 * Windows guests). NOTE that this does not disable the flushes caused by
47 * the periodic flush cache feature above.
48 * If this feature is enabled, it can be configured via the CFGM key
49 * "VBoxInternal/Devices/piix3ide/0/LUN#<x>/Config/IgnoreFlush". <x>
50 * must be replaced with the correct LUN number of the disk that should
51 * ignore flush requests. The value of the key is a boolean. The default
52 * is to ignore flushes, i.e. true. */
53#define VBOX_IGNORE_FLUSH
54
55/*******************************************************************************
56* Structures and Typedefs *
57*******************************************************************************/
58/**
59 * Block driver instance data.
60 */
61typedef struct DRVBLOCK
62{
63 /** Pointer driver instance. */
64 PPDMDRVINS pDrvIns;
65 /** Drive type. */
66 PDMBLOCKTYPE enmType;
67 /** Locked indicator. */
68 bool fLocked;
69 /** Mountable indicator. */
70 bool fMountable;
71 /** Visible to the BIOS. */
72 bool fBiosVisible;
73#ifdef VBOX_PERIODIC_FLUSH
74 /** HACK: Configuration value for number of bytes written after which to flush. */
75 uint32_t cbFlushInterval;
76 /** HACK: Current count for the number of bytes written since the last flush. */
77 uint32_t cbDataWritten;
78#endif /* VBOX_PERIODIC_FLUSH */
79#ifdef VBOX_IGNORE_FLUSH
80 /** HACK: Disable flushes for this drive. */
81 bool fIgnoreFlush;
82#endif /* VBOX_IGNORE_FLUSH */
83 /** Pointer to the media driver below us.
84 * This is NULL if the media is not mounted. */
85 PPDMIMEDIA pDrvMedia;
86 /** Pointer to the block port interface above us. */
87 PPDMIBLOCKPORT pDrvBlockPort;
88 /** Pointer to the mount notify interface above us. */
89 PPDMIMOUNTNOTIFY pDrvMountNotify;
90 /** Our block interface. */
91 PDMIBLOCK IBlock;
92 /** Our block interface. */
93 PDMIBLOCKBIOS IBlockBios;
94 /** Our mountable interface. */
95 PDMIMOUNT IMount;
96
97 /** Uuid of the drive. */
98 RTUUID Uuid;
99
100 /** BIOS PCHS Geometry. */
101 PDMMEDIAGEOMETRY PCHSGeometry;
102 /** BIOS LCHS Geometry. */
103 PDMMEDIAGEOMETRY LCHSGeometry;
104} DRVBLOCK, *PDRVBLOCK;
105
106
107/* -=-=-=-=- IBlock -=-=-=-=- */
108
109/** Makes a PDRVBLOCK out of a PPDMIBLOCK. */
110#define PDMIBLOCK_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlock)) )
111
112
113/** @copydoc PDMIBLOCK::pfnRead */
114static DECLCALLBACK(int) drvblockRead(PPDMIBLOCK pInterface, uint64_t off, void *pvBuf, size_t cbRead)
115{
116 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
117
118 /*
119 * Check the state.
120 */
121 if (!pData->pDrvMedia)
122 {
123 AssertMsgFailed(("Invalid state! Not mounted!\n"));
124 return VERR_PDM_MEDIA_NOT_MOUNTED;
125 }
126
127 int rc = pData->pDrvMedia->pfnRead(pData->pDrvMedia, off, pvBuf, cbRead);
128 return rc;
129}
130
131
132/** @copydoc PDMIBLOCK::pfnWrite */
133static DECLCALLBACK(int) drvblockWrite(PPDMIBLOCK pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
134{
135 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
136
137 /*
138 * Check the state.
139 */
140 if (!pData->pDrvMedia)
141 {
142 AssertMsgFailed(("Invalid state! Not mounted!\n"));
143 return VERR_PDM_MEDIA_NOT_MOUNTED;
144 }
145
146 int rc = pData->pDrvMedia->pfnWrite(pData->pDrvMedia, off, pvBuf, cbWrite);
147#ifdef VBOX_PERIODIC_FLUSH
148 if (pData->cbFlushInterval)
149 {
150 pData->cbDataWritten += cbWrite;
151 if (pData->cbDataWritten > pData->cbFlushInterval)
152 {
153 pData->cbDataWritten = 0;
154 pData->pDrvMedia->pfnFlush(pData->pDrvMedia);
155 }
156 }
157#endif /* VBOX_PERIODIC_FLUSH */
158
159 return rc;
160}
161
162
163/** @copydoc PDMIBLOCK::pfnFlush */
164static DECLCALLBACK(int) drvblockFlush(PPDMIBLOCK pInterface)
165{
166 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
167
168 /*
169 * Check the state.
170 */
171 if (!pData->pDrvMedia)
172 {
173 AssertMsgFailed(("Invalid state! Not mounted!\n"));
174 return VERR_PDM_MEDIA_NOT_MOUNTED;
175 }
176
177#ifdef VBOX_IGNORE_FLUSH
178 if (pData->fIgnoreFlush)
179 return VINF_SUCCESS;
180#endif /* VBOX_IGNORE_FLUSH */
181
182 int rc = pData->pDrvMedia->pfnFlush(pData->pDrvMedia);
183 if (rc == VERR_NOT_IMPLEMENTED)
184 rc = VINF_SUCCESS;
185 return rc;
186}
187
188
189/** @copydoc PDMIBLOCK::pfnIsReadOnly */
190static DECLCALLBACK(bool) drvblockIsReadOnly(PPDMIBLOCK pInterface)
191{
192 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
193
194 /*
195 * Check the state.
196 */
197 if (!pData->pDrvMedia)
198 return false;
199
200 bool fRc = pData->pDrvMedia->pfnIsReadOnly(pData->pDrvMedia);
201 return fRc;
202}
203
204
205/** @copydoc PDMIBLOCK::pfnGetSize */
206static DECLCALLBACK(uint64_t) drvblockGetSize(PPDMIBLOCK pInterface)
207{
208 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
209
210 /*
211 * Check the state.
212 */
213 if (!pData->pDrvMedia)
214 return 0;
215
216 uint64_t cb = pData->pDrvMedia->pfnGetSize(pData->pDrvMedia);
217 LogFlow(("drvblockGetSize: returns %llu\n", cb));
218 return cb;
219}
220
221
222/** @copydoc PDMIBLOCK::pfnGetType */
223static DECLCALLBACK(PDMBLOCKTYPE) drvblockGetType(PPDMIBLOCK pInterface)
224{
225 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
226 LogFlow(("drvblockGetType: returns %d\n", pData->enmType));
227 return pData->enmType;
228}
229
230
231/** @copydoc PDMIBLOCK::pfnGetUuid */
232static DECLCALLBACK(int) drvblockGetUuid(PPDMIBLOCK pInterface, PRTUUID pUuid)
233{
234 PDRVBLOCK pData = PDMIBLOCK_2_DRVBLOCK(pInterface);
235
236 /*
237 * Copy the uuid.
238 */
239 *pUuid = pData->Uuid;
240 return VINF_SUCCESS;
241}
242
243
244/* -=-=-=-=- IBlockBios -=-=-=-=- */
245
246/** Makes a PDRVBLOCK out of a PPDMIBLOCKBIOS. */
247#define PDMIBLOCKBIOS_2_DRVBLOCK(pInterface) ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlockBios))) )
248
249
250/** @copydoc PDMIBLOCKBIOS::pfnGetPCHSGeometry */
251static DECLCALLBACK(int) drvblockGetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
252{
253 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
254
255 /*
256 * Check the state.
257 */
258 if (!pData->pDrvMedia)
259 return VERR_PDM_MEDIA_NOT_MOUNTED;
260
261 /*
262 * Use configured/cached values if present.
263 */
264 if ( pData->PCHSGeometry.cCylinders > 0
265 && pData->PCHSGeometry.cHeads > 0
266 && pData->PCHSGeometry.cSectors > 0)
267 {
268 *pPCHSGeometry = pData->PCHSGeometry;
269 LogFlow(("%s: returns VINF_SUCCESS {%d,%d,%d}\n", __FUNCTION__, pData->PCHSGeometry.cCylinders, pData->PCHSGeometry.cHeads, pData->PCHSGeometry.cSectors));
270 return VINF_SUCCESS;
271 }
272
273 /*
274 * Call media.
275 */
276 int rc = pData->pDrvMedia->pfnBiosGetPCHSGeometry(pData->pDrvMedia, &pData->PCHSGeometry);
277 if (VBOX_SUCCESS(rc))
278 {
279 *pPCHSGeometry = pData->PCHSGeometry;
280 LogFlow(("%s: returns %Vrc {%d,%d,%d}\n", __FUNCTION__, rc, pData->PCHSGeometry.cCylinders, pData->PCHSGeometry.cHeads, pData->PCHSGeometry.cSectors));
281 }
282 else if (rc == VERR_NOT_IMPLEMENTED)
283 {
284 rc = VERR_PDM_GEOMETRY_NOT_SET;
285 LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
286 }
287 return rc;
288}
289
290
291/** @copydoc PDMIBLOCKBIOS::pfnSetPCHSGeometry */
292static DECLCALLBACK(int) drvblockSetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
293{
294 LogFlow(("%s: cCylinders=%d cHeads=%d cSectors=%d\n", __FUNCTION__, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
295 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
296
297 /*
298 * Check the state.
299 */
300 if (!pData->pDrvMedia)
301 {
302 AssertMsgFailed(("Invalid state! Not mounted!\n"));
303 return VERR_PDM_MEDIA_NOT_MOUNTED;
304 }
305
306 /*
307 * Call media. Ignore the not implemented return code.
308 */
309 int rc = pData->pDrvMedia->pfnBiosSetPCHSGeometry(pData->pDrvMedia, pPCHSGeometry);
310 if ( VBOX_SUCCESS(rc)
311 || rc == VERR_NOT_IMPLEMENTED)
312 {
313 pData->PCHSGeometry = *pPCHSGeometry;
314 rc = VINF_SUCCESS;
315 }
316 return rc;
317}
318
319
320/** @copydoc PDMIBLOCKBIOS::pfnGetLCHSGeometry */
321static DECLCALLBACK(int) drvblockGetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
322{
323 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
324
325 /*
326 * Check the state.
327 */
328 if (!pData->pDrvMedia)
329 return VERR_PDM_MEDIA_NOT_MOUNTED;
330
331 /*
332 * Use configured/cached values if present.
333 */
334 if ( pData->LCHSGeometry.cCylinders > 0
335 && pData->LCHSGeometry.cHeads > 0
336 && pData->LCHSGeometry.cSectors > 0)
337 {
338 *pLCHSGeometry = pData->LCHSGeometry;
339 LogFlow(("%s: returns VINF_SUCCESS {%d,%d,%d}\n", __FUNCTION__, pData->LCHSGeometry.cCylinders, pData->LCHSGeometry.cHeads, pData->LCHSGeometry.cSectors));
340 return VINF_SUCCESS;
341 }
342
343 /*
344 * Call media.
345 */
346 int rc = pData->pDrvMedia->pfnBiosGetLCHSGeometry(pData->pDrvMedia, &pData->LCHSGeometry);
347 if (VBOX_SUCCESS(rc))
348 {
349 *pLCHSGeometry = pData->LCHSGeometry;
350 LogFlow(("%s: returns %Vrc {%d,%d,%d}\n", __FUNCTION__, rc, pData->LCHSGeometry.cCylinders, pData->LCHSGeometry.cHeads, pData->LCHSGeometry.cSectors));
351 }
352 else if (rc == VERR_NOT_IMPLEMENTED)
353 {
354 rc = VERR_PDM_GEOMETRY_NOT_SET;
355 LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
356 }
357 return rc;
358}
359
360
361/** @copydoc PDMIBLOCKBIOS::pfnSetLCHSGeometry */
362static DECLCALLBACK(int) drvblockSetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
363{
364 LogFlow(("%s: cCylinders=%d cHeads=%d cSectors=%d\n", __FUNCTION__, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
365 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
366
367 /*
368 * Check the state.
369 */
370 if (!pData->pDrvMedia)
371 {
372 AssertMsgFailed(("Invalid state! Not mounted!\n"));
373 return VERR_PDM_MEDIA_NOT_MOUNTED;
374 }
375
376 /*
377 * Call media. Ignore the not implemented return code.
378 */
379 int rc = pData->pDrvMedia->pfnBiosSetLCHSGeometry(pData->pDrvMedia, pLCHSGeometry);
380 if ( VBOX_SUCCESS(rc)
381 || rc == VERR_NOT_IMPLEMENTED)
382 {
383 pData->LCHSGeometry = *pLCHSGeometry;
384 rc = VINF_SUCCESS;
385 }
386 return rc;
387}
388
389
390/** @copydoc PDMIBLOCKBIOS::pfnIsVisible */
391static DECLCALLBACK(bool) drvblockIsVisible(PPDMIBLOCKBIOS pInterface)
392{
393 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
394 LogFlow(("drvblockIsVisible: returns %d\n", pData->fBiosVisible));
395 return pData->fBiosVisible;
396}
397
398
399/** @copydoc PDMIBLOCKBIOS::pfnGetType */
400static DECLCALLBACK(PDMBLOCKTYPE) drvblockBiosGetType(PPDMIBLOCKBIOS pInterface)
401{
402 PDRVBLOCK pData = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
403 LogFlow(("drvblockBiosGetType: returns %d\n", pData->enmType));
404 return pData->enmType;
405}
406
407
408
409/* -=-=-=-=- IMount -=-=-=-=- */
410
411/** Makes a PDRVBLOCK out of a PPDMIMOUNT. */
412#define PDMIMOUNT_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMount)) )
413
414
415/** @copydoc PDMIMOUNT::pfnMount */
416static DECLCALLBACK(int) drvblockMount(PPDMIMOUNT pInterface, const char *pszFilename, const char *pszCoreDriver)
417{
418 LogFlow(("drvblockMount: pszFilename=%p:{%s} pszCoreDriver=%p:{%s}\n", pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
419 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
420
421 /*
422 * Validate state.
423 */
424 if (pData->pDrvMedia)
425 {
426 AssertMsgFailed(("Already mounted\n"));
427 return VERR_PDM_MEDIA_MOUNTED;
428 }
429
430 /*
431 * Prepare configuration.
432 */
433 if (pszFilename)
434 {
435 int rc = pData->pDrvIns->pDrvHlp->pfnMountPrepare(pData->pDrvIns, pszFilename, pszCoreDriver);
436 if (VBOX_FAILURE(rc))
437 {
438 Log(("drvblockMount: Prepare failed for \"%s\" rc=%Vrc\n", pszFilename, rc));
439 return rc;
440 }
441 }
442
443 /*
444 * Attach the media driver and query it's interface.
445 */
446 PPDMIBASE pBase;
447 int rc = pData->pDrvIns->pDrvHlp->pfnAttach(pData->pDrvIns, &pBase);
448 if (VBOX_FAILURE(rc))
449 {
450 Log(("drvblockMount: Attach failed rc=%Vrc\n", rc));
451 return rc;
452 }
453
454 pData->pDrvMedia = (PPDMIMEDIA)pBase->pfnQueryInterface(pBase, PDMINTERFACE_MEDIA);
455 if (pData->pDrvMedia)
456 {
457 /*
458 * Initialize state.
459 */
460 pData->fLocked = false;
461 pData->PCHSGeometry.cCylinders = 0;
462 pData->PCHSGeometry.cHeads = 0;
463 pData->PCHSGeometry.cSectors = 0;
464 pData->LCHSGeometry.cCylinders = 0;
465 pData->LCHSGeometry.cHeads = 0;
466 pData->LCHSGeometry.cSectors = 0;
467#ifdef VBOX_PERIODIC_FLUSH
468 pData->cbDataWritten = 0;
469#endif /* VBOX_PERIODIC_FLUSH */
470
471 /*
472 * Notify driver/device above us.
473 */
474 if (pData->pDrvMountNotify)
475 pData->pDrvMountNotify->pfnMountNotify(pData->pDrvMountNotify);
476 Log(("drvblockMount: Success\n"));
477 return VINF_SUCCESS;
478 }
479 else
480 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
481
482 /*
483 * Failed, detatch the media driver.
484 */
485 AssertMsgFailed(("No media interface!\n"));
486 int rc2 = pData->pDrvIns->pDrvHlp->pfnDetach(pData->pDrvIns);
487 AssertRC(rc2);
488 pData->pDrvMedia = NULL;
489 return rc;
490}
491
492
493/** @copydoc PDMIMOUNT::pfnUnmount */
494static DECLCALLBACK(int) drvblockUnmount(PPDMIMOUNT pInterface, bool fForce)
495{
496 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
497
498 /*
499 * Validate state.
500 */
501 if (!pData->pDrvMedia)
502 {
503 Log(("drvblockUmount: Not mounted\n"));
504 return VERR_PDM_MEDIA_NOT_MOUNTED;
505 }
506 if (pData->fLocked && !fForce)
507 {
508 Log(("drvblockUmount: Locked\n"));
509 return VERR_PDM_MEDIA_LOCKED;
510 }
511
512 /* Media is no longer locked even if it was previously. */
513 pData->fLocked = false;
514
515 /*
516 * Detach the media driver and query it's interface.
517 */
518 int rc = pData->pDrvIns->pDrvHlp->pfnDetach(pData->pDrvIns);
519 if (VBOX_FAILURE(rc))
520 {
521 Log(("drvblockUnmount: Detach failed rc=%Vrc\n", rc));
522 return rc;
523 }
524 Assert(!pData->pDrvMedia);
525
526 /*
527 * Notify driver/device above us.
528 */
529 if (pData->pDrvMountNotify)
530 pData->pDrvMountNotify->pfnUnmountNotify(pData->pDrvMountNotify);
531 Log(("drvblockUnmount: success\n"));
532 return VINF_SUCCESS;
533}
534
535
536/** @copydoc PDMIMOUNT::pfnIsMounted */
537static DECLCALLBACK(bool) drvblockIsMounted(PPDMIMOUNT pInterface)
538{
539 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
540 return pData->pDrvMedia != NULL;
541}
542
543/** @copydoc PDMIMOUNT::pfnLock */
544static DECLCALLBACK(int) drvblockLock(PPDMIMOUNT pInterface)
545{
546 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
547 Log(("drvblockLock: %d -> %d\n", pData->fLocked, true));
548 pData->fLocked = true;
549 return VINF_SUCCESS;
550}
551
552/** @copydoc PDMIMOUNT::pfnUnlock */
553static DECLCALLBACK(int) drvblockUnlock(PPDMIMOUNT pInterface)
554{
555 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
556 Log(("drvblockUnlock: %d -> %d\n", pData->fLocked, false));
557 pData->fLocked = false;
558 return VINF_SUCCESS;
559}
560
561/** @copydoc PDMIMOUNT::pfnIsLocked */
562static DECLCALLBACK(bool) drvblockIsLocked(PPDMIMOUNT pInterface)
563{
564 PDRVBLOCK pData = PDMIMOUNT_2_DRVBLOCK(pInterface);
565 return pData->fLocked;
566}
567
568
569/* -=-=-=-=- IBase -=-=-=-=- */
570
571/** @copydoc PDMIBASE::pfnQueryInterface. */
572static DECLCALLBACK(void *) drvblockQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
573{
574 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
575 PDRVBLOCK pData = PDMINS2DATA(pDrvIns, PDRVBLOCK);
576 switch (enmInterface)
577 {
578 case PDMINTERFACE_BASE:
579 return &pDrvIns->IBase;
580 case PDMINTERFACE_BLOCK:
581 return &pData->IBlock;
582 case PDMINTERFACE_BLOCK_BIOS:
583 return pData->fBiosVisible ? &pData->IBlockBios : NULL;
584 case PDMINTERFACE_MOUNT:
585 return pData->fMountable ? &pData->IMount : NULL;
586 default:
587 return NULL;
588 }
589}
590
591
592/* -=-=-=-=- driver interface -=-=-=-=- */
593
594/** @copydoc FNPDMDRVDETACH. */
595static DECLCALLBACK(void) drvblockDetach(PPDMDRVINS pDrvIns)
596{
597 PDRVBLOCK pData = PDMINS2DATA(pDrvIns, PDRVBLOCK);
598 pData->pDrvMedia = NULL;
599}
600
601
602/**
603 * Construct a block driver instance.
604 *
605 * @returns VBox status.
606 * @param pDrvIns The driver instance data.
607 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
608 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
609 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
610 * iInstance it's expected to be used a bit in this function.
611 */
612static DECLCALLBACK(int) drvblockConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
613{
614 PDRVBLOCK pData = PDMINS2DATA(pDrvIns, PDRVBLOCK);
615 LogFlow(("drvblockConstruct: iInstance=%d\n", pDrvIns->iInstance));
616
617 /*
618 * Validate configuration.
619 */
620#if defined(VBOX_PERIODIC_FLUSH) || defined(VBOX_IGNORE_FLUSH)
621 if (!CFGMR3AreValuesValid(pCfgHandle, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Mountable\0FlushInterval\0IgnoreFlush\0"))
622#else /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
623 if (!CFGMR3AreValuesValid(pCfgHandle, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Mountable\0"))
624#endif /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
625 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
626
627 /*
628 * Initialize most of the data members.
629 */
630 pData->pDrvIns = pDrvIns;
631
632 /* IBase. */
633 pDrvIns->IBase.pfnQueryInterface = drvblockQueryInterface;
634
635 /* IBlock. */
636 pData->IBlock.pfnRead = drvblockRead;
637 pData->IBlock.pfnWrite = drvblockWrite;
638 pData->IBlock.pfnFlush = drvblockFlush;
639 pData->IBlock.pfnIsReadOnly = drvblockIsReadOnly;
640 pData->IBlock.pfnGetSize = drvblockGetSize;
641 pData->IBlock.pfnGetType = drvblockGetType;
642 pData->IBlock.pfnGetUuid = drvblockGetUuid;
643
644 /* IBlockBios. */
645 pData->IBlockBios.pfnGetPCHSGeometry = drvblockGetPCHSGeometry;
646 pData->IBlockBios.pfnSetPCHSGeometry = drvblockSetPCHSGeometry;
647 pData->IBlockBios.pfnGetLCHSGeometry = drvblockGetLCHSGeometry;
648 pData->IBlockBios.pfnSetLCHSGeometry = drvblockSetLCHSGeometry;
649 pData->IBlockBios.pfnIsVisible = drvblockIsVisible;
650 pData->IBlockBios.pfnGetType = drvblockBiosGetType;
651
652 /* IMount. */
653 pData->IMount.pfnMount = drvblockMount;
654 pData->IMount.pfnUnmount = drvblockUnmount;
655 pData->IMount.pfnIsMounted = drvblockIsMounted;
656 pData->IMount.pfnLock = drvblockLock;
657 pData->IMount.pfnUnlock = drvblockUnlock;
658 pData->IMount.pfnIsLocked = drvblockIsLocked;
659
660 /*
661 * Get the IBlockPort & IMountNotify interfaces of the above driver/device.
662 */
663 pData->pDrvBlockPort = (PPDMIBLOCKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_BLOCK_PORT);
664 if (!pData->pDrvBlockPort)
665 {
666 AssertMsgFailed(("Configuration error: No block port interface above!\n"));
667 return VERR_PDM_MISSING_INTERFACE_ABOVE;
668 }
669 pData->pDrvMountNotify = (PPDMIMOUNTNOTIFY)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_MOUNT_NOTIFY);
670
671 /*
672 * Query configuration.
673 */
674 /* type */
675 char *psz;
676 int rc = CFGMR3QueryStringAlloc(pCfgHandle, "Type", &psz);
677 if (VBOX_FAILURE(rc))
678 {
679 AssertMsgFailed(("Configuration error: Failed to obtain the type, rc=%Vrc.\n", rc));
680 return VERR_PDM_BLOCK_NO_TYPE;
681 }
682 if (!strcmp(psz, "HardDisk"))
683 pData->enmType = PDMBLOCKTYPE_HARD_DISK;
684 else if (!strcmp(psz, "DVD"))
685 pData->enmType = PDMBLOCKTYPE_DVD;
686 else if (!strcmp(psz, "CDROM"))
687 pData->enmType = PDMBLOCKTYPE_CDROM;
688 else if (!strcmp(psz, "Floppy 2.88"))
689 pData->enmType = PDMBLOCKTYPE_FLOPPY_2_88;
690 else if (!strcmp(psz, "Floppy 1.44"))
691 pData->enmType = PDMBLOCKTYPE_FLOPPY_1_44;
692 else if (!strcmp(psz, "Floppy 1.20"))
693 pData->enmType = PDMBLOCKTYPE_FLOPPY_1_20;
694 else if (!strcmp(psz, "Floppy 720"))
695 pData->enmType = PDMBLOCKTYPE_FLOPPY_720;
696 else if (!strcmp(psz, "Floppy 360"))
697 pData->enmType = PDMBLOCKTYPE_FLOPPY_360;
698 else
699 {
700 AssertMsgFailed(("Configuration error: Unknown type \"%s\".\n", psz));
701 MMR3HeapFree(psz);
702 return VERR_PDM_BLOCK_UNKNOWN_TYPE;
703 }
704 Log2(("drvblockConstruct: enmType=%d\n", pData->enmType));
705 MMR3HeapFree(psz); psz = NULL;
706
707 /* Mountable */
708 rc = CFGMR3QueryBool(pCfgHandle, "Mountable", &pData->fMountable);
709 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
710 pData->fMountable = false;
711 else if (VBOX_FAILURE(rc))
712 {
713 AssertMsgFailed(("Configuration error: Query \"Mountable\" resulted in %Vrc.\n", rc));
714 return rc;
715 }
716
717 /* Locked */
718 rc = CFGMR3QueryBool(pCfgHandle, "Locked", &pData->fLocked);
719 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
720 pData->fLocked = false;
721 else if (VBOX_FAILURE(rc))
722 {
723 AssertMsgFailed(("Configuration error: Query \"Locked\" resulted in %Vrc.\n", rc));
724 return rc;
725 }
726
727 /* BIOS visible */
728 rc = CFGMR3QueryBool(pCfgHandle, "BIOSVisible", &pData->fBiosVisible);
729 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
730 pData->fBiosVisible = true;
731 else if (VBOX_FAILURE(rc))
732 {
733 AssertMsgFailed(("Configuration error: Query \"BIOSVisible\" resulted in %Vrc.\n", rc));
734 return rc;
735 }
736
737 /** @todo AttachFailError is currently completely ignored. */
738
739 /* Cylinders */
740 rc = CFGMR3QueryU32(pCfgHandle, "Cylinders", &pData->LCHSGeometry.cCylinders);
741 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
742 pData->LCHSGeometry.cCylinders = 0;
743 else if (VBOX_FAILURE(rc))
744 {
745 AssertMsgFailed(("Configuration error: Query \"Cylinders\" resulted in %Vrc.\n", rc));
746 return rc;
747 }
748
749 /* Heads */
750 rc = CFGMR3QueryU32(pCfgHandle, "Heads", &pData->LCHSGeometry.cHeads);
751 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
752 pData->LCHSGeometry.cHeads = 0;
753 else if (VBOX_FAILURE(rc))
754 {
755 AssertMsgFailed(("Configuration error: Query \"Heads\" resulted in %Vrc.\n", rc));
756 return rc;
757 }
758
759 /* Sectors */
760 rc = CFGMR3QueryU32(pCfgHandle, "Sectors", &pData->LCHSGeometry.cSectors);
761 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
762 pData->LCHSGeometry.cSectors = 0;
763 else if (VBOX_FAILURE(rc))
764 {
765 AssertMsgFailed(("Configuration error: Query \"Sectors\" resulted in %Vrc.\n", rc));
766 return rc;
767 }
768
769 /* Uuid */
770 rc = CFGMR3QueryStringAlloc(pCfgHandle, "Uuid", &psz);
771 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
772 RTUuidClear(&pData->Uuid);
773 else if (VBOX_SUCCESS(rc))
774 {
775 rc = RTUuidFromStr(&pData->Uuid, psz);
776 if (VBOX_FAILURE(rc))
777 {
778 AssertMsgFailed(("Configuration error: Uuid from string failed on \"%s\", rc=%Vrc.\n", psz, rc));
779 MMR3HeapFree(psz);
780 return rc;
781 }
782 MMR3HeapFree(psz); psz = NULL;
783 }
784 else
785 {
786 AssertMsgFailed(("Configuration error: Failed to obtain the type, rc=%Vrc.\n", rc));
787 return VERR_PDM_BLOCK_NO_TYPE;
788 }
789
790#ifdef VBOX_PERIODIC_FLUSH
791 rc = CFGMR3QueryU32(pCfgHandle, "FlushInterval", &pData->cbFlushInterval);
792 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
793 pData->cbFlushInterval = 0;
794 else if (VBOX_FAILURE(rc))
795 {
796 AssertMsgFailed(("Configuration error: Query \"FlushInterval\" resulted in %Vrc.\n", rc));
797 return rc;
798 }
799#endif /* VBOX_PERIODIC_FLUSH */
800
801#ifdef VBOX_IGNORE_FLUSH
802 rc = CFGMR3QueryBool(pCfgHandle, "IgnoreFlush", &pData->fIgnoreFlush);
803 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
804 pData->fIgnoreFlush = true; /* The default is to ignore flushes. */
805 else if (VBOX_FAILURE(rc))
806 {
807 AssertMsgFailed(("Configuration error: Query \"IgnoreFlush\" resulted in %Vrc.\n", rc));
808 return rc;
809 }
810#endif /* VBOX_IGNORE_FLUSH */
811
812 /*
813 * Try attach driver below and query it's media interface.
814 */
815 PPDMIBASE pBase;
816 rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBase);
817 if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
818 && pData->enmType != PDMBLOCKTYPE_HARD_DISK)
819 return VINF_SUCCESS;
820 if (VBOX_FAILURE(rc))
821 {
822 AssertMsgFailed(("Failed to attach driver below us! rc=%Vra\n", rc));
823 return rc;
824 }
825 pData->pDrvMedia = (PPDMIMEDIA)pBase->pfnQueryInterface(pBase, PDMINTERFACE_MEDIA);
826 if (!pData->pDrvMedia)
827 {
828 AssertMsgFailed(("Configuration error: No media interface below!\n"));
829 return VERR_PDM_MISSING_INTERFACE_BELOW;
830 }
831 if (RTUuidIsNull(&pData->Uuid))
832 {
833 if (pData->enmType == PDMBLOCKTYPE_HARD_DISK)
834 pData->pDrvMedia->pfnGetUuid(pData->pDrvMedia, &pData->Uuid);
835 }
836
837 return VINF_SUCCESS;
838}
839
840
841/**
842 * Block driver registration record.
843 */
844const PDMDRVREG g_DrvBlock =
845{
846 /* u32Version */
847 PDM_DRVREG_VERSION,
848 /* szDriverName */
849 "Block",
850 /* pszDescription */
851 "Generic block driver.",
852 /* fFlags */
853 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
854 /* fClass. */
855 PDM_DRVREG_CLASS_BLOCK,
856 /* cMaxInstances */
857 ~0,
858 /* cbInstance */
859 sizeof(DRVBLOCK),
860 /* pfnConstruct */
861 drvblockConstruct,
862 /* pfnDestruct */
863 NULL,
864 /* pfnIOCtl */
865 NULL,
866 /* pfnPowerOn */
867 NULL,
868 /* pfnReset */
869 NULL,
870 /* pfnSuspend */
871 NULL,
872 /* pfnResume */
873 NULL,
874 /* pfnDetach */
875 drvblockDetach
876};
877
878
879
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