VirtualBox

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

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

Main/Console,Storage/DrvVD+fdc: Allow readonly floppy images (suppress runtime error on VM start for readonly media), and take this as the signal to make the floppy medium readonly. Never attempt to write to such images, and signal the appropriate error.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette