VirtualBox

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

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

VBoxHDD: Move the FinishWrite call from DrvVD to VBoxHDD where we can determine the type of the operation (read/write)

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