VirtualBox

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

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

Port a part of r95116 (disk encryption changes in 4.3) which was forgotten to trunk. Fixes starting a VM with an encrypted VHD image

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