VirtualBox

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

Last change on this file since 28855 was 28835, checked in by vboxsync, 14 years ago

Main: live snapshot merging. initially limited to forward merging (i.e. everything but the first snapshot can be deleted)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.8 KB
Line 
1/* $Id: DrvVD.cpp 28835 2010-04-27 14:46:23Z 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
1186 if (VALID_PTR(pThis->pDisk))
1187 {
1188 VDDestroy(pThis->pDisk);
1189 pThis->pDisk = NULL;
1190 }
1191 drvvdFreeImages(pThis);
1192
1193 if (pThis->MergeLock != NIL_RTSEMRW)
1194 {
1195 int rc = RTSemRWDestroy(pThis->MergeLock);
1196 AssertRC(rc);
1197 pThis->MergeLock = NIL_RTSEMRW;
1198 }
1199}
1200
1201/**
1202 * Construct a VBox disk media driver instance.
1203 *
1204 * @copydoc FNPDMDRVCONSTRUCT
1205 */
1206static DECLCALLBACK(int) drvvdConstruct(PPDMDRVINS pDrvIns,
1207 PCFGMNODE pCfg,
1208 uint32_t fFlags)
1209{
1210 LogFlow(("%s:\n", __FUNCTION__));
1211 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1212 int rc = VINF_SUCCESS;
1213 char *pszName = NULL; /**< The path of the disk image file. */
1214 char *pszFormat = NULL; /**< The format backed to use for this image. */
1215 bool fReadOnly; /**< True if the media is read-only. */
1216 bool fHonorZeroWrites; /**< True if zero blocks should be written. */
1217 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1218
1219 /*
1220 * Init the static parts.
1221 */
1222 pDrvIns->IBase.pfnQueryInterface = drvvdQueryInterface;
1223 pThis->pDrvIns = pDrvIns;
1224 pThis->fTempReadOnly = false;
1225 pThis->pDisk = NULL;
1226 pThis->fAsyncIOSupported = false;
1227 pThis->fMergePending = false;
1228 pThis->MergeCompleteMutex = NIL_RTSEMFASTMUTEX;
1229 pThis->uMergeSource = VD_LAST_IMAGE;
1230 pThis->uMergeTarget = VD_LAST_IMAGE;
1231
1232 /* IMedia */
1233 pThis->IMedia.pfnRead = drvvdRead;
1234 pThis->IMedia.pfnWrite = drvvdWrite;
1235 pThis->IMedia.pfnFlush = drvvdFlush;
1236 pThis->IMedia.pfnMerge = drvvdMerge;
1237 pThis->IMedia.pfnGetSize = drvvdGetSize;
1238 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly;
1239 pThis->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
1240 pThis->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
1241 pThis->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
1242 pThis->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
1243 pThis->IMedia.pfnGetUuid = drvvdGetUuid;
1244
1245 /* IMediaAsync */
1246 pThis->IMediaAsync.pfnStartRead = drvvdStartRead;
1247 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite;
1248 pThis->IMediaAsync.pfnStartFlush = drvvdStartFlush;
1249
1250 /* Initialize supported VD interfaces. */
1251 pThis->pVDIfsDisk = NULL;
1252
1253 pThis->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1254 pThis->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1255 pThis->VDIErrorCallbacks.pfnError = drvvdErrorCallback;
1256 pThis->VDIErrorCallbacks.pfnMessage = NULL;
1257
1258 rc = VDInterfaceAdd(&pThis->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
1259 &pThis->VDIErrorCallbacks, pDrvIns, &pThis->pVDIfsDisk);
1260 AssertRC(rc);
1261
1262 /* This is just prepared here, the actual interface is per-image, so it's
1263 * added later. No need to have separate callback tables. */
1264 pThis->VDIConfigCallbacks.cbSize = sizeof(VDINTERFACECONFIG);
1265 pThis->VDIConfigCallbacks.enmInterface = VDINTERFACETYPE_CONFIG;
1266 pThis->VDIConfigCallbacks.pfnAreKeysValid = drvvdCfgAreKeysValid;
1267 pThis->VDIConfigCallbacks.pfnQuerySize = drvvdCfgQuerySize;
1268 pThis->VDIConfigCallbacks.pfnQuery = drvvdCfgQuery;
1269
1270 /* List of images is empty now. */
1271 pThis->pImages = NULL;
1272
1273 /* Try to attach async media port interface above.*/
1274 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1275
1276 /*
1277 * Validate configuration and find all parent images.
1278 * It's sort of up side down from the image dependency tree.
1279 */
1280 bool fHostIP = false;
1281 bool fUseNewIo = false;
1282 unsigned iLevel = 0;
1283 PCFGMNODE pCurNode = pCfg;
1284
1285 for (;;)
1286 {
1287 bool fValid;
1288
1289 if (pCurNode == pCfg)
1290 {
1291 /* Toplevel configuration additionally contains the global image
1292 * open flags. Some might be converted to per-image flags later. */
1293 fValid = CFGMR3AreValuesValid(pCurNode,
1294 "Format\0Path\0"
1295 "ReadOnly\0TempReadOnly\0HonorZeroWrites\0"
1296 "HostIPStack\0UseNewIo\0"
1297 "SetupMerge\0MergeSource\0MergeTarget\0");
1298 }
1299 else
1300 {
1301 /* All other image configurations only contain image name and
1302 * the format information. */
1303 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0"
1304 "MergeSource\0MergeTarget\0");
1305 }
1306 if (!fValid)
1307 {
1308 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1309 RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
1310 break;
1311 }
1312
1313 if (pCurNode == pCfg)
1314 {
1315 rc = CFGMR3QueryBoolDef(pCurNode, "HostIPStack", &fHostIP, true);
1316 if (RT_FAILURE(rc))
1317 {
1318 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1319 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
1320 break;
1321 }
1322
1323 rc = CFGMR3QueryBoolDef(pCurNode, "HonorZeroWrites", &fHonorZeroWrites, false);
1324 if (RT_FAILURE(rc))
1325 {
1326 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1327 N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
1328 break;
1329 }
1330
1331 rc = CFGMR3QueryBoolDef(pCurNode, "ReadOnly", &fReadOnly, false);
1332 if (RT_FAILURE(rc))
1333 {
1334 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1335 N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
1336 break;
1337 }
1338
1339 rc = CFGMR3QueryBoolDef(pCurNode, "TempReadOnly", &pThis->fTempReadOnly, false);
1340 if (RT_FAILURE(rc))
1341 {
1342 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1343 N_("DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
1344 break;
1345 }
1346 if (fReadOnly && pThis->fTempReadOnly)
1347 {
1348 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1349 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
1350 break;
1351 }
1352 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
1353 if (RT_FAILURE(rc))
1354 {
1355 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1356 N_("DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
1357 break;
1358 }
1359 rc = CFGMR3QueryBoolDef(pCurNode, "SetupMerge", &pThis->fMergePending, false);
1360 if (RT_FAILURE(rc))
1361 {
1362 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1363 N_("DrvVD: Configuration error: Querying \"SetupMerge\" as boolean failed"));
1364 break;
1365 }
1366 if (fReadOnly && pThis->fMergePending)
1367 {
1368 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1369 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"MergePending\" are set"));
1370 break;
1371 }
1372 }
1373
1374 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
1375 if (!pParent)
1376 break;
1377 pCurNode = pParent;
1378 iLevel++;
1379 }
1380
1381 /*
1382 * Create the image container and the necessary interfaces.
1383 */
1384 if (RT_SUCCESS(rc))
1385 {
1386 /* First of all figure out what kind of TCP networking stack interface
1387 * to use. This is done unconditionally, as backends which don't need
1388 * it will just ignore it. */
1389 if (fHostIP)
1390 {
1391 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1392 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1393 pThis->VDITcpNetCallbacks.pfnClientConnect = RTTcpClientConnect;
1394 pThis->VDITcpNetCallbacks.pfnClientClose = RTTcpClientClose;
1395 pThis->VDITcpNetCallbacks.pfnSelectOne = RTTcpSelectOne;
1396 pThis->VDITcpNetCallbacks.pfnRead = RTTcpRead;
1397 pThis->VDITcpNetCallbacks.pfnWrite = RTTcpWrite;
1398 pThis->VDITcpNetCallbacks.pfnFlush = RTTcpFlush;
1399 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = RTTcpGetLocalAddress;
1400 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = RTTcpGetPeerAddress;
1401 }
1402 else
1403 {
1404#ifndef VBOX_WITH_INIP
1405 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1406 RT_SRC_POS, N_("DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
1407#else /* VBOX_WITH_INIP */
1408 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1409 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1410 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
1411 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
1412 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
1413 pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
1414 pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite;
1415 pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush;
1416 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdINIPGetLocalAddress;
1417 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdINIPGetPeerAddress;
1418#endif /* VBOX_WITH_INIP */
1419 }
1420 if (RT_SUCCESS(rc))
1421 {
1422 rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP",
1423 VDINTERFACETYPE_TCPNET,
1424 &pThis->VDITcpNetCallbacks, NULL,
1425 &pThis->pVDIfsDisk);
1426 }
1427
1428 if (RT_SUCCESS(rc) && fUseNewIo)
1429 {
1430#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1431 pThis->VDIAsyncIOCallbacks.cbSize = sizeof(VDINTERFACEASYNCIO);
1432 pThis->VDIAsyncIOCallbacks.enmInterface = VDINTERFACETYPE_ASYNCIO;
1433 pThis->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen;
1434 pThis->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose;
1435 pThis->VDIAsyncIOCallbacks.pfnGetSize = drvvdAsyncIOGetSize;
1436 pThis->VDIAsyncIOCallbacks.pfnSetSize = drvvdAsyncIOSetSize;
1437 pThis->VDIAsyncIOCallbacks.pfnReadSync = drvvdAsyncIOReadSync;
1438 pThis->VDIAsyncIOCallbacks.pfnWriteSync = drvvdAsyncIOWriteSync;
1439 pThis->VDIAsyncIOCallbacks.pfnFlushSync = drvvdAsyncIOFlushSync;
1440 pThis->VDIAsyncIOCallbacks.pfnReadAsync = drvvdAsyncIOReadAsync;
1441 pThis->VDIAsyncIOCallbacks.pfnWriteAsync = drvvdAsyncIOWriteAsync;
1442 pThis->VDIAsyncIOCallbacks.pfnFlushAsync = drvvdAsyncIOFlushAsync;
1443
1444 rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
1445 &pThis->VDIAsyncIOCallbacks, pThis, &pThis->pVDIfsDisk);
1446#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1447 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1448 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
1449#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1450 }
1451
1452 if (RT_SUCCESS(rc) && pThis->fMergePending)
1453 {
1454 rc = RTSemFastMutexCreate(&pThis->MergeCompleteMutex);
1455 if (RT_SUCCESS(rc))
1456 rc = RTSemRWCreate(&pThis->MergeLock);
1457 if (RT_SUCCESS(rc))
1458 {
1459 pThis->VDIThreadSyncCallbacks.cbSize = sizeof(VDINTERFACETHREADSYNC);
1460 pThis->VDIThreadSyncCallbacks.enmInterface = VDINTERFACETYPE_THREADSYNC;
1461 pThis->VDIThreadSyncCallbacks.pfnStartRead = drvvdThreadStartRead;
1462 pThis->VDIThreadSyncCallbacks.pfnFinishRead = drvvdThreadFinishRead;
1463 pThis->VDIThreadSyncCallbacks.pfnStartWrite = drvvdThreadStartWrite;
1464 pThis->VDIThreadSyncCallbacks.pfnFinishWrite = drvvdThreadFinishWrite;
1465
1466 rc = VDInterfaceAdd(&pThis->VDIThreadSync, "DrvVD_ThreadSync", VDINTERFACETYPE_THREADSYNC,
1467 &pThis->VDIThreadSyncCallbacks, pThis, &pThis->pVDIfsDisk);
1468 }
1469 else
1470 {
1471 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1472 N_("DrvVD: Failed to create semaphores for \"MergePending\""));
1473 }
1474 }
1475
1476 if (RT_SUCCESS(rc))
1477 {
1478 rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk);
1479 /* Error message is already set correctly. */
1480 }
1481 }
1482
1483 if (pThis->pDrvMediaAsyncPort && fUseNewIo)
1484 pThis->fAsyncIOSupported = true;
1485
1486 unsigned iImageIdx = 0;
1487 while (pCurNode && RT_SUCCESS(rc))
1488 {
1489 /* Allocate per-image data. */
1490 PVBOXIMAGE pImage = drvvdNewImage(pThis);
1491 if (!pImage)
1492 {
1493 rc = VERR_NO_MEMORY;
1494 break;
1495 }
1496
1497 /*
1498 * Read the image configuration.
1499 */
1500 rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
1501 if (RT_FAILURE(rc))
1502 {
1503 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1504 N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
1505 break;
1506 }
1507
1508 rc = CFGMR3QueryStringAlloc(pCurNode, "Format", &pszFormat);
1509 if (RT_FAILURE(rc))
1510 {
1511 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1512 N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
1513 break;
1514 }
1515
1516 bool fMergeSource;
1517 rc = CFGMR3QueryBoolDef(pCurNode, "MergeSource", &fMergeSource, false);
1518 if (RT_FAILURE(rc))
1519 {
1520 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1521 N_("DrvVD: Configuration error: Querying \"MergeSource\" as boolean failed"));
1522 break;
1523 }
1524 if (fMergeSource)
1525 {
1526 if (pThis->uMergeSource == VD_LAST_IMAGE)
1527 pThis->uMergeSource = iImageIdx;
1528 else
1529 {
1530 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1531 N_("DrvVD: Configuration error: Multiple \"MergeSource\" occurrences"));
1532 break;
1533 }
1534 }
1535
1536 bool fMergeTarget;
1537 rc = CFGMR3QueryBoolDef(pCurNode, "MergeTarget", &fMergeTarget, false);
1538 if (RT_FAILURE(rc))
1539 {
1540 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1541 N_("DrvVD: Configuration error: Querying \"MergeTarget\" as boolean failed"));
1542 break;
1543 }
1544 if (fMergeTarget)
1545 {
1546 if (pThis->uMergeTarget == VD_LAST_IMAGE)
1547 pThis->uMergeTarget = iImageIdx;
1548 else
1549 {
1550 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1551 N_("DrvVD: Configuration error: Multiple \"MergeTarget\" occurrences"));
1552 break;
1553 }
1554 }
1555
1556 PCFGMNODE pCfgVDConfig = CFGMR3GetChild(pCurNode, "VDConfig");
1557 rc = VDInterfaceAdd(&pImage->VDIConfig, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
1558 &pThis->VDIConfigCallbacks, pCfgVDConfig, &pImage->pVDIfsImage);
1559 AssertRC(rc);
1560
1561 /*
1562 * Open the image.
1563 */
1564 unsigned uOpenFlags;
1565 if (fReadOnly || pThis->fTempReadOnly || iLevel != 0)
1566 uOpenFlags = VD_OPEN_FLAGS_READONLY;
1567 else
1568 uOpenFlags = VD_OPEN_FLAGS_NORMAL;
1569 if (fHonorZeroWrites)
1570 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
1571 if (pThis->fAsyncIOSupported)
1572 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
1573
1574 /* Try to open backend in async I/O mode first. */
1575 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1576 if (rc == VERR_NOT_SUPPORTED)
1577 {
1578 pThis->fAsyncIOSupported = false;
1579 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
1580 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1581 }
1582
1583 if (RT_SUCCESS(rc))
1584 {
1585 Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
1586 iLevel, pszName,
1587 VDIsReadOnly(pThis->pDisk) ? "read-only" : "read-write"));
1588 if ( VDIsReadOnly(pThis->pDisk)
1589 && !fReadOnly
1590 && !pThis->fTempReadOnly
1591 && iLevel == 0)
1592 {
1593 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_VD_IMAGE_READ_ONLY, RT_SRC_POS,
1594 N_("Failed to open image '%s' for writing due to wrong permissions"),
1595 pszName);
1596 break;
1597 }
1598 }
1599 else
1600 {
1601 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1602 N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName,
1603 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc);
1604 break;
1605 }
1606
1607
1608 MMR3HeapFree(pszName);
1609 pszName = NULL;
1610 MMR3HeapFree(pszFormat);
1611 pszFormat = NULL;
1612
1613 /* next */
1614 iLevel--;
1615 iImageIdx++;
1616 pCurNode = CFGMR3GetParent(pCurNode);
1617 }
1618
1619 if ( RT_SUCCESS(rc)
1620 && pThis->fMergePending
1621 && ( pThis->uMergeSource == VD_LAST_IMAGE
1622 || pThis->uMergeTarget == VD_LAST_IMAGE))
1623 {
1624 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1625 N_("DrvVD: Configuration error: Inconsistent image merge data"));
1626 }
1627
1628 /*
1629 * Register a load-done callback so we can undo TempReadOnly config before
1630 * we get to drvvdResume. Autoamtically deregistered upon destruction.
1631 */
1632 if (RT_SUCCESS(rc))
1633 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
1634 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
1635 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
1636 NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
1637
1638
1639 if (RT_FAILURE(rc))
1640 {
1641 if (VALID_PTR(pszName))
1642 MMR3HeapFree(pszName);
1643 if (VALID_PTR(pszFormat))
1644 MMR3HeapFree(pszFormat);
1645 /* drvvdDestruct does the rest. */
1646 }
1647
1648 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1649 return rc;
1650}
1651
1652/**
1653 * VBox disk container media driver registration record.
1654 */
1655const PDMDRVREG g_DrvVD =
1656{
1657 /* u32Version */
1658 PDM_DRVREG_VERSION,
1659 /* szName */
1660 "VD",
1661 /* szRCMod */
1662 "",
1663 /* szR0Mod */
1664 "",
1665 /* pszDescription */
1666 "Generic VBox disk media driver.",
1667 /* fFlags */
1668 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1669 /* fClass. */
1670 PDM_DRVREG_CLASS_MEDIA,
1671 /* cMaxInstances */
1672 ~0,
1673 /* cbInstance */
1674 sizeof(VBOXDISK),
1675 /* pfnConstruct */
1676 drvvdConstruct,
1677 /* pfnDestruct */
1678 drvvdDestruct,
1679 /* pfnRelocate */
1680 NULL,
1681 /* pfnIOCtl */
1682 NULL,
1683 /* pfnPowerOn */
1684 drvvdPowerOn,
1685 /* pfnReset */
1686 NULL,
1687 /* pfnSuspend */
1688 drvvdSuspend,
1689 /* pfnResume */
1690 drvvdResume,
1691 /* pfnAttach */
1692 NULL,
1693 /* pfnDetach */
1694 NULL,
1695 /* pfnPowerOff */
1696 drvvdPowerOff,
1697 /* pfnSoftReset */
1698 NULL,
1699 /* u32EndVersion */
1700 PDM_DRVREG_VERSION
1701};
1702
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use