VirtualBox

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

最後變更 在這個檔案從57358是 57358,由 vboxsync 提交於 10 年 前

*: scm cleanup run.

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

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