VirtualBox

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

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

whitespace

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