VirtualBox

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

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

VBoxHDD: Make the non blocking read/write socket APIs available in the VDTCPNET interface

  • 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 31456 2010-08-08 13:46:41Z 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 {
1196 uint32_t fPollEvents = 0;
1197
1198 if (fEvents & VD_INTERFACETCPNET_EVT_READ)
1199 fPollEvents |= RTPOLL_EVT_READ;
1200 if (fEvents & VD_INTERFACETCPNET_EVT_WRITE)
1201 fPollEvents |= RTPOLL_EVT_WRITE;
1202 if (fEvents & VD_INTERFACETCPNET_EVT_ERROR)
1203 fPollEvents |= RTPOLL_EVT_ERROR;
1204
1205 rc = RTPollSetEventsChange(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET, fPollEvents);
1206 if (RT_FAILURE(rc))
1207 return rc;
1208
1209 pSockInt->fEventsOld = fEvents;
1210 }
1211
1212 ASMAtomicXchgBool(&pSockInt->fWaiting, true);
1213 if (ASMAtomicXchgBool(&pSockInt->fWokenUp, false))
1214 {
1215 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
1216 return VERR_INTERRUPTED;
1217 }
1218
1219 rc = RTPoll(pSockInt->hPollSet, cMillies, &fEventsRecv, &id);
1220 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1221
1222 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
1223
1224 if (RT_SUCCESS(rc))
1225 {
1226 if (id == VDSOCKET_POLL_ID_SOCKET)
1227 {
1228 fEventsRecv &= RTPOLL_EVT_VALID_MASK;
1229
1230 if (fEventsRecv & RTPOLL_EVT_READ)
1231 *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
1232 if (fEventsRecv & RTPOLL_EVT_WRITE)
1233 *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
1234 if (fEventsRecv & RTPOLL_EVT_ERROR)
1235 *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
1236 }
1237 else
1238 {
1239 size_t cbRead = 0;
1240 uint8_t abBuf[10];
1241 Assert(id == VDSOCKET_POLL_ID_PIPE);
1242 Assert((fEvents & RTPOLL_EVT_VALID_MASK) == RTPOLL_EVT_READ);
1243
1244 /* We got interrupted, drain the pipe. */
1245 rc = RTPipeRead(pSockInt->hPipeR, abBuf, sizeof(abBuf), &cbRead);
1246 AssertRC(rc);
1247
1248 ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
1249
1250 rc = VERR_INTERRUPTED;
1251 }
1252 }
1253
1254 return rc;
1255}
1256
1257/** @copydoc VDINTERFACETCPNET::pfnPoke */
1258static DECLCALLBACK(int) drvvdTcpPoke(VDSOCKET Sock)
1259{
1260 int rc = VINF_SUCCESS;
1261 size_t cbWritten = 0;
1262 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1263
1264 ASMAtomicXchgBool(&pSockInt->fWokenUp, true);
1265
1266 if (ASMAtomicReadBool(&pSockInt->fWaiting))
1267 {
1268 rc = RTPipeWrite(pSockInt->hPipeW, "", 1, &cbWritten);
1269 Assert(RT_SUCCESS(rc) || cbWritten == 0);
1270 }
1271
1272 return VINF_SUCCESS;
1273}
1274
1275
1276/*******************************************************************************
1277* Media interface methods *
1278*******************************************************************************/
1279
1280/** @copydoc PDMIMEDIA::pfnRead */
1281static DECLCALLBACK(int) drvvdRead(PPDMIMEDIA pInterface,
1282 uint64_t off, void *pvBuf, size_t cbRead)
1283{
1284 LogFlow(("%s: off=%#llx pvBuf=%p cbRead=%d\n", __FUNCTION__,
1285 off, pvBuf, cbRead));
1286 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1287 int rc = VDRead(pThis->pDisk, off, pvBuf, cbRead);
1288 if (RT_SUCCESS(rc))
1289 Log2(("%s: off=%#llx pvBuf=%p cbRead=%d %.*Rhxd\n", __FUNCTION__,
1290 off, pvBuf, cbRead, cbRead, pvBuf));
1291 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1292 return rc;
1293}
1294
1295/** @copydoc PDMIMEDIA::pfnWrite */
1296static DECLCALLBACK(int) drvvdWrite(PPDMIMEDIA pInterface,
1297 uint64_t off, const void *pvBuf,
1298 size_t cbWrite)
1299{
1300 LogFlow(("%s: off=%#llx pvBuf=%p cbWrite=%d\n", __FUNCTION__,
1301 off, pvBuf, cbWrite));
1302 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1303 Log2(("%s: off=%#llx pvBuf=%p cbWrite=%d %.*Rhxd\n", __FUNCTION__,
1304 off, pvBuf, cbWrite, cbWrite, pvBuf));
1305 int rc = VDWrite(pThis->pDisk, off, pvBuf, cbWrite);
1306 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1307 return rc;
1308}
1309
1310/** @copydoc PDMIMEDIA::pfnFlush */
1311static DECLCALLBACK(int) drvvdFlush(PPDMIMEDIA pInterface)
1312{
1313 LogFlow(("%s:\n", __FUNCTION__));
1314 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1315 int rc = VDFlush(pThis->pDisk);
1316 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1317 return rc;
1318}
1319
1320/** @copydoc PDMIMEDIA::pfnMerge */
1321static DECLCALLBACK(int) drvvdMerge(PPDMIMEDIA pInterface,
1322 PFNSIMPLEPROGRESS pfnProgress,
1323 void *pvUser)
1324{
1325 LogFlow(("%s:\n", __FUNCTION__));
1326 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1327 int rc = VINF_SUCCESS;
1328
1329 /* Note: There is an unavoidable race between destruction and another
1330 * thread invoking this function. This is handled safely and gracefully by
1331 * atomically invalidating the lock handle in drvvdDestruct. */
1332 int rc2 = RTSemFastMutexRequest(pThis->MergeCompleteMutex);
1333 AssertRC(rc2);
1334 if (RT_SUCCESS(rc2) && pThis->fMergePending)
1335 {
1336 /* Take shortcut: PFNSIMPLEPROGRESS is exactly the same type as
1337 * PFNVDPROGRESS, so there's no need for a conversion function. */
1338 /** @todo maybe introduce a conversion which limits update frequency. */
1339 PVDINTERFACE pVDIfsOperation = NULL;
1340 VDINTERFACE VDIProgress;
1341 VDINTERFACEPROGRESS VDIProgressCallbacks;
1342 VDIProgressCallbacks.cbSize = sizeof(VDINTERFACEPROGRESS);
1343 VDIProgressCallbacks.enmInterface = VDINTERFACETYPE_PROGRESS;
1344 VDIProgressCallbacks.pfnProgress = pfnProgress;
1345 rc2 = VDInterfaceAdd(&VDIProgress, "DrvVD_VDIProgress", VDINTERFACETYPE_PROGRESS,
1346 &VDIProgressCallbacks, pvUser, &pVDIfsOperation);
1347 AssertRC(rc2);
1348 pThis->fMergePending = false;
1349 rc = VDMerge(pThis->pDisk, pThis->uMergeSource,
1350 pThis->uMergeTarget, pVDIfsOperation);
1351 }
1352 rc2 = RTSemFastMutexRelease(pThis->MergeCompleteMutex);
1353 AssertRC(rc2);
1354 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1355 return rc;
1356}
1357
1358/** @copydoc PDMIMEDIA::pfnGetSize */
1359static DECLCALLBACK(uint64_t) drvvdGetSize(PPDMIMEDIA pInterface)
1360{
1361 LogFlow(("%s:\n", __FUNCTION__));
1362 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1363 uint64_t cb = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
1364 LogFlow(("%s: returns %#llx (%llu)\n", __FUNCTION__, cb, cb));
1365 return cb;
1366}
1367
1368/** @copydoc PDMIMEDIA::pfnIsReadOnly */
1369static DECLCALLBACK(bool) drvvdIsReadOnly(PPDMIMEDIA pInterface)
1370{
1371 LogFlow(("%s:\n", __FUNCTION__));
1372 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1373 bool f = VDIsReadOnly(pThis->pDisk);
1374 LogFlow(("%s: returns %d\n", __FUNCTION__, f));
1375 return f;
1376}
1377
1378/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
1379static DECLCALLBACK(int) drvvdBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
1380 PPDMMEDIAGEOMETRY pPCHSGeometry)
1381{
1382 LogFlow(("%s:\n", __FUNCTION__));
1383 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1384 int rc = VDGetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
1385 if (RT_FAILURE(rc))
1386 {
1387 Log(("%s: geometry not available.\n", __FUNCTION__));
1388 rc = VERR_PDM_GEOMETRY_NOT_SET;
1389 }
1390 LogFlow(("%s: returns %Rrc (CHS=%d/%d/%d)\n", __FUNCTION__,
1391 rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
1392 return rc;
1393}
1394
1395/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
1396static DECLCALLBACK(int) drvvdBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
1397 PCPDMMEDIAGEOMETRY pPCHSGeometry)
1398{
1399 LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
1400 pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
1401 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1402 int rc = VDSetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
1403 if (rc == VERR_VD_GEOMETRY_NOT_SET)
1404 rc = VERR_PDM_GEOMETRY_NOT_SET;
1405 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1406 return rc;
1407}
1408
1409/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
1410static DECLCALLBACK(int) drvvdBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
1411 PPDMMEDIAGEOMETRY pLCHSGeometry)
1412{
1413 LogFlow(("%s:\n", __FUNCTION__));
1414 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1415 int rc = VDGetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
1416 if (RT_FAILURE(rc))
1417 {
1418 Log(("%s: geometry not available.\n", __FUNCTION__));
1419 rc = VERR_PDM_GEOMETRY_NOT_SET;
1420 }
1421 LogFlow(("%s: returns %Rrc (CHS=%d/%d/%d)\n", __FUNCTION__,
1422 rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
1423 return rc;
1424}
1425
1426/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
1427static DECLCALLBACK(int) drvvdBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
1428 PCPDMMEDIAGEOMETRY pLCHSGeometry)
1429{
1430 LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
1431 pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
1432 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1433 int rc = VDSetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
1434 if (rc == VERR_VD_GEOMETRY_NOT_SET)
1435 rc = VERR_PDM_GEOMETRY_NOT_SET;
1436 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1437 return rc;
1438}
1439
1440/** @copydoc PDMIMEDIA::pfnGetUuid */
1441static DECLCALLBACK(int) drvvdGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
1442{
1443 LogFlow(("%s:\n", __FUNCTION__));
1444 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1445 int rc = VDGetUuid(pThis->pDisk, 0, pUuid);
1446 LogFlow(("%s: returns %Rrc ({%RTuuid})\n", __FUNCTION__, rc, pUuid));
1447 return rc;
1448}
1449
1450/*******************************************************************************
1451* Async Media interface methods *
1452*******************************************************************************/
1453
1454static void drvvdAsyncReqComplete(void *pvUser1, void *pvUser2, int rcReq)
1455{
1456 PVBOXDISK pThis = (PVBOXDISK)pvUser1;
1457
1458 int rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort,
1459 pvUser2, rcReq);
1460 AssertRC(rc);
1461}
1462
1463static DECLCALLBACK(int) drvvdStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
1464 PCRTSGSEG paSeg, unsigned cSeg,
1465 size_t cbRead, void *pvUser)
1466{
1467 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d\n pvUser=%#p", __FUNCTION__,
1468 uOffset, paSeg, cSeg, cbRead, pvUser));
1469 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
1470 int rc = VDAsyncRead(pThis->pDisk, uOffset, cbRead, paSeg, cSeg,
1471 drvvdAsyncReqComplete, pThis, pvUser);
1472 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1473 return rc;
1474}
1475
1476static DECLCALLBACK(int) drvvdStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
1477 PCRTSGSEG paSeg, unsigned cSeg,
1478 size_t cbWrite, void *pvUser)
1479{
1480 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d pvUser=%#p\n", __FUNCTION__,
1481 uOffset, paSeg, cSeg, cbWrite, pvUser));
1482 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
1483 int rc = VDAsyncWrite(pThis->pDisk, uOffset, cbWrite, paSeg, cSeg,
1484 drvvdAsyncReqComplete, pThis, pvUser);
1485 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1486 return rc;
1487}
1488
1489static DECLCALLBACK(int) drvvdStartFlush(PPDMIMEDIAASYNC pInterface, void *pvUser)
1490{
1491 LogFlow(("%s: pvUser=%#p\n", __FUNCTION__, pvUser));
1492 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
1493 int rc = VDAsyncFlush(pThis->pDisk, drvvdAsyncReqComplete, pThis, pvUser);
1494 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1495 return rc;
1496}
1497
1498
1499/*******************************************************************************
1500* Base interface methods *
1501*******************************************************************************/
1502
1503/**
1504 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1505 */
1506static DECLCALLBACK(void *) drvvdQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1507{
1508 PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
1509 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1510
1511 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1512 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
1513 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->fAsyncIOSupported ? &pThis->IMediaAsync : NULL);
1514 return NULL;
1515}
1516
1517
1518/*******************************************************************************
1519* Saved state notification methods *
1520*******************************************************************************/
1521
1522/**
1523 * Load done callback for re-opening the image writable during teleportation.
1524 *
1525 * This is called both for successful and failed load runs, we only care about
1526 * successfull ones.
1527 *
1528 * @returns VBox status code.
1529 * @param pDrvIns The driver instance.
1530 * @param pSSM The saved state handle.
1531 */
1532static DECLCALLBACK(int) drvvdLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
1533{
1534 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1535 Assert(!pThis->fErrorUseRuntime);
1536
1537 /* Drop out if we don't have any work to do or if it's a failed load. */
1538 if ( !pThis->fTempReadOnly
1539 || RT_FAILURE(SSMR3HandleGetStatus(pSSM)))
1540 return VINF_SUCCESS;
1541
1542 int rc = drvvdSetWritable(pThis);
1543 if (RT_FAILURE(rc)) /** @todo does the bugger set any errors? */
1544 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
1545 N_("Failed to write lock the images"));
1546 return VINF_SUCCESS;
1547}
1548
1549
1550/*******************************************************************************
1551* Driver methods *
1552*******************************************************************************/
1553
1554static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
1555{
1556 LogFlow(("%s:\n", __FUNCTION__));
1557 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1558
1559 /*
1560 * We must close the disk here to ensure that
1561 * the backend closes all files before the
1562 * async transport driver is destructed.
1563 */
1564 int rc = VDCloseAll(pThis->pDisk);
1565 AssertRC(rc);
1566}
1567
1568/**
1569 * VM resume notification that we use to undo what the temporary read-only image
1570 * mode set by drvvdSuspend.
1571 *
1572 * Also switch to runtime error mode if we're resuming after a state load
1573 * without having been powered on first.
1574 *
1575 * @param pDrvIns The driver instance data.
1576 *
1577 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
1578 * we're making assumptions about Main behavior here!
1579 */
1580static DECLCALLBACK(void) drvvdResume(PPDMDRVINS pDrvIns)
1581{
1582 LogFlow(("%s:\n", __FUNCTION__));
1583 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1584 drvvdSetWritable(pThis);
1585 pThis->fErrorUseRuntime = true;
1586}
1587
1588/**
1589 * The VM is being suspended, temporarily change to read-only image mode.
1590 *
1591 * This is important for several reasons:
1592 * -# It makes sure that there are no pending writes to the image. Most
1593 * backends implements this by closing and reopening the image in read-only
1594 * mode.
1595 * -# It allows Main to read the images during snapshotting without having
1596 * to account for concurrent writes.
1597 * -# This is essential for making teleportation targets sharing images work
1598 * right. Both with regards to caching and with regards to file sharing
1599 * locks (RTFILE_O_DENY_*). (See also drvvdLoadDone.)
1600 *
1601 * @param pDrvIns The driver instance data.
1602 */
1603static DECLCALLBACK(void) drvvdSuspend(PPDMDRVINS pDrvIns)
1604{
1605 LogFlow(("%s:\n", __FUNCTION__));
1606 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1607 drvvdSetReadonly(pThis);
1608}
1609
1610/**
1611 * VM PowerOn notification for undoing the TempReadOnly config option and
1612 * changing to runtime error mode.
1613 *
1614 * @param pDrvIns The driver instance data.
1615 *
1616 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
1617 * we're making assumptions about Main behavior here!
1618 */
1619static DECLCALLBACK(void) drvvdPowerOn(PPDMDRVINS pDrvIns)
1620{
1621 LogFlow(("%s:\n", __FUNCTION__));
1622 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1623 drvvdSetWritable(pThis);
1624 pThis->fErrorUseRuntime = true;
1625}
1626
1627/**
1628 * @copydoc FNPDMDRVDESTRUCT
1629 */
1630static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
1631{
1632 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1633 LogFlow(("%s:\n", __FUNCTION__));
1634 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1635
1636 RTSEMFASTMUTEX mutex;
1637 ASMAtomicXchgHandle(&pThis->MergeCompleteMutex, NIL_RTSEMFASTMUTEX, &mutex);
1638 if (mutex != NIL_RTSEMFASTMUTEX)
1639 {
1640 /* Request the semaphore to wait until a potentially running merge
1641 * operation has been finished. */
1642 int rc = RTSemFastMutexRequest(mutex);
1643 AssertRC(rc);
1644 pThis->fMergePending = false;
1645 rc = RTSemFastMutexRelease(mutex);
1646 AssertRC(rc);
1647 rc = RTSemFastMutexDestroy(mutex);
1648 AssertRC(rc);
1649 }
1650
1651 if (VALID_PTR(pThis->pDisk))
1652 {
1653 VDDestroy(pThis->pDisk);
1654 pThis->pDisk = NULL;
1655 }
1656 drvvdFreeImages(pThis);
1657
1658 if (pThis->MergeLock != NIL_RTSEMRW)
1659 {
1660 int rc = RTSemRWDestroy(pThis->MergeLock);
1661 AssertRC(rc);
1662 pThis->MergeLock = NIL_RTSEMRW;
1663 }
1664}
1665
1666/**
1667 * Construct a VBox disk media driver instance.
1668 *
1669 * @copydoc FNPDMDRVCONSTRUCT
1670 */
1671static DECLCALLBACK(int) drvvdConstruct(PPDMDRVINS pDrvIns,
1672 PCFGMNODE pCfg,
1673 uint32_t fFlags)
1674{
1675 LogFlow(("%s:\n", __FUNCTION__));
1676 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1677 int rc = VINF_SUCCESS;
1678 char *pszName = NULL; /**< The path of the disk image file. */
1679 char *pszFormat = NULL; /**< The format backed to use for this image. */
1680 bool fReadOnly; /**< True if the media is read-only. */
1681 bool fMaybeReadOnly; /**< True if the media may or may not be read-only. */
1682 bool fHonorZeroWrites; /**< True if zero blocks should be written. */
1683 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1684
1685 /*
1686 * Init the static parts.
1687 */
1688 pDrvIns->IBase.pfnQueryInterface = drvvdQueryInterface;
1689 pThis->pDrvIns = pDrvIns;
1690 pThis->fTempReadOnly = false;
1691 pThis->pDisk = NULL;
1692 pThis->fAsyncIOSupported = false;
1693 pThis->fShareable = false;
1694 pThis->fMergePending = false;
1695 pThis->MergeCompleteMutex = NIL_RTSEMFASTMUTEX;
1696 pThis->uMergeSource = VD_LAST_IMAGE;
1697 pThis->uMergeTarget = VD_LAST_IMAGE;
1698
1699 /* IMedia */
1700 pThis->IMedia.pfnRead = drvvdRead;
1701 pThis->IMedia.pfnWrite = drvvdWrite;
1702 pThis->IMedia.pfnFlush = drvvdFlush;
1703 pThis->IMedia.pfnMerge = drvvdMerge;
1704 pThis->IMedia.pfnGetSize = drvvdGetSize;
1705 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly;
1706 pThis->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
1707 pThis->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
1708 pThis->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
1709 pThis->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
1710 pThis->IMedia.pfnGetUuid = drvvdGetUuid;
1711
1712 /* IMediaAsync */
1713 pThis->IMediaAsync.pfnStartRead = drvvdStartRead;
1714 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite;
1715 pThis->IMediaAsync.pfnStartFlush = drvvdStartFlush;
1716
1717 /* Initialize supported VD interfaces. */
1718 pThis->pVDIfsDisk = NULL;
1719
1720 pThis->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1721 pThis->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1722 pThis->VDIErrorCallbacks.pfnError = drvvdErrorCallback;
1723 pThis->VDIErrorCallbacks.pfnMessage = NULL;
1724
1725 rc = VDInterfaceAdd(&pThis->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
1726 &pThis->VDIErrorCallbacks, pDrvIns, &pThis->pVDIfsDisk);
1727 AssertRC(rc);
1728
1729 /* This is just prepared here, the actual interface is per-image, so it's
1730 * added later. No need to have separate callback tables. */
1731 pThis->VDIConfigCallbacks.cbSize = sizeof(VDINTERFACECONFIG);
1732 pThis->VDIConfigCallbacks.enmInterface = VDINTERFACETYPE_CONFIG;
1733 pThis->VDIConfigCallbacks.pfnAreKeysValid = drvvdCfgAreKeysValid;
1734 pThis->VDIConfigCallbacks.pfnQuerySize = drvvdCfgQuerySize;
1735 pThis->VDIConfigCallbacks.pfnQuery = drvvdCfgQuery;
1736
1737 /* List of images is empty now. */
1738 pThis->pImages = NULL;
1739
1740 /* Try to attach async media port interface above.*/
1741 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1742
1743 /*
1744 * Validate configuration and find all parent images.
1745 * It's sort of up side down from the image dependency tree.
1746 */
1747 bool fHostIP = false;
1748 bool fUseNewIo = false;
1749 unsigned iLevel = 0;
1750 PCFGMNODE pCurNode = pCfg;
1751
1752 for (;;)
1753 {
1754 bool fValid;
1755
1756 if (pCurNode == pCfg)
1757 {
1758 /* Toplevel configuration additionally contains the global image
1759 * open flags. Some might be converted to per-image flags later. */
1760 fValid = CFGMR3AreValuesValid(pCurNode,
1761 "Format\0Path\0"
1762 "ReadOnly\0MaybeReadOnly\0TempReadOnly\0Shareable\0HonorZeroWrites\0"
1763 "HostIPStack\0UseNewIo\0"
1764 "SetupMerge\0MergeSource\0MergeTarget\0");
1765 }
1766 else
1767 {
1768 /* All other image configurations only contain image name and
1769 * the format information. */
1770 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0"
1771 "MergeSource\0MergeTarget\0");
1772 }
1773 if (!fValid)
1774 {
1775 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1776 RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
1777 break;
1778 }
1779
1780 if (pCurNode == pCfg)
1781 {
1782 rc = CFGMR3QueryBoolDef(pCurNode, "HostIPStack", &fHostIP, true);
1783 if (RT_FAILURE(rc))
1784 {
1785 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1786 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
1787 break;
1788 }
1789
1790 rc = CFGMR3QueryBoolDef(pCurNode, "HonorZeroWrites", &fHonorZeroWrites, false);
1791 if (RT_FAILURE(rc))
1792 {
1793 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1794 N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
1795 break;
1796 }
1797
1798 rc = CFGMR3QueryBoolDef(pCurNode, "ReadOnly", &fReadOnly, false);
1799 if (RT_FAILURE(rc))
1800 {
1801 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1802 N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
1803 break;
1804 }
1805
1806 rc = CFGMR3QueryBoolDef(pCurNode, "MaybeReadOnly", &fMaybeReadOnly, false);
1807 if (RT_FAILURE(rc))
1808 {
1809 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1810 N_("DrvVD: Configuration error: Querying \"MaybeReadOnly\" as boolean failed"));
1811 break;
1812 }
1813
1814 rc = CFGMR3QueryBoolDef(pCurNode, "TempReadOnly", &pThis->fTempReadOnly, false);
1815 if (RT_FAILURE(rc))
1816 {
1817 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1818 N_("DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
1819 break;
1820 }
1821 if (fReadOnly && pThis->fTempReadOnly)
1822 {
1823 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1824 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
1825 break;
1826 }
1827
1828 rc = CFGMR3QueryBoolDef(pCurNode, "Shareable", &pThis->fShareable, false);
1829 if (RT_FAILURE(rc))
1830 {
1831 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1832 N_("DrvVD: Configuration error: Querying \"Shareable\" as boolean failed"));
1833 break;
1834 }
1835
1836 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
1837 if (RT_FAILURE(rc))
1838 {
1839 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1840 N_("DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
1841 break;
1842 }
1843 rc = CFGMR3QueryBoolDef(pCurNode, "SetupMerge", &pThis->fMergePending, false);
1844 if (RT_FAILURE(rc))
1845 {
1846 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1847 N_("DrvVD: Configuration error: Querying \"SetupMerge\" as boolean failed"));
1848 break;
1849 }
1850 if (fReadOnly && pThis->fMergePending)
1851 {
1852 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1853 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"MergePending\" are set"));
1854 break;
1855 }
1856 }
1857
1858 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
1859 if (!pParent)
1860 break;
1861 pCurNode = pParent;
1862 iLevel++;
1863 }
1864
1865 /*
1866 * Create the image container and the necessary interfaces.
1867 */
1868 if (RT_SUCCESS(rc))
1869 {
1870 /* First of all figure out what kind of TCP networking stack interface
1871 * to use. This is done unconditionally, as backends which don't need
1872 * it will just ignore it. */
1873 if (fHostIP)
1874 {
1875 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1876 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1877 pThis->VDITcpNetCallbacks.pfnSocketCreate = drvvdTcpSocketCreate;
1878 pThis->VDITcpNetCallbacks.pfnSocketDestroy = drvvdTcpSocketDestroy;
1879 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdTcpClientConnect;
1880 pThis->VDITcpNetCallbacks.pfnIsClientConnected = drvvdTcpIsClientConnected;
1881 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdTcpClientClose;
1882 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdTcpSelectOne;
1883 pThis->VDITcpNetCallbacks.pfnRead = drvvdTcpRead;
1884 pThis->VDITcpNetCallbacks.pfnWrite = drvvdTcpWrite;
1885 pThis->VDITcpNetCallbacks.pfnSgWrite = drvvdTcpSgWrite;
1886 pThis->VDITcpNetCallbacks.pfnReadNB = drvvdTcpReadNB;
1887 pThis->VDITcpNetCallbacks.pfnWriteNB = drvvdTcpWriteNB;
1888 pThis->VDITcpNetCallbacks.pfnSgWriteNB = drvvdTcpSgWriteNB;
1889 pThis->VDITcpNetCallbacks.pfnFlush = drvvdTcpFlush;
1890 pThis->VDITcpNetCallbacks.pfnSetSendCoalescing = drvvdTcpSetSendCoalescing;
1891 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdTcpGetLocalAddress;
1892 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdTcpGetPeerAddress;
1893 pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdTcpSelectOneEx;
1894 pThis->VDITcpNetCallbacks.pfnPoke = drvvdTcpPoke;
1895 }
1896 else
1897 {
1898#ifndef VBOX_WITH_INIP
1899 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1900 RT_SRC_POS, N_("DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
1901#else /* VBOX_WITH_INIP */
1902 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1903 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1904 pThis->VDITcpNetCallbacks.pfnSocketCreate = drvvdINIPSocketCreate;
1905 pThis->VDITcpNetCallbacks.pfnSocketDestroy = drvvdINIPSocketDestroy;
1906 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
1907 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
1908 pThis->VDITcpNetCallbacks.pfnIsClientConnected = drvvdINIPIsClientConnected;
1909 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
1910 pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
1911 pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite;
1912 pThis->VDITcpNetCallbacks.pfnSgWrite = drvvdINIPSgWrite;
1913 pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush;
1914 pThis->VDITcpNetCallbacks.pfnSetSendCoalescing = drvvdINIPSetSendCoalescing;
1915 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdINIPGetLocalAddress;
1916 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdINIPGetPeerAddress;
1917 pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdINIPSelectOneEx;
1918 pThis->VDITcpNetCallbacks.pfnPoke = drvvdINIPPoke;
1919#endif /* VBOX_WITH_INIP */
1920 }
1921 if (RT_SUCCESS(rc))
1922 {
1923 rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP",
1924 VDINTERFACETYPE_TCPNET,
1925 &pThis->VDITcpNetCallbacks, NULL,
1926 &pThis->pVDIfsDisk);
1927 }
1928
1929 /** @todo quick hack to work around problems in the async I/O
1930 * implementation (rw semaphore thread ownership problem)
1931 * while a merge is running. Remove once this is fixed. */
1932 if (pThis->fMergePending)
1933 fUseNewIo = false;
1934
1935 if (RT_SUCCESS(rc) && fUseNewIo)
1936 {
1937#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1938 pThis->VDIAsyncIOCallbacks.cbSize = sizeof(VDINTERFACEASYNCIO);
1939 pThis->VDIAsyncIOCallbacks.enmInterface = VDINTERFACETYPE_ASYNCIO;
1940 pThis->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen;
1941 pThis->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose;
1942 pThis->VDIAsyncIOCallbacks.pfnGetSize = drvvdAsyncIOGetSize;
1943 pThis->VDIAsyncIOCallbacks.pfnSetSize = drvvdAsyncIOSetSize;
1944 pThis->VDIAsyncIOCallbacks.pfnReadSync = drvvdAsyncIOReadSync;
1945 pThis->VDIAsyncIOCallbacks.pfnWriteSync = drvvdAsyncIOWriteSync;
1946 pThis->VDIAsyncIOCallbacks.pfnFlushSync = drvvdAsyncIOFlushSync;
1947 pThis->VDIAsyncIOCallbacks.pfnReadAsync = drvvdAsyncIOReadAsync;
1948 pThis->VDIAsyncIOCallbacks.pfnWriteAsync = drvvdAsyncIOWriteAsync;
1949 pThis->VDIAsyncIOCallbacks.pfnFlushAsync = drvvdAsyncIOFlushAsync;
1950
1951 rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
1952 &pThis->VDIAsyncIOCallbacks, pThis, &pThis->pVDIfsDisk);
1953#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1954 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1955 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
1956#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1957 }
1958
1959 if (RT_SUCCESS(rc) && pThis->fMergePending)
1960 {
1961 rc = RTSemFastMutexCreate(&pThis->MergeCompleteMutex);
1962 if (RT_SUCCESS(rc))
1963 rc = RTSemRWCreate(&pThis->MergeLock);
1964 if (RT_SUCCESS(rc))
1965 {
1966 pThis->VDIThreadSyncCallbacks.cbSize = sizeof(VDINTERFACETHREADSYNC);
1967 pThis->VDIThreadSyncCallbacks.enmInterface = VDINTERFACETYPE_THREADSYNC;
1968 pThis->VDIThreadSyncCallbacks.pfnStartRead = drvvdThreadStartRead;
1969 pThis->VDIThreadSyncCallbacks.pfnFinishRead = drvvdThreadFinishRead;
1970 pThis->VDIThreadSyncCallbacks.pfnStartWrite = drvvdThreadStartWrite;
1971 pThis->VDIThreadSyncCallbacks.pfnFinishWrite = drvvdThreadFinishWrite;
1972
1973 rc = VDInterfaceAdd(&pThis->VDIThreadSync, "DrvVD_ThreadSync", VDINTERFACETYPE_THREADSYNC,
1974 &pThis->VDIThreadSyncCallbacks, pThis, &pThis->pVDIfsDisk);
1975 }
1976 else
1977 {
1978 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1979 N_("DrvVD: Failed to create semaphores for \"MergePending\""));
1980 }
1981 }
1982
1983 if (RT_SUCCESS(rc))
1984 {
1985 rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk);
1986 /* Error message is already set correctly. */
1987 }
1988 }
1989
1990 if (pThis->pDrvMediaAsyncPort && fUseNewIo)
1991 pThis->fAsyncIOSupported = true;
1992
1993 unsigned iImageIdx = 0;
1994 while (pCurNode && RT_SUCCESS(rc))
1995 {
1996 /* Allocate per-image data. */
1997 PVBOXIMAGE pImage = drvvdNewImage(pThis);
1998 if (!pImage)
1999 {
2000 rc = VERR_NO_MEMORY;
2001 break;
2002 }
2003
2004 /*
2005 * Read the image configuration.
2006 */
2007 rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
2008 if (RT_FAILURE(rc))
2009 {
2010 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2011 N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
2012 break;
2013 }
2014
2015 rc = CFGMR3QueryStringAlloc(pCurNode, "Format", &pszFormat);
2016 if (RT_FAILURE(rc))
2017 {
2018 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2019 N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
2020 break;
2021 }
2022
2023 bool fMergeSource;
2024 rc = CFGMR3QueryBoolDef(pCurNode, "MergeSource", &fMergeSource, false);
2025 if (RT_FAILURE(rc))
2026 {
2027 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2028 N_("DrvVD: Configuration error: Querying \"MergeSource\" as boolean failed"));
2029 break;
2030 }
2031 if (fMergeSource)
2032 {
2033 if (pThis->uMergeSource == VD_LAST_IMAGE)
2034 pThis->uMergeSource = iImageIdx;
2035 else
2036 {
2037 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2038 N_("DrvVD: Configuration error: Multiple \"MergeSource\" occurrences"));
2039 break;
2040 }
2041 }
2042
2043 bool fMergeTarget;
2044 rc = CFGMR3QueryBoolDef(pCurNode, "MergeTarget", &fMergeTarget, false);
2045 if (RT_FAILURE(rc))
2046 {
2047 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2048 N_("DrvVD: Configuration error: Querying \"MergeTarget\" as boolean failed"));
2049 break;
2050 }
2051 if (fMergeTarget)
2052 {
2053 if (pThis->uMergeTarget == VD_LAST_IMAGE)
2054 pThis->uMergeTarget = iImageIdx;
2055 else
2056 {
2057 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2058 N_("DrvVD: Configuration error: Multiple \"MergeTarget\" occurrences"));
2059 break;
2060 }
2061 }
2062
2063 PCFGMNODE pCfgVDConfig = CFGMR3GetChild(pCurNode, "VDConfig");
2064 rc = VDInterfaceAdd(&pImage->VDIConfig, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
2065 &pThis->VDIConfigCallbacks, pCfgVDConfig, &pImage->pVDIfsImage);
2066 AssertRC(rc);
2067
2068 /*
2069 * Open the image.
2070 */
2071 unsigned uOpenFlags;
2072 if (fReadOnly || pThis->fTempReadOnly || iLevel != 0)
2073 uOpenFlags = VD_OPEN_FLAGS_READONLY;
2074 else
2075 uOpenFlags = VD_OPEN_FLAGS_NORMAL;
2076 if (fHonorZeroWrites)
2077 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
2078 if (pThis->fAsyncIOSupported)
2079 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
2080 if (pThis->fShareable)
2081 uOpenFlags |= VD_OPEN_FLAGS_SHAREABLE;
2082
2083 /* Try to open backend in async I/O mode first. */
2084 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
2085 if (rc == VERR_NOT_SUPPORTED)
2086 {
2087 pThis->fAsyncIOSupported = false;
2088 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
2089 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
2090 }
2091
2092 if (RT_SUCCESS(rc))
2093 {
2094 Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
2095 iLevel, pszName,
2096 VDIsReadOnly(pThis->pDisk) ? "read-only" : "read-write"));
2097 if ( VDIsReadOnly(pThis->pDisk)
2098 && !fReadOnly
2099 && !fMaybeReadOnly
2100 && !pThis->fTempReadOnly
2101 && iLevel == 0)
2102 {
2103 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_VD_IMAGE_READ_ONLY, RT_SRC_POS,
2104 N_("Failed to open image '%s' for writing due to wrong permissions"),
2105 pszName);
2106 break;
2107 }
2108 }
2109 else
2110 {
2111 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
2112 N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName,
2113 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc);
2114 break;
2115 }
2116
2117
2118 MMR3HeapFree(pszName);
2119 pszName = NULL;
2120 MMR3HeapFree(pszFormat);
2121 pszFormat = NULL;
2122
2123 /* next */
2124 iLevel--;
2125 iImageIdx++;
2126 pCurNode = CFGMR3GetParent(pCurNode);
2127 }
2128
2129 if ( RT_SUCCESS(rc)
2130 && pThis->fMergePending
2131 && ( pThis->uMergeSource == VD_LAST_IMAGE
2132 || pThis->uMergeTarget == VD_LAST_IMAGE))
2133 {
2134 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2135 N_("DrvVD: Configuration error: Inconsistent image merge data"));
2136 }
2137
2138 /*
2139 * Register a load-done callback so we can undo TempReadOnly config before
2140 * we get to drvvdResume. Autoamtically deregistered upon destruction.
2141 */
2142 if (RT_SUCCESS(rc))
2143 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
2144 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
2145 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
2146 NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
2147
2148
2149 if (RT_FAILURE(rc))
2150 {
2151 if (VALID_PTR(pszName))
2152 MMR3HeapFree(pszName);
2153 if (VALID_PTR(pszFormat))
2154 MMR3HeapFree(pszFormat);
2155 /* drvvdDestruct does the rest. */
2156 }
2157
2158 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
2159 return rc;
2160}
2161
2162/**
2163 * VBox disk container media driver registration record.
2164 */
2165const PDMDRVREG g_DrvVD =
2166{
2167 /* u32Version */
2168 PDM_DRVREG_VERSION,
2169 /* szName */
2170 "VD",
2171 /* szRCMod */
2172 "",
2173 /* szR0Mod */
2174 "",
2175 /* pszDescription */
2176 "Generic VBox disk media driver.",
2177 /* fFlags */
2178 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
2179 /* fClass. */
2180 PDM_DRVREG_CLASS_MEDIA,
2181 /* cMaxInstances */
2182 ~0,
2183 /* cbInstance */
2184 sizeof(VBOXDISK),
2185 /* pfnConstruct */
2186 drvvdConstruct,
2187 /* pfnDestruct */
2188 drvvdDestruct,
2189 /* pfnRelocate */
2190 NULL,
2191 /* pfnIOCtl */
2192 NULL,
2193 /* pfnPowerOn */
2194 drvvdPowerOn,
2195 /* pfnReset */
2196 NULL,
2197 /* pfnSuspend */
2198 drvvdSuspend,
2199 /* pfnResume */
2200 drvvdResume,
2201 /* pfnAttach */
2202 NULL,
2203 /* pfnDetach */
2204 NULL,
2205 /* pfnPowerOff */
2206 drvvdPowerOff,
2207 /* pfnSoftReset */
2208 NULL,
2209 /* u32EndVersion */
2210 PDM_DRVREG_VERSION
2211};
2212
Note: See TracBrowser for help on using the repository browser.

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