VirtualBox

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

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

iSCSI: First part for async I/O. Move I/O into a separate thread and handle NOP-in requests properly to prevent disconnects if the guest isn't doing any I/O.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 74.6 KB
Line 
1/* $Id: DrvVD.cpp 31098 2010-07-26 09:06:52Z 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 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 fHonorZeroWrites; /**< True if zero blocks should be written. */
1625 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1626
1627 /*
1628 * Init the static parts.
1629 */
1630 pDrvIns->IBase.pfnQueryInterface = drvvdQueryInterface;
1631 pThis->pDrvIns = pDrvIns;
1632 pThis->fTempReadOnly = false;
1633 pThis->pDisk = NULL;
1634 pThis->fAsyncIOSupported = false;
1635 pThis->fMergePending = false;
1636 pThis->MergeCompleteMutex = NIL_RTSEMFASTMUTEX;
1637 pThis->uMergeSource = VD_LAST_IMAGE;
1638 pThis->uMergeTarget = VD_LAST_IMAGE;
1639
1640 /* IMedia */
1641 pThis->IMedia.pfnRead = drvvdRead;
1642 pThis->IMedia.pfnWrite = drvvdWrite;
1643 pThis->IMedia.pfnFlush = drvvdFlush;
1644 pThis->IMedia.pfnMerge = drvvdMerge;
1645 pThis->IMedia.pfnGetSize = drvvdGetSize;
1646 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly;
1647 pThis->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
1648 pThis->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
1649 pThis->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
1650 pThis->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
1651 pThis->IMedia.pfnGetUuid = drvvdGetUuid;
1652
1653 /* IMediaAsync */
1654 pThis->IMediaAsync.pfnStartRead = drvvdStartRead;
1655 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite;
1656 pThis->IMediaAsync.pfnStartFlush = drvvdStartFlush;
1657
1658 /* Initialize supported VD interfaces. */
1659 pThis->pVDIfsDisk = NULL;
1660
1661 pThis->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1662 pThis->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1663 pThis->VDIErrorCallbacks.pfnError = drvvdErrorCallback;
1664 pThis->VDIErrorCallbacks.pfnMessage = NULL;
1665
1666 rc = VDInterfaceAdd(&pThis->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
1667 &pThis->VDIErrorCallbacks, pDrvIns, &pThis->pVDIfsDisk);
1668 AssertRC(rc);
1669
1670 /* This is just prepared here, the actual interface is per-image, so it's
1671 * added later. No need to have separate callback tables. */
1672 pThis->VDIConfigCallbacks.cbSize = sizeof(VDINTERFACECONFIG);
1673 pThis->VDIConfigCallbacks.enmInterface = VDINTERFACETYPE_CONFIG;
1674 pThis->VDIConfigCallbacks.pfnAreKeysValid = drvvdCfgAreKeysValid;
1675 pThis->VDIConfigCallbacks.pfnQuerySize = drvvdCfgQuerySize;
1676 pThis->VDIConfigCallbacks.pfnQuery = drvvdCfgQuery;
1677
1678 /* List of images is empty now. */
1679 pThis->pImages = NULL;
1680
1681 /* Try to attach async media port interface above.*/
1682 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1683
1684 /*
1685 * Validate configuration and find all parent images.
1686 * It's sort of up side down from the image dependency tree.
1687 */
1688 bool fHostIP = false;
1689 bool fUseNewIo = false;
1690 unsigned iLevel = 0;
1691 PCFGMNODE pCurNode = pCfg;
1692
1693 for (;;)
1694 {
1695 bool fValid;
1696
1697 if (pCurNode == pCfg)
1698 {
1699 /* Toplevel configuration additionally contains the global image
1700 * open flags. Some might be converted to per-image flags later. */
1701 fValid = CFGMR3AreValuesValid(pCurNode,
1702 "Format\0Path\0"
1703 "ReadOnly\0TempReadOnly\0HonorZeroWrites\0"
1704 "HostIPStack\0UseNewIo\0"
1705 "SetupMerge\0MergeSource\0MergeTarget\0");
1706 }
1707 else
1708 {
1709 /* All other image configurations only contain image name and
1710 * the format information. */
1711 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0"
1712 "MergeSource\0MergeTarget\0");
1713 }
1714 if (!fValid)
1715 {
1716 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1717 RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
1718 break;
1719 }
1720
1721 if (pCurNode == pCfg)
1722 {
1723 rc = CFGMR3QueryBoolDef(pCurNode, "HostIPStack", &fHostIP, true);
1724 if (RT_FAILURE(rc))
1725 {
1726 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1727 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
1728 break;
1729 }
1730
1731 rc = CFGMR3QueryBoolDef(pCurNode, "HonorZeroWrites", &fHonorZeroWrites, false);
1732 if (RT_FAILURE(rc))
1733 {
1734 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1735 N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
1736 break;
1737 }
1738
1739 rc = CFGMR3QueryBoolDef(pCurNode, "ReadOnly", &fReadOnly, false);
1740 if (RT_FAILURE(rc))
1741 {
1742 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1743 N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
1744 break;
1745 }
1746
1747 rc = CFGMR3QueryBoolDef(pCurNode, "TempReadOnly", &pThis->fTempReadOnly, false);
1748 if (RT_FAILURE(rc))
1749 {
1750 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1751 N_("DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
1752 break;
1753 }
1754 if (fReadOnly && pThis->fTempReadOnly)
1755 {
1756 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1757 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
1758 break;
1759 }
1760 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
1761 if (RT_FAILURE(rc))
1762 {
1763 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1764 N_("DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
1765 break;
1766 }
1767 rc = CFGMR3QueryBoolDef(pCurNode, "SetupMerge", &pThis->fMergePending, false);
1768 if (RT_FAILURE(rc))
1769 {
1770 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1771 N_("DrvVD: Configuration error: Querying \"SetupMerge\" as boolean failed"));
1772 break;
1773 }
1774 if (fReadOnly && pThis->fMergePending)
1775 {
1776 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1777 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"MergePending\" are set"));
1778 break;
1779 }
1780 }
1781
1782 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
1783 if (!pParent)
1784 break;
1785 pCurNode = pParent;
1786 iLevel++;
1787 }
1788
1789 /*
1790 * Create the image container and the necessary interfaces.
1791 */
1792 if (RT_SUCCESS(rc))
1793 {
1794 /* First of all figure out what kind of TCP networking stack interface
1795 * to use. This is done unconditionally, as backends which don't need
1796 * it will just ignore it. */
1797 if (fHostIP)
1798 {
1799 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1800 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1801 pThis->VDITcpNetCallbacks.pfnSocketCreate = drvvdTcpSocketCreate;
1802 pThis->VDITcpNetCallbacks.pfnSocketDestroy = drvvdTcpSocketDestroy;
1803 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdTcpClientConnect;
1804 pThis->VDITcpNetCallbacks.pfnIsClientConnected = drvvdTcpIsClientConnected;
1805 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdTcpClientClose;
1806 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdTcpSelectOne;
1807 pThis->VDITcpNetCallbacks.pfnRead = drvvdTcpRead;
1808 pThis->VDITcpNetCallbacks.pfnWrite = drvvdTcpWrite;
1809 pThis->VDITcpNetCallbacks.pfnSgWrite = drvvdTcpSgWrite;
1810 pThis->VDITcpNetCallbacks.pfnFlush = drvvdTcpFlush;
1811 pThis->VDITcpNetCallbacks.pfnSetSendCoalescing = drvvdTcpSetSendCoalescing;
1812 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdTcpGetLocalAddress;
1813 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdTcpGetPeerAddress;
1814 pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdTcpSelectOneEx;
1815 pThis->VDITcpNetCallbacks.pfnPoke = drvvdTcpPoke;
1816 }
1817 else
1818 {
1819#ifndef VBOX_WITH_INIP
1820 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1821 RT_SRC_POS, N_("DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
1822#else /* VBOX_WITH_INIP */
1823 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1824 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1825 pThis->VDITcpNetCallbacks.pfnSocketCreate = drvvdINIPSocketCreate;
1826 pThis->VDITcpNetCallbacks.pfnSocketDestroy = drvvdINIPSocketDestroy;
1827 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
1828 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
1829 pThis->VDITcpNetCallbacks.pfnIsClientConnected = drvvdINIPIsClientConnected;
1830 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
1831 pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
1832 pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite;
1833 pThis->VDITcpNetCallbacks.pfnSgWrite = drvvdINIPSgWrite;
1834 pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush;
1835 pThis->VDITcpNetCallbacks.pfnSetSendCoalescing = drvvdINIPSetSendCoalescing;
1836 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdINIPGetLocalAddress;
1837 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdINIPGetPeerAddress;
1838 pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdINIPSelectOneEx;
1839 pThis->VDITcpNetCallbacks.pfnPoke = drvvdINIPPoke;
1840#endif /* VBOX_WITH_INIP */
1841 }
1842 if (RT_SUCCESS(rc))
1843 {
1844 rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP",
1845 VDINTERFACETYPE_TCPNET,
1846 &pThis->VDITcpNetCallbacks, NULL,
1847 &pThis->pVDIfsDisk);
1848 }
1849
1850 /** @todo quick hack to work around problems in the async I/O
1851 * implementation (rw semaphore thread ownership problem)
1852 * while a merge is running. Remove once this is fixed. */
1853 if (pThis->fMergePending)
1854 fUseNewIo = false;
1855
1856 if (RT_SUCCESS(rc) && fUseNewIo)
1857 {
1858#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1859 pThis->VDIAsyncIOCallbacks.cbSize = sizeof(VDINTERFACEASYNCIO);
1860 pThis->VDIAsyncIOCallbacks.enmInterface = VDINTERFACETYPE_ASYNCIO;
1861 pThis->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen;
1862 pThis->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose;
1863 pThis->VDIAsyncIOCallbacks.pfnGetSize = drvvdAsyncIOGetSize;
1864 pThis->VDIAsyncIOCallbacks.pfnSetSize = drvvdAsyncIOSetSize;
1865 pThis->VDIAsyncIOCallbacks.pfnReadSync = drvvdAsyncIOReadSync;
1866 pThis->VDIAsyncIOCallbacks.pfnWriteSync = drvvdAsyncIOWriteSync;
1867 pThis->VDIAsyncIOCallbacks.pfnFlushSync = drvvdAsyncIOFlushSync;
1868 pThis->VDIAsyncIOCallbacks.pfnReadAsync = drvvdAsyncIOReadAsync;
1869 pThis->VDIAsyncIOCallbacks.pfnWriteAsync = drvvdAsyncIOWriteAsync;
1870 pThis->VDIAsyncIOCallbacks.pfnFlushAsync = drvvdAsyncIOFlushAsync;
1871
1872 rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
1873 &pThis->VDIAsyncIOCallbacks, pThis, &pThis->pVDIfsDisk);
1874#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1875 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1876 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
1877#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1878 }
1879
1880 if (RT_SUCCESS(rc) && pThis->fMergePending)
1881 {
1882 rc = RTSemFastMutexCreate(&pThis->MergeCompleteMutex);
1883 if (RT_SUCCESS(rc))
1884 rc = RTSemRWCreate(&pThis->MergeLock);
1885 if (RT_SUCCESS(rc))
1886 {
1887 pThis->VDIThreadSyncCallbacks.cbSize = sizeof(VDINTERFACETHREADSYNC);
1888 pThis->VDIThreadSyncCallbacks.enmInterface = VDINTERFACETYPE_THREADSYNC;
1889 pThis->VDIThreadSyncCallbacks.pfnStartRead = drvvdThreadStartRead;
1890 pThis->VDIThreadSyncCallbacks.pfnFinishRead = drvvdThreadFinishRead;
1891 pThis->VDIThreadSyncCallbacks.pfnStartWrite = drvvdThreadStartWrite;
1892 pThis->VDIThreadSyncCallbacks.pfnFinishWrite = drvvdThreadFinishWrite;
1893
1894 rc = VDInterfaceAdd(&pThis->VDIThreadSync, "DrvVD_ThreadSync", VDINTERFACETYPE_THREADSYNC,
1895 &pThis->VDIThreadSyncCallbacks, pThis, &pThis->pVDIfsDisk);
1896 }
1897 else
1898 {
1899 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1900 N_("DrvVD: Failed to create semaphores for \"MergePending\""));
1901 }
1902 }
1903
1904 if (RT_SUCCESS(rc))
1905 {
1906 rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk);
1907 /* Error message is already set correctly. */
1908 }
1909 }
1910
1911 if (pThis->pDrvMediaAsyncPort && fUseNewIo)
1912 pThis->fAsyncIOSupported = true;
1913
1914 unsigned iImageIdx = 0;
1915 while (pCurNode && RT_SUCCESS(rc))
1916 {
1917 /* Allocate per-image data. */
1918 PVBOXIMAGE pImage = drvvdNewImage(pThis);
1919 if (!pImage)
1920 {
1921 rc = VERR_NO_MEMORY;
1922 break;
1923 }
1924
1925 /*
1926 * Read the image configuration.
1927 */
1928 rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
1929 if (RT_FAILURE(rc))
1930 {
1931 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1932 N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
1933 break;
1934 }
1935
1936 rc = CFGMR3QueryStringAlloc(pCurNode, "Format", &pszFormat);
1937 if (RT_FAILURE(rc))
1938 {
1939 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1940 N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
1941 break;
1942 }
1943
1944 bool fMergeSource;
1945 rc = CFGMR3QueryBoolDef(pCurNode, "MergeSource", &fMergeSource, false);
1946 if (RT_FAILURE(rc))
1947 {
1948 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1949 N_("DrvVD: Configuration error: Querying \"MergeSource\" as boolean failed"));
1950 break;
1951 }
1952 if (fMergeSource)
1953 {
1954 if (pThis->uMergeSource == VD_LAST_IMAGE)
1955 pThis->uMergeSource = iImageIdx;
1956 else
1957 {
1958 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1959 N_("DrvVD: Configuration error: Multiple \"MergeSource\" occurrences"));
1960 break;
1961 }
1962 }
1963
1964 bool fMergeTarget;
1965 rc = CFGMR3QueryBoolDef(pCurNode, "MergeTarget", &fMergeTarget, false);
1966 if (RT_FAILURE(rc))
1967 {
1968 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1969 N_("DrvVD: Configuration error: Querying \"MergeTarget\" as boolean failed"));
1970 break;
1971 }
1972 if (fMergeTarget)
1973 {
1974 if (pThis->uMergeTarget == VD_LAST_IMAGE)
1975 pThis->uMergeTarget = iImageIdx;
1976 else
1977 {
1978 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1979 N_("DrvVD: Configuration error: Multiple \"MergeTarget\" occurrences"));
1980 break;
1981 }
1982 }
1983
1984 PCFGMNODE pCfgVDConfig = CFGMR3GetChild(pCurNode, "VDConfig");
1985 rc = VDInterfaceAdd(&pImage->VDIConfig, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
1986 &pThis->VDIConfigCallbacks, pCfgVDConfig, &pImage->pVDIfsImage);
1987 AssertRC(rc);
1988
1989 /*
1990 * Open the image.
1991 */
1992 unsigned uOpenFlags;
1993 if (fReadOnly || pThis->fTempReadOnly || iLevel != 0)
1994 uOpenFlags = VD_OPEN_FLAGS_READONLY;
1995 else
1996 uOpenFlags = VD_OPEN_FLAGS_NORMAL;
1997 if (fHonorZeroWrites)
1998 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
1999 if (pThis->fAsyncIOSupported)
2000 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
2001
2002 /* Try to open backend in async I/O mode first. */
2003 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
2004 if (rc == VERR_NOT_SUPPORTED)
2005 {
2006 pThis->fAsyncIOSupported = false;
2007 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
2008 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
2009 }
2010
2011 if (RT_SUCCESS(rc))
2012 {
2013 Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
2014 iLevel, pszName,
2015 VDIsReadOnly(pThis->pDisk) ? "read-only" : "read-write"));
2016 if ( VDIsReadOnly(pThis->pDisk)
2017 && !fReadOnly
2018 && !pThis->fTempReadOnly
2019 && iLevel == 0)
2020 {
2021 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_VD_IMAGE_READ_ONLY, RT_SRC_POS,
2022 N_("Failed to open image '%s' for writing due to wrong permissions"),
2023 pszName);
2024 break;
2025 }
2026 }
2027 else
2028 {
2029 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
2030 N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName,
2031 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc);
2032 break;
2033 }
2034
2035
2036 MMR3HeapFree(pszName);
2037 pszName = NULL;
2038 MMR3HeapFree(pszFormat);
2039 pszFormat = NULL;
2040
2041 /* next */
2042 iLevel--;
2043 iImageIdx++;
2044 pCurNode = CFGMR3GetParent(pCurNode);
2045 }
2046
2047 if ( RT_SUCCESS(rc)
2048 && pThis->fMergePending
2049 && ( pThis->uMergeSource == VD_LAST_IMAGE
2050 || pThis->uMergeTarget == VD_LAST_IMAGE))
2051 {
2052 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2053 N_("DrvVD: Configuration error: Inconsistent image merge data"));
2054 }
2055
2056 /*
2057 * Register a load-done callback so we can undo TempReadOnly config before
2058 * we get to drvvdResume. Autoamtically deregistered upon destruction.
2059 */
2060 if (RT_SUCCESS(rc))
2061 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
2062 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
2063 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
2064 NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
2065
2066
2067 if (RT_FAILURE(rc))
2068 {
2069 if (VALID_PTR(pszName))
2070 MMR3HeapFree(pszName);
2071 if (VALID_PTR(pszFormat))
2072 MMR3HeapFree(pszFormat);
2073 /* drvvdDestruct does the rest. */
2074 }
2075
2076 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
2077 return rc;
2078}
2079
2080/**
2081 * VBox disk container media driver registration record.
2082 */
2083const PDMDRVREG g_DrvVD =
2084{
2085 /* u32Version */
2086 PDM_DRVREG_VERSION,
2087 /* szName */
2088 "VD",
2089 /* szRCMod */
2090 "",
2091 /* szR0Mod */
2092 "",
2093 /* pszDescription */
2094 "Generic VBox disk media driver.",
2095 /* fFlags */
2096 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
2097 /* fClass. */
2098 PDM_DRVREG_CLASS_MEDIA,
2099 /* cMaxInstances */
2100 ~0,
2101 /* cbInstance */
2102 sizeof(VBOXDISK),
2103 /* pfnConstruct */
2104 drvvdConstruct,
2105 /* pfnDestruct */
2106 drvvdDestruct,
2107 /* pfnRelocate */
2108 NULL,
2109 /* pfnIOCtl */
2110 NULL,
2111 /* pfnPowerOn */
2112 drvvdPowerOn,
2113 /* pfnReset */
2114 NULL,
2115 /* pfnSuspend */
2116 drvvdSuspend,
2117 /* pfnResume */
2118 drvvdResume,
2119 /* pfnAttach */
2120 NULL,
2121 /* pfnDetach */
2122 NULL,
2123 /* pfnPowerOff */
2124 drvvdPowerOff,
2125 /* pfnSoftReset */
2126 NULL,
2127 /* u32EndVersion */
2128 PDM_DRVREG_VERSION
2129};
2130
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