VirtualBox

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

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

Storage: Implement offical support for other disk types like DVD and floppy images. DMG images can be used now without hacks

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

© 2023 Oracle
ContactPrivacy policyTerms of Use