VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/VBoxHDD.cpp@ 11287

Last change on this file since 11287 was 11287, checked in by vboxsync, 16 years ago

Devices: %Vuuid -> %RTuuid (just preferred, not mandatory (yet))

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.5 KB
Line 
1/** $Id: VBoxHDD.cpp 11287 2008-08-08 22:35:40Z vboxsync $ */
2/** @file
3 *
4 * VBox storage devices:
5 * VBox HDD container implementation
6 */
7
8/*
9 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_DRV_VBOXHDD
28#include <VBox/VBoxHDD.h>
29#include <VBox/pdmdrv.h>
30#include <iprt/alloc.h>
31#include <iprt/assert.h>
32#include <iprt/uuid.h>
33#include <iprt/file.h>
34#include <iprt/string.h>
35
36#include "VDICore.h"
37#include "Builtins.h"
38
39
40/*******************************************************************************
41* Defined Constants And Macros *
42*******************************************************************************/
43/** Converts a pointer to VDIDISK::IMedia to a PVDIDISK. */
44#define PDMIMEDIA_2_VDIDISK(pInterface) ( (PVDIDISK)((uintptr_t)pInterface - RT_OFFSETOF(VDIDISK, IMedia)) )
45
46/** Converts a pointer to PDMDRVINS::IBase to a PPDMDRVINS. */
47#define PDMIBASE_2_DRVINS(pInterface) ( (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) )
48
49/** Converts a pointer to PDMDRVINS::IBase to a PVDIDISK. */
50#define PDMIBASE_2_VDIDISK(pInterface) ( PDMINS_2_DATA(PDMIBASE_2_DRVINS(pInterface), PVDIDISK) )
51
52
53
54
55/** @copydoc PDMIMEDIA::pfnGetSize */
56static DECLCALLBACK(uint64_t) vdiGetSize(PPDMIMEDIA pInterface)
57{
58 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
59 uint64_t cb = VDIDiskGetSize(pThis);
60 LogFlow(("vdiGetSize: returns %#llx (%llu)\n", cb, cb));
61 return cb;
62}
63
64
65/**
66 * Get stored media PCHS geometry - BIOS property.
67 *
68 * @see PDMIMEDIA::pfnBiosGetPCHSGeometry for details.
69 */
70static DECLCALLBACK(int) vdiBiosGetPCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
71{
72 LogFlow(("%s: returns VERR_NOT_IMPLEMENTED\n", __FUNCTION__));
73 return VERR_NOT_IMPLEMENTED;
74}
75
76
77/**
78 * Set stored media PCHS geometry - BIOS property.
79 *
80 * @see PDMIMEDIA::pfnBiosSetPCHSGeometry for details.
81 */
82static DECLCALLBACK(int) vdiBiosSetPCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
83{
84 LogFlow(("%s: returns VERR_NOT_IMPLEMENTED\n", __FUNCTION__));
85 return VERR_NOT_IMPLEMENTED;
86}
87
88
89/**
90 * Get stored media LCHS geometry - BIOS property.
91 *
92 * @see PDMIMEDIA::pfnBiosGetLCHSGeometry for details.
93 */
94static DECLCALLBACK(int) vdiBiosGetLCHSGeometry(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
95{
96 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
97 int rc = VDIDiskGetLCHSGeometry(pThis, pLCHSGeometry);
98 if (RT_SUCCESS(rc))
99 {
100 LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
101 return VINF_SUCCESS;
102 }
103 Log(("%s: The Bios geometry data was not available.\n", __FUNCTION__));
104 return VERR_PDM_GEOMETRY_NOT_SET;
105}
106
107
108/**
109 * Set stored media LCHS geometry - BIOS property.
110 *
111 * @see PDMIMEDIA::pfnBiosSetLCHSGeometry for details.
112 */
113static DECLCALLBACK(int) vdiBiosSetLCHSGeometry(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
114{
115 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
116 int rc = VDIDiskSetLCHSGeometry(pThis, pLCHSGeometry);
117 LogFlow(("%s: returns %Rrc (%d,%d,%d)\n", __FUNCTION__, rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
118 return rc;
119}
120
121
122/**
123 * Read bits.
124 *
125 * @see PDMIMEDIA::pfnRead for details.
126 */
127static DECLCALLBACK(int) vdiRead(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)
128{
129 LogFlow(("vdiRead: off=%#llx pvBuf=%p cbRead=%d\n", off, pvBuf, cbRead));
130 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
131 int rc = VDIDiskRead(pThis, off, pvBuf, cbRead);
132 if (RT_SUCCESS(rc))
133 Log2(("vdiRead: off=%#llx pvBuf=%p cbRead=%d\n"
134 "%.*Vhxd\n",
135 off, pvBuf, cbRead, cbRead, pvBuf));
136 LogFlow(("vdiRead: returns %Rrc\n", rc));
137 return rc;
138}
139
140
141/**
142 * Write bits.
143 *
144 * @see PDMIMEDIA::pfnWrite for details.
145 */
146static DECLCALLBACK(int) vdiWrite(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
147{
148 LogFlow(("vdiWrite: off=%#llx pvBuf=%p cbWrite=%d\n", off, pvBuf, cbWrite));
149 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
150 Log2(("vdiWrite: off=%#llx pvBuf=%p cbWrite=%d\n"
151 "%.*Vhxd\n",
152 off, pvBuf, cbWrite, cbWrite, pvBuf));
153 int rc = VDIDiskWrite(pThis, off, pvBuf, cbWrite);
154 LogFlow(("vdiWrite: returns %Rrc\n", rc));
155 return rc;
156}
157
158
159/**
160 * Flush bits to media.
161 *
162 * @see PDMIMEDIA::pfnFlush for details.
163 */
164static DECLCALLBACK(int) vdiFlush(PPDMIMEDIA pInterface)
165{
166 LogFlow(("vdiFlush:\n"));
167 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
168 VDIFlushImage(pThis->pLast);
169 int rc = VINF_SUCCESS;
170 LogFlow(("vdiFlush: returns %Rrc\n", rc));
171 return rc;
172}
173
174
175/** @copydoc PDMIMEDIA::pfnGetUuid */
176static DECLCALLBACK(int) vdiGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
177{
178 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
179 int rc = VDIDiskGetImageUuid(pThis, 0, pUuid);
180 LogFlow(("vdiGetUuid: returns %Rrc ({%RTuuid})\n", rc, pUuid));
181 return rc;
182}
183
184
185/** @copydoc PDMIMEDIA::pfnIsReadOnly */
186static DECLCALLBACK(bool) vdiIsReadOnly(PPDMIMEDIA pInterface)
187{
188 PVDIDISK pThis = PDMIMEDIA_2_VDIDISK(pInterface);
189 LogFlow(("vdiIsReadOnly: returns %d\n", VDIDiskIsReadOnly(pThis)));
190 return VDIDiskIsReadOnly(pThis);
191}
192
193
194/**
195 * Queries an interface to the driver.
196 *
197 * @returns Pointer to interface.
198 * @returns NULL if the interface was not supported by the driver.
199 * @param pInterface Pointer to this interface structure.
200 * @param enmInterface The requested interface identification.
201 * @thread Any thread.
202 */
203static DECLCALLBACK(void *) vdiQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
204{
205 PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
206 PVDIDISK pThis = PDMINS_2_DATA(pDrvIns, PVDIDISK);
207 switch (enmInterface)
208 {
209 case PDMINTERFACE_BASE:
210 return &pDrvIns->IBase;
211 case PDMINTERFACE_MEDIA:
212 return &pThis->IMedia;
213 default:
214 return NULL;
215 }
216}
217
218
219/**
220 * Before the VM resumes we'll have to undo the read-only mode change
221 * done in vdiSuspend.
222 *
223 * @param pDrvIns The driver instance data.
224 */
225static DECLCALLBACK(void) vdiResume(PPDMDRVINS pDrvIns)
226{
227 LogFlow(("vdiSuspend:\n"));
228#if 1 //#ifdef DEBUG_dmik
229 PVDIDISK pThis = PDMINS_2_DATA(pDrvIns, PVDIDISK);
230 if (!(pThis->pLast->fOpen & VDI_OPEN_FLAGS_READONLY))
231 {
232 int rc = vdiChangeImageMode(pThis->pLast, false);
233 AssertRC(rc);
234 }
235#endif
236}
237
238
239/**
240 * When the VM has been suspended we'll change the image mode to read-only
241 * so that main and others can read the VDIs. This is important when
242 * saving state and so forth.
243 *
244 * @param pDrvIns The driver instance data.
245 */
246static DECLCALLBACK(void) vdiSuspend(PPDMDRVINS pDrvIns)
247{
248 LogFlow(("vdiSuspend:\n"));
249#if 1 // #ifdef DEBUG_dmik
250 PVDIDISK pThis = PDMINS_2_DATA(pDrvIns, PVDIDISK);
251 if (!(pThis->pLast->fOpen & VDI_OPEN_FLAGS_READONLY))
252 {
253 int rc = vdiChangeImageMode(pThis->pLast, true);
254 AssertRC(rc);
255 }
256#endif
257}
258
259
260/**
261 * Destruct a driver instance.
262 *
263 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
264 * resources can be freed correctly.
265 *
266 * @param pDrvIns The driver instance data.
267 */
268static DECLCALLBACK(void) vdiDestruct(PPDMDRVINS pDrvIns)
269{
270 LogFlow(("vdiDestruct:\n"));
271 PVDIDISK pThis = PDMINS_2_DATA(pDrvIns, PVDIDISK);
272 VDIDiskCloseAllImages(pThis);
273}
274
275
276/**
277 * Construct a VBox HDD media driver instance.
278 *
279 * @returns VBox status.
280 * @param pDrvIns The driver instance data.
281 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
282 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
283 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
284 * iInstance it's expected to be used a bit in this function.
285 */
286static DECLCALLBACK(int) vdiConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
287{
288 LogFlow(("vdiConstruct:\n"));
289 PVDIDISK pThis = PDMINS_2_DATA(pDrvIns, PVDIDISK);
290 char *pszName; /**< The path of the disk image file. */
291 bool fReadOnly; /**< True if the media is readonly. */
292 bool fHonorZeroWrites = false;
293
294 /*
295 * Init the static parts.
296 */
297 pDrvIns->IBase.pfnQueryInterface = vdiQueryInterface;
298 pThis->pDrvIns = pDrvIns;
299
300 vdiInitVDIDisk(pThis);
301
302 /* IMedia */
303 pThis->IMedia.pfnRead = vdiRead;
304 pThis->IMedia.pfnWrite = vdiWrite;
305 pThis->IMedia.pfnFlush = vdiFlush;
306 pThis->IMedia.pfnGetSize = vdiGetSize;
307 pThis->IMedia.pfnGetUuid = vdiGetUuid;
308 pThis->IMedia.pfnIsReadOnly = vdiIsReadOnly;
309 pThis->IMedia.pfnBiosGetPCHSGeometry = vdiBiosGetPCHSGeometry;
310 pThis->IMedia.pfnBiosSetPCHSGeometry = vdiBiosSetPCHSGeometry;
311 pThis->IMedia.pfnBiosGetLCHSGeometry = vdiBiosGetLCHSGeometry;
312 pThis->IMedia.pfnBiosSetLCHSGeometry = vdiBiosSetLCHSGeometry;
313
314 /*
315 * Validate configuration and find the great to the level of umpteen grandparent.
316 * The parents are found in the 'Parent' subtree, so it's sorta up side down
317 * from the image dependency tree.
318 */
319 unsigned iLevel = 0;
320 PCFGMNODE pCurNode = pCfgHandle;
321 for (;;)
322 {
323 if (!CFGMR3AreValuesValid(pCfgHandle, "Path\0ReadOnly\0HonorZeroWrites\0"))
324 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
325
326 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
327 if (!pParent)
328 break;
329 pCurNode = pParent;
330 iLevel++;
331 }
332
333 /*
334 * Open the images.
335 */
336 int rc = VINF_SUCCESS;
337 while (pCurNode && RT_SUCCESS(rc))
338 {
339 /*
340 * Read the image configuration.
341 */
342 int rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
343 if (RT_FAILURE(rc))
344 return PDMDRV_SET_ERROR(pDrvIns, rc,
345 N_("VHDD: Configuration error: Querying \"Path\" as string failed"));
346
347 rc = CFGMR3QueryBool(pCurNode, "ReadOnly", &fReadOnly);
348 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
349 fReadOnly = false;
350 else if (RT_FAILURE(rc))
351 {
352 MMR3HeapFree(pszName);
353 return PDMDRV_SET_ERROR(pDrvIns, rc,
354 N_("VHDD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
355 }
356
357 if (!fHonorZeroWrites)
358 {
359 rc = CFGMR3QueryBool(pCfgHandle, "HonorZeroWrites", &fHonorZeroWrites);
360 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
361 fHonorZeroWrites = false;
362 else if (RT_FAILURE(rc))
363 {
364 MMR3HeapFree(pszName);
365 return PDMDRV_SET_ERROR(pDrvIns, rc,
366 N_("VHDD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
367 }
368 }
369
370 /*
371 * Open the image.
372 */
373 rc = VDIDiskOpenImage(pThis, pszName, fReadOnly ? VDI_OPEN_FLAGS_READONLY
374 : VDI_OPEN_FLAGS_NORMAL);
375 if (RT_SUCCESS(rc))
376 Log(("vdiConstruct: %d - Opened '%s' in %s mode\n",
377 iLevel, pszName, VDIDiskIsReadOnly(pThis) ? "read-only" : "read-write"));
378 else
379 AssertMsgFailed(("Failed to open image '%s' rc=%Rrc\n", pszName, rc));
380 MMR3HeapFree(pszName);
381
382 /* next */
383 iLevel--;
384 pCurNode = CFGMR3GetParent(pCurNode);
385 }
386
387 /* If any of the images has the flag set, handle zero writes like normal. */
388 if (RT_SUCCESS(rc))
389 pThis->fHonorZeroWrites = fHonorZeroWrites;
390
391 /* On failure, vdiDestruct will be called, so no need to clean up here. */
392
393 if (rc == VERR_ACCESS_DENIED)
394 /* This should never happen here since this case is covered by Console::PowerUp */
395 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
396 N_("Cannot open virtual disk image '%s' for %s access"),
397 pszName, fReadOnly ? "readonly" : "read/write");
398
399 return rc;
400}
401
402
403/**
404 * VBox HDD driver registration record.
405 */
406const PDMDRVREG g_DrvVBoxHDD =
407{
408 /* u32Version */
409 PDM_DRVREG_VERSION,
410 /* szDriverName */
411 "VBoxHDD",
412 /* pszDescription */
413 "VBoxHDD media driver.",
414 /* fFlags */
415 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
416 /* fClass. */
417 PDM_DRVREG_CLASS_MEDIA,
418 /* cMaxInstances */
419 ~0,
420 /* cbInstance */
421 sizeof(VDIDISK),
422 /* pfnConstruct */
423 vdiConstruct,
424 /* pfnDestruct */
425 vdiDestruct,
426 /* pfnIOCtl */
427 NULL,
428 /* pfnPowerOn */
429 NULL,
430 /* pfnReset */
431 NULL,
432 /* pfnSuspend */
433 vdiSuspend,
434 /* pfnResume */
435 vdiResume,
436 /* pfnDetach */
437 NULL
438};
439
Note: See TracBrowser for help on using the repository browser.

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