VirtualBox

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

Last change on this file since 55871 was 55871, checked in by vboxsync, 10 years ago

Storage/DrvVD: Fix VM hang during power off because of an order mismatch in the driver termination for the iSCSI over internal network case. DevINIP is destructed before DrvVD and closing the iSCSI connection fails. Moved closing of the disk to the power off instead of destruction stage.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 114.7 KB
Line 
1/* $Id: DrvVD.cpp 55871 2015-05-15 07:50:49Z vboxsync $ */
2/** @file
3 * DrvVD - Generic VBox disk media driver.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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/vd.h>
24#include <VBox/vmm/pdmdrv.h>
25#include <VBox/vmm/pdmasynccompletion.h>
26#include <VBox/vmm/pdmblkcache.h>
27#include <iprt/asm.h>
28#include <iprt/alloc.h>
29#include <iprt/assert.h>
30#include <iprt/uuid.h>
31#include <iprt/file.h>
32#include <iprt/string.h>
33#include <iprt/tcp.h>
34#include <iprt/semaphore.h>
35#include <iprt/sg.h>
36#include <iprt/poll.h>
37#include <iprt/pipe.h>
38#include <iprt/system.h>
39#include <iprt/memsafer.h>
40
41#ifdef VBOX_WITH_INIP
42/* All lwip header files are not C++ safe. So hack around this. */
43RT_C_DECLS_BEGIN
44#include <lwip/opt.h>
45#include <lwip/inet.h>
46#include <lwip/tcp.h>
47#include <lwip/sockets.h>
48# if LWIP_IPV6
49# include <lwip/inet6.h>
50# endif
51RT_C_DECLS_END
52#endif /* VBOX_WITH_INIP */
53
54#include "VBoxDD.h"
55
56#ifdef VBOX_WITH_INIP
57/* Small hack to get at lwIP initialized status */
58extern bool DevINIPConfigured(void);
59#endif /* VBOX_WITH_INIP */
60
61
62/*******************************************************************************
63* Defined types, constants and macros *
64*******************************************************************************/
65
66/** Converts a pointer to VBOXDISK::IMedia to a PVBOXDISK. */
67#define PDMIMEDIA_2_VBOXDISK(pInterface) \
68 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMedia)) )
69
70/** Converts a pointer to VBOXDISK::IMediaAsync to a PVBOXDISK. */
71#define PDMIMEDIAASYNC_2_VBOXDISK(pInterface) \
72 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMediaAsync)) )
73
74/**
75 * VBox disk container, image information, private part.
76 */
77
78typedef struct VBOXIMAGE
79{
80 /** Pointer to next image. */
81 struct VBOXIMAGE *pNext;
82 /** Pointer to list of VD interfaces. Per-image. */
83 PVDINTERFACE pVDIfsImage;
84 /** Configuration information interface. */
85 VDINTERFACECONFIG VDIfConfig;
86 /** TCP network stack interface. */
87 VDINTERFACETCPNET VDIfTcpNet;
88 /** I/O interface. */
89 VDINTERFACEIO VDIfIo;
90} VBOXIMAGE, *PVBOXIMAGE;
91
92/**
93 * Storage backend data.
94 */
95typedef struct DRVVDSTORAGEBACKEND
96{
97 /** PDM async completion end point. */
98 PPDMASYNCCOMPLETIONENDPOINT pEndpoint;
99 /** The template. */
100 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
101 /** Event semaphore for synchronous operations. */
102 RTSEMEVENT EventSem;
103 /** Flag whether a synchronous operation is currently pending. */
104 volatile bool fSyncIoPending;
105 /** Return code of the last completed request. */
106 int rcReqLast;
107 /** Callback routine */
108 PFNVDCOMPLETED pfnCompleted;
109} DRVVDSTORAGEBACKEND, *PDRVVDSTORAGEBACKEND;
110
111/**
112 * VBox disk container media main structure, private part.
113 *
114 * @implements PDMIMEDIA
115 * @implements PDMIMEDIAASYNC
116 * @implements VDINTERFACEERROR
117 * @implements VDINTERFACETCPNET
118 * @implements VDINTERFACEASYNCIO
119 * @implements VDINTERFACECONFIG
120 */
121typedef struct VBOXDISK
122{
123 /** The VBox disk container. */
124 PVBOXHDD pDisk;
125 /** The media interface. */
126 PDMIMEDIA IMedia;
127 /** Media port. */
128 PPDMIMEDIAPORT pDrvMediaPort;
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 /** Error interface. */
138 VDINTERFACEERROR VDIfError;
139 /** Thread synchronization interface. */
140 VDINTERFACETHREADSYNC VDIfThreadSync;
141
142 /** Flag whether opened disk supports async I/O operations. */
143 bool fAsyncIOSupported;
144 /** The async media interface. */
145 PDMIMEDIAASYNC IMediaAsync;
146 /** The async media port interface above. */
147 PPDMIMEDIAASYNCPORT pDrvMediaAsyncPort;
148 /** Pointer to the list of data we need to keep per image. */
149 PVBOXIMAGE pImages;
150 /** Flag whether the media should allow concurrent open for writing. */
151 bool fShareable;
152 /** Flag whether a merge operation has been set up. */
153 bool fMergePending;
154 /** Synchronization to prevent destruction before merge finishes. */
155 RTSEMFASTMUTEX MergeCompleteMutex;
156 /** Synchronization between merge and other image accesses. */
157 RTSEMRW MergeLock;
158 /** Source image index for merging. */
159 unsigned uMergeSource;
160 /** Target image index for merging. */
161 unsigned uMergeTarget;
162
163 /** Flag whether boot acceleration is enabled. */
164 bool fBootAccelEnabled;
165 /** Flag whether boot acceleration is currently active. */
166 bool fBootAccelActive;
167 /** Size of the disk, used for read truncation. */
168 uint64_t cbDisk;
169 /** Size of the configured buffer. */
170 size_t cbBootAccelBuffer;
171 /** Start offset for which the buffer holds data. */
172 uint64_t offDisk;
173 /** Number of valid bytes in the buffer. */
174 size_t cbDataValid;
175 /** The disk buffer. */
176 uint8_t *pbData;
177 /** Bandwidth group the disk is assigned to. */
178 char *pszBwGroup;
179 /** Flag whether async I/O using the host cache is enabled. */
180 bool fAsyncIoWithHostCache;
181
182 /** I/O interface for a cache image. */
183 VDINTERFACEIO VDIfIoCache;
184 /** Interface list for the cache image. */
185 PVDINTERFACE pVDIfsCache;
186
187 /** The block cache handle if configured. */
188 PPDMBLKCACHE pBlkCache;
189
190 /** Cryptographic support
191 * @{ */
192 /** Pointer to the CFGM node containing the config of the crypto filter
193 * if enable. */
194 PCFGMNODE pCfgCrypto;
195 /** Config interface for the encryption filter. */
196 VDINTERFACECONFIG VDIfCfg;
197 /** Crypto interface for the encryption filter. */
198 VDINTERFACECRYPTO VDIfCrypto;
199 /** The secret key interface used to retrieve keys. */
200 PPDMISECKEY pIfSecKey;
201 /** The secret key helper interface used to notify about missing keys. */
202 PPDMISECKEYHLP pIfSecKeyHlp;
203 /** @} */
204} VBOXDISK, *PVBOXDISK;
205
206
207/*******************************************************************************
208* Internal Functions *
209*******************************************************************************/
210
211/**
212 * Internal: allocate new image descriptor and put it in the list
213 */
214static PVBOXIMAGE drvvdNewImage(PVBOXDISK pThis)
215{
216 AssertPtr(pThis);
217 PVBOXIMAGE pImage = (PVBOXIMAGE)RTMemAllocZ(sizeof(VBOXIMAGE));
218 if (pImage)
219 {
220 pImage->pVDIfsImage = NULL;
221 PVBOXIMAGE *pp = &pThis->pImages;
222 while (*pp != NULL)
223 pp = &(*pp)->pNext;
224 *pp = pImage;
225 pImage->pNext = NULL;
226 }
227
228 return pImage;
229}
230
231/**
232 * Internal: free the list of images descriptors.
233 */
234static void drvvdFreeImages(PVBOXDISK pThis)
235{
236 while (pThis->pImages != NULL)
237 {
238 PVBOXIMAGE p = pThis->pImages;
239 pThis->pImages = pThis->pImages->pNext;
240 RTMemFree(p);
241 }
242}
243
244
245/**
246 * Make the image temporarily read-only.
247 *
248 * @returns VBox status code.
249 * @param pThis The driver instance data.
250 */
251static int drvvdSetReadonly(PVBOXDISK pThis)
252{
253 int rc = VINF_SUCCESS;
254 if (!VDIsReadOnly(pThis->pDisk))
255 {
256 unsigned uOpenFlags;
257 rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
258 AssertRC(rc);
259 uOpenFlags |= VD_OPEN_FLAGS_READONLY;
260 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
261 AssertRC(rc);
262 pThis->fTempReadOnly = true;
263 }
264 return rc;
265}
266
267
268/**
269 * Undo the temporary read-only status of the image.
270 *
271 * @returns VBox status code.
272 * @param pThis The driver instance data.
273 */
274static int drvvdSetWritable(PVBOXDISK pThis)
275{
276 int rc = VINF_SUCCESS;
277 if (pThis->fTempReadOnly)
278 {
279 unsigned uOpenFlags;
280 rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
281 AssertRC(rc);
282 uOpenFlags &= ~VD_OPEN_FLAGS_READONLY;
283 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
284 if (RT_SUCCESS(rc))
285 pThis->fTempReadOnly = false;
286 else
287 AssertRC(rc);
288 }
289 return rc;
290}
291
292
293/*******************************************************************************
294* Error reporting callback *
295*******************************************************************************/
296
297static void drvvdErrorCallback(void *pvUser, int rc, RT_SRC_POS_DECL,
298 const char *pszFormat, va_list va)
299{
300 PPDMDRVINS pDrvIns = (PPDMDRVINS)pvUser;
301 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
302 if (pThis->fErrorUseRuntime)
303 /* We must not pass VMSETRTERR_FLAGS_FATAL as it could lead to a
304 * deadlock: We are probably executed in a thread context != EMT
305 * and the EM thread would wait until every thread is suspended
306 * but we would wait for the EM thread ... */
307
308 PDMDrvHlpVMSetRuntimeErrorV(pDrvIns, /* fFlags=*/ 0, "DrvVD", pszFormat, va);
309 else
310 PDMDrvHlpVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va);
311}
312
313/*******************************************************************************
314* VD Async I/O interface implementation *
315*******************************************************************************/
316
317#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
318
319static DECLCALLBACK(void) drvvdAsyncTaskCompleted(PPDMDRVINS pDrvIns, void *pvTemplateUser, void *pvUser, int rcReq)
320{
321 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
322 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pvTemplateUser;
323
324 LogFlowFunc(("pDrvIns=%#p pvTemplateUser=%#p pvUser=%#p rcReq=%d\n",
325 pDrvIns, pvTemplateUser, pvUser, rcReq));
326
327 if (pStorageBackend->fSyncIoPending)
328 {
329 Assert(!pvUser);
330 pStorageBackend->rcReqLast = rcReq;
331 ASMAtomicWriteBool(&pStorageBackend->fSyncIoPending, false);
332 RTSemEventSignal(pStorageBackend->EventSem);
333 }
334 else
335 {
336 int rc;
337
338 AssertPtr(pvUser);
339
340 AssertPtr(pStorageBackend->pfnCompleted);
341 rc = pStorageBackend->pfnCompleted(pvUser, rcReq);
342 AssertRC(rc);
343 }
344}
345
346static DECLCALLBACK(int) drvvdAsyncIOOpen(void *pvUser, const char *pszLocation,
347 uint32_t fOpen,
348 PFNVDCOMPLETED pfnCompleted,
349 void **ppStorage)
350{
351 PVBOXDISK pThis = (PVBOXDISK)pvUser;
352 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)RTMemAllocZ(sizeof(DRVVDSTORAGEBACKEND));
353 int rc = VINF_SUCCESS;
354
355 if (pStorageBackend)
356 {
357 pStorageBackend->fSyncIoPending = false;
358 pStorageBackend->rcReqLast = VINF_SUCCESS;
359 pStorageBackend->pfnCompleted = pfnCompleted;
360
361 rc = RTSemEventCreate(&pStorageBackend->EventSem);
362 if (RT_SUCCESS(rc))
363 {
364 rc = PDMDrvHlpAsyncCompletionTemplateCreate(pThis->pDrvIns, &pStorageBackend->pTemplate,
365 drvvdAsyncTaskCompleted, pStorageBackend, "AsyncTaskCompleted");
366 if (RT_SUCCESS(rc))
367 {
368 uint32_t fFlags = (fOpen & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ
369 ? PDMACEP_FILE_FLAGS_READ_ONLY
370 : 0;
371 if (pThis->fShareable)
372 {
373 Assert((fOpen & RTFILE_O_DENY_MASK) == RTFILE_O_DENY_NONE);
374
375 fFlags |= PDMACEP_FILE_FLAGS_DONT_LOCK;
376 }
377 if (pThis->fAsyncIoWithHostCache)
378 fFlags |= PDMACEP_FILE_FLAGS_HOST_CACHE_ENABLED;
379
380 rc = PDMR3AsyncCompletionEpCreateForFile(&pStorageBackend->pEndpoint,
381 pszLocation, fFlags,
382 pStorageBackend->pTemplate);
383
384 if (RT_SUCCESS(rc))
385 {
386 if (pThis->pszBwGroup)
387 rc = PDMR3AsyncCompletionEpSetBwMgr(pStorageBackend->pEndpoint, pThis->pszBwGroup);
388
389 if (RT_SUCCESS(rc))
390 {
391 LogFlow(("drvvdAsyncIOOpen: Successfully opened '%s'; fOpen=%#x pStorage=%p\n",
392 pszLocation, fOpen, pStorageBackend));
393 *ppStorage = pStorageBackend;
394 return VINF_SUCCESS;
395 }
396
397 PDMR3AsyncCompletionEpClose(pStorageBackend->pEndpoint);
398 }
399
400 PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate);
401 }
402 RTSemEventDestroy(pStorageBackend->EventSem);
403 }
404 RTMemFree(pStorageBackend);
405 }
406 else
407 rc = VERR_NO_MEMORY;
408
409 return rc;
410}
411
412static DECLCALLBACK(int) drvvdAsyncIOClose(void *pvUser, void *pStorage)
413{
414 PVBOXDISK pThis = (PVBOXDISK)pvUser;
415 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
416
417 PDMR3AsyncCompletionEpClose(pStorageBackend->pEndpoint);
418 PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate);
419 RTSemEventDestroy(pStorageBackend->EventSem);
420 RTMemFree(pStorageBackend);
421
422 return VINF_SUCCESS;;
423}
424
425static DECLCALLBACK(int) drvvdAsyncIOReadSync(void *pvUser, void *pStorage, uint64_t uOffset,
426 void *pvBuf, size_t cbRead, size_t *pcbRead)
427{
428 PVBOXDISK pThis = (PVBOXDISK)pvUser;
429 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
430 RTSGSEG DataSeg;
431 PPDMASYNCCOMPLETIONTASK pTask;
432
433 bool fOld = ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
434 Assert(!fOld);
435 DataSeg.cbSeg = cbRead;
436 DataSeg.pvSeg = pvBuf;
437
438 int rc = PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbRead, NULL, &pTask);
439 if (RT_FAILURE(rc))
440 return rc;
441
442 if (rc == VINF_AIO_TASK_PENDING)
443 {
444 /* Wait */
445 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
446 AssertRC(rc);
447 }
448 else
449 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
450
451 if (pcbRead)
452 *pcbRead = cbRead;
453
454 return pStorageBackend->rcReqLast;
455}
456
457static DECLCALLBACK(int) drvvdAsyncIOWriteSync(void *pvUser, void *pStorage, uint64_t uOffset,
458 const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
459{
460 PVBOXDISK pThis = (PVBOXDISK)pvUser;
461 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
462 RTSGSEG DataSeg;
463 PPDMASYNCCOMPLETIONTASK pTask;
464
465 bool fOld = ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
466 Assert(!fOld);
467 DataSeg.cbSeg = cbWrite;
468 DataSeg.pvSeg = (void *)pvBuf;
469
470 int rc = PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbWrite, NULL, &pTask);
471 if (RT_FAILURE(rc))
472 return rc;
473
474 if (rc == VINF_AIO_TASK_PENDING)
475 {
476 /* Wait */
477 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
478 AssertRC(rc);
479 }
480 else
481 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
482
483 if (pcbWritten)
484 *pcbWritten = cbWrite;
485
486 return pStorageBackend->rcReqLast;
487}
488
489static DECLCALLBACK(int) drvvdAsyncIOFlushSync(void *pvUser, void *pStorage)
490{
491 PVBOXDISK pThis = (PVBOXDISK)pvUser;
492 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
493 PPDMASYNCCOMPLETIONTASK pTask;
494
495 LogFlowFunc(("pvUser=%#p pStorage=%#p\n", pvUser, pStorage));
496
497 bool fOld = ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
498 Assert(!fOld);
499
500 int rc = PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, NULL, &pTask);
501 if (RT_FAILURE(rc))
502 return rc;
503
504 if (rc == VINF_AIO_TASK_PENDING)
505 {
506 /* Wait */
507 LogFlowFunc(("Waiting for flush to complete\n"));
508 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
509 AssertRC(rc);
510 }
511 else
512 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
513
514 return pStorageBackend->rcReqLast;
515}
516
517static DECLCALLBACK(int) drvvdAsyncIOReadAsync(void *pvUser, void *pStorage, uint64_t uOffset,
518 PCRTSGSEG paSegments, size_t cSegments,
519 size_t cbRead, void *pvCompletion,
520 void **ppTask)
521{
522 PVBOXDISK pThis = (PVBOXDISK)pvUser;
523 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
524
525 int rc = PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, paSegments, (unsigned)cSegments, cbRead,
526 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
527 if (rc == VINF_AIO_TASK_PENDING)
528 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
529
530 return rc;
531}
532
533static DECLCALLBACK(int) drvvdAsyncIOWriteAsync(void *pvUser, void *pStorage, uint64_t uOffset,
534 PCRTSGSEG paSegments, size_t cSegments,
535 size_t cbWrite, void *pvCompletion,
536 void **ppTask)
537{
538 PVBOXDISK pThis = (PVBOXDISK)pvUser;
539 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
540
541 int rc = PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, paSegments, (unsigned)cSegments, cbWrite,
542 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
543 if (rc == VINF_AIO_TASK_PENDING)
544 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
545
546 return rc;
547}
548
549static DECLCALLBACK(int) drvvdAsyncIOFlushAsync(void *pvUser, void *pStorage,
550 void *pvCompletion, void **ppTask)
551{
552 PVBOXDISK pThis = (PVBOXDISK)pvUser;
553 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
554
555 int rc = PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, pvCompletion,
556 (PPPDMASYNCCOMPLETIONTASK)ppTask);
557 if (rc == VINF_AIO_TASK_PENDING)
558 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
559
560 return rc;
561}
562
563static DECLCALLBACK(int) drvvdAsyncIOGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
564{
565 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
566 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
567
568 return PDMR3AsyncCompletionEpGetSize(pStorageBackend->pEndpoint, pcbSize);
569}
570
571static DECLCALLBACK(int) drvvdAsyncIOSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
572{
573 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
574 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
575
576 return PDMR3AsyncCompletionEpSetSize(pStorageBackend->pEndpoint, cbSize);
577}
578
579#endif /* VBOX_WITH_PDM_ASYNC_COMPLETION */
580
581
582/*******************************************************************************
583* VD Thread Synchronization interface implementation *
584*******************************************************************************/
585
586static DECLCALLBACK(int) drvvdThreadStartRead(void *pvUser)
587{
588 PVBOXDISK pThis = (PVBOXDISK)pvUser;
589
590 return RTSemRWRequestRead(pThis->MergeLock, RT_INDEFINITE_WAIT);
591}
592
593static DECLCALLBACK(int) drvvdThreadFinishRead(void *pvUser)
594{
595 PVBOXDISK pThis = (PVBOXDISK)pvUser;
596
597 return RTSemRWReleaseRead(pThis->MergeLock);
598}
599
600static DECLCALLBACK(int) drvvdThreadStartWrite(void *pvUser)
601{
602 PVBOXDISK pThis = (PVBOXDISK)pvUser;
603
604 return RTSemRWRequestWrite(pThis->MergeLock, RT_INDEFINITE_WAIT);
605}
606
607static DECLCALLBACK(int) drvvdThreadFinishWrite(void *pvUser)
608{
609 PVBOXDISK pThis = (PVBOXDISK)pvUser;
610
611 return RTSemRWReleaseWrite(pThis->MergeLock);
612}
613
614
615/*******************************************************************************
616* VD Configuration interface implementation *
617*******************************************************************************/
618
619static bool drvvdCfgAreKeysValid(void *pvUser, const char *pszzValid)
620{
621 return CFGMR3AreValuesValid((PCFGMNODE)pvUser, pszzValid);
622}
623
624static int drvvdCfgQuerySize(void *pvUser, const char *pszName, size_t *pcb)
625{
626 return CFGMR3QuerySize((PCFGMNODE)pvUser, pszName, pcb);
627}
628
629static int drvvdCfgQuery(void *pvUser, const char *pszName, char *pszString, size_t cchString)
630{
631 return CFGMR3QueryString((PCFGMNODE)pvUser, pszName, pszString, cchString);
632}
633
634static int drvvdCfgQueryBytes(void *pvUser, const char *pszName, void *ppvData, size_t cbData)
635{
636 return CFGMR3QueryBytes((PCFGMNODE)pvUser, pszName, ppvData, cbData);
637}
638
639
640/*******************************************************************************
641* VD Crypto interface implementation for the encryption support *
642*******************************************************************************/
643
644static DECLCALLBACK(int) drvvdCryptoKeyRetain(void *pvUser, const char *pszId, const uint8_t **ppbKey, size_t *pcbKey)
645{
646 PVBOXDISK pThis = (PVBOXDISK)pvUser;
647 int rc = VINF_SUCCESS;
648
649 AssertPtr(pThis->pIfSecKey);
650 if (pThis->pIfSecKey)
651 rc = pThis->pIfSecKey->pfnKeyRetain(pThis->pIfSecKey, pszId, ppbKey, pcbKey);
652 else
653 rc = VERR_NOT_SUPPORTED;
654
655 return rc;
656}
657
658static DECLCALLBACK(int) drvvdCryptoKeyRelease(void *pvUser, const char *pszId)
659{
660 PVBOXDISK pThis = (PVBOXDISK)pvUser;
661 int rc = VINF_SUCCESS;
662
663 AssertPtr(pThis->pIfSecKey);
664 if (pThis->pIfSecKey)
665 rc = pThis->pIfSecKey->pfnKeyRelease(pThis->pIfSecKey, pszId);
666 else
667 rc = VERR_NOT_SUPPORTED;
668
669 return rc;
670}
671
672static DECLCALLBACK(int) drvvdCryptoKeyStorePasswordRetain(void *pvUser, const char *pszId, const char **ppszPassword)
673{
674 PVBOXDISK pThis = (PVBOXDISK)pvUser;
675 int rc = VINF_SUCCESS;
676
677 AssertPtr(pThis->pIfSecKey);
678 if (pThis->pIfSecKey)
679 rc = pThis->pIfSecKey->pfnPasswordRetain(pThis->pIfSecKey, pszId, ppszPassword);
680 else
681 rc = VERR_NOT_SUPPORTED;
682
683 return rc;
684}
685
686static DECLCALLBACK(int) drvvdCryptoKeyStorePasswordRelease(void *pvUser, const char *pszId)
687{
688 PVBOXDISK pThis = (PVBOXDISK)pvUser;
689 int rc = VINF_SUCCESS;
690
691 AssertPtr(pThis->pIfSecKey);
692 if (pThis->pIfSecKey)
693 rc = pThis->pIfSecKey->pfnPasswordRelease(pThis->pIfSecKey, pszId);
694 else
695 rc = VERR_NOT_SUPPORTED;
696
697 return rc;
698}
699
700#ifdef VBOX_WITH_INIP
701/*******************************************************************************
702* VD TCP network stack interface implementation - INIP case *
703*******************************************************************************/
704
705/**
706 * vvl: this structure duplicate meaning of sockaddr,
707 * perhaps it'd be better to get rid of it.
708 */
709typedef union INIPSOCKADDRUNION
710{
711 struct sockaddr Addr;
712 struct sockaddr_in Ipv4;
713#if LWIP_IPV6
714 struct sockaddr_in6 Ipv6;
715#endif
716} INIPSOCKADDRUNION;
717
718typedef struct INIPSOCKET
719{
720 int hSock;
721} INIPSOCKET, *PINIPSOCKET;
722
723static DECLCALLBACK(int) drvvdINIPFlush(VDSOCKET Sock);
724
725/** @copydoc VDINTERFACETCPNET::pfnSocketCreate */
726static DECLCALLBACK(int) drvvdINIPSocketCreate(uint32_t fFlags, PVDSOCKET pSock)
727{
728 PINIPSOCKET pSocketInt = NULL;
729
730 /*
731 * The extended select method is not supported because it is impossible to wakeup
732 * the thread.
733 */
734 if (fFlags & VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT)
735 return VERR_NOT_SUPPORTED;
736
737 pSocketInt = (PINIPSOCKET)RTMemAllocZ(sizeof(INIPSOCKET));
738 if (pSocketInt)
739 {
740 pSocketInt->hSock = INT32_MAX;
741 *pSock = (VDSOCKET)pSocketInt;
742 return VINF_SUCCESS;
743 }
744
745 return VERR_NO_MEMORY;
746}
747
748/** @copydoc VDINTERFACETCPNET::pfnSocketCreate */
749static DECLCALLBACK(int) drvvdINIPSocketDestroy(VDSOCKET Sock)
750{
751 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
752
753 RTMemFree(pSocketInt);
754 return VINF_SUCCESS;
755}
756
757/** @copydoc VDINTERFACETCPNET::pfnClientConnect */
758static DECLCALLBACK(int) drvvdINIPClientConnect(VDSOCKET Sock, const char *pszAddress, uint32_t uPort,
759 RTMSINTERVAL cMillies)
760{
761 int rc = VINF_SUCCESS;
762 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
763 int iInetFamily = PF_INET;
764 struct in_addr ip;
765#if LWIP_IPV6
766 ip6_addr_t ip6;
767#endif
768
769 NOREF(cMillies); /** LwIP doesn't support connect timeout. */
770
771 /* Check whether lwIP is set up in this VM instance. */
772 if (!DevINIPConfigured())
773 {
774 LogRelFunc(("no IP stack\n"));
775 return VERR_NET_HOST_UNREACHABLE;
776 }
777 /* Resolve hostname. As there is no standard resolver for lwIP yet,
778 * just accept numeric IP addresses for now. */
779#if LWIP_IPV6
780 if (inet6_aton(pszAddress, &ip6))
781 iInetFamily = PF_INET6;
782 else /* concatination with if */
783#endif
784 if (!lwip_inet_aton(pszAddress, &ip))
785 {
786 LogRelFunc(("cannot resolve IP %s\n", pszAddress));
787 return VERR_NET_HOST_UNREACHABLE;
788 }
789 /* Create socket and connect. */
790 int iSock = lwip_socket(iInetFamily, SOCK_STREAM, 0);
791 if (iSock != -1)
792 {
793 struct sockaddr *pSockAddr = NULL;
794 struct sockaddr_in InAddr = {0};
795#if LWIP_IPV6
796 struct sockaddr_in6 In6Addr = {0};
797#endif
798 if (iInetFamily == PF_INET)
799 {
800 InAddr.sin_family = AF_INET;
801 InAddr.sin_port = htons(uPort);
802 InAddr.sin_addr = ip;
803 InAddr.sin_len = sizeof(InAddr);
804 pSockAddr = (struct sockaddr *)&InAddr;
805 }
806#if LWIP_IPV6
807 else
808 {
809 In6Addr.sin6_family = AF_INET6;
810 In6Addr.sin6_port = htons(uPort);
811 memcpy(&In6Addr.sin6_addr, &ip6, sizeof(ip6));
812 In6Addr.sin6_len = sizeof(In6Addr);
813 pSockAddr = (struct sockaddr *)&In6Addr;
814 }
815#endif
816 if ( pSockAddr
817 && !lwip_connect(iSock, pSockAddr, pSockAddr->sa_len))
818 {
819 pSocketInt->hSock = iSock;
820 return VINF_SUCCESS;
821 }
822 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
823 lwip_close(iSock);
824 }
825 else
826 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
827 return rc;
828}
829
830/** @copydoc VDINTERFACETCPNET::pfnClientClose */
831static DECLCALLBACK(int) drvvdINIPClientClose(VDSOCKET Sock)
832{
833 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
834
835 lwip_close(pSocketInt->hSock);
836 pSocketInt->hSock = INT32_MAX;
837 return VINF_SUCCESS; /** @todo real solution needed */
838}
839
840/** @copydoc VDINTERFACETCPNET::pfnIsClientConnected */
841static DECLCALLBACK(bool) drvvdINIPIsClientConnected(VDSOCKET Sock)
842{
843 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
844
845 return pSocketInt->hSock != INT32_MAX;
846}
847
848/** @copydoc VDINTERFACETCPNET::pfnSelectOne */
849static DECLCALLBACK(int) drvvdINIPSelectOne(VDSOCKET Sock, RTMSINTERVAL cMillies)
850{
851 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
852 fd_set fdsetR;
853 FD_ZERO(&fdsetR);
854 FD_SET((uintptr_t)pSocketInt->hSock, &fdsetR);
855 fd_set fdsetE = fdsetR;
856
857 int rc;
858 if (cMillies == RT_INDEFINITE_WAIT)
859 rc = lwip_select(pSocketInt->hSock + 1, &fdsetR, NULL, &fdsetE, NULL);
860 else
861 {
862 struct timeval timeout;
863 timeout.tv_sec = cMillies / 1000;
864 timeout.tv_usec = (cMillies % 1000) * 1000;
865 rc = lwip_select(pSocketInt->hSock + 1, &fdsetR, NULL, &fdsetE, &timeout);
866 }
867 if (rc > 0)
868 return VINF_SUCCESS;
869 if (rc == 0)
870 return VERR_TIMEOUT;
871 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
872}
873
874/** @copydoc VDINTERFACETCPNET::pfnRead */
875static DECLCALLBACK(int) drvvdINIPRead(VDSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
876{
877 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
878
879 /* Do params checking */
880 if (!pvBuffer || !cbBuffer)
881 {
882 AssertMsgFailed(("Invalid params\n"));
883 return VERR_INVALID_PARAMETER;
884 }
885
886 /*
887 * Read loop.
888 * If pcbRead is NULL we have to fill the entire buffer!
889 */
890 size_t cbRead = 0;
891 size_t cbToRead = cbBuffer;
892 for (;;)
893 {
894 /** @todo this clipping here is just in case (the send function
895 * needed it, so I added it here, too). Didn't investigate if this
896 * really has issues. Better be safe than sorry. */
897 ssize_t cbBytesRead = lwip_recv(pSocketInt->hSock, (char *)pvBuffer + cbRead,
898 RT_MIN(cbToRead, 32768), 0);
899 if (cbBytesRead < 0)
900 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
901 if (cbBytesRead == 0 && errno) /** @todo r=bird: lwip_recv will not touch errno on Windows. This may apply to other hosts as well */
902 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
903 if (pcbRead)
904 {
905 /* return partial data */
906 *pcbRead = cbBytesRead;
907 break;
908 }
909
910 /* read more? */
911 cbRead += cbBytesRead;
912 if (cbRead == cbBuffer)
913 break;
914
915 /* next */
916 cbToRead = cbBuffer - cbRead;
917 }
918
919 return VINF_SUCCESS;
920}
921
922/** @copydoc VDINTERFACETCPNET::pfnWrite */
923static DECLCALLBACK(int) drvvdINIPWrite(VDSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
924{
925 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
926
927 do
928 {
929 /** @todo lwip send only supports up to 65535 bytes in a single
930 * send (stupid limitation buried in the code), so make sure we
931 * don't get any wraparounds. This should be moved to DevINIP
932 * stack interface once that's implemented. */
933 ssize_t cbWritten = lwip_send(pSocketInt->hSock, (void *)pvBuffer,
934 RT_MIN(cbBuffer, 32768), 0);
935 if (cbWritten < 0)
936 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
937 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%d cbBuffer=%d\n",
938 cbWritten, cbBuffer));
939 cbBuffer -= cbWritten;
940 pvBuffer = (const char *)pvBuffer + cbWritten;
941 } while (cbBuffer);
942
943 return VINF_SUCCESS;
944}
945
946/** @copydoc VDINTERFACETCPNET::pfnSgWrite */
947static DECLCALLBACK(int) drvvdINIPSgWrite(VDSOCKET Sock, PCRTSGBUF pSgBuf)
948{
949 int rc = VINF_SUCCESS;
950
951 /* This is an extremely crude emulation, however it's good enough
952 * for our iSCSI code. INIP has no sendmsg(). */
953 for (unsigned i = 0; i < pSgBuf->cSegs; i++)
954 {
955 rc = drvvdINIPWrite(Sock, pSgBuf->paSegs[i].pvSeg,
956 pSgBuf->paSegs[i].cbSeg);
957 if (RT_FAILURE(rc))
958 break;
959 }
960 if (RT_SUCCESS(rc))
961 drvvdINIPFlush(Sock);
962
963 return rc;
964}
965
966/** @copydoc VDINTERFACETCPNET::pfnFlush */
967static DECLCALLBACK(int) drvvdINIPFlush(VDSOCKET Sock)
968{
969 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
970
971 int fFlag = 1;
972 lwip_setsockopt(pSocketInt->hSock, IPPROTO_TCP, TCP_NODELAY,
973 (const char *)&fFlag, sizeof(fFlag));
974 fFlag = 0;
975 lwip_setsockopt(pSocketInt->hSock, IPPROTO_TCP, TCP_NODELAY,
976 (const char *)&fFlag, sizeof(fFlag));
977 return VINF_SUCCESS;
978}
979
980/** @copydoc VDINTERFACETCPNET::pfnSetSendCoalescing */
981static DECLCALLBACK(int) drvvdINIPSetSendCoalescing(VDSOCKET Sock, bool fEnable)
982{
983 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
984
985 int fFlag = fEnable ? 0 : 1;
986 lwip_setsockopt(pSocketInt->hSock, IPPROTO_TCP, TCP_NODELAY,
987 (const char *)&fFlag, sizeof(fFlag));
988 return VINF_SUCCESS;
989}
990
991/** @copydoc VDINTERFACETCPNET::pfnGetLocalAddress */
992static DECLCALLBACK(int) drvvdINIPGetLocalAddress(VDSOCKET Sock, PRTNETADDR pAddr)
993{
994 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
995 INIPSOCKADDRUNION u;
996 socklen_t cbAddr = sizeof(u);
997 RT_ZERO(u);
998 if (!lwip_getsockname(pSocketInt->hSock, &u.Addr, &cbAddr))
999 {
1000 /*
1001 * Convert the address.
1002 */
1003 if ( cbAddr == sizeof(struct sockaddr_in)
1004 && u.Addr.sa_family == AF_INET)
1005 {
1006 RT_ZERO(*pAddr);
1007 pAddr->enmType = RTNETADDRTYPE_IPV4;
1008 pAddr->uPort = RT_N2H_U16(u.Ipv4.sin_port);
1009 pAddr->uAddr.IPv4.u = u.Ipv4.sin_addr.s_addr;
1010 }
1011#if LWIP_IPV6
1012 else if ( cbAddr == sizeof(struct sockaddr_in6)
1013 && u.Addr.sa_family == AF_INET6)
1014 {
1015 RT_ZERO(*pAddr);
1016 pAddr->enmType = RTNETADDRTYPE_IPV6;
1017 pAddr->uPort = RT_N2H_U16(u.Ipv6.sin6_port);
1018 memcpy(&pAddr->uAddr.IPv6, &u.Ipv6.sin6_addr, sizeof(RTNETADDRIPV6));
1019 }
1020#endif
1021 else
1022 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
1023 return VINF_SUCCESS;
1024 }
1025 return VERR_NET_OPERATION_NOT_SUPPORTED;
1026}
1027
1028/** @copydoc VDINTERFACETCPNET::pfnGetPeerAddress */
1029static DECLCALLBACK(int) drvvdINIPGetPeerAddress(VDSOCKET Sock, PRTNETADDR pAddr)
1030{
1031 PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
1032 INIPSOCKADDRUNION u;
1033 socklen_t cbAddr = sizeof(u);
1034 RT_ZERO(u);
1035 if (!lwip_getpeername(pSocketInt->hSock, &u.Addr, &cbAddr))
1036 {
1037 /*
1038 * Convert the address.
1039 */
1040 if ( cbAddr == sizeof(struct sockaddr_in)
1041 && u.Addr.sa_family == AF_INET)
1042 {
1043 RT_ZERO(*pAddr);
1044 pAddr->enmType = RTNETADDRTYPE_IPV4;
1045 pAddr->uPort = RT_N2H_U16(u.Ipv4.sin_port);
1046 pAddr->uAddr.IPv4.u = u.Ipv4.sin_addr.s_addr;
1047 }
1048#if LWIP_IPV6
1049 else if ( cbAddr == sizeof(struct sockaddr_in6)
1050 && u.Addr.sa_family == AF_INET6)
1051 {
1052 RT_ZERO(*pAddr);
1053 pAddr->enmType = RTNETADDRTYPE_IPV6;
1054 pAddr->uPort = RT_N2H_U16(u.Ipv6.sin6_port);
1055 memcpy(&pAddr->uAddr.IPv6, &u.Ipv6.sin6_addr, sizeof(RTNETADDRIPV6));
1056 }
1057#endif
1058 else
1059 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
1060 return VINF_SUCCESS;
1061 }
1062 return VERR_NET_OPERATION_NOT_SUPPORTED;
1063}
1064
1065/** @copydoc VDINTERFACETCPNET::pfnSelectOneEx */
1066static DECLCALLBACK(int) drvvdINIPSelectOneEx(VDSOCKET Sock, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies)
1067{
1068 AssertMsgFailed(("Not supported!\n"));
1069 return VERR_NOT_SUPPORTED;
1070}
1071
1072/** @copydoc VDINTERFACETCPNET::pfnPoke */
1073static DECLCALLBACK(int) drvvdINIPPoke(VDSOCKET Sock)
1074{
1075 AssertMsgFailed(("Not supported!\n"));
1076 return VERR_NOT_SUPPORTED;
1077}
1078
1079#endif /* VBOX_WITH_INIP */
1080
1081
1082/*******************************************************************************
1083* VD TCP network stack interface implementation - Host TCP case *
1084*******************************************************************************/
1085
1086/**
1087 * Socket data.
1088 */
1089typedef struct VDSOCKETINT
1090{
1091 /** IPRT socket handle. */
1092 RTSOCKET hSocket;
1093 /** Pollset with the wakeup pipe and socket. */
1094 RTPOLLSET hPollSet;
1095 /** Pipe endpoint - read (in the pollset). */
1096 RTPIPE hPipeR;
1097 /** Pipe endpoint - write. */
1098 RTPIPE hPipeW;
1099 /** Flag whether the thread was woken up. */
1100 volatile bool fWokenUp;
1101 /** Flag whether the thread is waiting in the select call. */
1102 volatile bool fWaiting;
1103 /** Old event mask. */
1104 uint32_t fEventsOld;
1105} VDSOCKETINT, *PVDSOCKETINT;
1106
1107/** Pollset id of the socket. */
1108#define VDSOCKET_POLL_ID_SOCKET 0
1109/** Pollset id of the pipe. */
1110#define VDSOCKET_POLL_ID_PIPE 1
1111
1112/** @copydoc VDINTERFACETCPNET::pfnSocketCreate */
1113static DECLCALLBACK(int) drvvdTcpSocketCreate(uint32_t fFlags, PVDSOCKET pSock)
1114{
1115 int rc = VINF_SUCCESS;
1116 int rc2 = VINF_SUCCESS;
1117 PVDSOCKETINT pSockInt = NULL;
1118
1119 pSockInt = (PVDSOCKETINT)RTMemAllocZ(sizeof(VDSOCKETINT));
1120 if (!pSockInt)
1121 return VERR_NO_MEMORY;
1122
1123 pSockInt->hSocket = NIL_RTSOCKET;
1124 pSockInt->hPollSet = NIL_RTPOLLSET;
1125 pSockInt->hPipeR = NIL_RTPIPE;
1126 pSockInt->hPipeW = NIL_RTPIPE;
1127 pSockInt->fWokenUp = false;
1128 pSockInt->fWaiting = false;
1129
1130 if (fFlags & VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT)
1131 {
1132 /* Init pipe and pollset. */
1133 rc = RTPipeCreate(&pSockInt->hPipeR, &pSockInt->hPipeW, 0);
1134 if (RT_SUCCESS(rc))
1135 {
1136 rc = RTPollSetCreate(&pSockInt->hPollSet);
1137 if (RT_SUCCESS(rc))
1138 {
1139 rc = RTPollSetAddPipe(pSockInt->hPollSet, pSockInt->hPipeR,
1140 RTPOLL_EVT_READ, VDSOCKET_POLL_ID_PIPE);
1141 if (RT_SUCCESS(rc))
1142 {
1143 *pSock = pSockInt;
1144 return VINF_SUCCESS;
1145 }
1146
1147 RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_PIPE);
1148 rc2 = RTPollSetDestroy(pSockInt->hPollSet);
1149 AssertRC(rc2);
1150 }
1151
1152 rc2 = RTPipeClose(pSockInt->hPipeR);
1153 AssertRC(rc2);
1154 rc2 = RTPipeClose(pSockInt->hPipeW);
1155 AssertRC(rc2);
1156 }
1157 }
1158 else
1159 {
1160 *pSock = pSockInt;
1161 return VINF_SUCCESS;
1162 }
1163
1164 RTMemFree(pSockInt);
1165
1166 return rc;
1167}
1168
1169/** @copydoc VDINTERFACETCPNET::pfnSocketDestroy */
1170static DECLCALLBACK(int) drvvdTcpSocketDestroy(VDSOCKET Sock)
1171{
1172 int rc = VINF_SUCCESS;
1173 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1174
1175 /* Destroy the pipe and pollset if necessary. */
1176 if (pSockInt->hPollSet != NIL_RTPOLLSET)
1177 {
1178 if (pSockInt->hSocket != NIL_RTSOCKET)
1179 {
1180 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
1181 Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
1182 }
1183 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_PIPE);
1184 AssertRC(rc);
1185 rc = RTPollSetDestroy(pSockInt->hPollSet);
1186 AssertRC(rc);
1187 rc = RTPipeClose(pSockInt->hPipeR);
1188 AssertRC(rc);
1189 rc = RTPipeClose(pSockInt->hPipeW);
1190 AssertRC(rc);
1191 }
1192
1193 if (pSockInt->hSocket != NIL_RTSOCKET)
1194 rc = RTTcpClientCloseEx(pSockInt->hSocket, false /*fGracefulShutdown*/);
1195
1196 RTMemFree(pSockInt);
1197
1198 return rc;
1199}
1200
1201/** @copydoc VDINTERFACETCPNET::pfnClientConnect */
1202static DECLCALLBACK(int) drvvdTcpClientConnect(VDSOCKET Sock, const char *pszAddress, uint32_t uPort,
1203 RTMSINTERVAL cMillies)
1204{
1205 int rc = VINF_SUCCESS;
1206 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1207
1208 rc = RTTcpClientConnectEx(pszAddress, uPort, &pSockInt->hSocket, cMillies, NULL);
1209 if (RT_SUCCESS(rc))
1210 {
1211 /* Add to the pollset if required. */
1212 if (pSockInt->hPollSet != NIL_RTPOLLSET)
1213 {
1214 pSockInt->fEventsOld = RTPOLL_EVT_READ | RTPOLL_EVT_WRITE | RTPOLL_EVT_ERROR;
1215
1216 rc = RTPollSetAddSocket(pSockInt->hPollSet, pSockInt->hSocket,
1217 pSockInt->fEventsOld, VDSOCKET_POLL_ID_SOCKET);
1218 }
1219
1220 if (RT_SUCCESS(rc))
1221 return VINF_SUCCESS;
1222
1223 rc = RTTcpClientCloseEx(pSockInt->hSocket, false /*fGracefulShutdown*/);
1224 }
1225
1226 return rc;
1227}
1228
1229/** @copydoc VDINTERFACETCPNET::pfnClientClose */
1230static DECLCALLBACK(int) drvvdTcpClientClose(VDSOCKET Sock)
1231{
1232 int rc = VINF_SUCCESS;
1233 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1234
1235 if (pSockInt->hPollSet != NIL_RTPOLLSET)
1236 {
1237 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
1238 AssertRC(rc);
1239 }
1240
1241 rc = RTTcpClientCloseEx(pSockInt->hSocket, false /*fGracefulShutdown*/);
1242 pSockInt->hSocket = NIL_RTSOCKET;
1243
1244 return rc;
1245}
1246
1247/** @copydoc VDINTERFACETCPNET::pfnIsClientConnected */
1248static DECLCALLBACK(bool) drvvdTcpIsClientConnected(VDSOCKET Sock)
1249{
1250 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1251
1252 return pSockInt->hSocket != NIL_RTSOCKET;
1253}
1254
1255/** @copydoc VDINTERFACETCPNET::pfnSelectOne */
1256static DECLCALLBACK(int) drvvdTcpSelectOne(VDSOCKET Sock, RTMSINTERVAL cMillies)
1257{
1258 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1259
1260 return RTTcpSelectOne(pSockInt->hSocket, cMillies);
1261}
1262
1263/** @copydoc VDINTERFACETCPNET::pfnRead */
1264static DECLCALLBACK(int) drvvdTcpRead(VDSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
1265{
1266 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1267
1268 return RTTcpRead(pSockInt->hSocket, pvBuffer, cbBuffer, pcbRead);
1269}
1270
1271/** @copydoc VDINTERFACETCPNET::pfnWrite */
1272static DECLCALLBACK(int) drvvdTcpWrite(VDSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
1273{
1274 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1275
1276 return RTTcpWrite(pSockInt->hSocket, pvBuffer, cbBuffer);
1277}
1278
1279/** @copydoc VDINTERFACETCPNET::pfnSgWrite */
1280static DECLCALLBACK(int) drvvdTcpSgWrite(VDSOCKET Sock, PCRTSGBUF pSgBuf)
1281{
1282 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1283
1284 return RTTcpSgWrite(pSockInt->hSocket, pSgBuf);
1285}
1286
1287/** @copydoc VDINTERFACETCPNET::pfnReadNB */
1288static DECLCALLBACK(int) drvvdTcpReadNB(VDSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
1289{
1290 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1291
1292 return RTTcpReadNB(pSockInt->hSocket, pvBuffer, cbBuffer, pcbRead);
1293}
1294
1295/** @copydoc VDINTERFACETCPNET::pfnWriteNB */
1296static DECLCALLBACK(int) drvvdTcpWriteNB(VDSOCKET Sock, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten)
1297{
1298 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1299
1300 return RTTcpWriteNB(pSockInt->hSocket, pvBuffer, cbBuffer, pcbWritten);
1301}
1302
1303/** @copydoc VDINTERFACETCPNET::pfnSgWriteNB */
1304static DECLCALLBACK(int) drvvdTcpSgWriteNB(VDSOCKET Sock, PRTSGBUF pSgBuf, size_t *pcbWritten)
1305{
1306 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1307
1308 return RTTcpSgWriteNB(pSockInt->hSocket, pSgBuf, pcbWritten);
1309}
1310
1311/** @copydoc VDINTERFACETCPNET::pfnFlush */
1312static DECLCALLBACK(int) drvvdTcpFlush(VDSOCKET Sock)
1313{
1314 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1315
1316 return RTTcpFlush(pSockInt->hSocket);
1317}
1318
1319/** @copydoc VDINTERFACETCPNET::pfnSetSendCoalescing */
1320static DECLCALLBACK(int) drvvdTcpSetSendCoalescing(VDSOCKET Sock, bool fEnable)
1321{
1322 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1323
1324 return RTTcpSetSendCoalescing(pSockInt->hSocket, fEnable);
1325}
1326
1327/** @copydoc VDINTERFACETCPNET::pfnGetLocalAddress */
1328static DECLCALLBACK(int) drvvdTcpGetLocalAddress(VDSOCKET Sock, PRTNETADDR pAddr)
1329{
1330 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1331
1332 return RTTcpGetLocalAddress(pSockInt->hSocket, pAddr);
1333}
1334
1335/** @copydoc VDINTERFACETCPNET::pfnGetPeerAddress */
1336static DECLCALLBACK(int) drvvdTcpGetPeerAddress(VDSOCKET Sock, PRTNETADDR pAddr)
1337{
1338 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1339
1340 return RTTcpGetPeerAddress(pSockInt->hSocket, pAddr);
1341}
1342
1343static int drvvdTcpSelectOneExPoll(VDSOCKET Sock, uint32_t fEvents,
1344 uint32_t *pfEvents, RTMSINTERVAL cMillies)
1345{
1346 int rc = VINF_SUCCESS;
1347 uint32_t id = 0;
1348 uint32_t fEventsRecv = 0;
1349 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1350
1351 *pfEvents = 0;
1352
1353 if ( pSockInt->fEventsOld != fEvents
1354 && pSockInt->hSocket != NIL_RTSOCKET)
1355 {
1356 uint32_t fPollEvents = 0;
1357
1358 if (fEvents & VD_INTERFACETCPNET_EVT_READ)
1359 fPollEvents |= RTPOLL_EVT_READ;
1360 if (fEvents & VD_INTERFACETCPNET_EVT_WRITE)
1361 fPollEvents |= RTPOLL_EVT_WRITE;
1362 if (fEvents & VD_INTERFACETCPNET_EVT_ERROR)
1363 fPollEvents |= RTPOLL_EVT_ERROR;
1364
1365 rc = RTPollSetEventsChange(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET, fPollEvents);
1366 if (RT_FAILURE(rc))
1367 return rc;
1368
1369 pSockInt->fEventsOld = fEvents;
1370 }
1371
1372 ASMAtomicXchgBool(&pSockInt->fWaiting, true);
1373 if (ASMAtomicXchgBool(&pSockInt->fWokenUp, false))
1374 {
1375 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
1376 return VERR_INTERRUPTED;
1377 }
1378
1379 rc = RTPoll(pSockInt->hPollSet, cMillies, &fEventsRecv, &id);
1380 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
1381
1382 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
1383
1384 if (RT_SUCCESS(rc))
1385 {
1386 if (id == VDSOCKET_POLL_ID_SOCKET)
1387 {
1388 fEventsRecv &= RTPOLL_EVT_VALID_MASK;
1389
1390 if (fEventsRecv & RTPOLL_EVT_READ)
1391 *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
1392 if (fEventsRecv & RTPOLL_EVT_WRITE)
1393 *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
1394 if (fEventsRecv & RTPOLL_EVT_ERROR)
1395 *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
1396 }
1397 else
1398 {
1399 size_t cbRead = 0;
1400 uint8_t abBuf[10];
1401 Assert(id == VDSOCKET_POLL_ID_PIPE);
1402 Assert((fEventsRecv & RTPOLL_EVT_VALID_MASK) == RTPOLL_EVT_READ);
1403
1404 /* We got interrupted, drain the pipe. */
1405 rc = RTPipeRead(pSockInt->hPipeR, abBuf, sizeof(abBuf), &cbRead);
1406 AssertRC(rc);
1407
1408 ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
1409
1410 rc = VERR_INTERRUPTED;
1411 }
1412 }
1413
1414 return rc;
1415}
1416
1417/** @copydoc VDINTERFACETCPNET::pfnSelectOneEx */
1418static DECLCALLBACK(int) drvvdTcpSelectOneExNoPoll(VDSOCKET Sock, uint32_t fEvents,
1419 uint32_t *pfEvents, RTMSINTERVAL cMillies)
1420{
1421 int rc = VINF_SUCCESS;
1422 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1423
1424 *pfEvents = 0;
1425
1426 ASMAtomicXchgBool(&pSockInt->fWaiting, true);
1427 if (ASMAtomicXchgBool(&pSockInt->fWokenUp, false))
1428 {
1429 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
1430 return VERR_INTERRUPTED;
1431 }
1432
1433 if ( pSockInt->hSocket == NIL_RTSOCKET
1434 || !fEvents)
1435 {
1436 /*
1437 * Only the pipe is configured or the caller doesn't wait for a socket event,
1438 * wait until there is something to read from the pipe.
1439 */
1440 size_t cbRead = 0;
1441 char ch = 0;
1442 rc = RTPipeReadBlocking(pSockInt->hPipeR, &ch, 1, &cbRead);
1443 if (RT_SUCCESS(rc))
1444 {
1445 Assert(cbRead == 1);
1446 rc = VERR_INTERRUPTED;
1447 ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
1448 }
1449 }
1450 else
1451 {
1452 uint32_t fSelectEvents = 0;
1453
1454 if (fEvents & VD_INTERFACETCPNET_EVT_READ)
1455 fSelectEvents |= RTSOCKET_EVT_READ;
1456 if (fEvents & VD_INTERFACETCPNET_EVT_WRITE)
1457 fSelectEvents |= RTSOCKET_EVT_WRITE;
1458 if (fEvents & VD_INTERFACETCPNET_EVT_ERROR)
1459 fSelectEvents |= RTSOCKET_EVT_ERROR;
1460
1461 if (fEvents & VD_INTERFACETCPNET_HINT_INTERRUPT)
1462 {
1463 uint32_t fEventsRecv = 0;
1464
1465 /* Make sure the socket is not in the pollset. */
1466 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
1467 Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
1468
1469 for (;;)
1470 {
1471 uint32_t id = 0;
1472 rc = RTPoll(pSockInt->hPollSet, 5, &fEvents, &id);
1473 if (rc == VERR_TIMEOUT)
1474 {
1475 /* Check the socket. */
1476 rc = RTTcpSelectOneEx(pSockInt->hSocket, fSelectEvents, &fEventsRecv, 0);
1477 if (RT_SUCCESS(rc))
1478 {
1479 if (fEventsRecv & RTSOCKET_EVT_READ)
1480 *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
1481 if (fEventsRecv & RTSOCKET_EVT_WRITE)
1482 *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
1483 if (fEventsRecv & RTSOCKET_EVT_ERROR)
1484 *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
1485 break; /* Quit */
1486 }
1487 else if (rc != VERR_TIMEOUT)
1488 break;
1489 }
1490 else if (RT_SUCCESS(rc))
1491 {
1492 size_t cbRead = 0;
1493 uint8_t abBuf[10];
1494 Assert(id == VDSOCKET_POLL_ID_PIPE);
1495 Assert((fEventsRecv & RTPOLL_EVT_VALID_MASK) == RTPOLL_EVT_READ);
1496
1497 /* We got interrupted, drain the pipe. */
1498 rc = RTPipeRead(pSockInt->hPipeR, abBuf, sizeof(abBuf), &cbRead);
1499 AssertRC(rc);
1500
1501 ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
1502
1503 rc = VERR_INTERRUPTED;
1504 break;
1505 }
1506 else
1507 break;
1508 }
1509 }
1510 else /* The caller waits for a socket event. */
1511 {
1512 uint32_t fEventsRecv = 0;
1513
1514 /* Loop until we got woken up or a socket event occurred. */
1515 for (;;)
1516 {
1517 /** @todo find an adaptive wait algorithm based on the
1518 * number of wakeups in the past. */
1519 rc = RTTcpSelectOneEx(pSockInt->hSocket, fSelectEvents, &fEventsRecv, 5);
1520 if (rc == VERR_TIMEOUT)
1521 {
1522 /* Check if there is an event pending. */
1523 size_t cbRead = 0;
1524 char ch = 0;
1525 rc = RTPipeRead(pSockInt->hPipeR, &ch, 1, &cbRead);
1526 if (RT_SUCCESS(rc) && rc != VINF_TRY_AGAIN)
1527 {
1528 Assert(cbRead == 1);
1529 rc = VERR_INTERRUPTED;
1530 ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
1531 break; /* Quit */
1532 }
1533 else
1534 Assert(rc == VINF_TRY_AGAIN);
1535 }
1536 else if (RT_SUCCESS(rc))
1537 {
1538 if (fEventsRecv & RTSOCKET_EVT_READ)
1539 *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
1540 if (fEventsRecv & RTSOCKET_EVT_WRITE)
1541 *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
1542 if (fEventsRecv & RTSOCKET_EVT_ERROR)
1543 *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
1544 break; /* Quit */
1545 }
1546 else
1547 break;
1548 }
1549 }
1550 }
1551
1552 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
1553
1554 return rc;
1555}
1556
1557/** @copydoc VDINTERFACETCPNET::pfnPoke */
1558static DECLCALLBACK(int) drvvdTcpPoke(VDSOCKET Sock)
1559{
1560 int rc = VINF_SUCCESS;
1561 size_t cbWritten = 0;
1562 PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
1563
1564 ASMAtomicXchgBool(&pSockInt->fWokenUp, true);
1565
1566 if (ASMAtomicReadBool(&pSockInt->fWaiting))
1567 {
1568 rc = RTPipeWrite(pSockInt->hPipeW, "", 1, &cbWritten);
1569 Assert(RT_SUCCESS(rc) || cbWritten == 0);
1570 }
1571
1572 return VINF_SUCCESS;
1573}
1574
1575/**
1576 * Checks the prerequisites for encrypted I/O.
1577 *
1578 * @returns VBox status code.
1579 * @param pThis The VD driver instance data.
1580 */
1581static int drvvdKeyCheckPrereqs(PVBOXDISK pThis)
1582{
1583 if ( pThis->pCfgCrypto
1584 && !pThis->pIfSecKey)
1585 {
1586 AssertPtr(pThis->pIfSecKeyHlp);
1587 pThis->pIfSecKeyHlp->pfnKeyMissingNotify(pThis->pIfSecKeyHlp);
1588
1589 int rc = PDMDrvHlpVMSetRuntimeError(pThis->pDrvIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DrvVD_DEKMISSING",
1590 N_("VD: The DEK for this disk is missing"));
1591 AssertRC(rc);
1592 return VERR_VD_DEK_MISSING;
1593 }
1594
1595 return VINF_SUCCESS;
1596}
1597
1598/*******************************************************************************
1599* Media interface methods *
1600*******************************************************************************/
1601
1602/** @copydoc PDMIMEDIA::pfnRead */
1603static DECLCALLBACK(int) drvvdRead(PPDMIMEDIA pInterface,
1604 uint64_t off, void *pvBuf, size_t cbRead)
1605{
1606 int rc = VINF_SUCCESS;
1607
1608 LogFlowFunc(("off=%#llx pvBuf=%p cbRead=%d\n", off, pvBuf, cbRead));
1609 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1610
1611 rc = drvvdKeyCheckPrereqs(pThis);
1612 if (RT_FAILURE(rc))
1613 return rc;
1614
1615 if (!pThis->fBootAccelActive)
1616 rc = VDRead(pThis->pDisk, off, pvBuf, cbRead);
1617 else
1618 {
1619 /* Can we serve the request from the buffer? */
1620 if ( off >= pThis->offDisk
1621 && off - pThis->offDisk < pThis->cbDataValid)
1622 {
1623 size_t cbToCopy = RT_MIN(cbRead, pThis->offDisk + pThis->cbDataValid - off);
1624
1625 memcpy(pvBuf, pThis->pbData + (off - pThis->offDisk), cbToCopy);
1626 cbRead -= cbToCopy;
1627 off += cbToCopy;
1628 pvBuf = (char *)pvBuf + cbToCopy;
1629 }
1630
1631 if ( cbRead > 0
1632 && cbRead < pThis->cbBootAccelBuffer)
1633 {
1634 /* Increase request to the buffer size and read. */
1635 pThis->cbDataValid = RT_MIN(pThis->cbDisk - off, pThis->cbBootAccelBuffer);
1636 pThis->offDisk = off;
1637 rc = VDRead(pThis->pDisk, off, pThis->pbData, pThis->cbDataValid);
1638 if (RT_FAILURE(rc))
1639 pThis->cbDataValid = 0;
1640 else
1641 memcpy(pvBuf, pThis->pbData, cbRead);
1642 }
1643 else if (cbRead >= pThis->cbBootAccelBuffer)
1644 {
1645 pThis->fBootAccelActive = false; /* Deactiviate */
1646 }
1647 }
1648
1649 if (RT_SUCCESS(rc))
1650 Log2(("%s: off=%#llx pvBuf=%p cbRead=%d\n%.*Rhxd\n", __FUNCTION__,
1651 off, pvBuf, cbRead, cbRead, pvBuf));
1652 LogFlowFunc(("returns %Rrc\n", rc));
1653 return rc;
1654}
1655
1656/** @copydoc PDMIMEDIA::pfnRead */
1657static DECLCALLBACK(int) drvvdReadPcBios(PPDMIMEDIA pInterface,
1658 uint64_t off, void *pvBuf, size_t cbRead)
1659{
1660 int rc = VINF_SUCCESS;
1661
1662 LogFlowFunc(("off=%#llx pvBuf=%p cbRead=%d\n", off, pvBuf, cbRead));
1663 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1664
1665 if ( pThis->pCfgCrypto
1666 && !pThis->pIfSecKey)
1667 return VERR_VD_DEK_MISSING;
1668
1669 if (!pThis->fBootAccelActive)
1670 rc = VDRead(pThis->pDisk, off, pvBuf, cbRead);
1671 else
1672 {
1673 /* Can we serve the request from the buffer? */
1674 if ( off >= pThis->offDisk
1675 && off - pThis->offDisk < pThis->cbDataValid)
1676 {
1677 size_t cbToCopy = RT_MIN(cbRead, pThis->offDisk + pThis->cbDataValid - off);
1678
1679 memcpy(pvBuf, pThis->pbData + (off - pThis->offDisk), cbToCopy);
1680 cbRead -= cbToCopy;
1681 off += cbToCopy;
1682 pvBuf = (char *)pvBuf + cbToCopy;
1683 }
1684
1685 if ( cbRead > 0
1686 && cbRead < pThis->cbBootAccelBuffer)
1687 {
1688 /* Increase request to the buffer size and read. */
1689 pThis->cbDataValid = RT_MIN(pThis->cbDisk - off, pThis->cbBootAccelBuffer);
1690 pThis->offDisk = off;
1691 rc = VDRead(pThis->pDisk, off, pThis->pbData, pThis->cbDataValid);
1692 if (RT_FAILURE(rc))
1693 pThis->cbDataValid = 0;
1694 else
1695 memcpy(pvBuf, pThis->pbData, cbRead);
1696 }
1697 else if (cbRead >= pThis->cbBootAccelBuffer)
1698 {
1699 pThis->fBootAccelActive = false; /* Deactiviate */
1700 }
1701 }
1702
1703 if (RT_SUCCESS(rc))
1704 Log2(("%s: off=%#llx pvBuf=%p cbRead=%d\n%.*Rhxd\n", __FUNCTION__,
1705 off, pvBuf, cbRead, cbRead, pvBuf));
1706 LogFlowFunc(("returns %Rrc\n", rc));
1707 return rc;
1708}
1709
1710
1711/** @copydoc PDMIMEDIA::pfnWrite */
1712static DECLCALLBACK(int) drvvdWrite(PPDMIMEDIA pInterface,
1713 uint64_t off, const void *pvBuf,
1714 size_t cbWrite)
1715{
1716 LogFlowFunc(("off=%#llx pvBuf=%p cbWrite=%d\n", off, pvBuf, cbWrite));
1717 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1718 Log2(("%s: off=%#llx pvBuf=%p cbWrite=%d\n%.*Rhxd\n", __FUNCTION__,
1719 off, pvBuf, cbWrite, cbWrite, pvBuf));
1720
1721 int rc = drvvdKeyCheckPrereqs(pThis);
1722 if (RT_FAILURE(rc))
1723 return rc;
1724
1725 /* Invalidate any buffer if boot acceleration is enabled. */
1726 if (pThis->fBootAccelActive)
1727 {
1728 pThis->cbDataValid = 0;
1729 pThis->offDisk = 0;
1730 }
1731
1732 rc = VDWrite(pThis->pDisk, off, pvBuf, cbWrite);
1733 LogFlowFunc(("returns %Rrc\n", rc));
1734 return rc;
1735}
1736
1737/** @copydoc PDMIMEDIA::pfnFlush */
1738static DECLCALLBACK(int) drvvdFlush(PPDMIMEDIA pInterface)
1739{
1740 LogFlowFunc(("\n"));
1741 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1742 int rc = VDFlush(pThis->pDisk);
1743 LogFlowFunc(("returns %Rrc\n", rc));
1744 return rc;
1745}
1746
1747/** @copydoc PDMIMEDIA::pfnMerge */
1748static DECLCALLBACK(int) drvvdMerge(PPDMIMEDIA pInterface,
1749 PFNSIMPLEPROGRESS pfnProgress,
1750 void *pvUser)
1751{
1752 LogFlowFunc(("\n"));
1753 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1754 int rc = VINF_SUCCESS;
1755
1756 /* Note: There is an unavoidable race between destruction and another
1757 * thread invoking this function. This is handled safely and gracefully by
1758 * atomically invalidating the lock handle in drvvdDestruct. */
1759 int rc2 = RTSemFastMutexRequest(pThis->MergeCompleteMutex);
1760 AssertRC(rc2);
1761 if (RT_SUCCESS(rc2) && pThis->fMergePending)
1762 {
1763 /* Take shortcut: PFNSIMPLEPROGRESS is exactly the same type as
1764 * PFNVDPROGRESS, so there's no need for a conversion function. */
1765 /** @todo maybe introduce a conversion which limits update frequency. */
1766 PVDINTERFACE pVDIfsOperation = NULL;
1767 VDINTERFACEPROGRESS VDIfProgress;
1768 VDIfProgress.pfnProgress = pfnProgress;
1769 rc2 = VDInterfaceAdd(&VDIfProgress.Core, "DrvVD_VDIProgress", VDINTERFACETYPE_PROGRESS,
1770 pvUser, sizeof(VDINTERFACEPROGRESS), &pVDIfsOperation);
1771 AssertRC(rc2);
1772 pThis->fMergePending = false;
1773 rc = VDMerge(pThis->pDisk, pThis->uMergeSource,
1774 pThis->uMergeTarget, pVDIfsOperation);
1775 }
1776 rc2 = RTSemFastMutexRelease(pThis->MergeCompleteMutex);
1777 AssertRC(rc2);
1778 LogFlowFunc(("returns %Rrc\n", rc));
1779 return rc;
1780}
1781
1782/** @copydoc PDMIMEDIA::pfnSetKey */
1783static DECLCALLBACK(int) drvvdSetSecKeyIf(PPDMIMEDIA pInterface, PPDMISECKEY pIfSecKey, PPDMISECKEYHLP pIfSecKeyHlp)
1784{
1785 LogFlowFunc(("\n"));
1786 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1787 int rc = VINF_SUCCESS;
1788
1789 if (pThis->pCfgCrypto)
1790 {
1791 PVDINTERFACE pVDIfFilter = NULL;
1792
1793 pThis->pIfSecKeyHlp = pIfSecKeyHlp;
1794
1795 if ( pThis->pIfSecKey
1796 && !pIfSecKey)
1797 {
1798 /* Unload the crypto filter first to make sure it doesn't access the keys anymore. */
1799 rc = VDFilterRemove(pThis->pDisk, VD_FILTER_FLAGS_DEFAULT);
1800 AssertRC(rc);
1801
1802 pThis->pIfSecKey = NULL;
1803 }
1804
1805 if ( pIfSecKey
1806 && RT_SUCCESS(rc))
1807 {
1808 pThis->pIfSecKey = pIfSecKey;
1809
1810 rc = VDInterfaceAdd(&pThis->VDIfCfg.Core, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
1811 pThis->pCfgCrypto, sizeof(VDINTERFACECONFIG), &pVDIfFilter);
1812 AssertRC(rc);
1813
1814 rc = VDInterfaceAdd(&pThis->VDIfCrypto.Core, "DrvVD_Crypto", VDINTERFACETYPE_CRYPTO,
1815 pThis, sizeof(VDINTERFACECRYPTO), &pVDIfFilter);
1816 AssertRC(rc);
1817
1818 /* Load the crypt filter plugin. */
1819 rc = VDFilterAdd(pThis->pDisk, "CRYPT", VD_FILTER_FLAGS_DEFAULT, pVDIfFilter);
1820 if (RT_FAILURE(rc))
1821 pThis->pIfSecKey = NULL;
1822 }
1823 }
1824 else
1825 rc = VERR_NOT_SUPPORTED;
1826
1827 LogFlowFunc(("returns %Rrc\n", rc));
1828 return rc;
1829}
1830
1831/** @copydoc PDMIMEDIA::pfnGetSize */
1832static DECLCALLBACK(uint64_t) drvvdGetSize(PPDMIMEDIA pInterface)
1833{
1834 LogFlowFunc(("\n"));
1835 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1836 uint64_t cb = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
1837 LogFlowFunc(("returns %#llx (%llu)\n", cb, cb));
1838 return cb;
1839}
1840
1841/** @copydoc PDMIMEDIA::pfnGetSectorSize */
1842static DECLCALLBACK(uint32_t) drvvdGetSectorSize(PPDMIMEDIA pInterface)
1843{
1844 LogFlowFunc(("\n"));
1845 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1846 uint32_t cb = VDGetSectorSize(pThis->pDisk, VD_LAST_IMAGE);
1847 LogFlowFunc(("returns %u\n", cb));
1848 return cb;
1849}
1850
1851/** @copydoc PDMIMEDIA::pfnIsReadOnly */
1852static DECLCALLBACK(bool) drvvdIsReadOnly(PPDMIMEDIA pInterface)
1853{
1854 LogFlowFunc(("\n"));
1855 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1856 bool f = VDIsReadOnly(pThis->pDisk);
1857 LogFlowFunc(("returns %d\n", f));
1858 return f;
1859}
1860
1861/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
1862static DECLCALLBACK(int) drvvdBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
1863 PPDMMEDIAGEOMETRY pPCHSGeometry)
1864{
1865 LogFlowFunc(("\n"));
1866 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1867 VDGEOMETRY geo;
1868 int rc = VDGetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, &geo);
1869 if (RT_SUCCESS(rc))
1870 {
1871 pPCHSGeometry->cCylinders = geo.cCylinders;
1872 pPCHSGeometry->cHeads = geo.cHeads;
1873 pPCHSGeometry->cSectors = geo.cSectors;
1874 }
1875 else
1876 {
1877 LogFunc(("geometry not available.\n"));
1878 rc = VERR_PDM_GEOMETRY_NOT_SET;
1879 }
1880 LogFlowFunc(("returns %Rrc (CHS=%d/%d/%d)\n",
1881 rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
1882 return rc;
1883}
1884
1885/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
1886static DECLCALLBACK(int) drvvdBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
1887 PCPDMMEDIAGEOMETRY pPCHSGeometry)
1888{
1889 LogFlowFunc(("CHS=%d/%d/%d\n",
1890 pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
1891 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1892 VDGEOMETRY geo;
1893 geo.cCylinders = pPCHSGeometry->cCylinders;
1894 geo.cHeads = pPCHSGeometry->cHeads;
1895 geo.cSectors = pPCHSGeometry->cSectors;
1896 int rc = VDSetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, &geo);
1897 if (rc == VERR_VD_GEOMETRY_NOT_SET)
1898 rc = VERR_PDM_GEOMETRY_NOT_SET;
1899 LogFlowFunc(("returns %Rrc\n", rc));
1900 return rc;
1901}
1902
1903/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
1904static DECLCALLBACK(int) drvvdBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
1905 PPDMMEDIAGEOMETRY pLCHSGeometry)
1906{
1907 LogFlowFunc(("\n"));
1908 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1909 VDGEOMETRY geo;
1910 int rc = VDGetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, &geo);
1911 if (RT_SUCCESS(rc))
1912 {
1913 pLCHSGeometry->cCylinders = geo.cCylinders;
1914 pLCHSGeometry->cHeads = geo.cHeads;
1915 pLCHSGeometry->cSectors = geo.cSectors;
1916 }
1917 else
1918 {
1919 LogFunc(("geometry not available.\n"));
1920 rc = VERR_PDM_GEOMETRY_NOT_SET;
1921 }
1922 LogFlowFunc(("returns %Rrc (CHS=%d/%d/%d)\n",
1923 rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
1924 return rc;
1925}
1926
1927/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
1928static DECLCALLBACK(int) drvvdBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
1929 PCPDMMEDIAGEOMETRY pLCHSGeometry)
1930{
1931 LogFlowFunc(("CHS=%d/%d/%d\n",
1932 pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
1933 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1934 VDGEOMETRY geo;
1935 geo.cCylinders = pLCHSGeometry->cCylinders;
1936 geo.cHeads = pLCHSGeometry->cHeads;
1937 geo.cSectors = pLCHSGeometry->cSectors;
1938 int rc = VDSetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, &geo);
1939 if (rc == VERR_VD_GEOMETRY_NOT_SET)
1940 rc = VERR_PDM_GEOMETRY_NOT_SET;
1941 LogFlowFunc(("returns %Rrc\n", rc));
1942 return rc;
1943}
1944
1945/** @copydoc PDMIMEDIA::pfnGetUuid */
1946static DECLCALLBACK(int) drvvdGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
1947{
1948 LogFlowFunc(("\n"));
1949 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1950 int rc = VDGetUuid(pThis->pDisk, 0, pUuid);
1951 LogFlowFunc(("returns %Rrc ({%RTuuid})\n", rc, pUuid));
1952 return rc;
1953}
1954
1955static DECLCALLBACK(int) drvvdDiscard(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges)
1956{
1957 LogFlowFunc(("\n"));
1958 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1959
1960 int rc = VDDiscardRanges(pThis->pDisk, paRanges, cRanges);
1961 LogFlowFunc(("returns %Rrc\n", rc));
1962 return rc;
1963}
1964
1965/** @copydoc PDMIMEDIA::pfnIoBufAlloc */
1966static DECLCALLBACK(int) drvvdIoBufAlloc(PPDMIMEDIA pInterface, size_t cb, void **ppvNew)
1967{
1968 LogFlowFunc(("\n"));
1969 int rc;
1970 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1971
1972 /* Configured encryption requires locked down memory. */
1973 if (pThis->pCfgCrypto)
1974 rc = RTMemSaferAllocZEx(ppvNew, cb, RTMEMSAFER_F_REQUIRE_NOT_PAGABLE);
1975 else
1976 {
1977 cb = RT_ALIGN_Z(cb, _4K);
1978 void *pvNew = RTMemPageAlloc(cb);
1979 if (RT_LIKELY(pvNew))
1980 {
1981 *ppvNew = pvNew;
1982 rc = VINF_SUCCESS;
1983 }
1984 else
1985 rc = VERR_NO_MEMORY;
1986 }
1987
1988 LogFlowFunc(("returns %Rrc\n", rc));
1989 return rc;
1990}
1991
1992/** @copydoc PDMIMEDIA::pfnIoBufFree */
1993static DECLCALLBACK(int) drvvdIoBufFree(PPDMIMEDIA pInterface, void *pv, size_t cb)
1994{
1995 LogFlowFunc(("\n"));
1996 int rc = VINF_SUCCESS;
1997 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
1998
1999 if (pThis->pCfgCrypto)
2000 RTMemSaferFree(pv, cb);
2001 else
2002 {
2003 cb = RT_ALIGN_Z(cb, _4K);
2004 RTMemPageFree(pv, cb);
2005 }
2006
2007 LogFlowFunc(("returns %Rrc\n", rc));
2008 return rc;
2009}
2010
2011
2012/*******************************************************************************
2013* Async Media interface methods *
2014*******************************************************************************/
2015
2016static void drvvdAsyncReqComplete(void *pvUser1, void *pvUser2, int rcReq)
2017{
2018 PVBOXDISK pThis = (PVBOXDISK)pvUser1;
2019
2020 if (!pThis->pBlkCache)
2021 {
2022 int rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort,
2023 pvUser2, rcReq);
2024 AssertRC(rc);
2025 }
2026 else
2027 PDMR3BlkCacheIoXferComplete(pThis->pBlkCache, (PPDMBLKCACHEIOXFER)pvUser2, rcReq);
2028}
2029
2030static DECLCALLBACK(int) drvvdStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
2031 PCRTSGSEG paSeg, unsigned cSeg,
2032 size_t cbRead, void *pvUser)
2033{
2034 LogFlowFunc(("uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d pvUser=%#p\n",
2035 uOffset, paSeg, cSeg, cbRead, pvUser));
2036 int rc = VINF_SUCCESS;
2037 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
2038
2039 rc = drvvdKeyCheckPrereqs(pThis);
2040 if (RT_FAILURE(rc))
2041 return rc;
2042
2043 pThis->fBootAccelActive = false;
2044
2045 RTSGBUF SgBuf;
2046 RTSgBufInit(&SgBuf, paSeg, cSeg);
2047 if (!pThis->pBlkCache)
2048 rc = VDAsyncRead(pThis->pDisk, uOffset, cbRead, &SgBuf,
2049 drvvdAsyncReqComplete, pThis, pvUser);
2050 else
2051 {
2052 rc = PDMR3BlkCacheRead(pThis->pBlkCache, uOffset, &SgBuf, cbRead, pvUser);
2053 if (rc == VINF_AIO_TASK_PENDING)
2054 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
2055 else if (rc == VINF_SUCCESS)
2056 rc = VINF_VD_ASYNC_IO_FINISHED;
2057 }
2058
2059 LogFlowFunc(("returns %Rrc\n", rc));
2060 return rc;
2061}
2062
2063static DECLCALLBACK(int) drvvdStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
2064 PCRTSGSEG paSeg, unsigned cSeg,
2065 size_t cbWrite, void *pvUser)
2066{
2067 LogFlowFunc(("uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d pvUser=%#p\n",
2068 uOffset, paSeg, cSeg, cbWrite, pvUser));
2069 int rc = VINF_SUCCESS;
2070 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
2071
2072 rc = drvvdKeyCheckPrereqs(pThis);
2073 if (RT_FAILURE(rc))
2074 return rc;
2075
2076 pThis->fBootAccelActive = false;
2077
2078 RTSGBUF SgBuf;
2079 RTSgBufInit(&SgBuf, paSeg, cSeg);
2080
2081 if (!pThis->pBlkCache)
2082 rc = VDAsyncWrite(pThis->pDisk, uOffset, cbWrite, &SgBuf,
2083 drvvdAsyncReqComplete, pThis, pvUser);
2084 else
2085 {
2086 rc = PDMR3BlkCacheWrite(pThis->pBlkCache, uOffset, &SgBuf, cbWrite, pvUser);
2087 if (rc == VINF_AIO_TASK_PENDING)
2088 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
2089 else if (rc == VINF_SUCCESS)
2090 rc = VINF_VD_ASYNC_IO_FINISHED;
2091 }
2092
2093 LogFlowFunc(("returns %Rrc\n", rc));
2094 return rc;
2095}
2096
2097static DECLCALLBACK(int) drvvdStartFlush(PPDMIMEDIAASYNC pInterface, void *pvUser)
2098{
2099 LogFlowFunc(("pvUser=%#p\n", pvUser));
2100 int rc = VINF_SUCCESS;
2101 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
2102
2103 if (!pThis->pBlkCache)
2104 rc = VDAsyncFlush(pThis->pDisk, drvvdAsyncReqComplete, pThis, pvUser);
2105 else
2106 {
2107 rc = PDMR3BlkCacheFlush(pThis->pBlkCache, pvUser);
2108 if (rc == VINF_AIO_TASK_PENDING)
2109 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
2110 else if (rc == VINF_SUCCESS)
2111 rc = VINF_VD_ASYNC_IO_FINISHED;
2112 }
2113 LogFlowFunc(("returns %Rrc\n", rc));
2114 return rc;
2115}
2116
2117static DECLCALLBACK(int) drvvdStartDiscard(PPDMIMEDIAASYNC pInterface, PCRTRANGE paRanges,
2118 unsigned cRanges, void *pvUser)
2119{
2120 int rc = VINF_SUCCESS;
2121 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
2122
2123 LogFlowFunc(("paRanges=%#p cRanges=%u pvUser=%#p\n",
2124 paRanges, cRanges, pvUser));
2125
2126 if (!pThis->pBlkCache)
2127 rc = VDAsyncDiscardRanges(pThis->pDisk, paRanges, cRanges, drvvdAsyncReqComplete,
2128 pThis, pvUser);
2129 else
2130 {
2131 rc = PDMR3BlkCacheDiscard(pThis->pBlkCache, paRanges, cRanges, pvUser);
2132 if (rc == VINF_AIO_TASK_PENDING)
2133 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
2134 else if (rc == VINF_SUCCESS)
2135 rc = VINF_VD_ASYNC_IO_FINISHED;
2136 }
2137 LogFlowFunc(("returns %Rrc\n", rc));
2138 return rc;
2139}
2140
2141/** @copydoc FNPDMBLKCACHEXFERCOMPLETEDRV */
2142static void drvvdBlkCacheXferComplete(PPDMDRVINS pDrvIns, void *pvUser, int rcReq)
2143{
2144 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2145
2146 int rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort,
2147 pvUser, rcReq);
2148 AssertRC(rc);
2149}
2150
2151/** @copydoc FNPDMBLKCACHEXFERENQUEUEDRV */
2152static int drvvdBlkCacheXferEnqueue(PPDMDRVINS pDrvIns,
2153 PDMBLKCACHEXFERDIR enmXferDir,
2154 uint64_t off, size_t cbXfer,
2155 PCRTSGBUF pcSgBuf, PPDMBLKCACHEIOXFER hIoXfer)
2156{
2157 int rc = VINF_SUCCESS;
2158 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2159
2160 Assert (!pThis->pCfgCrypto);
2161
2162 switch (enmXferDir)
2163 {
2164 case PDMBLKCACHEXFERDIR_READ:
2165 rc = VDAsyncRead(pThis->pDisk, off, cbXfer, pcSgBuf, drvvdAsyncReqComplete,
2166 pThis, hIoXfer);
2167 break;
2168 case PDMBLKCACHEXFERDIR_WRITE:
2169 rc = VDAsyncWrite(pThis->pDisk, off, cbXfer, pcSgBuf, drvvdAsyncReqComplete,
2170 pThis, hIoXfer);
2171 break;
2172 case PDMBLKCACHEXFERDIR_FLUSH:
2173 rc = VDAsyncFlush(pThis->pDisk, drvvdAsyncReqComplete, pThis, hIoXfer);
2174 break;
2175 default:
2176 AssertMsgFailed(("Invalid transfer type %d\n", enmXferDir));
2177 rc = VERR_INVALID_PARAMETER;
2178 }
2179
2180 if (rc == VINF_VD_ASYNC_IO_FINISHED)
2181 PDMR3BlkCacheIoXferComplete(pThis->pBlkCache, hIoXfer, VINF_SUCCESS);
2182 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
2183 PDMR3BlkCacheIoXferComplete(pThis->pBlkCache, hIoXfer, rc);
2184
2185 return VINF_SUCCESS;
2186}
2187
2188/** @copydoc FNPDMBLKCACHEXFERENQUEUEDISCARDDRV */
2189static int drvvdBlkCacheXferEnqueueDiscard(PPDMDRVINS pDrvIns, PCRTRANGE paRanges,
2190 unsigned cRanges, PPDMBLKCACHEIOXFER hIoXfer)
2191{
2192 int rc = VINF_SUCCESS;
2193 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2194
2195 rc = VDAsyncDiscardRanges(pThis->pDisk, paRanges, cRanges,
2196 drvvdAsyncReqComplete, pThis, hIoXfer);
2197
2198 if (rc == VINF_VD_ASYNC_IO_FINISHED)
2199 PDMR3BlkCacheIoXferComplete(pThis->pBlkCache, hIoXfer, VINF_SUCCESS);
2200 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
2201 PDMR3BlkCacheIoXferComplete(pThis->pBlkCache, hIoXfer, rc);
2202
2203 return VINF_SUCCESS;
2204}
2205
2206/**
2207 * Loads all configured plugins.
2208 *
2209 * @returns VBox status code.
2210 * @param pThis The disk instance.
2211 * @param pCfg CFGM node holding plugin list.
2212 */
2213static int drvvdLoadPlugins(PVBOXDISK pThis, PCFGMNODE pCfg)
2214{
2215 int rc = VINF_SUCCESS;
2216 PCFGMNODE pCfgPlugins = CFGMR3GetChild(pCfg, "Plugins");
2217
2218 if (pCfgPlugins)
2219 {
2220 PCFGMNODE pPluginCur = CFGMR3GetFirstChild(pCfgPlugins);
2221 while ( pPluginCur
2222 && RT_SUCCESS(rc))
2223 {
2224 char *pszPluginFilename = NULL;
2225 rc = CFGMR3QueryStringAlloc(pPluginCur, "Path", &pszPluginFilename);
2226 if (RT_SUCCESS(rc))
2227 rc = VDPluginLoadFromFilename(pszPluginFilename);
2228
2229 pPluginCur = CFGMR3GetNextChild(pPluginCur);
2230 }
2231 }
2232
2233 return rc;
2234}
2235
2236
2237/**
2238 * Sets up the disk filter chain.
2239 *
2240 * @returns VBox status code.
2241 * @param pThis The disk instance.
2242 * @param pCfg CFGM node holding the filter parameters.
2243 */
2244static int drvvdSetupFilters(PVBOXDISK pThis, PCFGMNODE pCfg)
2245{
2246 int rc = VINF_SUCCESS;
2247 PCFGMNODE pCfgFilter = CFGMR3GetChild(pCfg, "Filters");
2248
2249 if (pCfgFilter)
2250 {
2251 PCFGMNODE pCfgFilterConfig = CFGMR3GetChild(pCfgFilter, "VDConfig");
2252 char *pszFilterName = NULL;
2253 VDINTERFACECONFIG VDIfConfig;
2254 PVDINTERFACE pVDIfsFilter = NULL;
2255
2256 rc = CFGMR3QueryStringAlloc(pCfgFilter, "FilterName", &pszFilterName);
2257 if (RT_SUCCESS(rc))
2258 {
2259 VDIfConfig.pfnAreKeysValid = drvvdCfgAreKeysValid;
2260 VDIfConfig.pfnQuerySize = drvvdCfgQuerySize;
2261 VDIfConfig.pfnQuery = drvvdCfgQuery;
2262 VDIfConfig.pfnQueryBytes = drvvdCfgQueryBytes;
2263 rc = VDInterfaceAdd(&VDIfConfig.Core, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
2264 pCfgFilterConfig, sizeof(VDINTERFACECONFIG), &pVDIfsFilter);
2265 AssertRC(rc);
2266
2267 rc = VDFilterAdd(pThis->pDisk, pszFilterName, VD_FILTER_FLAGS_DEFAULT, pVDIfsFilter);
2268
2269 MMR3HeapFree(pszFilterName);
2270 }
2271 }
2272
2273 return rc;
2274}
2275
2276/*******************************************************************************
2277* Base interface methods *
2278*******************************************************************************/
2279
2280/**
2281 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2282 */
2283static DECLCALLBACK(void *) drvvdQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2284{
2285 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
2286 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2287
2288 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
2289 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
2290 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->fAsyncIOSupported ? &pThis->IMediaAsync : NULL);
2291 return NULL;
2292}
2293
2294
2295/*******************************************************************************
2296* Saved state notification methods *
2297*******************************************************************************/
2298
2299/**
2300 * Load done callback for re-opening the image writable during teleportation.
2301 *
2302 * This is called both for successful and failed load runs, we only care about
2303 * successful ones.
2304 *
2305 * @returns VBox status code.
2306 * @param pDrvIns The driver instance.
2307 * @param pSSM The saved state handle.
2308 */
2309static DECLCALLBACK(int) drvvdLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
2310{
2311 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2312 Assert(!pThis->fErrorUseRuntime);
2313
2314 /* Drop out if we don't have any work to do or if it's a failed load. */
2315 if ( !pThis->fTempReadOnly
2316 || RT_FAILURE(SSMR3HandleGetStatus(pSSM)))
2317 return VINF_SUCCESS;
2318
2319 int rc = drvvdSetWritable(pThis);
2320 if (RT_FAILURE(rc)) /** @todo does the bugger set any errors? */
2321 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
2322 N_("Failed to write lock the images"));
2323 return VINF_SUCCESS;
2324}
2325
2326
2327/*******************************************************************************
2328* Driver methods *
2329*******************************************************************************/
2330
2331/**
2332 * @copydoc FNPDMDRVPOWEROFF
2333 */
2334static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
2335{
2336 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
2337 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2338 LogFlowFunc(("\n"));
2339
2340 RTSEMFASTMUTEX mutex;
2341 ASMAtomicXchgHandle(&pThis->MergeCompleteMutex, NIL_RTSEMFASTMUTEX, &mutex);
2342 if (mutex != NIL_RTSEMFASTMUTEX)
2343 {
2344 /* Request the semaphore to wait until a potentially running merge
2345 * operation has been finished. */
2346 int rc = RTSemFastMutexRequest(mutex);
2347 AssertRC(rc);
2348 pThis->fMergePending = false;
2349 rc = RTSemFastMutexRelease(mutex);
2350 AssertRC(rc);
2351 rc = RTSemFastMutexDestroy(mutex);
2352 AssertRC(rc);
2353 }
2354
2355 if (RT_VALID_PTR(pThis->pBlkCache))
2356 {
2357 PDMR3BlkCacheRelease(pThis->pBlkCache);
2358 pThis->pBlkCache = NULL;
2359 }
2360
2361 if (RT_VALID_PTR(pThis->pDisk))
2362 {
2363 VDDestroy(pThis->pDisk);
2364 pThis->pDisk = NULL;
2365 }
2366 drvvdFreeImages(pThis);
2367}
2368
2369/**
2370 * VM resume notification that we use to undo what the temporary read-only image
2371 * mode set by drvvdSuspend.
2372 *
2373 * Also switch to runtime error mode if we're resuming after a state load
2374 * without having been powered on first.
2375 *
2376 * @param pDrvIns The driver instance data.
2377 *
2378 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
2379 * we're making assumptions about Main behavior here!
2380 */
2381static DECLCALLBACK(void) drvvdResume(PPDMDRVINS pDrvIns)
2382{
2383 LogFlowFunc(("\n"));
2384 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2385
2386 drvvdSetWritable(pThis);
2387 pThis->fErrorUseRuntime = true;
2388
2389 if (pThis->pBlkCache)
2390 {
2391 int rc = PDMR3BlkCacheResume(pThis->pBlkCache);
2392 AssertRC(rc);
2393 }
2394}
2395
2396/**
2397 * The VM is being suspended, temporarily change to read-only image mode.
2398 *
2399 * This is important for several reasons:
2400 * -# It makes sure that there are no pending writes to the image. Most
2401 * backends implements this by closing and reopening the image in read-only
2402 * mode.
2403 * -# It allows Main to read the images during snapshotting without having
2404 * to account for concurrent writes.
2405 * -# This is essential for making teleportation targets sharing images work
2406 * right. Both with regards to caching and with regards to file sharing
2407 * locks (RTFILE_O_DENY_*). (See also drvvdLoadDone.)
2408 *
2409 * @param pDrvIns The driver instance data.
2410 */
2411static DECLCALLBACK(void) drvvdSuspend(PPDMDRVINS pDrvIns)
2412{
2413 LogFlowFunc(("\n"));
2414 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2415
2416 if (pThis->pBlkCache)
2417 {
2418 int rc = PDMR3BlkCacheSuspend(pThis->pBlkCache);
2419 AssertRC(rc);
2420 }
2421
2422 drvvdSetReadonly(pThis);
2423}
2424
2425/**
2426 * VM PowerOn notification for undoing the TempReadOnly config option and
2427 * changing to runtime error mode.
2428 *
2429 * @param pDrvIns The driver instance data.
2430 *
2431 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
2432 * we're making assumptions about Main behavior here!
2433 */
2434static DECLCALLBACK(void) drvvdPowerOn(PPDMDRVINS pDrvIns)
2435{
2436 LogFlowFunc(("\n"));
2437 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2438 drvvdSetWritable(pThis);
2439 pThis->fErrorUseRuntime = true;
2440}
2441
2442/**
2443 * @copydoc FNPDMDRVRESET
2444 */
2445static DECLCALLBACK(void) drvvdReset(PPDMDRVINS pDrvIns)
2446{
2447 LogFlowFunc(("\n"));
2448 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2449
2450 if (pThis->pBlkCache)
2451 {
2452 int rc = PDMR3BlkCacheClear(pThis->pBlkCache);
2453 AssertRC(rc);
2454 }
2455
2456 if (pThis->fBootAccelEnabled)
2457 {
2458 pThis->fBootAccelActive = true;
2459 pThis->cbDataValid = 0;
2460 pThis->offDisk = 0;
2461 }
2462}
2463
2464/**
2465 * @copydoc FNPDMDRVDESTRUCT
2466 */
2467static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
2468{
2469 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
2470 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2471 LogFlowFunc(("\n"));
2472
2473 if (pThis->MergeLock != NIL_RTSEMRW)
2474 {
2475 int rc = RTSemRWDestroy(pThis->MergeLock);
2476 AssertRC(rc);
2477 pThis->MergeLock = NIL_RTSEMRW;
2478 }
2479 if (pThis->pbData)
2480 {
2481 RTMemFree(pThis->pbData);
2482 pThis->pbData = NULL;
2483 }
2484 if (pThis->pszBwGroup)
2485 {
2486 MMR3HeapFree(pThis->pszBwGroup);
2487 pThis->pszBwGroup = NULL;
2488 }
2489}
2490
2491/**
2492 * Construct a VBox disk media driver instance.
2493 *
2494 * @copydoc FNPDMDRVCONSTRUCT
2495 */
2496static DECLCALLBACK(int) drvvdConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
2497{
2498 LogFlowFunc(("\n"));
2499 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
2500 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
2501 int rc = VINF_SUCCESS;
2502 char *pszName = NULL; /**< The path of the disk image file. */
2503 char *pszFormat = NULL; /**< The format backed to use for this image. */
2504 char *pszCachePath = NULL; /**< The path to the cache image. */
2505 char *pszCacheFormat = NULL; /**< The format backend to use for the cache image. */
2506 bool fReadOnly; /**< True if the media is read-only. */
2507 bool fMaybeReadOnly; /**< True if the media may or may not be read-only. */
2508 bool fHonorZeroWrites; /**< True if zero blocks should be written. */
2509
2510 /*
2511 * Init the static parts.
2512 */
2513 pDrvIns->IBase.pfnQueryInterface = drvvdQueryInterface;
2514 pThis->pDrvIns = pDrvIns;
2515 pThis->fTempReadOnly = false;
2516 pThis->pDisk = NULL;
2517 pThis->fAsyncIOSupported = false;
2518 pThis->fShareable = false;
2519 pThis->fMergePending = false;
2520 pThis->MergeCompleteMutex = NIL_RTSEMFASTMUTEX;
2521 pThis->MergeLock = NIL_RTSEMRW;
2522 pThis->uMergeSource = VD_LAST_IMAGE;
2523 pThis->uMergeTarget = VD_LAST_IMAGE;
2524 pThis->pCfgCrypto = NULL;
2525 pThis->pIfSecKey = NULL;
2526
2527 /* IMedia */
2528 pThis->IMedia.pfnRead = drvvdRead;
2529 pThis->IMedia.pfnReadPcBios = drvvdReadPcBios;
2530 pThis->IMedia.pfnWrite = drvvdWrite;
2531 pThis->IMedia.pfnFlush = drvvdFlush;
2532 pThis->IMedia.pfnMerge = drvvdMerge;
2533 pThis->IMedia.pfnSetSecKeyIf = drvvdSetSecKeyIf;
2534 pThis->IMedia.pfnGetSize = drvvdGetSize;
2535 pThis->IMedia.pfnGetSectorSize = drvvdGetSectorSize;
2536 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly;
2537 pThis->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
2538 pThis->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
2539 pThis->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
2540 pThis->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
2541 pThis->IMedia.pfnGetUuid = drvvdGetUuid;
2542 pThis->IMedia.pfnDiscard = drvvdDiscard;
2543 pThis->IMedia.pfnIoBufAlloc = drvvdIoBufAlloc;
2544 pThis->IMedia.pfnIoBufFree = drvvdIoBufFree;
2545
2546 /* IMediaAsync */
2547 pThis->IMediaAsync.pfnStartRead = drvvdStartRead;
2548 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite;
2549 pThis->IMediaAsync.pfnStartFlush = drvvdStartFlush;
2550 pThis->IMediaAsync.pfnStartDiscard = drvvdStartDiscard;
2551
2552 /* Initialize supported VD interfaces. */
2553 pThis->pVDIfsDisk = NULL;
2554
2555 pThis->VDIfError.pfnError = drvvdErrorCallback;
2556 pThis->VDIfError.pfnMessage = NULL;
2557 rc = VDInterfaceAdd(&pThis->VDIfError.Core, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
2558 pDrvIns, sizeof(VDINTERFACEERROR), &pThis->pVDIfsDisk);
2559 AssertRC(rc);
2560
2561 /* List of images is empty now. */
2562 pThis->pImages = NULL;
2563
2564 pThis->pDrvMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
2565 if (!pThis->pDrvMediaPort)
2566 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
2567 N_("No media port interface above"));
2568
2569 /* Try to attach async media port interface above.*/
2570 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
2571
2572 /* Before we access any VD API load all given plugins. */
2573 rc = drvvdLoadPlugins(pThis, pCfg);
2574 if (RT_FAILURE(rc))
2575 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Loading VD plugins failed"));
2576
2577 /*
2578 * Validate configuration and find all parent images.
2579 * It's sort of up side down from the image dependency tree.
2580 */
2581 bool fHostIP = false;
2582 bool fUseNewIo = false;
2583 bool fUseBlockCache = false;
2584 bool fDiscard = false;
2585 bool fInformAboutZeroBlocks = false;
2586 bool fSkipConsistencyChecks = false;
2587 unsigned iLevel = 0;
2588 PCFGMNODE pCurNode = pCfg;
2589 VDTYPE enmType = VDTYPE_HDD;
2590
2591 for (;;)
2592 {
2593 bool fValid;
2594
2595 if (pCurNode == pCfg)
2596 {
2597 /* Toplevel configuration additionally contains the global image
2598 * open flags. Some might be converted to per-image flags later. */
2599 fValid = CFGMR3AreValuesValid(pCurNode,
2600 "Format\0Path\0"
2601 "ReadOnly\0MaybeReadOnly\0TempReadOnly\0Shareable\0HonorZeroWrites\0"
2602 "HostIPStack\0UseNewIo\0BootAcceleration\0BootAccelerationBuffer\0"
2603 "SetupMerge\0MergeSource\0MergeTarget\0BwGroup\0Type\0BlockCache\0"
2604 "CachePath\0CacheFormat\0Discard\0InformAboutZeroBlocks\0"
2605 "SkipConsistencyChecks\0");
2606 }
2607 else
2608 {
2609 /* All other image configurations only contain image name and
2610 * the format information. */
2611 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0"
2612 "MergeSource\0MergeTarget\0");
2613 }
2614 if (!fValid)
2615 {
2616 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
2617 RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
2618 break;
2619 }
2620
2621 if (pCurNode == pCfg)
2622 {
2623 rc = CFGMR3QueryBoolDef(pCurNode, "HostIPStack", &fHostIP, true);
2624 if (RT_FAILURE(rc))
2625 {
2626 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2627 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
2628 break;
2629 }
2630
2631 rc = CFGMR3QueryBoolDef(pCurNode, "HonorZeroWrites", &fHonorZeroWrites, false);
2632 if (RT_FAILURE(rc))
2633 {
2634 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2635 N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
2636 break;
2637 }
2638
2639 rc = CFGMR3QueryBoolDef(pCurNode, "ReadOnly", &fReadOnly, false);
2640 if (RT_FAILURE(rc))
2641 {
2642 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2643 N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
2644 break;
2645 }
2646
2647 rc = CFGMR3QueryBoolDef(pCurNode, "MaybeReadOnly", &fMaybeReadOnly, false);
2648 if (RT_FAILURE(rc))
2649 {
2650 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2651 N_("DrvVD: Configuration error: Querying \"MaybeReadOnly\" as boolean failed"));
2652 break;
2653 }
2654
2655 rc = CFGMR3QueryBoolDef(pCurNode, "TempReadOnly", &pThis->fTempReadOnly, false);
2656 if (RT_FAILURE(rc))
2657 {
2658 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2659 N_("DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
2660 break;
2661 }
2662 if (fReadOnly && pThis->fTempReadOnly)
2663 {
2664 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2665 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
2666 break;
2667 }
2668
2669 rc = CFGMR3QueryBoolDef(pCurNode, "Shareable", &pThis->fShareable, false);
2670 if (RT_FAILURE(rc))
2671 {
2672 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2673 N_("DrvVD: Configuration error: Querying \"Shareable\" as boolean failed"));
2674 break;
2675 }
2676
2677 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
2678 if (RT_FAILURE(rc))
2679 {
2680 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2681 N_("DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
2682 break;
2683 }
2684 rc = CFGMR3QueryBoolDef(pCurNode, "SetupMerge", &pThis->fMergePending, false);
2685 if (RT_FAILURE(rc))
2686 {
2687 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2688 N_("DrvVD: Configuration error: Querying \"SetupMerge\" as boolean failed"));
2689 break;
2690 }
2691 if (fReadOnly && pThis->fMergePending)
2692 {
2693 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2694 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"MergePending\" are set"));
2695 break;
2696 }
2697 rc = CFGMR3QueryBoolDef(pCurNode, "BootAcceleration", &pThis->fBootAccelEnabled, false);
2698 if (RT_FAILURE(rc))
2699 {
2700 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2701 N_("DrvVD: Configuration error: Querying \"BootAcceleration\" as boolean failed"));
2702 break;
2703 }
2704 rc = CFGMR3QueryU32Def(pCurNode, "BootAccelerationBuffer", (uint32_t *)&pThis->cbBootAccelBuffer, 16 * _1K);
2705 if (RT_FAILURE(rc))
2706 {
2707 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2708 N_("DrvVD: Configuration error: Querying \"BootAccelerationBuffer\" as integer failed"));
2709 break;
2710 }
2711 rc = CFGMR3QueryBoolDef(pCurNode, "BlockCache", &fUseBlockCache, false);
2712 if (RT_FAILURE(rc))
2713 {
2714 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2715 N_("DrvVD: Configuration error: Querying \"BlockCache\" as boolean failed"));
2716 break;
2717 }
2718 rc = CFGMR3QueryStringAlloc(pCurNode, "BwGroup", &pThis->pszBwGroup);
2719 if (RT_FAILURE(rc) && rc != VERR_CFGM_VALUE_NOT_FOUND)
2720 {
2721 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2722 N_("DrvVD: Configuration error: Querying \"BwGroup\" as string failed"));
2723 break;
2724 }
2725 else
2726 rc = VINF_SUCCESS;
2727 rc = CFGMR3QueryBoolDef(pCurNode, "Discard", &fDiscard, false);
2728 if (RT_FAILURE(rc))
2729 {
2730 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2731 N_("DrvVD: Configuration error: Querying \"Discard\" as boolean failed"));
2732 break;
2733 }
2734 if (fReadOnly && fDiscard)
2735 {
2736 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2737 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"Discard\" are set"));
2738 break;
2739 }
2740 rc = CFGMR3QueryBoolDef(pCurNode, "InformAboutZeroBlocks", &fInformAboutZeroBlocks, false);
2741 if (RT_FAILURE(rc))
2742 {
2743 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2744 N_("DrvVD: Configuration error: Querying \"InformAboutZeroBlocks\" as boolean failed"));
2745 break;
2746 }
2747 rc = CFGMR3QueryBoolDef(pCurNode, "SkipConsistencyChecks", &fSkipConsistencyChecks, true);
2748 if (RT_FAILURE(rc))
2749 {
2750 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2751 N_("DrvVD: Configuration error: Querying \"SKipConsistencyChecks\" as boolean failed"));
2752 break;
2753 }
2754
2755 char *psz;
2756 rc = CFGMR3QueryStringAlloc(pCfg, "Type", &psz);
2757 if (RT_FAILURE(rc))
2758 {
2759 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_BLOCK_NO_TYPE, N_("Failed to obtain the type"));
2760 break;
2761 }
2762 else if (!strcmp(psz, "HardDisk"))
2763 enmType = VDTYPE_HDD;
2764 else if (!strcmp(psz, "DVD"))
2765 enmType = VDTYPE_DVD;
2766 else if (!strcmp(psz, "Floppy"))
2767 enmType = VDTYPE_FLOPPY;
2768 else
2769 {
2770 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_BLOCK_UNKNOWN_TYPE, RT_SRC_POS,
2771 N_("Unknown type \"%s\""), psz);
2772 MMR3HeapFree(psz);
2773 break;
2774 }
2775 MMR3HeapFree(psz); psz = NULL;
2776
2777 rc = CFGMR3QueryStringAlloc(pCurNode, "CachePath", &pszCachePath);
2778 if (RT_FAILURE(rc) && rc != VERR_CFGM_VALUE_NOT_FOUND)
2779 {
2780 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2781 N_("DrvVD: Configuration error: Querying \"CachePath\" as string failed"));
2782 break;
2783 }
2784 else
2785 rc = VINF_SUCCESS;
2786
2787 if (pszCachePath)
2788 {
2789 rc = CFGMR3QueryStringAlloc(pCurNode, "CacheFormat", &pszCacheFormat);
2790 if (RT_FAILURE(rc))
2791 {
2792 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2793 N_("DrvVD: Configuration error: Querying \"CacheFormat\" as string failed"));
2794 break;
2795 }
2796 }
2797 }
2798
2799 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
2800 if (!pParent)
2801 break;
2802 pCurNode = pParent;
2803 iLevel++;
2804 }
2805
2806 /*
2807 * Create the image container and the necessary interfaces.
2808 */
2809 if (RT_SUCCESS(rc))
2810 {
2811 /*
2812 * The image has a bandwidth group but the host cache is enabled.
2813 * Use the async I/O framework but tell it to enable the host cache.
2814 */
2815 if (!fUseNewIo && pThis->pszBwGroup)
2816 {
2817 pThis->fAsyncIoWithHostCache = true;
2818 fUseNewIo = true;
2819 }
2820
2821 /** @todo quick hack to work around problems in the async I/O
2822 * implementation (rw semaphore thread ownership problem)
2823 * while a merge is running. Remove once this is fixed. */
2824 if (pThis->fMergePending)
2825 fUseNewIo = false;
2826
2827 if (RT_SUCCESS(rc) && pThis->fMergePending)
2828 {
2829 rc = RTSemFastMutexCreate(&pThis->MergeCompleteMutex);
2830 if (RT_SUCCESS(rc))
2831 rc = RTSemRWCreate(&pThis->MergeLock);
2832 if (RT_SUCCESS(rc))
2833 {
2834 pThis->VDIfThreadSync.pfnStartRead = drvvdThreadStartRead;
2835 pThis->VDIfThreadSync.pfnFinishRead = drvvdThreadFinishRead;
2836 pThis->VDIfThreadSync.pfnStartWrite = drvvdThreadStartWrite;
2837 pThis->VDIfThreadSync.pfnFinishWrite = drvvdThreadFinishWrite;
2838
2839 rc = VDInterfaceAdd(&pThis->VDIfThreadSync.Core, "DrvVD_ThreadSync", VDINTERFACETYPE_THREADSYNC,
2840 pThis, sizeof(VDINTERFACETHREADSYNC), &pThis->pVDIfsDisk);
2841 }
2842 else
2843 {
2844 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2845 N_("DrvVD: Failed to create semaphores for \"MergePending\""));
2846 }
2847 }
2848
2849 if (RT_SUCCESS(rc))
2850 {
2851 rc = VDCreate(pThis->pVDIfsDisk, enmType, &pThis->pDisk);
2852 /* Error message is already set correctly. */
2853 }
2854 }
2855
2856 if (pThis->pDrvMediaAsyncPort && fUseNewIo)
2857 pThis->fAsyncIOSupported = true;
2858
2859 uint64_t tsStart = RTTimeNanoTS();
2860
2861 unsigned iImageIdx = 0;
2862 while (pCurNode && RT_SUCCESS(rc))
2863 {
2864 /* Allocate per-image data. */
2865 PVBOXIMAGE pImage = drvvdNewImage(pThis);
2866 if (!pImage)
2867 {
2868 rc = VERR_NO_MEMORY;
2869 break;
2870 }
2871
2872 /*
2873 * Read the image configuration.
2874 */
2875 rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
2876 if (RT_FAILURE(rc))
2877 {
2878 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2879 N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
2880 break;
2881 }
2882
2883 rc = CFGMR3QueryStringAlloc(pCurNode, "Format", &pszFormat);
2884 if (RT_FAILURE(rc))
2885 {
2886 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2887 N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
2888 break;
2889 }
2890
2891 bool fMergeSource;
2892 rc = CFGMR3QueryBoolDef(pCurNode, "MergeSource", &fMergeSource, false);
2893 if (RT_FAILURE(rc))
2894 {
2895 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2896 N_("DrvVD: Configuration error: Querying \"MergeSource\" as boolean failed"));
2897 break;
2898 }
2899 if (fMergeSource)
2900 {
2901 if (pThis->uMergeSource == VD_LAST_IMAGE)
2902 pThis->uMergeSource = iImageIdx;
2903 else
2904 {
2905 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2906 N_("DrvVD: Configuration error: Multiple \"MergeSource\" occurrences"));
2907 break;
2908 }
2909 }
2910
2911 bool fMergeTarget;
2912 rc = CFGMR3QueryBoolDef(pCurNode, "MergeTarget", &fMergeTarget, false);
2913 if (RT_FAILURE(rc))
2914 {
2915 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
2916 N_("DrvVD: Configuration error: Querying \"MergeTarget\" as boolean failed"));
2917 break;
2918 }
2919 if (fMergeTarget)
2920 {
2921 if (pThis->uMergeTarget == VD_LAST_IMAGE)
2922 pThis->uMergeTarget = iImageIdx;
2923 else
2924 {
2925 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
2926 N_("DrvVD: Configuration error: Multiple \"MergeTarget\" occurrences"));
2927 break;
2928 }
2929 }
2930
2931 PCFGMNODE pCfgVDConfig = CFGMR3GetChild(pCurNode, "VDConfig");
2932 pImage->VDIfConfig.pfnAreKeysValid = drvvdCfgAreKeysValid;
2933 pImage->VDIfConfig.pfnQuerySize = drvvdCfgQuerySize;
2934 pImage->VDIfConfig.pfnQuery = drvvdCfgQuery;
2935 pImage->VDIfConfig.pfnQueryBytes = NULL;
2936 rc = VDInterfaceAdd(&pImage->VDIfConfig.Core, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
2937 pCfgVDConfig, sizeof(VDINTERFACECONFIG), &pImage->pVDIfsImage);
2938 AssertRC(rc);
2939
2940 /* Check VDConfig for encryption config. */
2941 if (pCfgVDConfig)
2942 pThis->pCfgCrypto = CFGMR3GetChild(pCfgVDConfig, "CRYPT");
2943
2944 if (pThis->pCfgCrypto)
2945 {
2946 /* Setup VDConfig interface for disk encryption support. */
2947 pThis->VDIfCfg.pfnAreKeysValid = drvvdCfgAreKeysValid;
2948 pThis->VDIfCfg.pfnQuerySize = drvvdCfgQuerySize;
2949 pThis->VDIfCfg.pfnQuery = drvvdCfgQuery;
2950 pThis->VDIfCfg.pfnQueryBytes = NULL;
2951
2952 pThis->VDIfCrypto.pfnKeyRetain = drvvdCryptoKeyRetain;
2953 pThis->VDIfCrypto.pfnKeyRelease = drvvdCryptoKeyRelease;
2954 pThis->VDIfCrypto.pfnKeyStorePasswordRetain = drvvdCryptoKeyStorePasswordRetain;
2955 pThis->VDIfCrypto.pfnKeyStorePasswordRelease = drvvdCryptoKeyStorePasswordRelease;
2956 }
2957
2958 /* Unconditionally insert the TCPNET interface, don't bother to check
2959 * if an image really needs it. Will be ignored. Since the TCPNET
2960 * interface is per image we could make this more flexible in the
2961 * future if we want to. */
2962 /* Construct TCPNET callback table depending on the config. This is
2963 * done unconditionally, as uninterested backends will ignore it. */
2964 if (fHostIP)
2965 {
2966 pImage->VDIfTcpNet.pfnSocketCreate = drvvdTcpSocketCreate;
2967 pImage->VDIfTcpNet.pfnSocketDestroy = drvvdTcpSocketDestroy;
2968 pImage->VDIfTcpNet.pfnClientConnect = drvvdTcpClientConnect;
2969 pImage->VDIfTcpNet.pfnIsClientConnected = drvvdTcpIsClientConnected;
2970 pImage->VDIfTcpNet.pfnClientClose = drvvdTcpClientClose;
2971 pImage->VDIfTcpNet.pfnSelectOne = drvvdTcpSelectOne;
2972 pImage->VDIfTcpNet.pfnRead = drvvdTcpRead;
2973 pImage->VDIfTcpNet.pfnWrite = drvvdTcpWrite;
2974 pImage->VDIfTcpNet.pfnSgWrite = drvvdTcpSgWrite;
2975 pImage->VDIfTcpNet.pfnReadNB = drvvdTcpReadNB;
2976 pImage->VDIfTcpNet.pfnWriteNB = drvvdTcpWriteNB;
2977 pImage->VDIfTcpNet.pfnSgWriteNB = drvvdTcpSgWriteNB;
2978 pImage->VDIfTcpNet.pfnFlush = drvvdTcpFlush;
2979 pImage->VDIfTcpNet.pfnSetSendCoalescing = drvvdTcpSetSendCoalescing;
2980 pImage->VDIfTcpNet.pfnGetLocalAddress = drvvdTcpGetLocalAddress;
2981 pImage->VDIfTcpNet.pfnGetPeerAddress = drvvdTcpGetPeerAddress;
2982
2983 /*
2984 * There is a 15ms delay between receiving the data and marking the socket
2985 * as readable on Windows XP which hurts async I/O performance of
2986 * TCP backends badly. Provide a different select method without
2987 * using poll on XP.
2988 * This is only used on XP because it is not as efficient as the one using poll
2989 * and all other Windows versions are working fine.
2990 */
2991 char szOS[64];
2992 memset(szOS, 0, sizeof(szOS));
2993 rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, &szOS[0], sizeof(szOS));
2994
2995 if (RT_SUCCESS(rc) && !strncmp(szOS, "Windows XP", 10))
2996 {
2997 LogRel(("VD: Detected Windows XP, disabled poll based waiting for TCP\n"));
2998 pImage->VDIfTcpNet.pfnSelectOneEx = drvvdTcpSelectOneExNoPoll;
2999 }
3000 else
3001 pImage->VDIfTcpNet.pfnSelectOneEx = drvvdTcpSelectOneExPoll;
3002
3003 pImage->VDIfTcpNet.pfnPoke = drvvdTcpPoke;
3004 }
3005 else
3006 {
3007#ifndef VBOX_WITH_INIP
3008 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
3009 RT_SRC_POS, N_("DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
3010#else /* VBOX_WITH_INIP */
3011 pImage->VDIfTcpNet.pfnSocketCreate = drvvdINIPSocketCreate;
3012 pImage->VDIfTcpNet.pfnSocketDestroy = drvvdINIPSocketDestroy;
3013 pImage->VDIfTcpNet.pfnClientConnect = drvvdINIPClientConnect;
3014 pImage->VDIfTcpNet.pfnClientClose = drvvdINIPClientClose;
3015 pImage->VDIfTcpNet.pfnIsClientConnected = drvvdINIPIsClientConnected;
3016 pImage->VDIfTcpNet.pfnSelectOne = drvvdINIPSelectOne;
3017 pImage->VDIfTcpNet.pfnRead = drvvdINIPRead;
3018 pImage->VDIfTcpNet.pfnWrite = drvvdINIPWrite;
3019 pImage->VDIfTcpNet.pfnSgWrite = drvvdINIPSgWrite;
3020 pImage->VDIfTcpNet.pfnFlush = drvvdINIPFlush;
3021 pImage->VDIfTcpNet.pfnSetSendCoalescing = drvvdINIPSetSendCoalescing;
3022 pImage->VDIfTcpNet.pfnGetLocalAddress = drvvdINIPGetLocalAddress;
3023 pImage->VDIfTcpNet.pfnGetPeerAddress = drvvdINIPGetPeerAddress;
3024 pImage->VDIfTcpNet.pfnSelectOneEx = drvvdINIPSelectOneEx;
3025 pImage->VDIfTcpNet.pfnPoke = drvvdINIPPoke;
3026#endif /* VBOX_WITH_INIP */
3027 }
3028 rc = VDInterfaceAdd(&pImage->VDIfTcpNet.Core, "DrvVD_TCPNET",
3029 VDINTERFACETYPE_TCPNET, NULL,
3030 sizeof(VDINTERFACETCPNET), &pImage->pVDIfsImage);
3031 AssertRC(rc);
3032
3033 /* Insert the custom I/O interface only if we're told to use new IO.
3034 * Since the I/O interface is per image we could make this more
3035 * flexible in the future if we want to. */
3036 if (fUseNewIo)
3037 {
3038#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
3039 pImage->VDIfIo.pfnOpen = drvvdAsyncIOOpen;
3040 pImage->VDIfIo.pfnClose = drvvdAsyncIOClose;
3041 pImage->VDIfIo.pfnGetSize = drvvdAsyncIOGetSize;
3042 pImage->VDIfIo.pfnSetSize = drvvdAsyncIOSetSize;
3043 pImage->VDIfIo.pfnReadSync = drvvdAsyncIOReadSync;
3044 pImage->VDIfIo.pfnWriteSync = drvvdAsyncIOWriteSync;
3045 pImage->VDIfIo.pfnFlushSync = drvvdAsyncIOFlushSync;
3046 pImage->VDIfIo.pfnReadAsync = drvvdAsyncIOReadAsync;
3047 pImage->VDIfIo.pfnWriteAsync = drvvdAsyncIOWriteAsync;
3048 pImage->VDIfIo.pfnFlushAsync = drvvdAsyncIOFlushAsync;
3049#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
3050 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
3051 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
3052#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
3053 if (RT_SUCCESS(rc))
3054 rc = VDInterfaceAdd(&pImage->VDIfIo.Core, "DrvVD_IO", VDINTERFACETYPE_IO,
3055 pThis, sizeof(VDINTERFACEIO), &pImage->pVDIfsImage);
3056 AssertRC(rc);
3057 }
3058
3059 /*
3060 * Open the image.
3061 */
3062 unsigned uOpenFlags;
3063 if (fReadOnly || pThis->fTempReadOnly || iLevel != 0)
3064 uOpenFlags = VD_OPEN_FLAGS_READONLY;
3065 else
3066 uOpenFlags = VD_OPEN_FLAGS_NORMAL;
3067 if (fHonorZeroWrites)
3068 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
3069 if (pThis->fAsyncIOSupported)
3070 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
3071 if (pThis->fShareable)
3072 uOpenFlags |= VD_OPEN_FLAGS_SHAREABLE;
3073 if (fDiscard && iLevel == 0)
3074 uOpenFlags |= VD_OPEN_FLAGS_DISCARD;
3075 if (fInformAboutZeroBlocks)
3076 uOpenFlags |= VD_OPEN_FLAGS_INFORM_ABOUT_ZERO_BLOCKS;
3077 if ( (uOpenFlags & VD_OPEN_FLAGS_READONLY)
3078 && fSkipConsistencyChecks)
3079 uOpenFlags |= VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS;
3080
3081 /* Try to open backend in async I/O mode first. */
3082 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
3083 if (rc == VERR_NOT_SUPPORTED)
3084 {
3085 pThis->fAsyncIOSupported = false;
3086 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
3087 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
3088 }
3089
3090 if (rc == VERR_VD_DISCARD_NOT_SUPPORTED)
3091 {
3092 fDiscard = false;
3093 uOpenFlags &= ~VD_OPEN_FLAGS_DISCARD;
3094 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
3095 }
3096
3097 if (!fDiscard)
3098 {
3099 pThis->IMedia.pfnDiscard = NULL;
3100 pThis->IMediaAsync.pfnStartDiscard = NULL;
3101 }
3102
3103 if (RT_SUCCESS(rc))
3104 {
3105 LogFunc(("%d - Opened '%s' in %s mode\n",
3106 iLevel, pszName,
3107 VDIsReadOnly(pThis->pDisk) ? "read-only" : "read-write"));
3108 if ( VDIsReadOnly(pThis->pDisk)
3109 && !fReadOnly
3110 && !fMaybeReadOnly
3111 && !pThis->fTempReadOnly
3112 && iLevel == 0)
3113 {
3114 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_VD_IMAGE_READ_ONLY, RT_SRC_POS,
3115 N_("Failed to open image '%s' for writing due to wrong permissions"),
3116 pszName);
3117 break;
3118 }
3119 }
3120 else
3121 {
3122 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
3123 N_("Failed to open image '%s' in %s mode"), pszName,
3124 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write");
3125 break;
3126 }
3127
3128
3129 MMR3HeapFree(pszName);
3130 pszName = NULL;
3131 MMR3HeapFree(pszFormat);
3132 pszFormat = NULL;
3133
3134 /* next */
3135 iLevel--;
3136 iImageIdx++;
3137 pCurNode = CFGMR3GetParent(pCurNode);
3138 }
3139
3140 LogRel(("VD: Opening the disk took %lld ns\n", RTTimeNanoTS() - tsStart));
3141
3142 /* Open the cache image if set. */
3143 if ( RT_SUCCESS(rc)
3144 && RT_VALID_PTR(pszCachePath))
3145 {
3146 /* Insert the custom I/O interface only if we're told to use new IO.
3147 * Since the I/O interface is per image we could make this more
3148 * flexible in the future if we want to. */
3149 if (fUseNewIo)
3150 {
3151#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
3152 pThis->VDIfIoCache.pfnOpen = drvvdAsyncIOOpen;
3153 pThis->VDIfIoCache.pfnClose = drvvdAsyncIOClose;
3154 pThis->VDIfIoCache.pfnGetSize = drvvdAsyncIOGetSize;
3155 pThis->VDIfIoCache.pfnSetSize = drvvdAsyncIOSetSize;
3156 pThis->VDIfIoCache.pfnReadSync = drvvdAsyncIOReadSync;
3157 pThis->VDIfIoCache.pfnWriteSync = drvvdAsyncIOWriteSync;
3158 pThis->VDIfIoCache.pfnFlushSync = drvvdAsyncIOFlushSync;
3159 pThis->VDIfIoCache.pfnReadAsync = drvvdAsyncIOReadAsync;
3160 pThis->VDIfIoCache.pfnWriteAsync = drvvdAsyncIOWriteAsync;
3161 pThis->VDIfIoCache.pfnFlushAsync = drvvdAsyncIOFlushAsync;
3162#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
3163 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
3164 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
3165#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
3166 if (RT_SUCCESS(rc))
3167 rc = VDInterfaceAdd(&pThis->VDIfIoCache.Core, "DrvVD_IO", VDINTERFACETYPE_IO,
3168 pThis, sizeof(VDINTERFACEIO), &pThis->pVDIfsCache);
3169 AssertRC(rc);
3170 }
3171
3172 rc = VDCacheOpen(pThis->pDisk, pszCacheFormat, pszCachePath, VD_OPEN_FLAGS_NORMAL, pThis->pVDIfsCache);
3173 if (RT_FAILURE(rc))
3174 rc = PDMDRV_SET_ERROR(pDrvIns, rc, N_("DrvVD: Could not open cache image"));
3175 }
3176
3177 if (RT_VALID_PTR(pszCachePath))
3178 MMR3HeapFree(pszCachePath);
3179 if (RT_VALID_PTR(pszCacheFormat))
3180 MMR3HeapFree(pszCacheFormat);
3181
3182 if ( RT_SUCCESS(rc)
3183 && pThis->fMergePending
3184 && ( pThis->uMergeSource == VD_LAST_IMAGE
3185 || pThis->uMergeTarget == VD_LAST_IMAGE))
3186 {
3187 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
3188 N_("DrvVD: Configuration error: Inconsistent image merge data"));
3189 }
3190
3191 /* Create the block cache if enabled. */
3192 if ( fUseBlockCache
3193 && !pThis->fShareable
3194 && !fDiscard
3195 && !pThis->pCfgCrypto /* Disk encryption disables the block cache for security reasons */
3196 && RT_SUCCESS(rc))
3197 {
3198 /*
3199 * We need a unique ID for the block cache (to identify the owner of data
3200 * blocks in a saved state). UUIDs are not really suitable because
3201 * there are image formats which don't support them. Furthermore it is
3202 * possible that a new diff image was attached after a saved state
3203 * which changes the UUID.
3204 * However the device "name + device instance + LUN" triple the disk is
3205 * attached to is always constant for saved states.
3206 */
3207 char *pszId = NULL;
3208 uint32_t iInstance, iLUN;
3209 const char *pcszController;
3210
3211 rc = pThis->pDrvMediaPort->pfnQueryDeviceLocation(pThis->pDrvMediaPort, &pcszController,
3212 &iInstance, &iLUN);
3213 if (RT_FAILURE(rc))
3214 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
3215 N_("DrvVD: Configuration error: Could not query device data"));
3216 else
3217 {
3218 int cbStr = RTStrAPrintf(&pszId, "%s-%d-%d", pcszController, iInstance, iLUN);
3219
3220 if (cbStr > 0)
3221 {
3222 rc = PDMDrvHlpBlkCacheRetain(pDrvIns, &pThis->pBlkCache,
3223 drvvdBlkCacheXferComplete,
3224 drvvdBlkCacheXferEnqueue,
3225 drvvdBlkCacheXferEnqueueDiscard,
3226 pszId);
3227 if (rc == VERR_NOT_SUPPORTED)
3228 {
3229 LogRel(("VD: Block cache is not supported\n"));
3230 rc = VINF_SUCCESS;
3231 }
3232 else
3233 AssertRC(rc);
3234
3235 RTStrFree(pszId);
3236 }
3237 else
3238 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
3239 N_("DrvVD: Out of memory when creating block cache"));
3240 }
3241 }
3242
3243 if (RT_SUCCESS(rc))
3244 rc = drvvdSetupFilters(pThis, pCfg);
3245
3246 /*
3247 * Register a load-done callback so we can undo TempReadOnly config before
3248 * we get to drvvdResume. Autoamtically deregistered upon destruction.
3249 */
3250 if (RT_SUCCESS(rc))
3251 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
3252 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
3253 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
3254 NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
3255
3256 /* Setup the boot acceleration stuff if enabled. */
3257 if (RT_SUCCESS(rc) && pThis->fBootAccelEnabled)
3258 {
3259 pThis->cbDisk = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
3260 Assert(pThis->cbDisk > 0);
3261 pThis->pbData = (uint8_t *)RTMemAllocZ(pThis->cbBootAccelBuffer);
3262 if (pThis->pbData)
3263 {
3264 pThis->fBootAccelActive = true;
3265 pThis->offDisk = 0;
3266 pThis->cbDataValid = 0;
3267 LogRel(("VD: Boot acceleration enabled\n"));
3268 }
3269 else
3270 LogRel(("VD: Boot acceleration, out of memory, disabled\n"));
3271 }
3272
3273 if (RT_FAILURE(rc))
3274 {
3275 if (RT_VALID_PTR(pszName))
3276 MMR3HeapFree(pszName);
3277 if (RT_VALID_PTR(pszFormat))
3278 MMR3HeapFree(pszFormat);
3279 /* drvvdDestruct does the rest. */
3280 }
3281
3282 LogFlowFunc(("returns %Rrc\n", rc));
3283 return rc;
3284}
3285
3286/**
3287 * VBox disk container media driver registration record.
3288 */
3289const PDMDRVREG g_DrvVD =
3290{
3291 /* u32Version */
3292 PDM_DRVREG_VERSION,
3293 /* szName */
3294 "VD",
3295 /* szRCMod */
3296 "",
3297 /* szR0Mod */
3298 "",
3299 /* pszDescription */
3300 "Generic VBox disk media driver.",
3301 /* fFlags */
3302 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
3303 /* fClass. */
3304 PDM_DRVREG_CLASS_MEDIA,
3305 /* cMaxInstances */
3306 ~0U,
3307 /* cbInstance */
3308 sizeof(VBOXDISK),
3309 /* pfnConstruct */
3310 drvvdConstruct,
3311 /* pfnDestruct */
3312 drvvdDestruct,
3313 /* pfnRelocate */
3314 NULL,
3315 /* pfnIOCtl */
3316 NULL,
3317 /* pfnPowerOn */
3318 drvvdPowerOn,
3319 /* pfnReset */
3320 drvvdReset,
3321 /* pfnSuspend */
3322 drvvdSuspend,
3323 /* pfnResume */
3324 drvvdResume,
3325 /* pfnAttach */
3326 NULL,
3327 /* pfnDetach */
3328 NULL,
3329 /* pfnPowerOff */
3330 drvvdPowerOff,
3331 /* pfnSoftReset */
3332 NULL,
3333 /* u32EndVersion */
3334 PDM_DRVREG_VERSION
3335};
3336
Note: See TracBrowser for help on using the repository browser.

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