VirtualBox

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

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

Grrr

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 75.9 KB
Line 
1/* $Id: DrvVD.cpp 31186 2010-07-28 21:00:49Z 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#include <iprt/poll.h>
36#include <iprt/pipe.h>
37
38#ifdef VBOX_WITH_INIP
39/* All lwip header files are not C++ safe. So hack around this. */
40RT_C_DECLS_BEGIN
41#include <lwip/inet.h>
42#include <lwip/tcp.h>
43#include <lwip/sockets.h>
44RT_C_DECLS_END
45#endif /* VBOX_WITH_INIP */
46
47#include "Builtins.h"
48
49#ifdef VBOX_WITH_INIP
50/* Small hack to get at lwIP initialized status */
51extern bool DevINIPConfigured(void);
52#endif /* VBOX_WITH_INIP */
53
54
55/*******************************************************************************
56* Defined types, constants and macros *
57*******************************************************************************/
58
59/** Converts a pointer to VBOXDISK::IMedia to a PVBOXDISK. */
60#define PDMIMEDIA_2_VBOXDISK(pInterface) \
61 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMedia)) )
62
63/** Converts a pointer to PDMDRVINS::IBase to a PPDMDRVINS. */
64#define PDMIBASE_2_DRVINS(pInterface) \
65 ( (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) )
66
67/** Converts a pointer to PDMDRVINS::IBase to a PVBOXDISK. */
68#define PDMIBASE_2_VBOXDISK(pInterface) \
69 ( PDMINS_2_DATA(PDMIBASE_2_DRVINS(pInterface), PVBOXDISK) )
70
71/** Converts a pointer to VBOXDISK::IMediaAsync to a PVBOXDISK. */
72#define PDMIMEDIAASYNC_2_VBOXDISK(pInterface) \
73 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMediaAsync)) )
74
75/**
76 * VBox disk container, image information, private part.
77 */
78
79typedef struct VBOXIMAGE
80{
81 /** Pointer to next image. */
82 struct VBOXIMAGE *pNext;
83 /** Pointer to list of VD interfaces. Per-image. */
84 PVDINTERFACE pVDIfsImage;
85 /** Common structure for the configuration information interface. */
86 VDINTERFACE VDIConfig;
87} VBOXIMAGE, *PVBOXIMAGE;
88
89/**
90 * Storage backend data.
91 */
92typedef struct DRVVDSTORAGEBACKEND
93{
94 /** PDM async completion end point. */
95 PPDMASYNCCOMPLETIONENDPOINT pEndpoint;
96 /** The template. */
97 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
98 /** Event semaphore for synchronous operations. */
99 RTSEMEVENT EventSem;
100 /** Flag whether a synchronous operation is currently pending. */
101 volatile bool fSyncIoPending;
102 /** Return code of the last completed request. */
103 int rcReqLast;
104 /** Callback routine */
105 PFNVDCOMPLETED pfnCompleted;
106
107 /** Pointer to the optional thread synchronization interface of the disk. */
108 PVDINTERFACE pInterfaceThreadSync;
109 /** Pointer to the optional thread synchronization callbacks of the disk. */
110 PVDINTERFACETHREADSYNC pInterfaceThreadSyncCallbacks;
111} DRVVDSTORAGEBACKEND, *PDRVVDSTORAGEBACKEND;
112
113/**
114 * VBox disk container media main structure, private part.
115 *
116 * @implements PDMIMEDIA
117 * @implements PDMIMEDIAASYNC
118 * @implements VDINTERFACEERROR
119 * @implements VDINTERFACETCPNET
120 * @implements VDINTERFACEASYNCIO
121 * @implements VDINTERFACECONFIG
122 */
123typedef struct VBOXDISK
124{
125 /** The VBox disk container. */
126 PVBOXHDD pDisk;
127 /** The media interface. */
128 PDMIMEDIA IMedia;
129 /** Pointer to the driver instance. */
130 PPDMDRVINS pDrvIns;
131 /** Flag whether suspend has changed image open mode to read only. */
132 bool fTempReadOnly;
133 /** Flag whether to use the runtime (true) or startup error facility. */
134 bool fErrorUseRuntime;
135 /** Pointer to list of VD interfaces. Per-disk. */
136 PVDINTERFACE pVDIfsDisk;
137 /** Common structure for the supported error interface. */
138 VDINTERFACE VDIError;
139 /** Callback table for error interface. */
140 VDINTERFACEERROR VDIErrorCallbacks;
141 /** Common structure for the supported TCP network stack interface. */
142 VDINTERFACE VDITcpNet;
143 /** Callback table for TCP network stack interface. */
144 VDINTERFACETCPNET VDITcpNetCallbacks;
145 /** Common structure for the supported async I/O interface. */
146 VDINTERFACE VDIAsyncIO;
147 /** Callback table for async I/O interface. */
148 VDINTERFACEASYNCIO VDIAsyncIOCallbacks;
149 /** Common structure for the supported thread synchronization interface. */
150 VDINTERFACE VDIThreadSync;
151 /** Callback table for thread synchronization interface. */
152 VDINTERFACETHREADSYNC VDIThreadSyncCallbacks;
153 /** Callback table for the configuration information interface. */
154 VDINTERFACECONFIG VDIConfigCallbacks;
155 /** Flag whether opened disk suppports async I/O operations. */
156 bool fAsyncIOSupported;
157 /** The async media interface. */
158 PDMIMEDIAASYNC IMediaAsync;
159 /** The async media port interface above. */
160 PPDMIMEDIAASYNCPORT pDrvMediaAsyncPort;
161 /** Pointer to the list of data we need to keep per image. */
162 PVBOXIMAGE pImages;
163 /** Flag whether the media should allow concurrent open for writing. */
164 bool fShareable;
165 /** Flag whether a merge operation has been set up. */
166 bool fMergePending;
167 /** Synchronization to prevent destruction before merge finishes. */
168 RTSEMFASTMUTEX MergeCompleteMutex;
169 /** Synchronization between merge and other image accesses. */
170 RTSEMRW MergeLock;
171 /** Source image index for merging. */
172 unsigned uMergeSource;
173 /** Target image index for merging. */
174 unsigned uMergeTarget;
175} VBOXDISK, *PVBOXDISK;
176
177
178/*******************************************************************************
179* Internal Functions *
180*******************************************************************************/
181
182/**
183 * Internal: allocate new image descriptor and put it in the list
184 */
185static PVBOXIMAGE drvvdNewImage(PVBOXDISK pThis)
186{
187 AssertPtr(pThis);
188 PVBOXIMAGE pImage = (PVBOXIMAGE)RTMemAllocZ(sizeof(VBOXIMAGE));
189 if (pImage)
190 {
191 pImage->pVDIfsImage = NULL;
192 PVBOXIMAGE *pp = &pThis->pImages;
193 while (*pp != NULL)
194 pp = &(*pp)->pNext;
195 *pp = pImage;
196 pImage->pNext = NULL;
197 }
198
199 return pImage;
200}
201
202/**
203 * Internal: free the list of images descriptors.
204 */
205static void drvvdFreeImages(PVBOXDISK pThis)
206{
207 while (pThis->pImages != NULL)
208 {
209 PVBOXIMAGE p = pThis->pImages;
210 pThis->pImages = pThis->pImages->pNext;
211 RTMemFree(p);
212 }
213}
214
215
216/**
217 * Make the image temporarily read-only.
218 *
219 * @returns VBox status code.
220 * @param pThis The driver instance data.
221 */
222static int drvvdSetReadonly(PVBOXDISK pThis)
223{
224 int rc = VINF_SUCCESS;
225 if (!VDIsReadOnly(pThis->pDisk))
226 {
227 unsigned uOpenFlags;
228 rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
229 AssertRC(rc);
230 uOpenFlags |= VD_OPEN_FLAGS_READONLY;
231 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
232 AssertRC(rc);
233 pThis->fTempReadOnly = true;
234 }
235 return rc;
236}
237
238
239/**
240 * Undo the temporary read-only status of the image.
241 *
242 * @returns VBox status code.
243 * @param pThis The driver instance data.
244 */
245static int drvvdSetWritable(PVBOXDISK pThis)
246{
247 int rc = VINF_SUCCESS;
248 if (pThis->fTempReadOnly)
249 {
250 unsigned uOpenFlags;
251 rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
252 AssertRC(rc);
253 uOpenFlags &= ~VD_OPEN_FLAGS_READONLY;
254 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
255 if (RT_SUCCESS(rc))
256 pThis->fTempReadOnly = false;
257 else
258 AssertRC(rc);
259 }
260 return rc;
261}
262
263
264/*******************************************************************************
265* Error reporting callback *
266*******************************************************************************/
267
268static void drvvdErrorCallback(void *pvUser, int rc, RT_SRC_POS_DECL,
269 const char *pszFormat, va_list va)
270{
271 PPDMDRVINS pDrvIns = (PPDMDRVINS)pvUser;
272 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
273 if (pThis->fErrorUseRuntime)
274 /* We must not pass VMSETRTERR_FLAGS_FATAL as it could lead to a
275 * deadlock: We are probably executed in a thread context != EMT
276 * and the EM thread would wait until every thread is suspended
277 * but we would wait for the EM thread ... */
278
279 PDMDrvHlpVMSetRuntimeErrorV(pDrvIns, /* fFlags=*/ 0, "DrvVD", pszFormat, va);
280 else
281 PDMDrvHlpVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va);
282}
283
284/*******************************************************************************
285* VD Async I/O interface implementation *
286*******************************************************************************/
287
288#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
289
290static DECLCALLBACK(void) drvvdAsyncTaskCompleted(PPDMDRVINS pDrvIns, void *pvTemplateUser, void *pvUser, int rcReq)
291{
292 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
293 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pvTemplateUser;
294
295 LogFlowFunc(("pDrvIns=%#p pvTemplateUser=%#p pvUser=%#p rcReq\n",
296 pDrvIns, pvTemplateUser, pvUser, rcReq));
297
298 if (pStorageBackend->fSyncIoPending)
299 {
300 Assert(!pvUser);
301 pStorageBackend->rcReqLast = rcReq;
302 pStorageBackend->fSyncIoPending = false;
303 RTSemEventSignal(pStorageBackend->EventSem);
304 }
305 else
306 {
307 int rc;
308
309 AssertPtr(pvUser);
310
311 AssertPtr(pStorageBackend->pfnCompleted);
312 rc = pStorageBackend->pfnCompleted(pvUser, rcReq);
313 AssertRC(rc);
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 uint32_t fFlags = uOpenFlags & VD_INTERFACEASYNCIO_OPEN_FLAGS_READONLY
347 ? PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_CACHING
348 : 0;
349 if (pThis->fShareable)
350 {
351 Assert(uOpenFlags & VD_INTERFACEASYNCIO_OPEN_FLAGS_DONT_LOCK);
352
353 fFlags |= PDMACEP_FILE_FLAGS_DONT_LOCK;
354 }
355 else
356 fFlags |= PDMACEP_FILE_FLAGS_CACHING;
357 rc = PDMR3AsyncCompletionEpCreateForFile(&pStorageBackend->pEndpoint,
358 pszLocation, fFlags,
359 pStorageBackend->pTemplate);
360 if (RT_SUCCESS(rc))
361 {
362 *ppStorage = pStorageBackend;
363 return VINF_SUCCESS;
364 }
365
366 PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate);
367 }
368 RTSemEventDestroy(pStorageBackend->EventSem);
369 }
370 RTMemFree(pStorageBackend);
371 }
372 else
373 rc = VERR_NO_MEMORY;
374
375 return rc;
376}
377
378static DECLCALLBACK(int) drvvdAsyncIOClose(void *pvUser, void *pStorage)
379{
380 PVBOXDISK pThis = (PVBOXDISK)pvUser;
381 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
382
383 PDMR3AsyncCompletionEpClose(pStorageBackend->pEndpoint);
384 PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate);
385 RTSemEventDestroy(pStorageBackend->EventSem);
386 RTMemFree(pStorageBackend);
387
388 return VINF_SUCCESS;;
389}
390
391static DECLCALLBACK(int) drvvdAsyncIOReadSync(void *pvUser, void *pStorage, uint64_t uOffset,
392 size_t cbRead, void *pvBuf, size_t *pcbRead)
393{
394 PVBOXDISK pThis = (PVBOXDISK)pvUser;
395 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
396 RTSGSEG DataSeg;
397 PPDMASYNCCOMPLETIONTASK pTask;
398
399 Assert(!pStorageBackend->fSyncIoPending);
400 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
401 DataSeg.cbSeg = cbRead;
402 DataSeg.pvSeg = pvBuf;
403
404 int rc = PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbRead, NULL, &pTask);
405 if (RT_FAILURE(rc))
406 return rc;
407
408 if (rc == VINF_AIO_TASK_PENDING)
409 {
410 /* Wait */
411 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
412 AssertRC(rc);
413 }
414 else
415 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
416
417 if (pcbRead)
418 *pcbRead = cbRead;
419
420 return pStorageBackend->rcReqLast;
421}
422
423static DECLCALLBACK(int) drvvdAsyncIOWriteSync(void *pvUser, void *pStorage, uint64_t uOffset,
424 size_t cbWrite, const void *pvBuf, size_t *pcbWritten)
425{
426 PVBOXDISK pThis = (PVBOXDISK)pvUser;
427 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
428 RTSGSEG DataSeg;
429 PPDMASYNCCOMPLETIONTASK pTask;
430
431 Assert(!pStorageBackend->fSyncIoPending);
432 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
433 DataSeg.cbSeg = cbWrite;
434 DataSeg.pvSeg = (void *)pvBuf;
435
436 int rc = PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbWrite, NULL, &pTask);
437 if (RT_FAILURE(rc))
438 return rc;
439
440 if (rc == VINF_AIO_TASK_PENDING)
441 {
442 /* Wait */
443 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
444 AssertRC(rc);
445 }
446 else
447 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
448
449 if (pcbWritten)
450 *pcbWritten = cbWrite;
451
452 return pStorageBackend->rcReqLast;
453}
454
455static DECLCALLBACK(int) drvvdAsyncIOFlushSync(void *pvUser, void *pStorage)
456{
457 PVBOXDISK pThis = (PVBOXDISK)pvUser;
458 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
459 PPDMASYNCCOMPLETIONTASK pTask;
460
461 LogFlowFunc(("pvUser=%#p pStorage=%#p\n", pvUser, pStorage));
462
463 Assert(!pStorageBackend->fSyncIoPending);
464 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
465
466 int rc = PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, NULL, &pTask);
467 if (RT_FAILURE(rc))
468 return rc;
469
470 if (rc == VINF_AIO_TASK_PENDING)
471 {
472 /* Wait */
473 LogFlowFunc(("Waiting for flush to complete\n"));
474 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
475 AssertRC(rc);
476 }
477 else
478 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
479
480 return pStorageBackend->rcReqLast;
481}
482
483static DECLCALLBACK(int) drvvdAsyncIOReadAsync(void *pvUser, void *pStorage, uint64_t uOffset,
484 PCRTSGSEG paSegments, size_t cSegments,
485 size_t cbRead, void *pvCompletion,
486 void **ppTask)
487{
488 PVBOXDISK pThis = (PVBOXDISK)pvUser;
489 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
490
491 int rc = PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbRead,
492 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
493 if (rc == VINF_AIO_TASK_PENDING)
494 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
495
496 return rc;
497}
498
499static DECLCALLBACK(int) drvvdAsyncIOWriteAsync(void *pvUser, void *pStorage, uint64_t uOffset,
500 PCRTSGSEG paSegments, size_t cSegments,
501 size_t cbWrite, void *pvCompletion,
502 void **ppTask)
503{
504 PVBOXDISK pThis = (PVBOXDISK)pvUser;
505 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
506
507 int rc = PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbWrite,
508 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
509 if (rc == VINF_AIO_TASK_PENDING)
510 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
511
512 return rc;
513}
514
515static DECLCALLBACK(int) drvvdAsyncIOFlushAsync(void *pvUser, void *pStorage,
516 void *pvCompletion, void **ppTask)
517{
518 PVBOXDISK pThis = (PVBOXDISK)pvUser;
519 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
520
521 int rc = PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, pvCompletion,
522 (PPPDMASYNCCOMPLETIONTASK)ppTask);
523 if (rc == VINF_AIO_TASK_PENDING)
524 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
525
526 return rc;
527}
528
529static DECLCALLBACK(int) drvvdAsyncIOGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
530{
531 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
532 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
533
534 return PDMR3AsyncCompletionEpGetSize(pStorageBackend->pEndpoint, pcbSize);
535}
536
537static DECLCALLBACK(int) drvvdAsyncIOSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
538{
539 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
540 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
541
542 int rc = drvvdAsyncIOFlushSync(pvUser, pStorage);
543 if (RT_SUCCESS(rc))
544 rc = PDMR3AsyncCompletionEpSetSize(pStorageBackend->pEndpoint, cbSize);
545
546 return rc;
547}
548
549#endif /* VBOX_WITH_PDM_ASYNC_COMPLETION */
550
551
552/*******************************************************************************
553* VD Thread Synchronization interface implementation *
554*******************************************************************************/
555
556static DECLCALLBACK(int) drvvdThreadStartRead(void *pvUser)
557{
558 PVBOXDISK pThis = (PVBOXDISK)pvUser;
559
560 return RTSemRWRequestRead(pThis->MergeLock, RT_INDEFINITE_WAIT);
561}
562
563static DECLCALLBACK(int) drvvdThreadFinishRead(void *pvUser)
564{
565 PVBOXDISK pThis = (PVBOXDISK)pvUser;
566
567 return RTSemRWReleaseRead(pThis->MergeLock);
568}
569
570static DECLCALLBACK(int) drvvdThreadStartWrite(void *pvUser)
571{
572 PVBOXDISK pThis = (PVBOXDISK)pvUser;
573
574 return RTSemRWRequestWrite(pThis->MergeLock, RT_INDEFINITE_WAIT);
575}
576
577static DECLCALLBACK(int) drvvdThreadFinishWrite(void *pvUser)
578{
579 PVBOXDISK pThis = (PVBOXDISK)pvUser;
580
581 return RTSemRWReleaseWrite(pThis->MergeLock);
582}
583
584
585/*******************************************************************************
586* VD Configuration interface implementation *
587*******************************************************************************/
588
589static bool drvvdCfgAreKeysValid(void *pvUser, const char *pszzValid)
590{
591 return CFGMR3AreValuesValid((PCFGMNODE)pvUser, pszzValid);
592}
593
594static int drvvdCfgQuerySize(void *pvUser, const char *pszName, size_t *pcb)
595{
596 return CFGMR3QuerySize((PCFGMNODE)pvUser, pszName, pcb);
597}
598
599static int drvvdCfgQuery(void *pvUser, const char *pszName, char *pszString, size_t cchString)
600{
601 return CFGMR3QueryString((PCFGMNODE)pvUser, pszName, pszString, cchString);
602}
603
604
605#ifdef VBOX_WITH_INIP
606/*******************************************************************************
607* VD TCP network stack interface implementation - INIP case *
608*******************************************************************************/
609
610typedef union INIPSOCKADDRUNION
611{
612 struct sockaddr Addr;
613 struct sockaddr_in Ipv4;
614} INIPSOCKADDRUNION;
615
616typedef struct INIPSOCKET
617{
618 int hSock;
619} INIPSOCKET, *PINIPSOCKET;
620
621static DECLCALLBACK(int) drvvdINIPFlush(VDSOCKET Sock);
622
623/** @copydoc VDINTERFACETCPNET::pfnSocketCreate */
624static DECLCALLBACK(int) drvvdINIPSocketCreate(uint32_t fFlags, PVDSOCKET pSock)
625{
626 PINIPSOCKET pSocketInt = NULL;
627
628 /*
629 * The extended select method is not supported because it is impossible to wakeup
630 * the thread.
631 */
632 if (fFlags & VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT)
633 return VERR_NOT_SUPPORTED;
634
635 pSocketInt = (PINIPSOCKET)RTMemAllocZ(sizeof(INIPSOCKET));
636 if (pSocketInt)
637 {
638 pSocketInt->hSock = INT32_MAX;
639 *pSock = (VDSOCKET)pSocketInt;
640 return VINF_SUCCESS;
641 }
642
643 return VERR_NO_MEMORY;
644}
645
646/** @copydoc VDINTERFACETCPNET::pfnSocketCreate */
647static DECLCALLBACK(int) drvvdINIPSocketDestroy(VDSOCKET Sock)
648{
649 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
650
651 RTMemFree(pSocketInt);
652 return VINF_SUCCESS;
653}
654
655/** @copydoc VDINTERFACETCPNET::pfnClientConnect */
656static DECLCALLBACK(int) drvvdINIPClientConnect(VDSOCKET Sock, const char *pszAddress, uint32_t uPort)
657{
658 int rc = VINF_SUCCESS;
659 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
660
661 /* Check whether lwIP is set up in this VM instance. */
662 if (!DevINIPConfigured())
663 {
664 LogRelFunc(("no IP stack\n"));
665 return VERR_NET_HOST_UNREACHABLE;
666 }
667 /* Resolve hostname. As there is no standard resolver for lwIP yet,
668 * just accept numeric IP addresses for now. */
669 struct in_addr ip;
670 if (!lwip_inet_aton(pszAddress, &ip))
671 {
672 LogRelFunc(("cannot resolve IP %s\n", pszAddress));
673 return VERR_NET_HOST_UNREACHABLE;
674 }
675 /* Create socket and connect. */
676 int iSock = lwip_socket(PF_INET, SOCK_STREAM, 0);
677 if (iSock != -1)
678 {
679 struct sockaddr_in InAddr = {0};
680 InAddr.sin_family = AF_INET;
681 InAddr.sin_port = htons(uPort);
682 InAddr.sin_addr = ip;
683 if (!lwip_connect(iSock, (struct sockaddr *)&InAddr, sizeof(InAddr)))
684 {
685 pSocketInt->hSock = iSock;
686 return VINF_SUCCESS;
687 }
688 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
689 lwip_close(iSock);
690 }
691 else
692 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
693 return rc;
694}
695
696/** @copydoc VDINTERFACETCPNET::pfnClientClose */
697static DECLCALLBACK(int) drvvdINIPClientClose(VDSOCKET Sock)
698{
699 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
700
701 lwip_close(pSocketInt->hSock);
702 pSocketInt->hSock = INT32_MAX;
703 return VINF_SUCCESS; /** @todo real solution needed */
704}
705
706/** @copydoc VDINTERFACETCPNET::pfnIsClientConnected */
707static DECLCALLBACK(bool) drvvdINIPIsClientConnected(VDSOCKET Sock)
708{
709 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
710
711 return pSocketInt->hSock != INT32_MAX;
712}
713
714/** @copydoc VDINTERFACETCPNET::pfnSelectOne */
715static DECLCALLBACK(int) drvvdINIPSelectOne(VDSOCKET Sock, RTMSINTERVAL cMillies)
716{
717 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
718 fd_set fdsetR;
719 FD_ZERO(&fdsetR);
720 FD_SET((uintptr_t)Sock, &fdsetR);
721 fd_set fdsetE = fdsetR;
722
723 int rc;
724 if (cMillies == RT_INDEFINITE_WAIT)
725 rc = lwip_select(pSocketInt->hSock + 1, &fdsetR, NULL, &fdsetE, NULL);
726 else
727 {
728 struct timeval timeout;
729 timeout.tv_sec = cMillies / 1000;
730 timeout.tv_usec = (cMillies % 1000) * 1000;
731 rc = lwip_select(pSocketInt->hSock + 1, &fdsetR, NULL, &fdsetE, &timeout);
732 }
733 if (rc > 0)
734 return VINF_SUCCESS;
735 if (rc == 0)
736 return VERR_TIMEOUT;
737 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
738}
739
740/** @copydoc VDINTERFACETCPNET::pfnRead */
741static DECLCALLBACK(int) drvvdINIPRead(VDSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
742{
743 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
744
745 /* Do params checking */
746 if (!pvBuffer || !cbBuffer)
747 {
748 AssertMsgFailed(("Invalid params\n"));
749 return VERR_INVALID_PARAMETER;
750 }
751
752 /*
753 * Read loop.
754 * If pcbRead is NULL we have to fill the entire buffer!
755 */
756 size_t cbRead = 0;
757 size_t cbToRead = cbBuffer;
758 for (;;)
759 {
760 /** @todo this clipping here is just in case (the send function
761 * needed it, so I added it here, too). Didn't investigate if this
762 * really has issues. Better be safe than sorry. */
763 ssize_t cbBytesRead = lwip_recv(pSocketInt->hSock, (char *)pvBuffer + cbRead,
764 RT_MIN(cbToRead, 32768), 0);
765 if (cbBytesRead < 0)
766 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
767 if (cbBytesRead == 0 && errno) /** @todo r=bird: lwip_recv will not touch errno on Windows. This may apply to other hosts as well */
768 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
769 if (pcbRead)
770 {
771 /* return partial data */
772 *pcbRead = cbBytesRead;
773 break;
774 }
775
776 /* read more? */
777 cbRead += cbBytesRead;
778 if (cbRead == cbBuffer)
779 break;
780
781 /* next */
782 cbToRead = cbBuffer - cbRead;
783 }
784
785 return VINF_SUCCESS;
786}
787
788/** @copydoc VDINTERFACETCPNET::pfnWrite */
789static DECLCALLBACK(int) drvvdINIPWrite(VDSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
790{
791 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
792
793 do
794 {
795 /** @todo lwip send only supports up to 65535 bytes in a single
796 * send (stupid limitation buried in the code), so make sure we
797 * don't get any wraparounds. This should be moved to DevINIP
798 * stack interface once that's implemented. */
799 ssize_t cbWritten = lwip_send(pSocketInt->hSock, (void *)pvBuffer,
800 RT_MIN(cbBuffer, 32768), 0);
801 if (cbWritten < 0)
802 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
803 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%d cbBuffer=%d\n",
804 cbWritten, cbBuffer));
805 cbBuffer -= cbWritten;
806 pvBuffer = (const char *)pvBuffer + cbWritten;
807 } while (cbBuffer);
808
809 return VINF_SUCCESS;
810}
811
812/** @copydoc VDINTERFACETCPNET::pfnSgWrite */
813static DECLCALLBACK(int) drvvdINIPSgWrite(VDSOCKET Sock, PCRTSGBUF pSgBuf)
814{
815 int rc = VINF_SUCCESS;
816
817 /* This is an extremely crude emulation, however it's good enough
818 * for our iSCSI code. INIP has no sendmsg(). */
819 for (unsigned i = 0; i < pSgBuf->cSegs; i++)
820 {
821 rc = drvvdINIPWrite(Sock, pSgBuf->paSegs[i].pvSeg,
822 pSgBuf->paSegs[i].cbSeg);
823 if (RT_FAILURE(rc))
824 break;
825 }
826 if (RT_SUCCESS(rc))
827 drvvdINIPFlush(Sock);
828
829 return rc;
830}
831
832/** @copydoc VDINTERFACETCPNET::pfnFlush */
833static DECLCALLBACK(int) drvvdINIPFlush(VDSOCKET Sock)
834{
835 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
836
837 int fFlag = 1;
838 lwip_setsockopt(pSocketInt->hSock, IPPROTO_TCP, TCP_NODELAY,
839 (const char *)&fFlag, sizeof(fFlag));
840 fFlag = 0;
841 lwip_setsockopt(pSocketInt->hSock, IPPROTO_TCP, TCP_NODELAY,
842 (const char *)&fFlag, sizeof(fFlag));
843 return VINF_SUCCESS;
844}
845
846/** @copydoc VDINTERFACETCPNET::pfnSetSendCoalescing */
847static DECLCALLBACK(int) drvvdINIPSetSendCoalescing(VDSOCKET Sock, bool fEnable)
848{
849 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
850
851 int fFlag = fEnable ? 0 : 1;
852 lwip_setsockopt(pSocketInt->hSock, IPPROTO_TCP, TCP_NODELAY,
853 (const char *)&fFlag, sizeof(fFlag));
854 return VINF_SUCCESS;
855}
856
857/** @copydoc VDINTERFACETCPNET::pfnGetLocalAddress */
858static DECLCALLBACK(int) drvvdINIPGetLocalAddress(VDSOCKET Sock, PRTNETADDR pAddr)
859{
860 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
861 INIPSOCKADDRUNION u;
862 socklen_t cbAddr = sizeof(u);
863 RT_ZERO(u);
864 if (!lwip_getsockname(pSocketInt->hSock, &u.Addr, &cbAddr))
865 {
866 /*
867 * Convert the address.
868 */
869 if ( cbAddr == sizeof(struct sockaddr_in)
870 && u.Addr.sa_family == AF_INET)
871 {
872 RT_ZERO(*pAddr);
873 pAddr->enmType = RTNETADDRTYPE_IPV4;
874 pAddr->uPort = RT_N2H_U16(u.Ipv4.sin_port);
875 pAddr->uAddr.IPv4.u = u.Ipv4.sin_addr.s_addr;
876 }
877 else
878 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
879 return VINF_SUCCESS;
880 }
881 return VERR_NET_OPERATION_NOT_SUPPORTED;
882}
883
884/** @copydoc VDINTERFACETCPNET::pfnGetPeerAddress */
885static DECLCALLBACK(int) drvvdINIPGetPeerAddress(VDSOCKET Sock, PRTNETADDR pAddr)
886{
887 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
888 INIPSOCKADDRUNION u;
889 socklen_t cbAddr = sizeof(u);
890 RT_ZERO(u);
891 if (!lwip_getpeername(pSocketInt->hSock, &u.Addr, &cbAddr))
892 {
893 /*
894 * Convert the address.
895 */
896 if ( cbAddr == sizeof(struct sockaddr_in)
897 && u.Addr.sa_family == AF_INET)
898 {
899 RT_ZERO(*pAddr);
900 pAddr->enmType = RTNETADDRTYPE_IPV4;
901 pAddr->uPort = RT_N2H_U16(u.Ipv4.sin_port);
902 pAddr->uAddr.IPv4.u = u.Ipv4.sin_addr.s_addr;
903 }
904 else
905 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
906 return VINF_SUCCESS;
907 }
908 return VERR_NET_OPERATION_NOT_SUPPORTED;
909}
910
911/** @copydoc VDINTERFACETCPNET::pfnSelectOneEx */
912static DECLCALLBACK(int) drvvdINIPSelectOneEx(VDSOCKET Sock, uint32_t *pfEvents, RTMSINTERVAL cMillies)
913{
914 AssertMsgFailed(("Not supported!\n"));
915 return VERR_NOT_SUPPORTED;
916}
917
918/** @copydoc VDINTERFACETCPNET::pfnPoke */
919static DECLCALLBACK(int) drvvdINIPPoke(VDSOCKET Sock)
920{
921 AssertMsgFailed(("Not supported!\n"));
922 return VERR_NOT_SUPPORTED;
923}
924
925#endif /* VBOX_WITH_INIP */
926
927
928/*******************************************************************************
929* VD TCP network stack interface implementation - Host TCP case *
930*******************************************************************************/
931
932/**
933 * Socket data.
934 */
935typedef struct VDSOCKETINT
936{
937 /** IPRT socket handle. */
938 RTSOCKET hSocket;
939 /** Pollset with the wakeup pipe and socket. */
940 RTPOLLSET hPollSet;
941 /** Pipe endpoint - read (in the pollset). */
942 RTPIPE hPipeR;
943 /** Pipe endpoint - write. */
944 RTPIPE hPipeW;
945 /** Flag whether the thread was woken up. */
946 volatile bool fWokenUp;
947 /** Flag whether the thread is waiting in the select call. */
948 volatile bool fWaiting;
949} VDSOCKETINT, *PVDSOCKETINT;
950
951/** Pollset id of the socket. */
952#define VDSOCKET_POLL_ID_SOCKET 0
953/** Pollset id of the pipe. */
954#define VDSOCKET_POLL_ID_PIPE 1
955
956/** @copydoc VDINTERFACETCPNET::pfnSocketCreate */
957static DECLCALLBACK(int) drvvdTcpSocketCreate(uint32_t fFlags, PVDSOCKET pSock)
958{
959 int rc = VINF_SUCCESS;
960 int rc2 = VINF_SUCCESS;
961 PVDSOCKETINT pSockInt = NULL;
962
963 pSockInt = (PVDSOCKETINT)RTMemAllocZ(sizeof(VDSOCKETINT));
964 if (!pSockInt)
965 return VERR_NO_MEMORY;
966
967 pSockInt->hSocket = NIL_RTSOCKET;
968 pSockInt->hPollSet = NIL_RTPOLLSET;
969 pSockInt->hPipeR = NIL_RTPIPE;
970 pSockInt->hPipeW = NIL_RTPIPE;
971 pSockInt->fWokenUp = false;
972 pSockInt->fWaiting = false;
973
974 if (fFlags & VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT)
975 {
976 /* Init pipe and pollset. */
977 rc = RTPipeCreate(&pSockInt->hPipeR, &pSockInt->hPipeW, 0);
978 if (RT_SUCCESS(rc))
979 {
980 rc = RTPollSetCreate(&pSockInt->hPollSet);
981 if (RT_SUCCESS(rc))
982 {
983 rc = RTPollSetAddPipe(pSockInt->hPollSet, pSockInt->hPipeR,
984 RTPOLL_EVT_READ, VDSOCKET_POLL_ID_PIPE);
985 if (RT_SUCCESS(rc))
986 {
987 *pSock = pSockInt;
988 return VINF_SUCCESS;
989 }
990
991 RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_PIPE);
992 rc2 = RTPollSetDestroy(pSockInt->hPollSet);
993 AssertRC(rc2);
994 }
995
996 rc2 = RTPipeClose(pSockInt->hPipeR);
997 AssertRC(rc2);
998 rc2 = RTPipeClose(pSockInt->hPipeW);
999 AssertRC(rc2);
1000 }
1001 }
1002
1003 RTMemFree(pSockInt);
1004
1005 return rc;
1006}
1007
1008/** @copydoc VDINTERFACETCPNET::pfnSocketDestroy */
1009static DECLCALLBACK(int) drvvdTcpSocketDestroy(VDSOCKET Sock)
1010{
1011 int rc = VINF_SUCCESS;
1012 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1013
1014 /* Destroy the pipe and pollset if necessary. */
1015 if (pSockInt->hPollSet != NIL_RTPOLLSET)
1016 {
1017 if (pSockInt->hSocket != NIL_RTSOCKET)
1018 {
1019 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
1020 AssertRC(rc);
1021 }
1022 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_PIPE);
1023 AssertRC(rc);
1024 rc = RTPollSetDestroy(pSockInt->hPollSet);
1025 AssertRC(rc);
1026 rc = RTPipeClose(pSockInt->hPipeR);
1027 AssertRC(rc);
1028 rc = RTPipeClose(pSockInt->hPipeW);
1029 AssertRC(rc);
1030 }
1031
1032 if (pSockInt->hSocket != NIL_RTSOCKET)
1033 rc = RTTcpClientClose(pSockInt->hSocket);
1034
1035 RTMemFree(pSockInt);
1036
1037 return rc;
1038}
1039
1040/** @copydoc VDINTERFACETCPNET::pfnClientConnect */
1041static DECLCALLBACK(int) drvvdTcpClientConnect(VDSOCKET Sock, const char *pszAddress, uint32_t uPort)
1042{
1043 int rc = VINF_SUCCESS;
1044 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1045
1046 rc = RTTcpClientConnect(pszAddress, uPort, &pSockInt->hSocket);
1047 if (RT_SUCCESS(rc))
1048 {
1049 /* Add to the pollset if required. */
1050 if (pSockInt->hPollSet != NIL_RTPOLLSET)
1051 {
1052 rc = RTPollSetAddSocket(pSockInt->hPollSet, pSockInt->hSocket,
1053 RTPOLL_EVT_READ | /*RTPOLL_EVT_WRITE |*/ RTPOLL_EVT_ERROR,
1054 VDSOCKET_POLL_ID_SOCKET);
1055
1056 if (RT_SUCCESS(rc))
1057 return VINF_SUCCESS;
1058 }
1059
1060 rc = RTTcpClientClose(pSockInt->hSocket);
1061 }
1062
1063 return rc;
1064}
1065
1066/** @copydoc VDINTERFACETCPNET::pfnClientClose */
1067static DECLCALLBACK(int) drvvdTcpClientClose(VDSOCKET Sock)
1068{
1069 int rc = VINF_SUCCESS;
1070 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1071
1072 if (pSockInt->hPollSet != NIL_RTPOLLSET)
1073 {
1074 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
1075 AssertRC(rc);
1076 }
1077
1078 rc = RTTcpClientClose(pSockInt->hSocket);
1079 pSockInt->hSocket = NIL_RTSOCKET;
1080
1081 return rc;
1082}
1083
1084/** @copydoc VDINTERFACETCPNET::pfnIsClientConnected */
1085static DECLCALLBACK(bool) drvvdTcpIsClientConnected(VDSOCKET Sock)
1086{
1087 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1088
1089 return pSockInt->hSocket != NIL_RTSOCKET;
1090}
1091
1092/** @copydoc VDINTERFACETCPNET::pfnSelectOne */
1093static DECLCALLBACK(int) drvvdTcpSelectOne(VDSOCKET Sock, RTMSINTERVAL cMillies)
1094{
1095 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1096
1097 return RTTcpSelectOne(pSockInt->hSocket, cMillies);
1098}
1099
1100/** @copydoc VDINTERFACETCPNET::pfnRead */
1101static DECLCALLBACK(int) drvvdTcpRead(VDSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
1102{
1103 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1104
1105 return RTTcpRead(pSockInt->hSocket, pvBuffer, cbBuffer, pcbRead);
1106}
1107
1108/** @copydoc VDINTERFACETCPNET::pfnWrite */
1109static DECLCALLBACK(int) drvvdTcpWrite(VDSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
1110{
1111 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1112
1113 return RTTcpWrite(pSockInt->hSocket, pvBuffer, cbBuffer);
1114}
1115
1116/** @copydoc VDINTERFACETCPNET::pfnSgWrite */
1117static DECLCALLBACK(int) drvvdTcpSgWrite(VDSOCKET Sock, PCRTSGBUF pSgBuf)
1118{
1119 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1120
1121 return RTTcpSgWrite(pSockInt->hSocket, pSgBuf);
1122}
1123
1124/** @copydoc VDINTERFACETCPNET::pfnFlush */
1125static DECLCALLBACK(int) drvvdTcpFlush(VDSOCKET Sock)
1126{
1127 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1128
1129 return RTTcpFlush(pSockInt->hSocket);
1130}
1131
1132/** @copydoc VDINTERFACETCPNET::pfnSetSendCoalescing */
1133static DECLCALLBACK(int) drvvdTcpSetSendCoalescing(VDSOCKET Sock, bool fEnable)
1134{
1135 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1136
1137 return RTTcpSetSendCoalescing(pSockInt->hSocket, fEnable);
1138}
1139
1140/** @copydoc VDINTERFACETCPNET::pfnGetLocalAddress */
1141static DECLCALLBACK(int) drvvdTcpGetLocalAddress(VDSOCKET Sock, PRTNETADDR pAddr)
1142{
1143 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1144
1145 return RTTcpGetLocalAddress(pSockInt->hSocket, pAddr);
1146}
1147
1148/** @copydoc VDINTERFACETCPNET::pfnGetPeerAddress */
1149static DECLCALLBACK(int) drvvdTcpGetPeerAddress(VDSOCKET Sock, PRTNETADDR pAddr)
1150{
1151 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1152
1153 return RTTcpGetPeerAddress(pSockInt->hSocket, pAddr);
1154}
1155
1156/** @copydoc VDINTERFACETCPNET::pfnSelectOneEx */
1157static DECLCALLBACK(int) drvvdTcpSelectOneEx(VDSOCKET Sock, uint32_t *pfEvents, RTMSINTERVAL cMillies)
1158{
1159 int rc = VINF_SUCCESS;
1160 uint32_t id = 0;
1161 uint32_t fEvents = 0;
1162 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1163
1164 *pfEvents = 0;
1165
1166 ASMAtomicXchgBool(&pSockInt->fWaiting, true);
1167 if (ASMAtomicXchgBool(&pSockInt->fWokenUp, false))
1168 {
1169 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
1170 return VERR_INTERRUPTED;
1171 }
1172
1173 rc = RTPoll(pSockInt->hPollSet, cMillies, &fEvents, &id);
1174 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1175
1176 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
1177
1178 if (RT_SUCCESS(rc))
1179 {
1180 if (id == VDSOCKET_POLL_ID_SOCKET)
1181 {
1182 fEvents &= RTPOLL_EVT_VALID_MASK;
1183
1184 if (fEvents & RTPOLL_EVT_READ)
1185 *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
1186 if (fEvents & RTPOLL_EVT_WRITE)
1187 *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
1188 if (fEvents & RTPOLL_EVT_ERROR)
1189 *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
1190 }
1191 else
1192 {
1193 size_t cbRead = 0;
1194 uint8_t abBuf[10];
1195 Assert(id == VDSOCKET_POLL_ID_PIPE);
1196 Assert((fEvents & RTPOLL_EVT_VALID_MASK) == RTPOLL_EVT_READ);
1197
1198 /* We got interrupted, drain the pipe. */
1199 rc = RTPipeRead(pSockInt->hPipeR, abBuf, sizeof(abBuf), &cbRead);
1200 AssertRC(rc);
1201
1202 ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
1203
1204 rc = VERR_INTERRUPTED;
1205 }
1206 }
1207
1208 return rc;
1209}
1210
1211/** @copydoc VDINTERFACETCPNET::pfnPoke */
1212static DECLCALLBACK(int) drvvdTcpPoke(VDSOCKET Sock)
1213{
1214 int rc = VINF_SUCCESS;
1215 size_t cbWritten = 0;
1216 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1217
1218 ASMAtomicXchgBool(&pSockInt->fWokenUp, true);
1219
1220 if (ASMAtomicReadBool(&pSockInt->fWaiting))
1221 {
1222 rc = RTPipeWrite(pSockInt->hPipeW, "", 1, &cbWritten);
1223 Assert(RT_SUCCESS(rc) || cbWritten == 0);
1224 }
1225
1226 return VINF_SUCCESS;
1227}
1228
1229
1230/*******************************************************************************
1231* Media interface methods *
1232*******************************************************************************/
1233
1234/** @copydoc PDMIMEDIA::pfnRead */
1235static DECLCALLBACK(int) drvvdRead(PPDMIMEDIA pInterface,
1236 uint64_t off, void *pvBuf, size_t cbRead)
1237{
1238 LogFlow(("%s: off=%#llx pvBuf=%p cbRead=%d\n", __FUNCTION__,
1239 off, pvBuf, cbRead));
1240 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1241 int rc = VDRead(pThis->pDisk, off, pvBuf, cbRead);
1242 if (RT_SUCCESS(rc))
1243 Log2(("%s: off=%#llx pvBuf=%p cbRead=%d %.*Rhxd\n", __FUNCTION__,
1244 off, pvBuf, cbRead, cbRead, pvBuf));
1245 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1246 return rc;
1247}
1248
1249/** @copydoc PDMIMEDIA::pfnWrite */
1250static DECLCALLBACK(int) drvvdWrite(PPDMIMEDIA pInterface,
1251 uint64_t off, const void *pvBuf,
1252 size_t cbWrite)
1253{
1254 LogFlow(("%s: off=%#llx pvBuf=%p cbWrite=%d\n", __FUNCTION__,
1255 off, pvBuf, cbWrite));
1256 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1257 Log2(("%s: off=%#llx pvBuf=%p cbWrite=%d %.*Rhxd\n", __FUNCTION__,
1258 off, pvBuf, cbWrite, cbWrite, pvBuf));
1259 int rc = VDWrite(pThis->pDisk, off, pvBuf, cbWrite);
1260 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1261 return rc;
1262}
1263
1264/** @copydoc PDMIMEDIA::pfnFlush */
1265static DECLCALLBACK(int) drvvdFlush(PPDMIMEDIA pInterface)
1266{
1267 LogFlow(("%s:\n", __FUNCTION__));
1268 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1269 int rc = VDFlush(pThis->pDisk);
1270 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1271 return rc;
1272}
1273
1274/** @copydoc PDMIMEDIA::pfnMerge */
1275static DECLCALLBACK(int) drvvdMerge(PPDMIMEDIA pInterface,
1276 PFNSIMPLEPROGRESS pfnProgress,
1277 void *pvUser)
1278{
1279 LogFlow(("%s:\n", __FUNCTION__));
1280 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1281 int rc = VINF_SUCCESS;
1282
1283 /* Note: There is an unavoidable race between destruction and another
1284 * thread invoking this function. This is handled safely and gracefully by
1285 * atomically invalidating the lock handle in drvvdDestruct. */
1286 int rc2 = RTSemFastMutexRequest(pThis->MergeCompleteMutex);
1287 AssertRC(rc2);
1288 if (RT_SUCCESS(rc2) && pThis->fMergePending)
1289 {
1290 /* Take shortcut: PFNSIMPLEPROGRESS is exactly the same type as
1291 * PFNVDPROGRESS, so there's no need for a conversion function. */
1292 /** @todo maybe introduce a conversion which limits update frequency. */
1293 PVDINTERFACE pVDIfsOperation = NULL;
1294 VDINTERFACE VDIProgress;
1295 VDINTERFACEPROGRESS VDIProgressCallbacks;
1296 VDIProgressCallbacks.cbSize = sizeof(VDINTERFACEPROGRESS);
1297 VDIProgressCallbacks.enmInterface = VDINTERFACETYPE_PROGRESS;
1298 VDIProgressCallbacks.pfnProgress = pfnProgress;
1299 rc2 = VDInterfaceAdd(&VDIProgress, "DrvVD_VDIProgress", VDINTERFACETYPE_PROGRESS,
1300 &VDIProgressCallbacks, pvUser, &pVDIfsOperation);
1301 AssertRC(rc2);
1302 pThis->fMergePending = false;
1303 rc = VDMerge(pThis->pDisk, pThis->uMergeSource,
1304 pThis->uMergeTarget, pVDIfsOperation);
1305 }
1306 rc2 = RTSemFastMutexRelease(pThis->MergeCompleteMutex);
1307 AssertRC(rc2);
1308 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1309 return rc;
1310}
1311
1312/** @copydoc PDMIMEDIA::pfnGetSize */
1313static DECLCALLBACK(uint64_t) drvvdGetSize(PPDMIMEDIA pInterface)
1314{
1315 LogFlow(("%s:\n", __FUNCTION__));
1316 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1317 uint64_t cb = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
1318 LogFlow(("%s: returns %#llx (%llu)\n", __FUNCTION__, cb, cb));
1319 return cb;
1320}
1321
1322/** @copydoc PDMIMEDIA::pfnIsReadOnly */
1323static DECLCALLBACK(bool) drvvdIsReadOnly(PPDMIMEDIA pInterface)
1324{
1325 LogFlow(("%s:\n", __FUNCTION__));
1326 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1327 bool f = VDIsReadOnly(pThis->pDisk);
1328 LogFlow(("%s: returns %d\n", __FUNCTION__, f));
1329 return f;
1330}
1331
1332/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
1333static DECLCALLBACK(int) drvvdBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
1334 PPDMMEDIAGEOMETRY pPCHSGeometry)
1335{
1336 LogFlow(("%s:\n", __FUNCTION__));
1337 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1338 int rc = VDGetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
1339 if (RT_FAILURE(rc))
1340 {
1341 Log(("%s: geometry not available.\n", __FUNCTION__));
1342 rc = VERR_PDM_GEOMETRY_NOT_SET;
1343 }
1344 LogFlow(("%s: returns %Rrc (CHS=%d/%d/%d)\n", __FUNCTION__,
1345 rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
1346 return rc;
1347}
1348
1349/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
1350static DECLCALLBACK(int) drvvdBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
1351 PCPDMMEDIAGEOMETRY pPCHSGeometry)
1352{
1353 LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
1354 pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
1355 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1356 int rc = VDSetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
1357 if (rc == VERR_VD_GEOMETRY_NOT_SET)
1358 rc = VERR_PDM_GEOMETRY_NOT_SET;
1359 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1360 return rc;
1361}
1362
1363/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
1364static DECLCALLBACK(int) drvvdBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
1365 PPDMMEDIAGEOMETRY pLCHSGeometry)
1366{
1367 LogFlow(("%s:\n", __FUNCTION__));
1368 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1369 int rc = VDGetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
1370 if (RT_FAILURE(rc))
1371 {
1372 Log(("%s: geometry not available.\n", __FUNCTION__));
1373 rc = VERR_PDM_GEOMETRY_NOT_SET;
1374 }
1375 LogFlow(("%s: returns %Rrc (CHS=%d/%d/%d)\n", __FUNCTION__,
1376 rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
1377 return rc;
1378}
1379
1380/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
1381static DECLCALLBACK(int) drvvdBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
1382 PCPDMMEDIAGEOMETRY pLCHSGeometry)
1383{
1384 LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
1385 pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
1386 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1387 int rc = VDSetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
1388 if (rc == VERR_VD_GEOMETRY_NOT_SET)
1389 rc = VERR_PDM_GEOMETRY_NOT_SET;
1390 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1391 return rc;
1392}
1393
1394/** @copydoc PDMIMEDIA::pfnGetUuid */
1395static DECLCALLBACK(int) drvvdGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
1396{
1397 LogFlow(("%s:\n", __FUNCTION__));
1398 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1399 int rc = VDGetUuid(pThis->pDisk, 0, pUuid);
1400 LogFlow(("%s: returns %Rrc ({%RTuuid})\n", __FUNCTION__, rc, pUuid));
1401 return rc;
1402}
1403
1404/*******************************************************************************
1405* Async Media interface methods *
1406*******************************************************************************/
1407
1408static void drvvdAsyncReqComplete(void *pvUser1, void *pvUser2, int rcReq)
1409{
1410 PVBOXDISK pThis = (PVBOXDISK)pvUser1;
1411
1412 int rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort,
1413 pvUser2, rcReq);
1414 AssertRC(rc);
1415}
1416
1417static DECLCALLBACK(int) drvvdStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
1418 PCRTSGSEG paSeg, unsigned cSeg,
1419 size_t cbRead, void *pvUser)
1420{
1421 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d\n pvUser=%#p", __FUNCTION__,
1422 uOffset, paSeg, cSeg, cbRead, pvUser));
1423 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
1424 int rc = VDAsyncRead(pThis->pDisk, uOffset, cbRead, paSeg, cSeg,
1425 drvvdAsyncReqComplete, pThis, pvUser);
1426 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1427 return rc;
1428}
1429
1430static DECLCALLBACK(int) drvvdStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
1431 PCRTSGSEG paSeg, unsigned cSeg,
1432 size_t cbWrite, void *pvUser)
1433{
1434 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d pvUser=%#p\n", __FUNCTION__,
1435 uOffset, paSeg, cSeg, cbWrite, pvUser));
1436 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
1437 int rc = VDAsyncWrite(pThis->pDisk, uOffset, cbWrite, paSeg, cSeg,
1438 drvvdAsyncReqComplete, pThis, pvUser);
1439 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1440 return rc;
1441}
1442
1443static DECLCALLBACK(int) drvvdStartFlush(PPDMIMEDIAASYNC pInterface, void *pvUser)
1444{
1445 LogFlow(("%s: pvUser=%#p\n", __FUNCTION__, pvUser));
1446 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
1447 int rc = VDAsyncFlush(pThis->pDisk, drvvdAsyncReqComplete, pThis, pvUser);
1448 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1449 return rc;
1450}
1451
1452
1453/*******************************************************************************
1454* Base interface methods *
1455*******************************************************************************/
1456
1457/**
1458 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1459 */
1460static DECLCALLBACK(void *) drvvdQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1461{
1462 PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
1463 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1464
1465 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1466 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
1467 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->fAsyncIOSupported ? &pThis->IMediaAsync : NULL);
1468 return NULL;
1469}
1470
1471
1472/*******************************************************************************
1473* Saved state notification methods *
1474*******************************************************************************/
1475
1476/**
1477 * Load done callback for re-opening the image writable during teleportation.
1478 *
1479 * This is called both for successful and failed load runs, we only care about
1480 * successfull ones.
1481 *
1482 * @returns VBox status code.
1483 * @param pDrvIns The driver instance.
1484 * @param pSSM The saved state handle.
1485 */
1486static DECLCALLBACK(int) drvvdLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
1487{
1488 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1489 Assert(!pThis->fErrorUseRuntime);
1490
1491 /* Drop out if we don't have any work to do or if it's a failed load. */
1492 if ( !pThis->fTempReadOnly
1493 || RT_FAILURE(SSMR3HandleGetStatus(pSSM)))
1494 return VINF_SUCCESS;
1495
1496 int rc = drvvdSetWritable(pThis);
1497 if (RT_FAILURE(rc)) /** @todo does the bugger set any errors? */
1498 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
1499 N_("Failed to write lock the images"));
1500 return VINF_SUCCESS;
1501}
1502
1503
1504/*******************************************************************************
1505* Driver methods *
1506*******************************************************************************/
1507
1508static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
1509{
1510 LogFlow(("%s:\n", __FUNCTION__));
1511 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1512
1513 /*
1514 * We must close the disk here to ensure that
1515 * the backend closes all files before the
1516 * async transport driver is destructed.
1517 */
1518 int rc = VDCloseAll(pThis->pDisk);
1519 AssertRC(rc);
1520}
1521
1522/**
1523 * VM resume notification that we use to undo what the temporary read-only image
1524 * mode set by drvvdSuspend.
1525 *
1526 * Also switch to runtime error mode if we're resuming after a state load
1527 * without having been powered on first.
1528 *
1529 * @param pDrvIns The driver instance data.
1530 *
1531 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
1532 * we're making assumptions about Main behavior here!
1533 */
1534static DECLCALLBACK(void) drvvdResume(PPDMDRVINS pDrvIns)
1535{
1536 LogFlow(("%s:\n", __FUNCTION__));
1537 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1538 drvvdSetWritable(pThis);
1539 pThis->fErrorUseRuntime = true;
1540}
1541
1542/**
1543 * The VM is being suspended, temporarily change to read-only image mode.
1544 *
1545 * This is important for several reasons:
1546 * -# It makes sure that there are no pending writes to the image. Most
1547 * backends implements this by closing and reopening the image in read-only
1548 * mode.
1549 * -# It allows Main to read the images during snapshotting without having
1550 * to account for concurrent writes.
1551 * -# This is essential for making teleportation targets sharing images work
1552 * right. Both with regards to caching and with regards to file sharing
1553 * locks (RTFILE_O_DENY_*). (See also drvvdLoadDone.)
1554 *
1555 * @param pDrvIns The driver instance data.
1556 */
1557static DECLCALLBACK(void) drvvdSuspend(PPDMDRVINS pDrvIns)
1558{
1559 LogFlow(("%s:\n", __FUNCTION__));
1560 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1561 drvvdSetReadonly(pThis);
1562}
1563
1564/**
1565 * VM PowerOn notification for undoing the TempReadOnly config option and
1566 * changing to runtime error mode.
1567 *
1568 * @param pDrvIns The driver instance data.
1569 *
1570 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
1571 * we're making assumptions about Main behavior here!
1572 */
1573static DECLCALLBACK(void) drvvdPowerOn(PPDMDRVINS pDrvIns)
1574{
1575 LogFlow(("%s:\n", __FUNCTION__));
1576 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1577 drvvdSetWritable(pThis);
1578 pThis->fErrorUseRuntime = true;
1579}
1580
1581/**
1582 * @copydoc FNPDMDRVDESTRUCT
1583 */
1584static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
1585{
1586 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1587 LogFlow(("%s:\n", __FUNCTION__));
1588 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1589
1590 RTSEMFASTMUTEX mutex;
1591 ASMAtomicXchgHandle(&pThis->MergeCompleteMutex, NIL_RTSEMFASTMUTEX, &mutex);
1592 if (mutex != NIL_RTSEMFASTMUTEX)
1593 {
1594 /* Request the semaphore to wait until a potentially running merge
1595 * operation has been finished. */
1596 int rc = RTSemFastMutexRequest(mutex);
1597 AssertRC(rc);
1598 pThis->fMergePending = false;
1599 rc = RTSemFastMutexRelease(mutex);
1600 AssertRC(rc);
1601 rc = RTSemFastMutexDestroy(mutex);
1602 AssertRC(rc);
1603 }
1604
1605 if (VALID_PTR(pThis->pDisk))
1606 {
1607 VDDestroy(pThis->pDisk);
1608 pThis->pDisk = NULL;
1609 }
1610 drvvdFreeImages(pThis);
1611
1612 if (pThis->MergeLock != NIL_RTSEMRW)
1613 {
1614 int rc = RTSemRWDestroy(pThis->MergeLock);
1615 AssertRC(rc);
1616 pThis->MergeLock = NIL_RTSEMRW;
1617 }
1618}
1619
1620/**
1621 * Construct a VBox disk media driver instance.
1622 *
1623 * @copydoc FNPDMDRVCONSTRUCT
1624 */
1625static DECLCALLBACK(int) drvvdConstruct(PPDMDRVINS pDrvIns,
1626 PCFGMNODE pCfg,
1627 uint32_t fFlags)
1628{
1629 LogFlow(("%s:\n", __FUNCTION__));
1630 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1631 int rc = VINF_SUCCESS;
1632 char *pszName = NULL; /**< The path of the disk image file. */
1633 char *pszFormat = NULL; /**< The format backed to use for this image. */
1634 bool fReadOnly; /**< True if the media is read-only. */
1635 bool fMaybeReadOnly; /**< True if the media may or may not be read-only. */
1636 bool fHonorZeroWrites; /**< True if zero blocks should be written. */
1637 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1638
1639 /*
1640 * Init the static parts.
1641 */
1642 pDrvIns->IBase.pfnQueryInterface = drvvdQueryInterface;
1643 pThis->pDrvIns = pDrvIns;
1644 pThis->fTempReadOnly = false;
1645 pThis->pDisk = NULL;
1646 pThis->fAsyncIOSupported = false;
1647 pThis->fShareable = false;
1648 pThis->fMergePending = false;
1649 pThis->MergeCompleteMutex = NIL_RTSEMFASTMUTEX;
1650 pThis->uMergeSource = VD_LAST_IMAGE;
1651 pThis->uMergeTarget = VD_LAST_IMAGE;
1652
1653 /* IMedia */
1654 pThis->IMedia.pfnRead = drvvdRead;
1655 pThis->IMedia.pfnWrite = drvvdWrite;
1656 pThis->IMedia.pfnFlush = drvvdFlush;
1657 pThis->IMedia.pfnMerge = drvvdMerge;
1658 pThis->IMedia.pfnGetSize = drvvdGetSize;
1659 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly;
1660 pThis->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
1661 pThis->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
1662 pThis->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
1663 pThis->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
1664 pThis->IMedia.pfnGetUuid = drvvdGetUuid;
1665
1666 /* IMediaAsync */
1667 pThis->IMediaAsync.pfnStartRead = drvvdStartRead;
1668 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite;
1669 pThis->IMediaAsync.pfnStartFlush = drvvdStartFlush;
1670
1671 /* Initialize supported VD interfaces. */
1672 pThis->pVDIfsDisk = NULL;
1673
1674 pThis->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1675 pThis->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1676 pThis->VDIErrorCallbacks.pfnError = drvvdErrorCallback;
1677 pThis->VDIErrorCallbacks.pfnMessage = NULL;
1678
1679 rc = VDInterfaceAdd(&pThis->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
1680 &pThis->VDIErrorCallbacks, pDrvIns, &pThis->pVDIfsDisk);
1681 AssertRC(rc);
1682
1683 /* This is just prepared here, the actual interface is per-image, so it's
1684 * added later. No need to have separate callback tables. */
1685 pThis->VDIConfigCallbacks.cbSize = sizeof(VDINTERFACECONFIG);
1686 pThis->VDIConfigCallbacks.enmInterface = VDINTERFACETYPE_CONFIG;
1687 pThis->VDIConfigCallbacks.pfnAreKeysValid = drvvdCfgAreKeysValid;
1688 pThis->VDIConfigCallbacks.pfnQuerySize = drvvdCfgQuerySize;
1689 pThis->VDIConfigCallbacks.pfnQuery = drvvdCfgQuery;
1690
1691 /* List of images is empty now. */
1692 pThis->pImages = NULL;
1693
1694 /* Try to attach async media port interface above.*/
1695 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1696
1697 /*
1698 * Validate configuration and find all parent images.
1699 * It's sort of up side down from the image dependency tree.
1700 */
1701 bool fHostIP = false;
1702 bool fUseNewIo = false;
1703 unsigned iLevel = 0;
1704 PCFGMNODE pCurNode = pCfg;
1705
1706 for (;;)
1707 {
1708 bool fValid;
1709
1710 if (pCurNode == pCfg)
1711 {
1712 /* Toplevel configuration additionally contains the global image
1713 * open flags. Some might be converted to per-image flags later. */
1714 fValid = CFGMR3AreValuesValid(pCurNode,
1715 "Format\0Path\0"
1716 "ReadOnly\0MaybeReadOnly\0TempReadOnly\0Shareable\0HonorZeroWrites\0"
1717 "HostIPStack\0UseNewIo\0"
1718 "SetupMerge\0MergeSource\0MergeTarget\0");
1719 }
1720 else
1721 {
1722 /* All other image configurations only contain image name and
1723 * the format information. */
1724 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0"
1725 "MergeSource\0MergeTarget\0");
1726 }
1727 if (!fValid)
1728 {
1729 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1730 RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
1731 break;
1732 }
1733
1734 if (pCurNode == pCfg)
1735 {
1736 rc = CFGMR3QueryBoolDef(pCurNode, "HostIPStack", &fHostIP, true);
1737 if (RT_FAILURE(rc))
1738 {
1739 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1740 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
1741 break;
1742 }
1743
1744 rc = CFGMR3QueryBoolDef(pCurNode, "HonorZeroWrites", &fHonorZeroWrites, false);
1745 if (RT_FAILURE(rc))
1746 {
1747 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1748 N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
1749 break;
1750 }
1751
1752 rc = CFGMR3QueryBoolDef(pCurNode, "ReadOnly", &fReadOnly, false);
1753 if (RT_FAILURE(rc))
1754 {
1755 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1756 N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
1757 break;
1758 }
1759
1760 rc = CFGMR3QueryBoolDef(pCurNode, "MaybeReadOnly", &fMaybeReadOnly, false);
1761 if (RT_FAILURE(rc))
1762 {
1763 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1764 N_("DrvVD: Configuration error: Querying \"MaybeReadOnly\" as boolean failed"));
1765 break;
1766 }
1767
1768 rc = CFGMR3QueryBoolDef(pCurNode, "TempReadOnly", &pThis->fTempReadOnly, false);
1769 if (RT_FAILURE(rc))
1770 {
1771 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1772 N_("DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
1773 break;
1774 }
1775 if (fReadOnly && pThis->fTempReadOnly)
1776 {
1777 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1778 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
1779 break;
1780 }
1781
1782 rc = CFGMR3QueryBoolDef(pCurNode, "Shareable", &pThis->fShareable, false);
1783 if (RT_FAILURE(rc))
1784 {
1785 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1786 N_("DrvVD: Configuration error: Querying \"Shareable\" as boolean failed"));
1787 break;
1788 }
1789
1790 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
1791 if (RT_FAILURE(rc))
1792 {
1793 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1794 N_("DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
1795 break;
1796 }
1797 rc = CFGMR3QueryBoolDef(pCurNode, "SetupMerge", &pThis->fMergePending, false);
1798 if (RT_FAILURE(rc))
1799 {
1800 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1801 N_("DrvVD: Configuration error: Querying \"SetupMerge\" as boolean failed"));
1802 break;
1803 }
1804 if (fReadOnly && pThis->fMergePending)
1805 {
1806 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1807 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"MergePending\" are set"));
1808 break;
1809 }
1810 }
1811
1812 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
1813 if (!pParent)
1814 break;
1815 pCurNode = pParent;
1816 iLevel++;
1817 }
1818
1819 /*
1820 * Create the image container and the necessary interfaces.
1821 */
1822 if (RT_SUCCESS(rc))
1823 {
1824 /* First of all figure out what kind of TCP networking stack interface
1825 * to use. This is done unconditionally, as backends which don't need
1826 * it will just ignore it. */
1827 if (fHostIP)
1828 {
1829 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1830 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1831 pThis->VDITcpNetCallbacks.pfnSocketCreate = drvvdTcpSocketCreate;
1832 pThis->VDITcpNetCallbacks.pfnSocketDestroy = drvvdTcpSocketDestroy;
1833 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdTcpClientConnect;
1834 pThis->VDITcpNetCallbacks.pfnIsClientConnected = drvvdTcpIsClientConnected;
1835 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdTcpClientClose;
1836 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdTcpSelectOne;
1837 pThis->VDITcpNetCallbacks.pfnRead = drvvdTcpRead;
1838 pThis->VDITcpNetCallbacks.pfnWrite = drvvdTcpWrite;
1839 pThis->VDITcpNetCallbacks.pfnSgWrite = drvvdTcpSgWrite;
1840 pThis->VDITcpNetCallbacks.pfnFlush = drvvdTcpFlush;
1841 pThis->VDITcpNetCallbacks.pfnSetSendCoalescing = drvvdTcpSetSendCoalescing;
1842 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdTcpGetLocalAddress;
1843 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdTcpGetPeerAddress;
1844 pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdTcpSelectOneEx;
1845 pThis->VDITcpNetCallbacks.pfnPoke = drvvdTcpPoke;
1846 }
1847 else
1848 {
1849#ifndef VBOX_WITH_INIP
1850 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1851 RT_SRC_POS, N_("DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
1852#else /* VBOX_WITH_INIP */
1853 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1854 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1855 pThis->VDITcpNetCallbacks.pfnSocketCreate = drvvdINIPSocketCreate;
1856 pThis->VDITcpNetCallbacks.pfnSocketDestroy = drvvdINIPSocketDestroy;
1857 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
1858 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
1859 pThis->VDITcpNetCallbacks.pfnIsClientConnected = drvvdINIPIsClientConnected;
1860 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
1861 pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
1862 pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite;
1863 pThis->VDITcpNetCallbacks.pfnSgWrite = drvvdINIPSgWrite;
1864 pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush;
1865 pThis->VDITcpNetCallbacks.pfnSetSendCoalescing = drvvdINIPSetSendCoalescing;
1866 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdINIPGetLocalAddress;
1867 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdINIPGetPeerAddress;
1868 pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdINIPSelectOneEx;
1869 pThis->VDITcpNetCallbacks.pfnPoke = drvvdINIPPoke;
1870#endif /* VBOX_WITH_INIP */
1871 }
1872 if (RT_SUCCESS(rc))
1873 {
1874 rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP",
1875 VDINTERFACETYPE_TCPNET,
1876 &pThis->VDITcpNetCallbacks, NULL,
1877 &pThis->pVDIfsDisk);
1878 }
1879
1880 /** @todo quick hack to work around problems in the async I/O
1881 * implementation (rw semaphore thread ownership problem)
1882 * while a merge is running. Remove once this is fixed. */
1883 if (pThis->fMergePending)
1884 fUseNewIo = false;
1885
1886 if (RT_SUCCESS(rc) && fUseNewIo)
1887 {
1888#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1889 pThis->VDIAsyncIOCallbacks.cbSize = sizeof(VDINTERFACEASYNCIO);
1890 pThis->VDIAsyncIOCallbacks.enmInterface = VDINTERFACETYPE_ASYNCIO;
1891 pThis->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen;
1892 pThis->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose;
1893 pThis->VDIAsyncIOCallbacks.pfnGetSize = drvvdAsyncIOGetSize;
1894 pThis->VDIAsyncIOCallbacks.pfnSetSize = drvvdAsyncIOSetSize;
1895 pThis->VDIAsyncIOCallbacks.pfnReadSync = drvvdAsyncIOReadSync;
1896 pThis->VDIAsyncIOCallbacks.pfnWriteSync = drvvdAsyncIOWriteSync;
1897 pThis->VDIAsyncIOCallbacks.pfnFlushSync = drvvdAsyncIOFlushSync;
1898 pThis->VDIAsyncIOCallbacks.pfnReadAsync = drvvdAsyncIOReadAsync;
1899 pThis->VDIAsyncIOCallbacks.pfnWriteAsync = drvvdAsyncIOWriteAsync;
1900 pThis->VDIAsyncIOCallbacks.pfnFlushAsync = drvvdAsyncIOFlushAsync;
1901
1902 rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
1903 &pThis->VDIAsyncIOCallbacks, pThis, &pThis->pVDIfsDisk);
1904#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1905 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1906 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
1907#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1908 }
1909
1910 if (RT_SUCCESS(rc) && pThis->fMergePending)
1911 {
1912 rc = RTSemFastMutexCreate(&pThis->MergeCompleteMutex);
1913 if (RT_SUCCESS(rc))
1914 rc = RTSemRWCreate(&pThis->MergeLock);
1915 if (RT_SUCCESS(rc))
1916 {
1917 pThis->VDIThreadSyncCallbacks.cbSize = sizeof(VDINTERFACETHREADSYNC);
1918 pThis->VDIThreadSyncCallbacks.enmInterface = VDINTERFACETYPE_THREADSYNC;
1919 pThis->VDIThreadSyncCallbacks.pfnStartRead = drvvdThreadStartRead;
1920 pThis->VDIThreadSyncCallbacks.pfnFinishRead = drvvdThreadFinishRead;
1921 pThis->VDIThreadSyncCallbacks.pfnStartWrite = drvvdThreadStartWrite;
1922 pThis->VDIThreadSyncCallbacks.pfnFinishWrite = drvvdThreadFinishWrite;
1923
1924 rc = VDInterfaceAdd(&pThis->VDIThreadSync, "DrvVD_ThreadSync", VDINTERFACETYPE_THREADSYNC,
1925 &pThis->VDIThreadSyncCallbacks, pThis, &pThis->pVDIfsDisk);
1926 }
1927 else
1928 {
1929 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1930 N_("DrvVD: Failed to create semaphores for \"MergePending\""));
1931 }
1932 }
1933
1934 if (RT_SUCCESS(rc))
1935 {
1936 rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk);
1937 /* Error message is already set correctly. */
1938 }
1939 }
1940
1941 if (pThis->pDrvMediaAsyncPort && fUseNewIo)
1942 pThis->fAsyncIOSupported = true;
1943
1944 unsigned iImageIdx = 0;
1945 while (pCurNode && RT_SUCCESS(rc))
1946 {
1947 /* Allocate per-image data. */
1948 PVBOXIMAGE pImage = drvvdNewImage(pThis);
1949 if (!pImage)
1950 {
1951 rc = VERR_NO_MEMORY;
1952 break;
1953 }
1954
1955 /*
1956 * Read the image configuration.
1957 */
1958 rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
1959 if (RT_FAILURE(rc))
1960 {
1961 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1962 N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
1963 break;
1964 }
1965
1966 rc = CFGMR3QueryStringAlloc(pCurNode, "Format", &pszFormat);
1967 if (RT_FAILURE(rc))
1968 {
1969 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1970 N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
1971 break;
1972 }
1973
1974 bool fMergeSource;
1975 rc = CFGMR3QueryBoolDef(pCurNode, "MergeSource", &fMergeSource, false);
1976 if (RT_FAILURE(rc))
1977 {
1978 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1979 N_("DrvVD: Configuration error: Querying \"MergeSource\" as boolean failed"));
1980 break;
1981 }
1982 if (fMergeSource)
1983 {
1984 if (pThis->uMergeSource == VD_LAST_IMAGE)
1985 pThis->uMergeSource = iImageIdx;
1986 else
1987 {
1988 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1989 N_("DrvVD: Configuration error: Multiple \"MergeSource\" occurrences"));
1990 break;
1991 }
1992 }
1993
1994 bool fMergeTarget;
1995 rc = CFGMR3QueryBoolDef(pCurNode, "MergeTarget", &fMergeTarget, false);
1996 if (RT_FAILURE(rc))
1997 {
1998 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1999 N_("DrvVD: Configuration error: Querying \"MergeTarget\" as boolean failed"));
2000 break;
2001 }
2002 if (fMergeTarget)
2003 {
2004 if (pThis->uMergeTarget == VD_LAST_IMAGE)
2005 pThis->uMergeTarget = iImageIdx;
2006 else
2007 {
2008 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2009 N_("DrvVD: Configuration error: Multiple \"MergeTarget\" occurrences"));
2010 break;
2011 }
2012 }
2013
2014 PCFGMNODE pCfgVDConfig = CFGMR3GetChild(pCurNode, "VDConfig");
2015 rc = VDInterfaceAdd(&pImage->VDIConfig, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
2016 &pThis->VDIConfigCallbacks, pCfgVDConfig, &pImage->pVDIfsImage);
2017 AssertRC(rc);
2018
2019 /*
2020 * Open the image.
2021 */
2022 unsigned uOpenFlags;
2023 if (fReadOnly || pThis->fTempReadOnly || iLevel != 0)
2024 uOpenFlags = VD_OPEN_FLAGS_READONLY;
2025 else
2026 uOpenFlags = VD_OPEN_FLAGS_NORMAL;
2027 if (fHonorZeroWrites)
2028 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
2029 if (pThis->fAsyncIOSupported)
2030 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
2031 if (pThis->fShareable)
2032 uOpenFlags |= VD_OPEN_FLAGS_SHAREABLE;
2033
2034 /* Try to open backend in async I/O mode first. */
2035 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
2036 if (rc == VERR_NOT_SUPPORTED)
2037 {
2038 pThis->fAsyncIOSupported = false;
2039 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
2040 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
2041 }
2042
2043 if (RT_SUCCESS(rc))
2044 {
2045 Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
2046 iLevel, pszName,
2047 VDIsReadOnly(pThis->pDisk) ? "read-only" : "read-write"));
2048 if ( VDIsReadOnly(pThis->pDisk)
2049 && !fReadOnly
2050 && !fMaybeReadOnly
2051 && !pThis->fTempReadOnly
2052 && iLevel == 0)
2053 {
2054 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_VD_IMAGE_READ_ONLY, RT_SRC_POS,
2055 N_("Failed to open image '%s' for writing due to wrong permissions"),
2056 pszName);
2057 break;
2058 }
2059 }
2060 else
2061 {
2062 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
2063 N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName,
2064 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc);
2065 break;
2066 }
2067
2068
2069 MMR3HeapFree(pszName);
2070 pszName = NULL;
2071 MMR3HeapFree(pszFormat);
2072 pszFormat = NULL;
2073
2074 /* next */
2075 iLevel--;
2076 iImageIdx++;
2077 pCurNode = CFGMR3GetParent(pCurNode);
2078 }
2079
2080 if ( RT_SUCCESS(rc)
2081 && pThis->fMergePending
2082 && ( pThis->uMergeSource == VD_LAST_IMAGE
2083 || pThis->uMergeTarget == VD_LAST_IMAGE))
2084 {
2085 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2086 N_("DrvVD: Configuration error: Inconsistent image merge data"));
2087 }
2088
2089 /*
2090 * Register a load-done callback so we can undo TempReadOnly config before
2091 * we get to drvvdResume. Autoamtically deregistered upon destruction.
2092 */
2093 if (RT_SUCCESS(rc))
2094 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
2095 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
2096 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
2097 NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
2098
2099
2100 if (RT_FAILURE(rc))
2101 {
2102 if (VALID_PTR(pszName))
2103 MMR3HeapFree(pszName);
2104 if (VALID_PTR(pszFormat))
2105 MMR3HeapFree(pszFormat);
2106 /* drvvdDestruct does the rest. */
2107 }
2108
2109 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
2110 return rc;
2111}
2112
2113/**
2114 * VBox disk container media driver registration record.
2115 */
2116const PDMDRVREG g_DrvVD =
2117{
2118 /* u32Version */
2119 PDM_DRVREG_VERSION,
2120 /* szName */
2121 "VD",
2122 /* szRCMod */
2123 "",
2124 /* szR0Mod */
2125 "",
2126 /* pszDescription */
2127 "Generic VBox disk media driver.",
2128 /* fFlags */
2129 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
2130 /* fClass. */
2131 PDM_DRVREG_CLASS_MEDIA,
2132 /* cMaxInstances */
2133 ~0,
2134 /* cbInstance */
2135 sizeof(VBOXDISK),
2136 /* pfnConstruct */
2137 drvvdConstruct,
2138 /* pfnDestruct */
2139 drvvdDestruct,
2140 /* pfnRelocate */
2141 NULL,
2142 /* pfnIOCtl */
2143 NULL,
2144 /* pfnPowerOn */
2145 drvvdPowerOn,
2146 /* pfnReset */
2147 NULL,
2148 /* pfnSuspend */
2149 drvvdSuspend,
2150 /* pfnResume */
2151 drvvdResume,
2152 /* pfnAttach */
2153 NULL,
2154 /* pfnDetach */
2155 NULL,
2156 /* pfnPowerOff */
2157 drvvdPowerOff,
2158 /* pfnSoftReset */
2159 NULL,
2160 /* u32EndVersion */
2161 PDM_DRVREG_VERSION
2162};
2163
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