VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvVD.cpp@ 27806

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

Storage/VBoxHDD+DrvBlock+DrvVD: implement core code for live snapshot merging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.3 KB
Line 
1/* $Id: DrvVD.cpp 27806 2010-03-29 20:18:50Z vboxsync $ */
2/** @file
3 * DrvVD - Generic VBox disk media driver.
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.virtualbox.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 * 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_VD
27#include <VBox/VBoxHDD.h>
28#include <VBox/pdmdrv.h>
29#include <VBox/pdmasynccompletion.h>
30#include <iprt/asm.h>
31#include <iprt/alloc.h>
32#include <iprt/assert.h>
33#include <iprt/uuid.h>
34#include <iprt/file.h>
35#include <iprt/string.h>
36#include <iprt/tcp.h>
37#include <iprt/semaphore.h>
38
39#ifdef VBOX_WITH_INIP
40/* All lwip header files are not C++ safe. So hack around this. */
41RT_C_DECLS_BEGIN
42#include <lwip/inet.h>
43#include <lwip/tcp.h>
44#include <lwip/sockets.h>
45RT_C_DECLS_END
46#endif /* VBOX_WITH_INIP */
47
48#include "Builtins.h"
49
50#ifdef VBOX_WITH_INIP
51/* Small hack to get at lwIP initialized status */
52extern bool DevINIPConfigured(void);
53#endif /* VBOX_WITH_INIP */
54
55
56/*******************************************************************************
57* Defined types, constants and macros *
58*******************************************************************************/
59
60/** Converts a pointer to VBOXDISK::IMedia to a PVBOXDISK. */
61#define PDMIMEDIA_2_VBOXDISK(pInterface) \
62 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMedia)) )
63
64/** Converts a pointer to PDMDRVINS::IBase to a PPDMDRVINS. */
65#define PDMIBASE_2_DRVINS(pInterface) \
66 ( (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) )
67
68/** Converts a pointer to PDMDRVINS::IBase to a PVBOXDISK. */
69#define PDMIBASE_2_VBOXDISK(pInterface) \
70 ( PDMINS_2_DATA(PDMIBASE_2_DRVINS(pInterface), PVBOXDISK) )
71
72/** Converts a pointer to VBOXDISK::IMediaAsync to a PVBOXDISK. */
73#define PDMIMEDIAASYNC_2_VBOXDISK(pInterface) \
74 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMediaAsync)) )
75
76/**
77 * VBox disk container, image information, private part.
78 */
79
80typedef struct VBOXIMAGE
81{
82 /** Pointer to next image. */
83 struct VBOXIMAGE *pNext;
84 /** Pointer to list of VD interfaces. Per-image. */
85 PVDINTERFACE pVDIfsImage;
86 /** Common structure for the configuration information interface. */
87 VDINTERFACE VDIConfig;
88} VBOXIMAGE, *PVBOXIMAGE;
89
90/**
91 * Storage backend data.
92 */
93typedef struct DRVVDSTORAGEBACKEND
94{
95 /** PDM async completion end point. */
96 PPDMASYNCCOMPLETIONENDPOINT pEndpoint;
97 /** The template. */
98 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
99 /** Event semaphore for synchronous operations. */
100 RTSEMEVENT EventSem;
101 /** Flag whether a synchronous operation is currently pending. */
102 volatile bool fSyncIoPending;
103 /** Callback routine */
104 PFNVDCOMPLETED pfnCompleted;
105
106 /** Pointer to the optional thread synchronization interface of the disk. */
107 PVDINTERFACE pInterfaceThreadSync;
108 /** Pointer to the optional thread synchronization callbacks of the disk. */
109 PVDINTERFACETHREADSYNC pInterfaceThreadSyncCallbacks;
110} DRVVDSTORAGEBACKEND, *PDRVVDSTORAGEBACKEND;
111
112/**
113 * VBox disk container media main structure, private part.
114 *
115 * @implements PDMIMEDIA
116 * @implements PDMIMEDIAASYNC
117 * @implements VDINTERFACEERROR
118 * @implements VDINTERFACETCPNET
119 * @implements VDINTERFACEASYNCIO
120 * @implements VDINTERFACECONFIG
121 */
122typedef struct VBOXDISK
123{
124 /** The VBox disk container. */
125 PVBOXHDD pDisk;
126 /** The media interface. */
127 PDMIMEDIA IMedia;
128 /** Pointer to the driver instance. */
129 PPDMDRVINS pDrvIns;
130 /** Flag whether suspend has changed image open mode to read only. */
131 bool fTempReadOnly;
132 /** Flag whether to use the runtime (true) or startup error facility. */
133 bool fErrorUseRuntime;
134 /** Pointer to list of VD interfaces. Per-disk. */
135 PVDINTERFACE pVDIfsDisk;
136 /** Common structure for the supported error interface. */
137 VDINTERFACE VDIError;
138 /** Callback table for error interface. */
139 VDINTERFACEERROR VDIErrorCallbacks;
140 /** Common structure for the supported TCP network stack interface. */
141 VDINTERFACE VDITcpNet;
142 /** Callback table for TCP network stack interface. */
143 VDINTERFACETCPNET VDITcpNetCallbacks;
144 /** Common structure for the supported async I/O interface. */
145 VDINTERFACE VDIAsyncIO;
146 /** Callback table for async I/O interface. */
147 VDINTERFACEASYNCIO VDIAsyncIOCallbacks;
148 /** Common structure for the supported thread synchronization interface. */
149 VDINTERFACE VDIThreadSync;
150 /** Callback table for thread synchronization interface. */
151 VDINTERFACETHREADSYNC VDIThreadSyncCallbacks;
152 /** Callback table for the configuration information interface. */
153 VDINTERFACECONFIG VDIConfigCallbacks;
154 /** Flag whether opened disk suppports async I/O operations. */
155 bool fAsyncIOSupported;
156 /** The async media interface. */
157 PDMIMEDIAASYNC IMediaAsync;
158 /** The async media port interface above. */
159 PPDMIMEDIAASYNCPORT pDrvMediaAsyncPort;
160 /** Pointer to the list of data we need to keep per image. */
161 PVBOXIMAGE pImages;
162 /** Flag whether a merge operation has been set up. */
163 bool fMergePending;
164 /** Synchronization to prevent destruction before merge finishes. */
165 RTSEMFASTMUTEX MergeCompleteMutex;
166 /** Synchronization between merge and other image accesses. */
167 RTSEMRW MergeLock;
168 /** Source image index for merging. */
169 unsigned uMergeSource;
170 /** Target image index for merging. */
171 unsigned uMergeTarget;
172} VBOXDISK, *PVBOXDISK;
173
174
175/*******************************************************************************
176* Internal Functions *
177*******************************************************************************/
178
179/**
180 * Internal: allocate new image descriptor and put it in the list
181 */
182static PVBOXIMAGE drvvdNewImage(PVBOXDISK pThis)
183{
184 AssertPtr(pThis);
185 PVBOXIMAGE pImage = (PVBOXIMAGE)RTMemAllocZ(sizeof(VBOXIMAGE));
186 if (pImage)
187 {
188 pImage->pVDIfsImage = NULL;
189 PVBOXIMAGE *pp = &pThis->pImages;
190 while (*pp != NULL)
191 pp = &(*pp)->pNext;
192 *pp = pImage;
193 pImage->pNext = NULL;
194 }
195
196 return pImage;
197}
198
199/**
200 * Internal: free the list of images descriptors.
201 */
202static void drvvdFreeImages(PVBOXDISK pThis)
203{
204 while (pThis->pImages != NULL)
205 {
206 PVBOXIMAGE p = pThis->pImages;
207 pThis->pImages = pThis->pImages->pNext;
208 RTMemFree(p);
209 }
210}
211
212
213/**
214 * Make the image temporarily read-only.
215 *
216 * @returns VBox status code.
217 * @param pThis The driver instance data.
218 */
219static int drvvdSetReadonly(PVBOXDISK pThis)
220{
221 int rc = VINF_SUCCESS;
222 if (!VDIsReadOnly(pThis->pDisk))
223 {
224 unsigned uOpenFlags;
225 rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
226 AssertRC(rc);
227 uOpenFlags |= VD_OPEN_FLAGS_READONLY;
228 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
229 AssertRC(rc);
230 pThis->fTempReadOnly = true;
231 }
232 return rc;
233}
234
235
236/**
237 * Undo the temporary read-only status of the image.
238 *
239 * @returns VBox status code.
240 * @param pThis The driver instance data.
241 */
242static int drvvdSetWritable(PVBOXDISK pThis)
243{
244 int rc = VINF_SUCCESS;
245 if (pThis->fTempReadOnly)
246 {
247 unsigned uOpenFlags;
248 rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
249 AssertRC(rc);
250 uOpenFlags &= ~VD_OPEN_FLAGS_READONLY;
251 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
252 if (RT_SUCCESS(rc))
253 pThis->fTempReadOnly = false;
254 else
255 AssertRC(rc);
256 }
257 return rc;
258}
259
260
261/*******************************************************************************
262* Error reporting callback *
263*******************************************************************************/
264
265static void drvvdErrorCallback(void *pvUser, int rc, RT_SRC_POS_DECL,
266 const char *pszFormat, va_list va)
267{
268 PPDMDRVINS pDrvIns = (PPDMDRVINS)pvUser;
269 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
270 if (pThis->fErrorUseRuntime)
271 /* We must not pass VMSETRTERR_FLAGS_FATAL as it could lead to a
272 * deadlock: We are probably executed in a thread context != EMT
273 * and the EM thread would wait until every thread is suspended
274 * but we would wait for the EM thread ... */
275
276 PDMDrvHlpVMSetRuntimeErrorV(pDrvIns, /* fFlags=*/ 0, "DrvVD", pszFormat, va);
277 else
278 PDMDrvHlpVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va);
279}
280
281/*******************************************************************************
282* VD Async I/O interface implementation *
283*******************************************************************************/
284
285#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
286
287static DECLCALLBACK(void) drvvdAsyncTaskCompleted(PPDMDRVINS pDrvIns, void *pvTemplateUser, void *pvUser)
288{
289 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
290 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pvTemplateUser;
291
292 if (pStorageBackend->fSyncIoPending)
293 {
294 pStorageBackend->fSyncIoPending = false;
295 RTSemEventSignal(pStorageBackend->EventSem);
296 }
297 else
298 {
299 int rc = VINF_VD_ASYNC_IO_FINISHED;
300 void *pvCallerUser = NULL;
301
302 if (pStorageBackend->pfnCompleted)
303 rc = pStorageBackend->pfnCompleted(pvUser, &pvCallerUser);
304 else
305 pvCallerUser = pvUser;
306
307 /* If thread synchronization is active, then signal the end of the
308 * this disk read/write operation. */
309 /** @todo provide a way to determine the type of task (read/write)
310 * which was completed, see also VBoxHDD.cpp. */
311 if (RT_UNLIKELY(pStorageBackend->pInterfaceThreadSyncCallbacks))
312 {
313 int rc2 = pStorageBackend->pInterfaceThreadSyncCallbacks->pfnFinishWrite(pStorageBackend->pInterfaceThreadSync->pvUser);
314 AssertRC(rc2);
315 }
316
317 if (rc == VINF_VD_ASYNC_IO_FINISHED)
318 {
319 rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort, pvCallerUser);
320 AssertRC(rc);
321 }
322 else
323 AssertMsg(rc == VERR_VD_ASYNC_IO_IN_PROGRESS, ("Invalid return code from disk backend rc=%Rrc\n", rc));
324 }
325}
326
327static DECLCALLBACK(int) drvvdAsyncIOOpen(void *pvUser, const char *pszLocation,
328 unsigned uOpenFlags,
329 PFNVDCOMPLETED pfnCompleted,
330 PVDINTERFACE pVDIfsDisk,
331 void **ppStorage)
332{
333 PVBOXDISK pThis = (PVBOXDISK)pvUser;
334 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)RTMemAllocZ(sizeof(DRVVDSTORAGEBACKEND));
335 int rc = VINF_SUCCESS;
336
337 if (pStorageBackend)
338 {
339 pStorageBackend->fSyncIoPending = false;
340 pStorageBackend->pfnCompleted = pfnCompleted;
341 pStorageBackend->pInterfaceThreadSync = NULL;
342 pStorageBackend->pInterfaceThreadSyncCallbacks = NULL;
343
344 pStorageBackend->pInterfaceThreadSync = VDInterfaceGet(pVDIfsDisk, VDINTERFACETYPE_THREADSYNC);
345 if (RT_UNLIKELY(pStorageBackend->pInterfaceThreadSync))
346 pStorageBackend->pInterfaceThreadSyncCallbacks = VDGetInterfaceThreadSync(pStorageBackend->pInterfaceThreadSync);
347
348 rc = RTSemEventCreate(&pStorageBackend->EventSem);
349 if (RT_SUCCESS(rc))
350 {
351 rc = PDMDrvHlpPDMAsyncCompletionTemplateCreate(pThis->pDrvIns, &pStorageBackend->pTemplate,
352 drvvdAsyncTaskCompleted, pStorageBackend, "AsyncTaskCompleted");
353 if (RT_SUCCESS(rc))
354 {
355 rc = PDMR3AsyncCompletionEpCreateForFile(&pStorageBackend->pEndpoint, pszLocation,
356 uOpenFlags & VD_INTERFACEASYNCIO_OPEN_FLAGS_READONLY
357 ? PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_CACHING
358 : PDMACEP_FILE_FLAGS_CACHING,
359 pStorageBackend->pTemplate);
360 if (RT_SUCCESS(rc))
361 {
362 *ppStorage = pStorageBackend;
363 return VINF_SUCCESS;
364 }
365
366 PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate);
367 }
368 RTSemEventDestroy(pStorageBackend->EventSem);
369 }
370 RTMemFree(pStorageBackend);
371 }
372 else
373 rc = VERR_NO_MEMORY;
374
375 return rc;
376}
377
378static DECLCALLBACK(int) drvvdAsyncIOClose(void *pvUser, void *pStorage)
379{
380 PVBOXDISK pThis = (PVBOXDISK)pvUser;
381 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
382
383 PDMR3AsyncCompletionEpClose(pStorageBackend->pEndpoint);
384 PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate);
385 RTSemEventDestroy(pStorageBackend->EventSem);
386 RTMemFree(pStorageBackend);
387
388 return VINF_SUCCESS;;
389}
390
391static DECLCALLBACK(int) drvvdAsyncIOReadSync(void *pvUser, void *pStorage, uint64_t uOffset,
392 size_t cbRead, void *pvBuf, size_t *pcbRead)
393{
394 PVBOXDISK pThis = (PVBOXDISK)pvUser;
395 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
396 PDMDATASEG DataSeg;
397 PPDMASYNCCOMPLETIONTASK pTask;
398
399 Assert(!pStorageBackend->fSyncIoPending);
400 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
401 DataSeg.cbSeg = cbRead;
402 DataSeg.pvSeg = pvBuf;
403
404 int rc = PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbRead, NULL, &pTask);
405 if (RT_FAILURE(rc))
406 return rc;
407
408 if (rc == VINF_AIO_TASK_PENDING)
409 {
410 /* Wait */
411 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
412 AssertRC(rc);
413 }
414 else
415 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
416
417 if (pcbRead)
418 *pcbRead = cbRead;
419
420 return VINF_SUCCESS;
421}
422
423static DECLCALLBACK(int) drvvdAsyncIOWriteSync(void *pvUser, void *pStorage, uint64_t uOffset,
424 size_t cbWrite, const void *pvBuf, size_t *pcbWritten)
425{
426 PVBOXDISK pThis = (PVBOXDISK)pvUser;
427 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
428 PDMDATASEG DataSeg;
429 PPDMASYNCCOMPLETIONTASK pTask;
430
431 Assert(!pStorageBackend->fSyncIoPending);
432 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
433 DataSeg.cbSeg = cbWrite;
434 DataSeg.pvSeg = (void *)pvBuf;
435
436 int rc = PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbWrite, NULL, &pTask);
437 if (RT_FAILURE(rc))
438 return rc;
439
440 if (rc == VINF_AIO_TASK_PENDING)
441 {
442 /* Wait */
443 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
444 AssertRC(rc);
445 }
446 else
447 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
448
449 if (pcbWritten)
450 *pcbWritten = cbWrite;
451
452 return VINF_SUCCESS;
453}
454
455static DECLCALLBACK(int) drvvdAsyncIOFlushSync(void *pvUser, void *pStorage)
456{
457 PVBOXDISK pThis = (PVBOXDISK)pvUser;
458 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
459 PPDMASYNCCOMPLETIONTASK pTask;
460
461 Assert(!pStorageBackend->fSyncIoPending);
462 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
463
464 int rc = PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, NULL, &pTask);
465 if (RT_FAILURE(rc))
466 return rc;
467
468 if (rc == VINF_AIO_TASK_PENDING)
469 {
470 /* Wait */
471 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
472 AssertRC(rc);
473 }
474 else
475 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
476
477 return VINF_SUCCESS;
478}
479
480static DECLCALLBACK(int) drvvdAsyncIOReadAsync(void *pvUser, void *pStorage, uint64_t uOffset,
481 PCPDMDATASEG paSegments, size_t cSegments,
482 size_t cbRead, void *pvCompletion,
483 void **ppTask)
484{
485 PVBOXDISK pThis = (PVBOXDISK)pvUser;
486 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
487
488 return PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbRead,
489 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
490}
491
492static DECLCALLBACK(int) drvvdAsyncIOWriteAsync(void *pvUser, void *pStorage, uint64_t uOffset,
493 PCPDMDATASEG paSegments, size_t cSegments,
494 size_t cbWrite, void *pvCompletion,
495 void **ppTask)
496{
497 PVBOXDISK pThis = (PVBOXDISK)pvUser;
498 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
499
500 return PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbWrite,
501 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
502}
503
504static DECLCALLBACK(int) drvvdAsyncIOFlushAsync(void *pvUser, void *pStorage,
505 void *pvCompletion, void **ppTask)
506{
507 PVBOXDISK pThis = (PVBOXDISK)pvUser;
508 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
509
510 return PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, pvCompletion,
511 (PPPDMASYNCCOMPLETIONTASK)ppTask);
512}
513
514static DECLCALLBACK(int) drvvdAsyncIOGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
515{
516 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
517 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
518
519 return PDMR3AsyncCompletionEpGetSize(pStorageBackend->pEndpoint, pcbSize);
520}
521
522static DECLCALLBACK(int) drvvdAsyncIOSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
523{
524 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
525 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
526
527 int rc = drvvdAsyncIOFlushSync(pvUser, pStorage);
528 if (RT_SUCCESS(rc))
529 rc = PDMR3AsyncCompletionEpSetSize(pStorageBackend->pEndpoint, cbSize);
530
531 return rc;
532}
533
534#endif /* VBOX_WITH_PDM_ASYNC_COMPLETION */
535
536
537/*******************************************************************************
538* VD Thread Synchronization interface implementation *
539*******************************************************************************/
540
541static DECLCALLBACK(int) drvvdThreadStartRead(void *pvUser)
542{
543 PVBOXDISK pThis = (PVBOXDISK)pvUser;
544
545 return RTSemRWRequestRead(pThis->MergeLock, RT_INDEFINITE_WAIT);
546}
547
548static DECLCALLBACK(int) drvvdThreadFinishRead(void *pvUser)
549{
550 PVBOXDISK pThis = (PVBOXDISK)pvUser;
551
552 return RTSemRWReleaseRead(pThis->MergeLock);
553}
554
555static DECLCALLBACK(int) drvvdThreadStartWrite(void *pvUser)
556{
557 PVBOXDISK pThis = (PVBOXDISK)pvUser;
558
559 return RTSemRWRequestWrite(pThis->MergeLock, RT_INDEFINITE_WAIT);
560}
561
562static DECLCALLBACK(int) drvvdThreadFinishWrite(void *pvUser)
563{
564 PVBOXDISK pThis = (PVBOXDISK)pvUser;
565
566 return RTSemRWReleaseWrite(pThis->MergeLock);
567}
568
569
570/*******************************************************************************
571* VD Configuration interface implementation *
572*******************************************************************************/
573
574static bool drvvdCfgAreKeysValid(void *pvUser, const char *pszzValid)
575{
576 return CFGMR3AreValuesValid((PCFGMNODE)pvUser, pszzValid);
577}
578
579static int drvvdCfgQuerySize(void *pvUser, const char *pszName, size_t *pcb)
580{
581 return CFGMR3QuerySize((PCFGMNODE)pvUser, pszName, pcb);
582}
583
584static int drvvdCfgQuery(void *pvUser, const char *pszName, char *pszString, size_t cchString)
585{
586 return CFGMR3QueryString((PCFGMNODE)pvUser, pszName, pszString, cchString);
587}
588
589
590#ifdef VBOX_WITH_INIP
591/*******************************************************************************
592* VD TCP network stack interface implementation - INIP case *
593*******************************************************************************/
594
595/** @copydoc VDINTERFACETCPNET::pfnClientConnect */
596static DECLCALLBACK(int) drvvdINIPClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
597{
598 int rc = VINF_SUCCESS;
599 /* First check whether lwIP is set up in this VM instance. */
600 if (!DevINIPConfigured())
601 {
602 LogRelFunc(("no IP stack\n"));
603 return VERR_NET_HOST_UNREACHABLE;
604 }
605 /* Resolve hostname. As there is no standard resolver for lwIP yet,
606 * just accept numeric IP addresses for now. */
607 struct in_addr ip;
608 if (!lwip_inet_aton(pszAddress, &ip))
609 {
610 LogRelFunc(("cannot resolve IP %s\n", pszAddress));
611 return VERR_NET_HOST_UNREACHABLE;
612 }
613 /* Create socket and connect. */
614 RTSOCKET Sock = lwip_socket(PF_INET, SOCK_STREAM, 0);
615 if (Sock != -1)
616 {
617 struct sockaddr_in InAddr = {0};
618 InAddr.sin_family = AF_INET;
619 InAddr.sin_port = htons(uPort);
620 InAddr.sin_addr = ip;
621 if (!lwip_connect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr)))
622 {
623 *pSock = Sock;
624 return VINF_SUCCESS;
625 }
626 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
627 lwip_close(Sock);
628 }
629 else
630 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
631 return rc;
632}
633
634/** @copydoc VDINTERFACETCPNET::pfnClientClose */
635static DECLCALLBACK(int) drvvdINIPClientClose(RTSOCKET Sock)
636{
637 lwip_close(Sock);
638 return VINF_SUCCESS; /** @todo real solution needed */
639}
640
641/** @copydoc VDINTERFACETCPNET::pfnSelectOne */
642static DECLCALLBACK(int) drvvdINIPSelectOne(RTSOCKET Sock, RTMSINTERVAL cMillies)
643{
644 fd_set fdsetR;
645 FD_ZERO(&fdsetR);
646 FD_SET(Sock, &fdsetR);
647 fd_set fdsetE = fdsetR;
648
649 int rc;
650 if (cMillies == RT_INDEFINITE_WAIT)
651 rc = lwip_select(Sock + 1, &fdsetR, NULL, &fdsetE, NULL);
652 else
653 {
654 struct timeval timeout;
655 timeout.tv_sec = cMillies / 1000;
656 timeout.tv_usec = (cMillies % 1000) * 1000;
657 rc = lwip_select(Sock + 1, &fdsetR, NULL, &fdsetE, &timeout);
658 }
659 if (rc > 0)
660 return VINF_SUCCESS;
661 if (rc == 0)
662 return VERR_TIMEOUT;
663 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
664}
665
666/** @copydoc VDINTERFACETCPNET::pfnRead */
667static DECLCALLBACK(int) drvvdINIPRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
668{
669 /* Do params checking */
670 if (!pvBuffer || !cbBuffer)
671 {
672 AssertMsgFailed(("Invalid params\n"));
673 return VERR_INVALID_PARAMETER;
674 }
675
676 /*
677 * Read loop.
678 * If pcbRead is NULL we have to fill the entire buffer!
679 */
680 size_t cbRead = 0;
681 size_t cbToRead = cbBuffer;
682 for (;;)
683 {
684 /** @todo this clipping here is just in case (the send function
685 * needed it, so I added it here, too). Didn't investigate if this
686 * really has issues. Better be safe than sorry. */
687 ssize_t cbBytesRead = lwip_recv(Sock, (char *)pvBuffer + cbRead,
688 RT_MIN(cbToRead, 32768), 0);
689 if (cbBytesRead < 0)
690 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
691 if (cbBytesRead == 0 && errno)
692 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
693 if (pcbRead)
694 {
695 /* return partial data */
696 *pcbRead = cbBytesRead;
697 break;
698 }
699
700 /* read more? */
701 cbRead += cbBytesRead;
702 if (cbRead == cbBuffer)
703 break;
704
705 /* next */
706 cbToRead = cbBuffer - cbRead;
707 }
708
709 return VINF_SUCCESS;
710}
711
712/** @copydoc VDINTERFACETCPNET::pfnWrite */
713static DECLCALLBACK(int) drvvdINIPWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
714{
715 do
716 {
717 /** @todo lwip send only supports up to 65535 bytes in a single
718 * send (stupid limitation buried in the code), so make sure we
719 * don't get any wraparounds. This should be moved to DevINIP
720 * stack interface once that's implemented. */
721 ssize_t cbWritten = lwip_send(Sock, (void *)pvBuffer,
722 RT_MIN(cbBuffer, 32768), 0);
723 if (cbWritten < 0)
724 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
725 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%d cbBuffer=%d\n",
726 cbWritten, cbBuffer));
727 cbBuffer -= cbWritten;
728 pvBuffer = (const char *)pvBuffer + cbWritten;
729 } while (cbBuffer);
730
731 return VINF_SUCCESS;
732}
733
734/** @copydoc VDINTERFACETCPNET::pfnFlush */
735static DECLCALLBACK(int) drvvdINIPFlush(RTSOCKET Sock)
736{
737 int fFlag = 1;
738 lwip_setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY,
739 (const char *)&fFlag, sizeof(fFlag));
740 fFlag = 0;
741 lwip_setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY,
742 (const char *)&fFlag, sizeof(fFlag));
743 return VINF_SUCCESS;
744}
745
746/** @copydoc VDINTERFACETCPNET::pfnGetLocalAddress */
747static DECLCALLBACK(int) drvvdINIPGetLocalAddress(RTSOCKET Sock, PRTNETADDR pAddr)
748{
749 union
750 {
751 struct sockaddr Addr;
752 struct sockaddr_in Ipv4;
753 } u;
754 socklen_t cbAddr = sizeof(u);
755 RT_ZERO(u);
756 if (!lwip_getsockname(Sock, &u.Addr, &cbAddr))
757 {
758 /*
759 * Convert the address.
760 */
761 if ( cbAddr == sizeof(struct sockaddr_in)
762 && u.Addr.sa_family == AF_INET)
763 {
764 RT_ZERO(*pAddr);
765 pAddr->enmType = RTNETADDRTYPE_IPV4;
766 pAddr->uPort = RT_N2H_U16(u.Ipv4.sin_port);
767 pAddr->uAddr.IPv4.u = u.Ipv4.sin_addr.s_addr;
768 }
769 else
770 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
771 return VINF_SUCCESS;
772 }
773 return VERR_NET_OPERATION_NOT_SUPPORTED;
774}
775
776/** @copydoc VDINTERFACETCPNET::pfnGetPeerAddress */
777static DECLCALLBACK(int) drvvdINIPGetPeerAddress(RTSOCKET Sock, PRTNETADDR pAddr)
778{
779 union
780 {
781 struct sockaddr Addr;
782 struct sockaddr_in Ipv4;
783 } u;
784 socklen_t cbAddr = sizeof(u);
785 RT_ZERO(u);
786 if (!lwip_getpeername(Sock, &u.Addr, &cbAddr))
787 {
788 /*
789 * Convert the address.
790 */
791 if ( cbAddr == sizeof(struct sockaddr_in)
792 && u.Addr.sa_family == AF_INET)
793 {
794 RT_ZERO(*pAddr);
795 pAddr->enmType = RTNETADDRTYPE_IPV4;
796 pAddr->uPort = RT_N2H_U16(u.Ipv4.sin_port);
797 pAddr->uAddr.IPv4.u = u.Ipv4.sin_addr.s_addr;
798 }
799 else
800 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
801 return VINF_SUCCESS;
802 }
803 return VERR_NET_OPERATION_NOT_SUPPORTED;
804}
805#endif /* VBOX_WITH_INIP */
806
807
808/*******************************************************************************
809* Media interface methods *
810*******************************************************************************/
811
812/** @copydoc PDMIMEDIA::pfnRead */
813static DECLCALLBACK(int) drvvdRead(PPDMIMEDIA pInterface,
814 uint64_t off, void *pvBuf, size_t cbRead)
815{
816 LogFlow(("%s: off=%#llx pvBuf=%p cbRead=%d\n", __FUNCTION__,
817 off, pvBuf, cbRead));
818 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
819 int rc = VDRead(pThis->pDisk, off, pvBuf, cbRead);
820 if (RT_SUCCESS(rc))
821 Log2(("%s: off=%#llx pvBuf=%p cbRead=%d %.*Rhxd\n", __FUNCTION__,
822 off, pvBuf, cbRead, cbRead, pvBuf));
823 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
824 return rc;
825}
826
827/** @copydoc PDMIMEDIA::pfnWrite */
828static DECLCALLBACK(int) drvvdWrite(PPDMIMEDIA pInterface,
829 uint64_t off, const void *pvBuf,
830 size_t cbWrite)
831{
832 LogFlow(("%s: off=%#llx pvBuf=%p cbWrite=%d\n", __FUNCTION__,
833 off, pvBuf, cbWrite));
834 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
835 Log2(("%s: off=%#llx pvBuf=%p cbWrite=%d %.*Rhxd\n", __FUNCTION__,
836 off, pvBuf, cbWrite, cbWrite, pvBuf));
837 int rc = VDWrite(pThis->pDisk, off, pvBuf, cbWrite);
838 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
839 return rc;
840}
841
842/** @copydoc PDMIMEDIA::pfnFlush */
843static DECLCALLBACK(int) drvvdFlush(PPDMIMEDIA pInterface)
844{
845 LogFlow(("%s:\n", __FUNCTION__));
846 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
847 int rc = VDFlush(pThis->pDisk);
848 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
849 return rc;
850}
851
852/** @copydoc PDMIMEDIA::pfnMerge */
853static DECLCALLBACK(int) drvvdMerge(PPDMIMEDIA pInterface,
854 PFNSIMPLEPROGRESS pfnProgress,
855 void *pvUser)
856{
857 LogFlow(("%s:\n", __FUNCTION__));
858 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
859 int rc = VINF_SUCCESS;
860
861 /* Note: There is an unavoidable race between destruction and another
862 * thread invoking this function. This is handled safely and gracefully by
863 * atomically invalidating the lock handle in drvvdDestruct. */
864 int rc2 = RTSemFastMutexRequest(pThis->MergeCompleteMutex);
865 AssertRC(rc2);
866 if (RT_SUCCESS(rc2) && pThis->fMergePending)
867 {
868 /* Take shortcut: PFNSIMPLEPROGRESS is exactly the same type as
869 * PFNVDPROGRESS, so there's no need for a conversion function. */
870 /** @todo maybe introduce a conversion which limits update frequency. */
871 PVDINTERFACE pVDIfsOperation = NULL;
872 VDINTERFACE VDIProgress;
873 VDINTERFACEPROGRESS VDIProgressCallbacks;
874 VDIProgressCallbacks.cbSize = sizeof(VDINTERFACEPROGRESS);
875 VDIProgressCallbacks.enmInterface = VDINTERFACETYPE_PROGRESS;
876 VDIProgressCallbacks.pfnProgress = pfnProgress;
877 rc2 = VDInterfaceAdd(&VDIProgress, "DrvVD_VDIProgress", VDINTERFACETYPE_PROGRESS,
878 &VDIProgressCallbacks, pvUser, &pVDIfsOperation);
879 AssertRC(rc2);
880 pThis->fMergePending = false;
881 rc = VDMerge(pThis->pDisk, pThis->uMergeSource,
882 pThis->uMergeTarget, pVDIfsOperation);
883 }
884 rc2 = RTSemFastMutexRelease(pThis->MergeCompleteMutex);
885 AssertRC(rc2);
886 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
887 return rc;
888}
889
890/** @copydoc PDMIMEDIA::pfnGetSize */
891static DECLCALLBACK(uint64_t) drvvdGetSize(PPDMIMEDIA pInterface)
892{
893 LogFlow(("%s:\n", __FUNCTION__));
894 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
895 uint64_t cb = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
896 LogFlow(("%s: returns %#llx (%llu)\n", __FUNCTION__, cb, cb));
897 return cb;
898}
899
900/** @copydoc PDMIMEDIA::pfnIsReadOnly */
901static DECLCALLBACK(bool) drvvdIsReadOnly(PPDMIMEDIA pInterface)
902{
903 LogFlow(("%s:\n", __FUNCTION__));
904 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
905 bool f = VDIsReadOnly(pThis->pDisk);
906 LogFlow(("%s: returns %d\n", __FUNCTION__, f));
907 return f;
908}
909
910/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
911static DECLCALLBACK(int) drvvdBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
912 PPDMMEDIAGEOMETRY pPCHSGeometry)
913{
914 LogFlow(("%s:\n", __FUNCTION__));
915 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
916 int rc = VDGetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
917 if (RT_FAILURE(rc))
918 {
919 Log(("%s: geometry not available.\n", __FUNCTION__));
920 rc = VERR_PDM_GEOMETRY_NOT_SET;
921 }
922 LogFlow(("%s: returns %Rrc (CHS=%d/%d/%d)\n", __FUNCTION__,
923 rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
924 return rc;
925}
926
927/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
928static DECLCALLBACK(int) drvvdBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
929 PCPDMMEDIAGEOMETRY pPCHSGeometry)
930{
931 LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
932 pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
933 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
934 int rc = VDSetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
935 if (rc == VERR_VD_GEOMETRY_NOT_SET)
936 rc = VERR_PDM_GEOMETRY_NOT_SET;
937 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
938 return rc;
939}
940
941/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
942static DECLCALLBACK(int) drvvdBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
943 PPDMMEDIAGEOMETRY pLCHSGeometry)
944{
945 LogFlow(("%s:\n", __FUNCTION__));
946 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
947 int rc = VDGetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
948 if (RT_FAILURE(rc))
949 {
950 Log(("%s: geometry not available.\n", __FUNCTION__));
951 rc = VERR_PDM_GEOMETRY_NOT_SET;
952 }
953 LogFlow(("%s: returns %Rrc (CHS=%d/%d/%d)\n", __FUNCTION__,
954 rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
955 return rc;
956}
957
958/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
959static DECLCALLBACK(int) drvvdBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
960 PCPDMMEDIAGEOMETRY pLCHSGeometry)
961{
962 LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
963 pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
964 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
965 int rc = VDSetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
966 if (rc == VERR_VD_GEOMETRY_NOT_SET)
967 rc = VERR_PDM_GEOMETRY_NOT_SET;
968 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
969 return rc;
970}
971
972/** @copydoc PDMIMEDIA::pfnGetUuid */
973static DECLCALLBACK(int) drvvdGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
974{
975 LogFlow(("%s:\n", __FUNCTION__));
976 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
977 int rc = VDGetUuid(pThis->pDisk, 0, pUuid);
978 LogFlow(("%s: returns %Rrc ({%RTuuid})\n", __FUNCTION__, rc, pUuid));
979 return rc;
980}
981
982/*******************************************************************************
983* Async Media interface methods *
984*******************************************************************************/
985
986static DECLCALLBACK(int) drvvdStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
987 PPDMDATASEG paSeg, unsigned cSeg,
988 size_t cbRead, void *pvUser)
989{
990 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d\n pvUser=%#p", __FUNCTION__,
991 uOffset, paSeg, cSeg, cbRead, pvUser));
992 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
993 int rc = VDAsyncRead(pThis->pDisk, uOffset, cbRead, paSeg, cSeg, pvUser);
994 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
995 return rc;
996}
997
998static DECLCALLBACK(int) drvvdStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
999 PPDMDATASEG paSeg, unsigned cSeg,
1000 size_t cbWrite, void *pvUser)
1001{
1002 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d\n pvUser=%#p", __FUNCTION__,
1003 uOffset, paSeg, cSeg, cbWrite, pvUser));
1004 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
1005 int rc = VDAsyncWrite(pThis->pDisk, uOffset, cbWrite, paSeg, cSeg, pvUser);
1006 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1007 return rc;
1008}
1009
1010/*******************************************************************************
1011* Async transport port interface methods *
1012*******************************************************************************/
1013
1014static DECLCALLBACK(int) drvvdTasksCompleteNotify(PPDMDRVINS pDrvIns, void *pvUser)
1015{
1016 return VERR_NOT_IMPLEMENTED;
1017}
1018
1019
1020/*******************************************************************************
1021* Base interface methods *
1022*******************************************************************************/
1023
1024/**
1025 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1026 */
1027static DECLCALLBACK(void *) drvvdQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1028{
1029 PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
1030 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1031
1032 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1033 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
1034 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->fAsyncIOSupported ? &pThis->IMediaAsync : NULL);
1035 return NULL;
1036}
1037
1038
1039/*******************************************************************************
1040* Saved state notification methods *
1041*******************************************************************************/
1042
1043/**
1044 * Load done callback for re-opening the image writable during teleportation.
1045 *
1046 * This is called both for successful and failed load runs, we only care about
1047 * successfull ones.
1048 *
1049 * @returns VBox status code.
1050 * @param pDrvIns The driver instance.
1051 * @param pSSM The saved state handle.
1052 */
1053static DECLCALLBACK(int) drvvdLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
1054{
1055 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1056 Assert(!pThis->fErrorUseRuntime);
1057
1058 /* Drop out if we don't have any work to do or if it's a failed load. */
1059 if ( !pThis->fTempReadOnly
1060 || RT_FAILURE(SSMR3HandleGetStatus(pSSM)))
1061 return VINF_SUCCESS;
1062
1063 int rc = drvvdSetWritable(pThis);
1064 if (RT_FAILURE(rc)) /** @todo does the bugger set any errors? */
1065 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
1066 N_("Failed to write lock the images"));
1067 return VINF_SUCCESS;
1068}
1069
1070
1071/*******************************************************************************
1072* Driver methods *
1073*******************************************************************************/
1074
1075static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
1076{
1077 LogFlow(("%s:\n", __FUNCTION__));
1078 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1079
1080 /*
1081 * We must close the disk here to ensure that
1082 * the backend closes all files before the
1083 * async transport driver is destructed.
1084 */
1085 int rc = VDCloseAll(pThis->pDisk);
1086 AssertRC(rc);
1087}
1088
1089/**
1090 * VM resume notification that we use to undo what the temporary read-only image
1091 * mode set by drvvdSuspend.
1092 *
1093 * Also switch to runtime error mode if we're resuming after a state load
1094 * without having been powered on first.
1095 *
1096 * @param pDrvIns The driver instance data.
1097 *
1098 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
1099 * we're making assumptions about Main behavior here!
1100 */
1101static DECLCALLBACK(void) drvvdResume(PPDMDRVINS pDrvIns)
1102{
1103 LogFlow(("%s:\n", __FUNCTION__));
1104 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1105 drvvdSetWritable(pThis);
1106 pThis->fErrorUseRuntime = true;
1107}
1108
1109/**
1110 * The VM is being suspended, temporarily change to read-only image mode.
1111 *
1112 * This is important for several reasons:
1113 * -# It makes sure that there are no pending writes to the image. Most
1114 * backends implements this by closing and reopening the image in read-only
1115 * mode.
1116 * -# It allows Main to read the images during snapshotting without having
1117 * to account for concurrent writes.
1118 * -# This is essential for making teleportation targets sharing images work
1119 * right. Both with regards to caching and with regards to file sharing
1120 * locks (RTFILE_O_DENY_*). (See also drvvdLoadDone.)
1121 *
1122 * @param pDrvIns The driver instance data.
1123 */
1124static DECLCALLBACK(void) drvvdSuspend(PPDMDRVINS pDrvIns)
1125{
1126 LogFlow(("%s:\n", __FUNCTION__));
1127 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1128 drvvdSetReadonly(pThis);
1129}
1130
1131/**
1132 * VM PowerOn notification for undoing the TempReadOnly config option and
1133 * changing to runtime error mode.
1134 *
1135 * @param pDrvIns The driver instance data.
1136 *
1137 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
1138 * we're making assumptions about Main behavior here!
1139 */
1140static DECLCALLBACK(void) drvvdPowerOn(PPDMDRVINS pDrvIns)
1141{
1142 LogFlow(("%s:\n", __FUNCTION__));
1143 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1144 drvvdSetWritable(pThis);
1145 pThis->fErrorUseRuntime = true;
1146}
1147
1148/**
1149 * @copydoc FNPDMDRVDESTRUCT
1150 */
1151static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
1152{
1153 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1154 LogFlow(("%s:\n", __FUNCTION__));
1155 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1156
1157 RTSEMFASTMUTEX mutex = (RTSEMFASTMUTEX)ASMAtomicXchgPtr((void **)&pThis->MergeCompleteMutex,
1158 (void *)NIL_RTSEMFASTMUTEX);
1159 if (mutex != NIL_RTSEMFASTMUTEX)
1160 {
1161 /* Request the semaphore to wait until a potentially running merge
1162 * operation has been finished. */
1163 int rc = RTSemFastMutexRequest(mutex);
1164 AssertRC(rc);
1165 pThis->fMergePending = false;
1166 rc = RTSemFastMutexRelease(mutex);
1167 AssertRC(rc);
1168 rc = RTSemFastMutexDestroy(mutex);
1169 AssertRC(rc);
1170 }
1171 if (pThis->MergeLock != NIL_RTSEMRW)
1172 {
1173 int rc = RTSemRWDestroy(pThis->MergeLock);
1174 AssertRC(rc);
1175 pThis->MergeLock = NIL_RTSEMRW;
1176 }
1177
1178 if (VALID_PTR(pThis->pDisk))
1179 {
1180 VDDestroy(pThis->pDisk);
1181 pThis->pDisk = NULL;
1182 }
1183 drvvdFreeImages(pThis);
1184}
1185
1186/**
1187 * Construct a VBox disk media driver instance.
1188 *
1189 * @copydoc FNPDMDRVCONSTRUCT
1190 */
1191static DECLCALLBACK(int) drvvdConstruct(PPDMDRVINS pDrvIns,
1192 PCFGMNODE pCfg,
1193 uint32_t fFlags)
1194{
1195 LogFlow(("%s:\n", __FUNCTION__));
1196 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1197 int rc = VINF_SUCCESS;
1198 char *pszName = NULL; /**< The path of the disk image file. */
1199 char *pszFormat = NULL; /**< The format backed to use for this image. */
1200 bool fReadOnly; /**< True if the media is read-only. */
1201 bool fHonorZeroWrites; /**< True if zero blocks should be written. */
1202 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1203
1204 /*
1205 * Init the static parts.
1206 */
1207 pDrvIns->IBase.pfnQueryInterface = drvvdQueryInterface;
1208 pThis->pDrvIns = pDrvIns;
1209 pThis->fTempReadOnly = false;
1210 pThis->pDisk = NULL;
1211 pThis->fAsyncIOSupported = false;
1212 pThis->fMergePending = false;
1213 pThis->MergeCompleteMutex = NIL_RTSEMFASTMUTEX;
1214 pThis->uMergeSource = VD_LAST_IMAGE;
1215 pThis->uMergeTarget = VD_LAST_IMAGE;
1216
1217 /* IMedia */
1218 pThis->IMedia.pfnRead = drvvdRead;
1219 pThis->IMedia.pfnWrite = drvvdWrite;
1220 pThis->IMedia.pfnFlush = drvvdFlush;
1221 pThis->IMedia.pfnMerge = drvvdMerge;
1222 pThis->IMedia.pfnGetSize = drvvdGetSize;
1223 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly;
1224 pThis->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
1225 pThis->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
1226 pThis->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
1227 pThis->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
1228 pThis->IMedia.pfnGetUuid = drvvdGetUuid;
1229
1230 /* IMediaAsync */
1231 pThis->IMediaAsync.pfnStartRead = drvvdStartRead;
1232 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite;
1233
1234 /* Initialize supported VD interfaces. */
1235 pThis->pVDIfsDisk = NULL;
1236
1237 pThis->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1238 pThis->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1239 pThis->VDIErrorCallbacks.pfnError = drvvdErrorCallback;
1240 pThis->VDIErrorCallbacks.pfnMessage = NULL;
1241
1242 rc = VDInterfaceAdd(&pThis->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
1243 &pThis->VDIErrorCallbacks, pDrvIns, &pThis->pVDIfsDisk);
1244 AssertRC(rc);
1245
1246 /* This is just prepared here, the actual interface is per-image, so it's
1247 * added later. No need to have separate callback tables. */
1248 pThis->VDIConfigCallbacks.cbSize = sizeof(VDINTERFACECONFIG);
1249 pThis->VDIConfigCallbacks.enmInterface = VDINTERFACETYPE_CONFIG;
1250 pThis->VDIConfigCallbacks.pfnAreKeysValid = drvvdCfgAreKeysValid;
1251 pThis->VDIConfigCallbacks.pfnQuerySize = drvvdCfgQuerySize;
1252 pThis->VDIConfigCallbacks.pfnQuery = drvvdCfgQuery;
1253
1254 /* List of images is empty now. */
1255 pThis->pImages = NULL;
1256
1257 /* Try to attach async media port interface above.*/
1258 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1259
1260 /*
1261 * Validate configuration and find all parent images.
1262 * It's sort of up side down from the image dependency tree.
1263 */
1264 bool fHostIP = false;
1265 bool fUseNewIo = false;
1266 unsigned iLevel = 0;
1267 PCFGMNODE pCurNode = pCfg;
1268
1269 for (;;)
1270 {
1271 bool fValid;
1272
1273 if (pCurNode == pCfg)
1274 {
1275 /* Toplevel configuration additionally contains the global image
1276 * open flags. Some might be converted to per-image flags later. */
1277 fValid = CFGMR3AreValuesValid(pCurNode,
1278 "Format\0Path\0"
1279 "ReadOnly\0TempReadOnly\0HonorZeroWrites\0"
1280 "HostIPStack\0UseNewIo\0SetupMerge\0");
1281 }
1282 else
1283 {
1284 /* All other image configurations only contain image name and
1285 * the format information. */
1286 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0"
1287 "MergeSource\0MergeTarget\0");
1288 }
1289 if (!fValid)
1290 {
1291 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1292 RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
1293 break;
1294 }
1295
1296 if (pCurNode == pCfg)
1297 {
1298 rc = CFGMR3QueryBoolDef(pCurNode, "HostIPStack", &fHostIP, true);
1299 if (RT_FAILURE(rc))
1300 {
1301 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1302 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
1303 break;
1304 }
1305
1306 rc = CFGMR3QueryBoolDef(pCurNode, "HonorZeroWrites", &fHonorZeroWrites, false);
1307 if (RT_FAILURE(rc))
1308 {
1309 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1310 N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
1311 break;
1312 }
1313
1314 rc = CFGMR3QueryBoolDef(pCurNode, "ReadOnly", &fReadOnly, false);
1315 if (RT_FAILURE(rc))
1316 {
1317 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1318 N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
1319 break;
1320 }
1321
1322 rc = CFGMR3QueryBoolDef(pCurNode, "TempReadOnly", &pThis->fTempReadOnly, false);
1323 if (RT_FAILURE(rc))
1324 {
1325 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1326 N_("DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
1327 break;
1328 }
1329 if (fReadOnly && pThis->fTempReadOnly)
1330 {
1331 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1332 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
1333 break;
1334 }
1335 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
1336 if (RT_FAILURE(rc))
1337 {
1338 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1339 N_("DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
1340 break;
1341 }
1342 rc = CFGMR3QueryBoolDef(pCurNode, "SetupMerge", &pThis->fMergePending, false);
1343 if (RT_FAILURE(rc))
1344 {
1345 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1346 N_("DrvVD: Configuration error: Querying \"SetupMerge\" as boolean failed"));
1347 break;
1348 }
1349 if (fReadOnly && pThis->fMergePending)
1350 {
1351 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1352 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"MergePending\" are set"));
1353 break;
1354 }
1355 }
1356
1357 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
1358 if (!pParent)
1359 break;
1360 pCurNode = pParent;
1361 iLevel++;
1362 }
1363
1364 /*
1365 * Create the image container and the necessary interfaces.
1366 */
1367 if (RT_SUCCESS(rc))
1368 {
1369 /* First of all figure out what kind of TCP networking stack interface
1370 * to use. This is done unconditionally, as backends which don't need
1371 * it will just ignore it. */
1372 if (fHostIP)
1373 {
1374 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1375 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1376 pThis->VDITcpNetCallbacks.pfnClientConnect = RTTcpClientConnect;
1377 pThis->VDITcpNetCallbacks.pfnClientClose = RTTcpClientClose;
1378 pThis->VDITcpNetCallbacks.pfnSelectOne = RTTcpSelectOne;
1379 pThis->VDITcpNetCallbacks.pfnRead = RTTcpRead;
1380 pThis->VDITcpNetCallbacks.pfnWrite = RTTcpWrite;
1381 pThis->VDITcpNetCallbacks.pfnFlush = RTTcpFlush;
1382 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = RTTcpGetLocalAddress;
1383 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = RTTcpGetPeerAddress;
1384 }
1385 else
1386 {
1387#ifndef VBOX_WITH_INIP
1388 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1389 RT_SRC_POS, N_("DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
1390#else /* VBOX_WITH_INIP */
1391 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1392 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1393 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
1394 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
1395 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
1396 pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
1397 pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite;
1398 pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush;
1399 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdINIPGetLocalAddress;
1400 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdINIPGetPeerAddress;
1401#endif /* VBOX_WITH_INIP */
1402 }
1403 if (RT_SUCCESS(rc))
1404 {
1405 rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP",
1406 VDINTERFACETYPE_TCPNET,
1407 &pThis->VDITcpNetCallbacks, NULL,
1408 &pThis->pVDIfsDisk);
1409 }
1410
1411 if (RT_SUCCESS(rc) && fUseNewIo)
1412 {
1413#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1414 pThis->VDIAsyncIOCallbacks.cbSize = sizeof(VDINTERFACEASYNCIO);
1415 pThis->VDIAsyncIOCallbacks.enmInterface = VDINTERFACETYPE_ASYNCIO;
1416 pThis->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen;
1417 pThis->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose;
1418 pThis->VDIAsyncIOCallbacks.pfnGetSize = drvvdAsyncIOGetSize;
1419 pThis->VDIAsyncIOCallbacks.pfnSetSize = drvvdAsyncIOSetSize;
1420 pThis->VDIAsyncIOCallbacks.pfnReadSync = drvvdAsyncIOReadSync;
1421 pThis->VDIAsyncIOCallbacks.pfnWriteSync = drvvdAsyncIOWriteSync;
1422 pThis->VDIAsyncIOCallbacks.pfnFlushSync = drvvdAsyncIOFlushSync;
1423 pThis->VDIAsyncIOCallbacks.pfnReadAsync = drvvdAsyncIOReadAsync;
1424 pThis->VDIAsyncIOCallbacks.pfnWriteAsync = drvvdAsyncIOWriteAsync;
1425 pThis->VDIAsyncIOCallbacks.pfnFlushAsync = drvvdAsyncIOFlushAsync;
1426
1427 rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
1428 &pThis->VDIAsyncIOCallbacks, pThis, &pThis->pVDIfsDisk);
1429#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1430 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1431 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
1432#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1433 }
1434
1435 if (RT_SUCCESS(rc) && pThis->fMergePending)
1436 {
1437 rc = RTSemFastMutexCreate(&pThis->MergeCompleteMutex);
1438 if (RT_SUCCESS(rc))
1439 rc = RTSemRWCreate(&pThis->MergeLock);
1440 if (RT_SUCCESS(rc))
1441 {
1442 pThis->VDIThreadSyncCallbacks.cbSize = sizeof(VDINTERFACETHREADSYNC);
1443 pThis->VDIThreadSyncCallbacks.enmInterface = VDINTERFACETYPE_THREADSYNC;
1444 pThis->VDIThreadSyncCallbacks.pfnStartRead = drvvdThreadStartRead;
1445 pThis->VDIThreadSyncCallbacks.pfnFinishRead = drvvdThreadFinishRead;
1446 pThis->VDIThreadSyncCallbacks.pfnStartWrite = drvvdThreadStartWrite;
1447 pThis->VDIThreadSyncCallbacks.pfnFinishWrite = drvvdThreadFinishWrite;
1448
1449 rc = VDInterfaceAdd(&pThis->VDIThreadSync, "DrvVD_ThreadSync", VDINTERFACETYPE_THREADSYNC,
1450 &pThis->VDIThreadSyncCallbacks, pThis, &pThis->pVDIfsDisk);
1451 }
1452 else
1453 {
1454 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1455 N_("DrvVD: Failed to create semaphores for \"MergePending\""));
1456 }
1457 }
1458
1459 if (RT_SUCCESS(rc))
1460 {
1461 rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk);
1462 /* Error message is already set correctly. */
1463 }
1464 }
1465
1466 if (pThis->pDrvMediaAsyncPort)
1467 pThis->fAsyncIOSupported = true;
1468
1469 unsigned iImageIdx = 0;
1470 while (pCurNode && RT_SUCCESS(rc))
1471 {
1472 /* Allocate per-image data. */
1473 PVBOXIMAGE pImage = drvvdNewImage(pThis);
1474 if (!pImage)
1475 {
1476 rc = VERR_NO_MEMORY;
1477 break;
1478 }
1479
1480 /*
1481 * Read the image configuration.
1482 */
1483 rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
1484 if (RT_FAILURE(rc))
1485 {
1486 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1487 N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
1488 break;
1489 }
1490
1491 rc = CFGMR3QueryStringAlloc(pCurNode, "Format", &pszFormat);
1492 if (RT_FAILURE(rc))
1493 {
1494 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1495 N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
1496 break;
1497 }
1498
1499 bool fMergeSource;
1500 rc = CFGMR3QueryBoolDef(pCurNode, "MergeSource", &fMergeSource, false);
1501 if (RT_FAILURE(rc))
1502 {
1503 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1504 N_("DrvVD: Configuration error: Querying \"MergeSource\" as boolean failed"));
1505 break;
1506 }
1507 if (fMergeSource)
1508 {
1509 if (pThis->uMergeSource == VD_LAST_IMAGE)
1510 pThis->uMergeSource = iImageIdx;
1511 else
1512 {
1513 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1514 N_("DrvVD: Configuration error: Multiple \"MergeSource\" occurrences"));
1515 break;
1516 }
1517 }
1518
1519 bool fMergeTarget;
1520 rc = CFGMR3QueryBoolDef(pCurNode, "MergeTarget", &fMergeTarget, false);
1521 if (RT_FAILURE(rc))
1522 {
1523 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1524 N_("DrvVD: Configuration error: Querying \"MergeTarget\" as boolean failed"));
1525 break;
1526 }
1527 if (fMergeTarget)
1528 {
1529 if (pThis->uMergeTarget == VD_LAST_IMAGE)
1530 pThis->uMergeTarget = iImageIdx;
1531 else
1532 {
1533 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1534 N_("DrvVD: Configuration error: Multiple \"MergeTarget\" occurrences"));
1535 break;
1536 }
1537 }
1538
1539 PCFGMNODE pCfgVDConfig = CFGMR3GetChild(pCurNode, "VDConfig");
1540 rc = VDInterfaceAdd(&pImage->VDIConfig, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
1541 &pThis->VDIConfigCallbacks, pCfgVDConfig, &pImage->pVDIfsImage);
1542 AssertRC(rc);
1543
1544 /*
1545 * Open the image.
1546 */
1547 unsigned uOpenFlags;
1548 if (fReadOnly || pThis->fTempReadOnly || iLevel != 0)
1549 uOpenFlags = VD_OPEN_FLAGS_READONLY;
1550 else
1551 uOpenFlags = VD_OPEN_FLAGS_NORMAL;
1552 if (fHonorZeroWrites)
1553 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
1554 if (pThis->fAsyncIOSupported)
1555 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
1556
1557 /* Try to open backend in async I/O mode first. */
1558 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1559 if (rc == VERR_NOT_SUPPORTED)
1560 {
1561 pThis->fAsyncIOSupported = false;
1562 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
1563 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1564 }
1565
1566 if (RT_SUCCESS(rc))
1567 {
1568 Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
1569 iLevel, pszName,
1570 VDIsReadOnly(pThis->pDisk) ? "read-only" : "read-write"));
1571 if ( VDIsReadOnly(pThis->pDisk)
1572 && !fReadOnly
1573 && !pThis->fTempReadOnly
1574 && iLevel == 0)
1575 {
1576 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_VD_IMAGE_READ_ONLY, RT_SRC_POS,
1577 N_("Failed to open image '%s' for writing due to wrong permissions"),
1578 pszName);
1579 break;
1580 }
1581 }
1582 else
1583 {
1584 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1585 N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName,
1586 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc);
1587 break;
1588 }
1589
1590
1591 MMR3HeapFree(pszName);
1592 pszName = NULL;
1593 MMR3HeapFree(pszFormat);
1594 pszFormat = NULL;
1595
1596 /* next */
1597 iLevel--;
1598 iImageIdx--;
1599 pCurNode = CFGMR3GetParent(pCurNode);
1600 }
1601
1602 if ( RT_SUCCESS(rc)
1603 && pThis->fMergePending
1604 && ( pThis->uMergeSource == VD_LAST_IMAGE
1605 || pThis->uMergeTarget == VD_LAST_IMAGE))
1606 {
1607 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1608 N_("DrvVD: Configuration error: Inconsistent image merge data"));
1609 }
1610
1611 /*
1612 * Register a load-done callback so we can undo TempReadOnly config before
1613 * we get to drvvdResume. Autoamtically deregistered upon destruction.
1614 */
1615 if (RT_SUCCESS(rc))
1616 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
1617 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
1618 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
1619 NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
1620
1621
1622 if (RT_FAILURE(rc))
1623 {
1624 if (VALID_PTR(pszName))
1625 MMR3HeapFree(pszName);
1626 if (VALID_PTR(pszFormat))
1627 MMR3HeapFree(pszFormat);
1628 /* drvvdDestruct does the rest. */
1629 }
1630
1631 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1632 return rc;
1633}
1634
1635/**
1636 * VBox disk container media driver registration record.
1637 */
1638const PDMDRVREG g_DrvVD =
1639{
1640 /* u32Version */
1641 PDM_DRVREG_VERSION,
1642 /* szName */
1643 "VD",
1644 /* szRCMod */
1645 "",
1646 /* szR0Mod */
1647 "",
1648 /* pszDescription */
1649 "Generic VBox disk media driver.",
1650 /* fFlags */
1651 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1652 /* fClass. */
1653 PDM_DRVREG_CLASS_MEDIA,
1654 /* cMaxInstances */
1655 ~0,
1656 /* cbInstance */
1657 sizeof(VBOXDISK),
1658 /* pfnConstruct */
1659 drvvdConstruct,
1660 /* pfnDestruct */
1661 drvvdDestruct,
1662 /* pfnRelocate */
1663 NULL,
1664 /* pfnIOCtl */
1665 NULL,
1666 /* pfnPowerOn */
1667 drvvdPowerOn,
1668 /* pfnReset */
1669 NULL,
1670 /* pfnSuspend */
1671 drvvdSuspend,
1672 /* pfnResume */
1673 drvvdResume,
1674 /* pfnAttach */
1675 NULL,
1676 /* pfnDetach */
1677 NULL,
1678 /* pfnPowerOff */
1679 drvvdPowerOff,
1680 /* pfnSoftReset */
1681 NULL,
1682 /* u32EndVersion */
1683 PDM_DRVREG_VERSION
1684};
1685
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