VirtualBox

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

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

Storage/iSCSI: Fail when a connection attempt takes too long to pause the VM more quickly when the target is not responding

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

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