VirtualBox

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

Last change on this file since 56992 was 56967, checked in by vboxsync, 9 years ago

Devices/Storage: Keep track of used host block devices and prevent the host from opening any device while it is still in use by VBox on OS X

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

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