VirtualBox

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

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

Disk encryption: Make sure the DekMissing guest property is set before the state change handler is called when the VM is suspended

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