VirtualBox

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

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

DrvVD: Implement alternate select interface for Windows XP to avoid the 15ms delay when waiting for the socket to become writable

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