VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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