VirtualBox

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

Last change on this file since 28125 was 28065, checked in by vboxsync, 15 years ago

Storage: Convert from PDMDATASEG to RTSGSEG to avoid casting between those two in VBoxHDD and more async I/O updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.5 KB
Line 
1/* $Id: DrvVD.cpp 28065 2010-04-07 20:54:34Z vboxsync $ */
2/** @file
3 * DrvVD - Generic VBox disk media driver.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_DRV_VD
27#include <VBox/VBoxHDD.h>
28#include <VBox/pdmdrv.h>
29#include <VBox/pdmasynccompletion.h>
30#include <iprt/asm.h>
31#include <iprt/alloc.h>
32#include <iprt/assert.h>
33#include <iprt/uuid.h>
34#include <iprt/file.h>
35#include <iprt/string.h>
36#include <iprt/tcp.h>
37#include <iprt/semaphore.h>
38#include <iprt/sg.h>
39
40#ifdef VBOX_WITH_INIP
41/* All lwip header files are not C++ safe. So hack around this. */
42RT_C_DECLS_BEGIN
43#include <lwip/inet.h>
44#include <lwip/tcp.h>
45#include <lwip/sockets.h>
46RT_C_DECLS_END
47#endif /* VBOX_WITH_INIP */
48
49#include "Builtins.h"
50
51#ifdef VBOX_WITH_INIP
52/* Small hack to get at lwIP initialized status */
53extern bool DevINIPConfigured(void);
54#endif /* VBOX_WITH_INIP */
55
56
57/*******************************************************************************
58* Defined types, constants and macros *
59*******************************************************************************/
60
61/** Converts a pointer to VBOXDISK::IMedia to a PVBOXDISK. */
62#define PDMIMEDIA_2_VBOXDISK(pInterface) \
63 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMedia)) )
64
65/** Converts a pointer to PDMDRVINS::IBase to a PPDMDRVINS. */
66#define PDMIBASE_2_DRVINS(pInterface) \
67 ( (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) )
68
69/** Converts a pointer to PDMDRVINS::IBase to a PVBOXDISK. */
70#define PDMIBASE_2_VBOXDISK(pInterface) \
71 ( PDMINS_2_DATA(PDMIBASE_2_DRVINS(pInterface), PVBOXDISK) )
72
73/** Converts a pointer to VBOXDISK::IMediaAsync to a PVBOXDISK. */
74#define PDMIMEDIAASYNC_2_VBOXDISK(pInterface) \
75 ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMediaAsync)) )
76
77/**
78 * VBox disk container, image information, private part.
79 */
80
81typedef struct VBOXIMAGE
82{
83 /** Pointer to next image. */
84 struct VBOXIMAGE *pNext;
85 /** Pointer to list of VD interfaces. Per-image. */
86 PVDINTERFACE pVDIfsImage;
87 /** Common structure for the configuration information interface. */
88 VDINTERFACE VDIConfig;
89} VBOXIMAGE, *PVBOXIMAGE;
90
91/**
92 * Storage backend data.
93 */
94typedef struct DRVVDSTORAGEBACKEND
95{
96 /** PDM async completion end point. */
97 PPDMASYNCCOMPLETIONENDPOINT pEndpoint;
98 /** The template. */
99 PPDMASYNCCOMPLETIONTEMPLATE pTemplate;
100 /** Event semaphore for synchronous operations. */
101 RTSEMEVENT EventSem;
102 /** Flag whether a synchronous operation is currently pending. */
103 volatile bool fSyncIoPending;
104 /** Return code of the last completed request. */
105 int rcReqLast;
106 /** Callback routine */
107 PFNVDCOMPLETED pfnCompleted;
108
109 /** Pointer to the optional thread synchronization interface of the disk. */
110 PVDINTERFACE pInterfaceThreadSync;
111 /** Pointer to the optional thread synchronization callbacks of the disk. */
112 PVDINTERFACETHREADSYNC pInterfaceThreadSyncCallbacks;
113} DRVVDSTORAGEBACKEND, *PDRVVDSTORAGEBACKEND;
114
115/**
116 * VBox disk container media main structure, private part.
117 *
118 * @implements PDMIMEDIA
119 * @implements PDMIMEDIAASYNC
120 * @implements VDINTERFACEERROR
121 * @implements VDINTERFACETCPNET
122 * @implements VDINTERFACEASYNCIO
123 * @implements VDINTERFACECONFIG
124 */
125typedef struct VBOXDISK
126{
127 /** The VBox disk container. */
128 PVBOXHDD pDisk;
129 /** The media interface. */
130 PDMIMEDIA IMedia;
131 /** Pointer to the driver instance. */
132 PPDMDRVINS pDrvIns;
133 /** Flag whether suspend has changed image open mode to read only. */
134 bool fTempReadOnly;
135 /** Flag whether to use the runtime (true) or startup error facility. */
136 bool fErrorUseRuntime;
137 /** Pointer to list of VD interfaces. Per-disk. */
138 PVDINTERFACE pVDIfsDisk;
139 /** Common structure for the supported error interface. */
140 VDINTERFACE VDIError;
141 /** Callback table for error interface. */
142 VDINTERFACEERROR VDIErrorCallbacks;
143 /** Common structure for the supported TCP network stack interface. */
144 VDINTERFACE VDITcpNet;
145 /** Callback table for TCP network stack interface. */
146 VDINTERFACETCPNET VDITcpNetCallbacks;
147 /** Common structure for the supported async I/O interface. */
148 VDINTERFACE VDIAsyncIO;
149 /** Callback table for async I/O interface. */
150 VDINTERFACEASYNCIO VDIAsyncIOCallbacks;
151 /** Common structure for the supported thread synchronization interface. */
152 VDINTERFACE VDIThreadSync;
153 /** Callback table for thread synchronization interface. */
154 VDINTERFACETHREADSYNC VDIThreadSyncCallbacks;
155 /** Callback table for the configuration information interface. */
156 VDINTERFACECONFIG VDIConfigCallbacks;
157 /** Flag whether opened disk suppports async I/O operations. */
158 bool fAsyncIOSupported;
159 /** The async media interface. */
160 PDMIMEDIAASYNC IMediaAsync;
161 /** The async media port interface above. */
162 PPDMIMEDIAASYNCPORT pDrvMediaAsyncPort;
163 /** Pointer to the list of data we need to keep per image. */
164 PVBOXIMAGE pImages;
165 /** Flag whether a merge operation has been set up. */
166 bool fMergePending;
167 /** Synchronization to prevent destruction before merge finishes. */
168 RTSEMFASTMUTEX MergeCompleteMutex;
169 /** Synchronization between merge and other image accesses. */
170 RTSEMRW MergeLock;
171 /** Source image index for merging. */
172 unsigned uMergeSource;
173 /** Target image index for merging. */
174 unsigned uMergeTarget;
175} VBOXDISK, *PVBOXDISK;
176
177
178/*******************************************************************************
179* Internal Functions *
180*******************************************************************************/
181
182/**
183 * Internal: allocate new image descriptor and put it in the list
184 */
185static PVBOXIMAGE drvvdNewImage(PVBOXDISK pThis)
186{
187 AssertPtr(pThis);
188 PVBOXIMAGE pImage = (PVBOXIMAGE)RTMemAllocZ(sizeof(VBOXIMAGE));
189 if (pImage)
190 {
191 pImage->pVDIfsImage = NULL;
192 PVBOXIMAGE *pp = &pThis->pImages;
193 while (*pp != NULL)
194 pp = &(*pp)->pNext;
195 *pp = pImage;
196 pImage->pNext = NULL;
197 }
198
199 return pImage;
200}
201
202/**
203 * Internal: free the list of images descriptors.
204 */
205static void drvvdFreeImages(PVBOXDISK pThis)
206{
207 while (pThis->pImages != NULL)
208 {
209 PVBOXIMAGE p = pThis->pImages;
210 pThis->pImages = pThis->pImages->pNext;
211 RTMemFree(p);
212 }
213}
214
215
216/**
217 * Make the image temporarily read-only.
218 *
219 * @returns VBox status code.
220 * @param pThis The driver instance data.
221 */
222static int drvvdSetReadonly(PVBOXDISK pThis)
223{
224 int rc = VINF_SUCCESS;
225 if (!VDIsReadOnly(pThis->pDisk))
226 {
227 unsigned uOpenFlags;
228 rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
229 AssertRC(rc);
230 uOpenFlags |= VD_OPEN_FLAGS_READONLY;
231 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
232 AssertRC(rc);
233 pThis->fTempReadOnly = true;
234 }
235 return rc;
236}
237
238
239/**
240 * Undo the temporary read-only status of the image.
241 *
242 * @returns VBox status code.
243 * @param pThis The driver instance data.
244 */
245static int drvvdSetWritable(PVBOXDISK pThis)
246{
247 int rc = VINF_SUCCESS;
248 if (pThis->fTempReadOnly)
249 {
250 unsigned uOpenFlags;
251 rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
252 AssertRC(rc);
253 uOpenFlags &= ~VD_OPEN_FLAGS_READONLY;
254 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
255 if (RT_SUCCESS(rc))
256 pThis->fTempReadOnly = false;
257 else
258 AssertRC(rc);
259 }
260 return rc;
261}
262
263
264/*******************************************************************************
265* Error reporting callback *
266*******************************************************************************/
267
268static void drvvdErrorCallback(void *pvUser, int rc, RT_SRC_POS_DECL,
269 const char *pszFormat, va_list va)
270{
271 PPDMDRVINS pDrvIns = (PPDMDRVINS)pvUser;
272 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
273 if (pThis->fErrorUseRuntime)
274 /* We must not pass VMSETRTERR_FLAGS_FATAL as it could lead to a
275 * deadlock: We are probably executed in a thread context != EMT
276 * and the EM thread would wait until every thread is suspended
277 * but we would wait for the EM thread ... */
278
279 PDMDrvHlpVMSetRuntimeErrorV(pDrvIns, /* fFlags=*/ 0, "DrvVD", pszFormat, va);
280 else
281 PDMDrvHlpVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va);
282}
283
284/*******************************************************************************
285* VD Async I/O interface implementation *
286*******************************************************************************/
287
288#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
289
290static DECLCALLBACK(void) drvvdAsyncTaskCompleted(PPDMDRVINS pDrvIns, void *pvTemplateUser, void *pvUser, int rcReq)
291{
292 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
293 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pvTemplateUser;
294
295 if (pStorageBackend->fSyncIoPending)
296 {
297 pStorageBackend->rcReqLast = rcReq;
298 pStorageBackend->fSyncIoPending = false;
299 RTSemEventSignal(pStorageBackend->EventSem);
300 }
301 else
302 {
303 int rc;
304
305 AssertPtr(pStorageBackend->pfnCompleted);
306 rc = pStorageBackend->pfnCompleted(pvUser);
307 AssertRC(rc);
308
309 /* If thread synchronization is active, then signal the end of the
310 * this disk read/write operation. */
311 /** @todo provide a way to determine the type of task (read/write)
312 * which was completed, see also VBoxHDD.cpp. */
313 if (RT_UNLIKELY(pStorageBackend->pInterfaceThreadSyncCallbacks))
314 {
315 int rc2 = pStorageBackend->pInterfaceThreadSyncCallbacks->pfnFinishWrite(pStorageBackend->pInterfaceThreadSync->pvUser);
316 AssertRC(rc2);
317 }
318 }
319}
320
321static DECLCALLBACK(int) drvvdAsyncIOOpen(void *pvUser, const char *pszLocation,
322 unsigned uOpenFlags,
323 PFNVDCOMPLETED pfnCompleted,
324 PVDINTERFACE pVDIfsDisk,
325 void **ppStorage)
326{
327 PVBOXDISK pThis = (PVBOXDISK)pvUser;
328 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)RTMemAllocZ(sizeof(DRVVDSTORAGEBACKEND));
329 int rc = VINF_SUCCESS;
330
331 if (pStorageBackend)
332 {
333 pStorageBackend->fSyncIoPending = false;
334 pStorageBackend->rcReqLast = VINF_SUCCESS;
335 pStorageBackend->pfnCompleted = pfnCompleted;
336 pStorageBackend->pInterfaceThreadSync = NULL;
337 pStorageBackend->pInterfaceThreadSyncCallbacks = NULL;
338
339 pStorageBackend->pInterfaceThreadSync = VDInterfaceGet(pVDIfsDisk, VDINTERFACETYPE_THREADSYNC);
340 if (RT_UNLIKELY(pStorageBackend->pInterfaceThreadSync))
341 pStorageBackend->pInterfaceThreadSyncCallbacks = VDGetInterfaceThreadSync(pStorageBackend->pInterfaceThreadSync);
342
343 rc = RTSemEventCreate(&pStorageBackend->EventSem);
344 if (RT_SUCCESS(rc))
345 {
346 rc = PDMDrvHlpPDMAsyncCompletionTemplateCreate(pThis->pDrvIns, &pStorageBackend->pTemplate,
347 drvvdAsyncTaskCompleted, pStorageBackend, "AsyncTaskCompleted");
348 if (RT_SUCCESS(rc))
349 {
350 rc = PDMR3AsyncCompletionEpCreateForFile(&pStorageBackend->pEndpoint, pszLocation,
351 uOpenFlags & VD_INTERFACEASYNCIO_OPEN_FLAGS_READONLY
352 ? PDMACEP_FILE_FLAGS_READ_ONLY | PDMACEP_FILE_FLAGS_CACHING
353 : PDMACEP_FILE_FLAGS_CACHING,
354 pStorageBackend->pTemplate);
355 if (RT_SUCCESS(rc))
356 {
357 *ppStorage = pStorageBackend;
358 return VINF_SUCCESS;
359 }
360
361 PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate);
362 }
363 RTSemEventDestroy(pStorageBackend->EventSem);
364 }
365 RTMemFree(pStorageBackend);
366 }
367 else
368 rc = VERR_NO_MEMORY;
369
370 return rc;
371}
372
373static DECLCALLBACK(int) drvvdAsyncIOClose(void *pvUser, void *pStorage)
374{
375 PVBOXDISK pThis = (PVBOXDISK)pvUser;
376 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
377
378 PDMR3AsyncCompletionEpClose(pStorageBackend->pEndpoint);
379 PDMR3AsyncCompletionTemplateDestroy(pStorageBackend->pTemplate);
380 RTSemEventDestroy(pStorageBackend->EventSem);
381 RTMemFree(pStorageBackend);
382
383 return VINF_SUCCESS;;
384}
385
386static DECLCALLBACK(int) drvvdAsyncIOReadSync(void *pvUser, void *pStorage, uint64_t uOffset,
387 size_t cbRead, void *pvBuf, size_t *pcbRead)
388{
389 PVBOXDISK pThis = (PVBOXDISK)pvUser;
390 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
391 RTSGSEG DataSeg;
392 PPDMASYNCCOMPLETIONTASK pTask;
393
394 Assert(!pStorageBackend->fSyncIoPending);
395 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
396 DataSeg.cbSeg = cbRead;
397 DataSeg.pvSeg = pvBuf;
398
399 int rc = PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbRead, NULL, &pTask);
400 if (RT_FAILURE(rc))
401 return rc;
402
403 if (rc == VINF_AIO_TASK_PENDING)
404 {
405 /* Wait */
406 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
407 AssertRC(rc);
408 }
409 else
410 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
411
412 if (pcbRead)
413 *pcbRead = cbRead;
414
415 return pStorageBackend->rcReqLast;
416}
417
418static DECLCALLBACK(int) drvvdAsyncIOWriteSync(void *pvUser, void *pStorage, uint64_t uOffset,
419 size_t cbWrite, const void *pvBuf, size_t *pcbWritten)
420{
421 PVBOXDISK pThis = (PVBOXDISK)pvUser;
422 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
423 RTSGSEG DataSeg;
424 PPDMASYNCCOMPLETIONTASK pTask;
425
426 Assert(!pStorageBackend->fSyncIoPending);
427 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
428 DataSeg.cbSeg = cbWrite;
429 DataSeg.pvSeg = (void *)pvBuf;
430
431 int rc = PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbWrite, NULL, &pTask);
432 if (RT_FAILURE(rc))
433 return rc;
434
435 if (rc == VINF_AIO_TASK_PENDING)
436 {
437 /* Wait */
438 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
439 AssertRC(rc);
440 }
441 else
442 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
443
444 if (pcbWritten)
445 *pcbWritten = cbWrite;
446
447 return pStorageBackend->rcReqLast;
448}
449
450static DECLCALLBACK(int) drvvdAsyncIOFlushSync(void *pvUser, void *pStorage)
451{
452 PVBOXDISK pThis = (PVBOXDISK)pvUser;
453 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
454 PPDMASYNCCOMPLETIONTASK pTask;
455
456 Assert(!pStorageBackend->fSyncIoPending);
457 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
458
459 int rc = PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, NULL, &pTask);
460 if (RT_FAILURE(rc))
461 return rc;
462
463 if (rc == VINF_AIO_TASK_PENDING)
464 {
465 /* Wait */
466 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
467 AssertRC(rc);
468 }
469 else
470 ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, false);
471
472 return pStorageBackend->rcReqLast;
473}
474
475static DECLCALLBACK(int) drvvdAsyncIOReadAsync(void *pvUser, void *pStorage, uint64_t uOffset,
476 PCRTSGSEG paSegments, size_t cSegments,
477 size_t cbRead, void *pvCompletion,
478 void **ppTask)
479{
480 PVBOXDISK pThis = (PVBOXDISK)pvUser;
481 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
482
483 int rc = PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbRead,
484 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
485 if (rc == VINF_AIO_TASK_PENDING)
486 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
487
488 return rc;
489}
490
491static DECLCALLBACK(int) drvvdAsyncIOWriteAsync(void *pvUser, void *pStorage, uint64_t uOffset,
492 PCRTSGSEG paSegments, size_t cSegments,
493 size_t cbWrite, void *pvCompletion,
494 void **ppTask)
495{
496 PVBOXDISK pThis = (PVBOXDISK)pvUser;
497 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
498
499 int rc = PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbWrite,
500 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
501 if (rc == VINF_AIO_TASK_PENDING)
502 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
503
504 return rc;
505}
506
507static DECLCALLBACK(int) drvvdAsyncIOFlushAsync(void *pvUser, void *pStorage,
508 void *pvCompletion, void **ppTask)
509{
510 PVBOXDISK pThis = (PVBOXDISK)pvUser;
511 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
512
513 int rc = PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, pvCompletion,
514 (PPPDMASYNCCOMPLETIONTASK)ppTask);
515 if (rc == VINF_AIO_TASK_PENDING)
516 rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
517
518 return rc;
519}
520
521static DECLCALLBACK(int) drvvdAsyncIOGetSize(void *pvUser, void *pStorage, uint64_t *pcbSize)
522{
523 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
524 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
525
526 return PDMR3AsyncCompletionEpGetSize(pStorageBackend->pEndpoint, pcbSize);
527}
528
529static DECLCALLBACK(int) drvvdAsyncIOSetSize(void *pvUser, void *pStorage, uint64_t cbSize)
530{
531 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
532 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
533
534 int rc = drvvdAsyncIOFlushSync(pvUser, pStorage);
535 if (RT_SUCCESS(rc))
536 rc = PDMR3AsyncCompletionEpSetSize(pStorageBackend->pEndpoint, cbSize);
537
538 return rc;
539}
540
541#endif /* VBOX_WITH_PDM_ASYNC_COMPLETION */
542
543
544/*******************************************************************************
545* VD Thread Synchronization interface implementation *
546*******************************************************************************/
547
548static DECLCALLBACK(int) drvvdThreadStartRead(void *pvUser)
549{
550 PVBOXDISK pThis = (PVBOXDISK)pvUser;
551
552 return RTSemRWRequestRead(pThis->MergeLock, RT_INDEFINITE_WAIT);
553}
554
555static DECLCALLBACK(int) drvvdThreadFinishRead(void *pvUser)
556{
557 PVBOXDISK pThis = (PVBOXDISK)pvUser;
558
559 return RTSemRWReleaseRead(pThis->MergeLock);
560}
561
562static DECLCALLBACK(int) drvvdThreadStartWrite(void *pvUser)
563{
564 PVBOXDISK pThis = (PVBOXDISK)pvUser;
565
566 return RTSemRWRequestWrite(pThis->MergeLock, RT_INDEFINITE_WAIT);
567}
568
569static DECLCALLBACK(int) drvvdThreadFinishWrite(void *pvUser)
570{
571 PVBOXDISK pThis = (PVBOXDISK)pvUser;
572
573 return RTSemRWReleaseWrite(pThis->MergeLock);
574}
575
576
577/*******************************************************************************
578* VD Configuration interface implementation *
579*******************************************************************************/
580
581static bool drvvdCfgAreKeysValid(void *pvUser, const char *pszzValid)
582{
583 return CFGMR3AreValuesValid((PCFGMNODE)pvUser, pszzValid);
584}
585
586static int drvvdCfgQuerySize(void *pvUser, const char *pszName, size_t *pcb)
587{
588 return CFGMR3QuerySize((PCFGMNODE)pvUser, pszName, pcb);
589}
590
591static int drvvdCfgQuery(void *pvUser, const char *pszName, char *pszString, size_t cchString)
592{
593 return CFGMR3QueryString((PCFGMNODE)pvUser, pszName, pszString, cchString);
594}
595
596
597#ifdef VBOX_WITH_INIP
598/*******************************************************************************
599* VD TCP network stack interface implementation - INIP case *
600*******************************************************************************/
601
602/** @copydoc VDINTERFACETCPNET::pfnClientConnect */
603static DECLCALLBACK(int) drvvdINIPClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
604{
605 int rc = VINF_SUCCESS;
606 /* First check whether lwIP is set up in this VM instance. */
607 if (!DevINIPConfigured())
608 {
609 LogRelFunc(("no IP stack\n"));
610 return VERR_NET_HOST_UNREACHABLE;
611 }
612 /* Resolve hostname. As there is no standard resolver for lwIP yet,
613 * just accept numeric IP addresses for now. */
614 struct in_addr ip;
615 if (!lwip_inet_aton(pszAddress, &ip))
616 {
617 LogRelFunc(("cannot resolve IP %s\n", pszAddress));
618 return VERR_NET_HOST_UNREACHABLE;
619 }
620 /* Create socket and connect. */
621 RTSOCKET Sock = lwip_socket(PF_INET, SOCK_STREAM, 0);
622 if (Sock != -1)
623 {
624 struct sockaddr_in InAddr = {0};
625 InAddr.sin_family = AF_INET;
626 InAddr.sin_port = htons(uPort);
627 InAddr.sin_addr = ip;
628 if (!lwip_connect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr)))
629 {
630 *pSock = Sock;
631 return VINF_SUCCESS;
632 }
633 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
634 lwip_close(Sock);
635 }
636 else
637 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
638 return rc;
639}
640
641/** @copydoc VDINTERFACETCPNET::pfnClientClose */
642static DECLCALLBACK(int) drvvdINIPClientClose(RTSOCKET Sock)
643{
644 lwip_close(Sock);
645 return VINF_SUCCESS; /** @todo real solution needed */
646}
647
648/** @copydoc VDINTERFACETCPNET::pfnSelectOne */
649static DECLCALLBACK(int) drvvdINIPSelectOne(RTSOCKET Sock, RTMSINTERVAL cMillies)
650{
651 fd_set fdsetR;
652 FD_ZERO(&fdsetR);
653 FD_SET(Sock, &fdsetR);
654 fd_set fdsetE = fdsetR;
655
656 int rc;
657 if (cMillies == RT_INDEFINITE_WAIT)
658 rc = lwip_select(Sock + 1, &fdsetR, NULL, &fdsetE, NULL);
659 else
660 {
661 struct timeval timeout;
662 timeout.tv_sec = cMillies / 1000;
663 timeout.tv_usec = (cMillies % 1000) * 1000;
664 rc = lwip_select(Sock + 1, &fdsetR, NULL, &fdsetE, &timeout);
665 }
666 if (rc > 0)
667 return VINF_SUCCESS;
668 if (rc == 0)
669 return VERR_TIMEOUT;
670 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
671}
672
673/** @copydoc VDINTERFACETCPNET::pfnRead */
674static DECLCALLBACK(int) drvvdINIPRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
675{
676 /* Do params checking */
677 if (!pvBuffer || !cbBuffer)
678 {
679 AssertMsgFailed(("Invalid params\n"));
680 return VERR_INVALID_PARAMETER;
681 }
682
683 /*
684 * Read loop.
685 * If pcbRead is NULL we have to fill the entire buffer!
686 */
687 size_t cbRead = 0;
688 size_t cbToRead = cbBuffer;
689 for (;;)
690 {
691 /** @todo this clipping here is just in case (the send function
692 * needed it, so I added it here, too). Didn't investigate if this
693 * really has issues. Better be safe than sorry. */
694 ssize_t cbBytesRead = lwip_recv(Sock, (char *)pvBuffer + cbRead,
695 RT_MIN(cbToRead, 32768), 0);
696 if (cbBytesRead < 0)
697 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
698 if (cbBytesRead == 0 && errno)
699 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
700 if (pcbRead)
701 {
702 /* return partial data */
703 *pcbRead = cbBytesRead;
704 break;
705 }
706
707 /* read more? */
708 cbRead += cbBytesRead;
709 if (cbRead == cbBuffer)
710 break;
711
712 /* next */
713 cbToRead = cbBuffer - cbRead;
714 }
715
716 return VINF_SUCCESS;
717}
718
719/** @copydoc VDINTERFACETCPNET::pfnWrite */
720static DECLCALLBACK(int) drvvdINIPWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
721{
722 do
723 {
724 /** @todo lwip send only supports up to 65535 bytes in a single
725 * send (stupid limitation buried in the code), so make sure we
726 * don't get any wraparounds. This should be moved to DevINIP
727 * stack interface once that's implemented. */
728 ssize_t cbWritten = lwip_send(Sock, (void *)pvBuffer,
729 RT_MIN(cbBuffer, 32768), 0);
730 if (cbWritten < 0)
731 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
732 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%d cbBuffer=%d\n",
733 cbWritten, cbBuffer));
734 cbBuffer -= cbWritten;
735 pvBuffer = (const char *)pvBuffer + cbWritten;
736 } while (cbBuffer);
737
738 return VINF_SUCCESS;
739}
740
741/** @copydoc VDINTERFACETCPNET::pfnFlush */
742static DECLCALLBACK(int) drvvdINIPFlush(RTSOCKET Sock)
743{
744 int fFlag = 1;
745 lwip_setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY,
746 (const char *)&fFlag, sizeof(fFlag));
747 fFlag = 0;
748 lwip_setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY,
749 (const char *)&fFlag, sizeof(fFlag));
750 return VINF_SUCCESS;
751}
752
753/** @copydoc VDINTERFACETCPNET::pfnGetLocalAddress */
754static DECLCALLBACK(int) drvvdINIPGetLocalAddress(RTSOCKET Sock, PRTNETADDR pAddr)
755{
756 union
757 {
758 struct sockaddr Addr;
759 struct sockaddr_in Ipv4;
760 } u;
761 socklen_t cbAddr = sizeof(u);
762 RT_ZERO(u);
763 if (!lwip_getsockname(Sock, &u.Addr, &cbAddr))
764 {
765 /*
766 * Convert the address.
767 */
768 if ( cbAddr == sizeof(struct sockaddr_in)
769 && u.Addr.sa_family == AF_INET)
770 {
771 RT_ZERO(*pAddr);
772 pAddr->enmType = RTNETADDRTYPE_IPV4;
773 pAddr->uPort = RT_N2H_U16(u.Ipv4.sin_port);
774 pAddr->uAddr.IPv4.u = u.Ipv4.sin_addr.s_addr;
775 }
776 else
777 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
778 return VINF_SUCCESS;
779 }
780 return VERR_NET_OPERATION_NOT_SUPPORTED;
781}
782
783/** @copydoc VDINTERFACETCPNET::pfnGetPeerAddress */
784static DECLCALLBACK(int) drvvdINIPGetPeerAddress(RTSOCKET Sock, PRTNETADDR pAddr)
785{
786 union
787 {
788 struct sockaddr Addr;
789 struct sockaddr_in Ipv4;
790 } u;
791 socklen_t cbAddr = sizeof(u);
792 RT_ZERO(u);
793 if (!lwip_getpeername(Sock, &u.Addr, &cbAddr))
794 {
795 /*
796 * Convert the address.
797 */
798 if ( cbAddr == sizeof(struct sockaddr_in)
799 && u.Addr.sa_family == AF_INET)
800 {
801 RT_ZERO(*pAddr);
802 pAddr->enmType = RTNETADDRTYPE_IPV4;
803 pAddr->uPort = RT_N2H_U16(u.Ipv4.sin_port);
804 pAddr->uAddr.IPv4.u = u.Ipv4.sin_addr.s_addr;
805 }
806 else
807 return VERR_NET_ADDRESS_FAMILY_NOT_SUPPORTED;
808 return VINF_SUCCESS;
809 }
810 return VERR_NET_OPERATION_NOT_SUPPORTED;
811}
812#endif /* VBOX_WITH_INIP */
813
814
815/*******************************************************************************
816* Media interface methods *
817*******************************************************************************/
818
819/** @copydoc PDMIMEDIA::pfnRead */
820static DECLCALLBACK(int) drvvdRead(PPDMIMEDIA pInterface,
821 uint64_t off, void *pvBuf, size_t cbRead)
822{
823 LogFlow(("%s: off=%#llx pvBuf=%p cbRead=%d\n", __FUNCTION__,
824 off, pvBuf, cbRead));
825 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
826 int rc = VDRead(pThis->pDisk, off, pvBuf, cbRead);
827 if (RT_SUCCESS(rc))
828 Log2(("%s: off=%#llx pvBuf=%p cbRead=%d %.*Rhxd\n", __FUNCTION__,
829 off, pvBuf, cbRead, cbRead, pvBuf));
830 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
831 return rc;
832}
833
834/** @copydoc PDMIMEDIA::pfnWrite */
835static DECLCALLBACK(int) drvvdWrite(PPDMIMEDIA pInterface,
836 uint64_t off, const void *pvBuf,
837 size_t cbWrite)
838{
839 LogFlow(("%s: off=%#llx pvBuf=%p cbWrite=%d\n", __FUNCTION__,
840 off, pvBuf, cbWrite));
841 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
842 Log2(("%s: off=%#llx pvBuf=%p cbWrite=%d %.*Rhxd\n", __FUNCTION__,
843 off, pvBuf, cbWrite, cbWrite, pvBuf));
844 int rc = VDWrite(pThis->pDisk, off, pvBuf, cbWrite);
845 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
846 return rc;
847}
848
849/** @copydoc PDMIMEDIA::pfnFlush */
850static DECLCALLBACK(int) drvvdFlush(PPDMIMEDIA pInterface)
851{
852 LogFlow(("%s:\n", __FUNCTION__));
853 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
854 int rc = VDFlush(pThis->pDisk);
855 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
856 return rc;
857}
858
859/** @copydoc PDMIMEDIA::pfnMerge */
860static DECLCALLBACK(int) drvvdMerge(PPDMIMEDIA pInterface,
861 PFNSIMPLEPROGRESS pfnProgress,
862 void *pvUser)
863{
864 LogFlow(("%s:\n", __FUNCTION__));
865 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
866 int rc = VINF_SUCCESS;
867
868 /* Note: There is an unavoidable race between destruction and another
869 * thread invoking this function. This is handled safely and gracefully by
870 * atomically invalidating the lock handle in drvvdDestruct. */
871 int rc2 = RTSemFastMutexRequest(pThis->MergeCompleteMutex);
872 AssertRC(rc2);
873 if (RT_SUCCESS(rc2) && pThis->fMergePending)
874 {
875 /* Take shortcut: PFNSIMPLEPROGRESS is exactly the same type as
876 * PFNVDPROGRESS, so there's no need for a conversion function. */
877 /** @todo maybe introduce a conversion which limits update frequency. */
878 PVDINTERFACE pVDIfsOperation = NULL;
879 VDINTERFACE VDIProgress;
880 VDINTERFACEPROGRESS VDIProgressCallbacks;
881 VDIProgressCallbacks.cbSize = sizeof(VDINTERFACEPROGRESS);
882 VDIProgressCallbacks.enmInterface = VDINTERFACETYPE_PROGRESS;
883 VDIProgressCallbacks.pfnProgress = pfnProgress;
884 rc2 = VDInterfaceAdd(&VDIProgress, "DrvVD_VDIProgress", VDINTERFACETYPE_PROGRESS,
885 &VDIProgressCallbacks, pvUser, &pVDIfsOperation);
886 AssertRC(rc2);
887 pThis->fMergePending = false;
888 rc = VDMerge(pThis->pDisk, pThis->uMergeSource,
889 pThis->uMergeTarget, pVDIfsOperation);
890 }
891 rc2 = RTSemFastMutexRelease(pThis->MergeCompleteMutex);
892 AssertRC(rc2);
893 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
894 return rc;
895}
896
897/** @copydoc PDMIMEDIA::pfnGetSize */
898static DECLCALLBACK(uint64_t) drvvdGetSize(PPDMIMEDIA pInterface)
899{
900 LogFlow(("%s:\n", __FUNCTION__));
901 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
902 uint64_t cb = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
903 LogFlow(("%s: returns %#llx (%llu)\n", __FUNCTION__, cb, cb));
904 return cb;
905}
906
907/** @copydoc PDMIMEDIA::pfnIsReadOnly */
908static DECLCALLBACK(bool) drvvdIsReadOnly(PPDMIMEDIA pInterface)
909{
910 LogFlow(("%s:\n", __FUNCTION__));
911 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
912 bool f = VDIsReadOnly(pThis->pDisk);
913 LogFlow(("%s: returns %d\n", __FUNCTION__, f));
914 return f;
915}
916
917/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
918static DECLCALLBACK(int) drvvdBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
919 PPDMMEDIAGEOMETRY pPCHSGeometry)
920{
921 LogFlow(("%s:\n", __FUNCTION__));
922 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
923 int rc = VDGetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
924 if (RT_FAILURE(rc))
925 {
926 Log(("%s: geometry not available.\n", __FUNCTION__));
927 rc = VERR_PDM_GEOMETRY_NOT_SET;
928 }
929 LogFlow(("%s: returns %Rrc (CHS=%d/%d/%d)\n", __FUNCTION__,
930 rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
931 return rc;
932}
933
934/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
935static DECLCALLBACK(int) drvvdBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
936 PCPDMMEDIAGEOMETRY pPCHSGeometry)
937{
938 LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
939 pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
940 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
941 int rc = VDSetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
942 if (rc == VERR_VD_GEOMETRY_NOT_SET)
943 rc = VERR_PDM_GEOMETRY_NOT_SET;
944 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
945 return rc;
946}
947
948/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
949static DECLCALLBACK(int) drvvdBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
950 PPDMMEDIAGEOMETRY pLCHSGeometry)
951{
952 LogFlow(("%s:\n", __FUNCTION__));
953 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
954 int rc = VDGetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
955 if (RT_FAILURE(rc))
956 {
957 Log(("%s: geometry not available.\n", __FUNCTION__));
958 rc = VERR_PDM_GEOMETRY_NOT_SET;
959 }
960 LogFlow(("%s: returns %Rrc (CHS=%d/%d/%d)\n", __FUNCTION__,
961 rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
962 return rc;
963}
964
965/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
966static DECLCALLBACK(int) drvvdBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
967 PCPDMMEDIAGEOMETRY pLCHSGeometry)
968{
969 LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
970 pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
971 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
972 int rc = VDSetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
973 if (rc == VERR_VD_GEOMETRY_NOT_SET)
974 rc = VERR_PDM_GEOMETRY_NOT_SET;
975 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
976 return rc;
977}
978
979/** @copydoc PDMIMEDIA::pfnGetUuid */
980static DECLCALLBACK(int) drvvdGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
981{
982 LogFlow(("%s:\n", __FUNCTION__));
983 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
984 int rc = VDGetUuid(pThis->pDisk, 0, pUuid);
985 LogFlow(("%s: returns %Rrc ({%RTuuid})\n", __FUNCTION__, rc, pUuid));
986 return rc;
987}
988
989/*******************************************************************************
990* Async Media interface methods *
991*******************************************************************************/
992
993static void drvvdAsyncReqComplete(void *pvUser1, void *pvUser2)
994{
995 PVBOXDISK pThis = (PVBOXDISK)pvUser1;
996
997 int rc = pThis->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pThis->pDrvMediaAsyncPort,
998 pvUser2);
999 AssertRC(rc);
1000}
1001
1002static DECLCALLBACK(int) drvvdStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
1003 PCRTSGSEG paSeg, unsigned cSeg,
1004 size_t cbRead, void *pvUser)
1005{
1006 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d\n pvUser=%#p", __FUNCTION__,
1007 uOffset, paSeg, cSeg, cbRead, pvUser));
1008 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
1009 int rc = VDAsyncRead(pThis->pDisk, uOffset, cbRead, paSeg, cSeg,
1010 drvvdAsyncReqComplete, pThis, pvUser);
1011 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1012 return rc;
1013}
1014
1015static DECLCALLBACK(int) drvvdStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
1016 PCRTSGSEG paSeg, unsigned cSeg,
1017 size_t cbWrite, void *pvUser)
1018{
1019 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d\n pvUser=%#p", __FUNCTION__,
1020 uOffset, paSeg, cSeg, cbWrite, pvUser));
1021 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
1022 int rc = VDAsyncWrite(pThis->pDisk, uOffset, cbWrite, paSeg, cSeg,
1023 drvvdAsyncReqComplete, pThis, pvUser);
1024 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1025 return rc;
1026}
1027
1028
1029/*******************************************************************************
1030* Base interface methods *
1031*******************************************************************************/
1032
1033/**
1034 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1035 */
1036static DECLCALLBACK(void *) drvvdQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1037{
1038 PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
1039 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1040
1041 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1042 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
1043 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->fAsyncIOSupported ? &pThis->IMediaAsync : NULL);
1044 return NULL;
1045}
1046
1047
1048/*******************************************************************************
1049* Saved state notification methods *
1050*******************************************************************************/
1051
1052/**
1053 * Load done callback for re-opening the image writable during teleportation.
1054 *
1055 * This is called both for successful and failed load runs, we only care about
1056 * successfull ones.
1057 *
1058 * @returns VBox status code.
1059 * @param pDrvIns The driver instance.
1060 * @param pSSM The saved state handle.
1061 */
1062static DECLCALLBACK(int) drvvdLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
1063{
1064 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1065 Assert(!pThis->fErrorUseRuntime);
1066
1067 /* Drop out if we don't have any work to do or if it's a failed load. */
1068 if ( !pThis->fTempReadOnly
1069 || RT_FAILURE(SSMR3HandleGetStatus(pSSM)))
1070 return VINF_SUCCESS;
1071
1072 int rc = drvvdSetWritable(pThis);
1073 if (RT_FAILURE(rc)) /** @todo does the bugger set any errors? */
1074 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
1075 N_("Failed to write lock the images"));
1076 return VINF_SUCCESS;
1077}
1078
1079
1080/*******************************************************************************
1081* Driver methods *
1082*******************************************************************************/
1083
1084static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
1085{
1086 LogFlow(("%s:\n", __FUNCTION__));
1087 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1088
1089 /*
1090 * We must close the disk here to ensure that
1091 * the backend closes all files before the
1092 * async transport driver is destructed.
1093 */
1094 int rc = VDCloseAll(pThis->pDisk);
1095 AssertRC(rc);
1096}
1097
1098/**
1099 * VM resume notification that we use to undo what the temporary read-only image
1100 * mode set by drvvdSuspend.
1101 *
1102 * Also switch to runtime error mode if we're resuming after a state load
1103 * without having been powered on first.
1104 *
1105 * @param pDrvIns The driver instance data.
1106 *
1107 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
1108 * we're making assumptions about Main behavior here!
1109 */
1110static DECLCALLBACK(void) drvvdResume(PPDMDRVINS pDrvIns)
1111{
1112 LogFlow(("%s:\n", __FUNCTION__));
1113 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1114 drvvdSetWritable(pThis);
1115 pThis->fErrorUseRuntime = true;
1116}
1117
1118/**
1119 * The VM is being suspended, temporarily change to read-only image mode.
1120 *
1121 * This is important for several reasons:
1122 * -# It makes sure that there are no pending writes to the image. Most
1123 * backends implements this by closing and reopening the image in read-only
1124 * mode.
1125 * -# It allows Main to read the images during snapshotting without having
1126 * to account for concurrent writes.
1127 * -# This is essential for making teleportation targets sharing images work
1128 * right. Both with regards to caching and with regards to file sharing
1129 * locks (RTFILE_O_DENY_*). (See also drvvdLoadDone.)
1130 *
1131 * @param pDrvIns The driver instance data.
1132 */
1133static DECLCALLBACK(void) drvvdSuspend(PPDMDRVINS pDrvIns)
1134{
1135 LogFlow(("%s:\n", __FUNCTION__));
1136 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1137 drvvdSetReadonly(pThis);
1138}
1139
1140/**
1141 * VM PowerOn notification for undoing the TempReadOnly config option and
1142 * changing to runtime error mode.
1143 *
1144 * @param pDrvIns The driver instance data.
1145 *
1146 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
1147 * we're making assumptions about Main behavior here!
1148 */
1149static DECLCALLBACK(void) drvvdPowerOn(PPDMDRVINS pDrvIns)
1150{
1151 LogFlow(("%s:\n", __FUNCTION__));
1152 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1153 drvvdSetWritable(pThis);
1154 pThis->fErrorUseRuntime = true;
1155}
1156
1157/**
1158 * @copydoc FNPDMDRVDESTRUCT
1159 */
1160static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
1161{
1162 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1163 LogFlow(("%s:\n", __FUNCTION__));
1164 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1165
1166 RTSEMFASTMUTEX mutex = (RTSEMFASTMUTEX)ASMAtomicXchgPtr((void **)&pThis->MergeCompleteMutex,
1167 (void *)NIL_RTSEMFASTMUTEX);
1168 if (mutex != NIL_RTSEMFASTMUTEX)
1169 {
1170 /* Request the semaphore to wait until a potentially running merge
1171 * operation has been finished. */
1172 int rc = RTSemFastMutexRequest(mutex);
1173 AssertRC(rc);
1174 pThis->fMergePending = false;
1175 rc = RTSemFastMutexRelease(mutex);
1176 AssertRC(rc);
1177 rc = RTSemFastMutexDestroy(mutex);
1178 AssertRC(rc);
1179 }
1180 if (pThis->MergeLock != NIL_RTSEMRW)
1181 {
1182 int rc = RTSemRWDestroy(pThis->MergeLock);
1183 AssertRC(rc);
1184 pThis->MergeLock = NIL_RTSEMRW;
1185 }
1186
1187 if (VALID_PTR(pThis->pDisk))
1188 {
1189 VDDestroy(pThis->pDisk);
1190 pThis->pDisk = NULL;
1191 }
1192 drvvdFreeImages(pThis);
1193}
1194
1195/**
1196 * Construct a VBox disk media driver instance.
1197 *
1198 * @copydoc FNPDMDRVCONSTRUCT
1199 */
1200static DECLCALLBACK(int) drvvdConstruct(PPDMDRVINS pDrvIns,
1201 PCFGMNODE pCfg,
1202 uint32_t fFlags)
1203{
1204 LogFlow(("%s:\n", __FUNCTION__));
1205 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
1206 int rc = VINF_SUCCESS;
1207 char *pszName = NULL; /**< The path of the disk image file. */
1208 char *pszFormat = NULL; /**< The format backed to use for this image. */
1209 bool fReadOnly; /**< True if the media is read-only. */
1210 bool fHonorZeroWrites; /**< True if zero blocks should be written. */
1211 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1212
1213 /*
1214 * Init the static parts.
1215 */
1216 pDrvIns->IBase.pfnQueryInterface = drvvdQueryInterface;
1217 pThis->pDrvIns = pDrvIns;
1218 pThis->fTempReadOnly = false;
1219 pThis->pDisk = NULL;
1220 pThis->fAsyncIOSupported = false;
1221 pThis->fMergePending = false;
1222 pThis->MergeCompleteMutex = NIL_RTSEMFASTMUTEX;
1223 pThis->uMergeSource = VD_LAST_IMAGE;
1224 pThis->uMergeTarget = VD_LAST_IMAGE;
1225
1226 /* IMedia */
1227 pThis->IMedia.pfnRead = drvvdRead;
1228 pThis->IMedia.pfnWrite = drvvdWrite;
1229 pThis->IMedia.pfnFlush = drvvdFlush;
1230 pThis->IMedia.pfnMerge = drvvdMerge;
1231 pThis->IMedia.pfnGetSize = drvvdGetSize;
1232 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly;
1233 pThis->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
1234 pThis->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
1235 pThis->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
1236 pThis->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
1237 pThis->IMedia.pfnGetUuid = drvvdGetUuid;
1238
1239 /* IMediaAsync */
1240 pThis->IMediaAsync.pfnStartRead = drvvdStartRead;
1241 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite;
1242
1243 /* Initialize supported VD interfaces. */
1244 pThis->pVDIfsDisk = NULL;
1245
1246 pThis->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1247 pThis->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1248 pThis->VDIErrorCallbacks.pfnError = drvvdErrorCallback;
1249 pThis->VDIErrorCallbacks.pfnMessage = NULL;
1250
1251 rc = VDInterfaceAdd(&pThis->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
1252 &pThis->VDIErrorCallbacks, pDrvIns, &pThis->pVDIfsDisk);
1253 AssertRC(rc);
1254
1255 /* This is just prepared here, the actual interface is per-image, so it's
1256 * added later. No need to have separate callback tables. */
1257 pThis->VDIConfigCallbacks.cbSize = sizeof(VDINTERFACECONFIG);
1258 pThis->VDIConfigCallbacks.enmInterface = VDINTERFACETYPE_CONFIG;
1259 pThis->VDIConfigCallbacks.pfnAreKeysValid = drvvdCfgAreKeysValid;
1260 pThis->VDIConfigCallbacks.pfnQuerySize = drvvdCfgQuerySize;
1261 pThis->VDIConfigCallbacks.pfnQuery = drvvdCfgQuery;
1262
1263 /* List of images is empty now. */
1264 pThis->pImages = NULL;
1265
1266 /* Try to attach async media port interface above.*/
1267 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1268
1269 /*
1270 * Validate configuration and find all parent images.
1271 * It's sort of up side down from the image dependency tree.
1272 */
1273 bool fHostIP = false;
1274 bool fUseNewIo = false;
1275 unsigned iLevel = 0;
1276 PCFGMNODE pCurNode = pCfg;
1277
1278 for (;;)
1279 {
1280 bool fValid;
1281
1282 if (pCurNode == pCfg)
1283 {
1284 /* Toplevel configuration additionally contains the global image
1285 * open flags. Some might be converted to per-image flags later. */
1286 fValid = CFGMR3AreValuesValid(pCurNode,
1287 "Format\0Path\0"
1288 "ReadOnly\0TempReadOnly\0HonorZeroWrites\0"
1289 "HostIPStack\0UseNewIo\0SetupMerge\0");
1290 }
1291 else
1292 {
1293 /* All other image configurations only contain image name and
1294 * the format information. */
1295 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0"
1296 "MergeSource\0MergeTarget\0");
1297 }
1298 if (!fValid)
1299 {
1300 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1301 RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
1302 break;
1303 }
1304
1305 if (pCurNode == pCfg)
1306 {
1307 rc = CFGMR3QueryBoolDef(pCurNode, "HostIPStack", &fHostIP, true);
1308 if (RT_FAILURE(rc))
1309 {
1310 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1311 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
1312 break;
1313 }
1314
1315 rc = CFGMR3QueryBoolDef(pCurNode, "HonorZeroWrites", &fHonorZeroWrites, false);
1316 if (RT_FAILURE(rc))
1317 {
1318 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1319 N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
1320 break;
1321 }
1322
1323 rc = CFGMR3QueryBoolDef(pCurNode, "ReadOnly", &fReadOnly, false);
1324 if (RT_FAILURE(rc))
1325 {
1326 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1327 N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
1328 break;
1329 }
1330
1331 rc = CFGMR3QueryBoolDef(pCurNode, "TempReadOnly", &pThis->fTempReadOnly, false);
1332 if (RT_FAILURE(rc))
1333 {
1334 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1335 N_("DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
1336 break;
1337 }
1338 if (fReadOnly && pThis->fTempReadOnly)
1339 {
1340 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1341 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
1342 break;
1343 }
1344 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
1345 if (RT_FAILURE(rc))
1346 {
1347 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1348 N_("DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
1349 break;
1350 }
1351 rc = CFGMR3QueryBoolDef(pCurNode, "SetupMerge", &pThis->fMergePending, false);
1352 if (RT_FAILURE(rc))
1353 {
1354 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1355 N_("DrvVD: Configuration error: Querying \"SetupMerge\" as boolean failed"));
1356 break;
1357 }
1358 if (fReadOnly && pThis->fMergePending)
1359 {
1360 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1361 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"MergePending\" are set"));
1362 break;
1363 }
1364 }
1365
1366 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
1367 if (!pParent)
1368 break;
1369 pCurNode = pParent;
1370 iLevel++;
1371 }
1372
1373 /*
1374 * Create the image container and the necessary interfaces.
1375 */
1376 if (RT_SUCCESS(rc))
1377 {
1378 /* First of all figure out what kind of TCP networking stack interface
1379 * to use. This is done unconditionally, as backends which don't need
1380 * it will just ignore it. */
1381 if (fHostIP)
1382 {
1383 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1384 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1385 pThis->VDITcpNetCallbacks.pfnClientConnect = RTTcpClientConnect;
1386 pThis->VDITcpNetCallbacks.pfnClientClose = RTTcpClientClose;
1387 pThis->VDITcpNetCallbacks.pfnSelectOne = RTTcpSelectOne;
1388 pThis->VDITcpNetCallbacks.pfnRead = RTTcpRead;
1389 pThis->VDITcpNetCallbacks.pfnWrite = RTTcpWrite;
1390 pThis->VDITcpNetCallbacks.pfnFlush = RTTcpFlush;
1391 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = RTTcpGetLocalAddress;
1392 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = RTTcpGetPeerAddress;
1393 }
1394 else
1395 {
1396#ifndef VBOX_WITH_INIP
1397 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1398 RT_SRC_POS, N_("DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
1399#else /* VBOX_WITH_INIP */
1400 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1401 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1402 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
1403 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
1404 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
1405 pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
1406 pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite;
1407 pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush;
1408 pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdINIPGetLocalAddress;
1409 pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdINIPGetPeerAddress;
1410#endif /* VBOX_WITH_INIP */
1411 }
1412 if (RT_SUCCESS(rc))
1413 {
1414 rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP",
1415 VDINTERFACETYPE_TCPNET,
1416 &pThis->VDITcpNetCallbacks, NULL,
1417 &pThis->pVDIfsDisk);
1418 }
1419
1420 if (RT_SUCCESS(rc) && fUseNewIo)
1421 {
1422#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1423 pThis->VDIAsyncIOCallbacks.cbSize = sizeof(VDINTERFACEASYNCIO);
1424 pThis->VDIAsyncIOCallbacks.enmInterface = VDINTERFACETYPE_ASYNCIO;
1425 pThis->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen;
1426 pThis->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose;
1427 pThis->VDIAsyncIOCallbacks.pfnGetSize = drvvdAsyncIOGetSize;
1428 pThis->VDIAsyncIOCallbacks.pfnSetSize = drvvdAsyncIOSetSize;
1429 pThis->VDIAsyncIOCallbacks.pfnReadSync = drvvdAsyncIOReadSync;
1430 pThis->VDIAsyncIOCallbacks.pfnWriteSync = drvvdAsyncIOWriteSync;
1431 pThis->VDIAsyncIOCallbacks.pfnFlushSync = drvvdAsyncIOFlushSync;
1432 pThis->VDIAsyncIOCallbacks.pfnReadAsync = drvvdAsyncIOReadAsync;
1433 pThis->VDIAsyncIOCallbacks.pfnWriteAsync = drvvdAsyncIOWriteAsync;
1434 pThis->VDIAsyncIOCallbacks.pfnFlushAsync = drvvdAsyncIOFlushAsync;
1435
1436 rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
1437 &pThis->VDIAsyncIOCallbacks, pThis, &pThis->pVDIfsDisk);
1438#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1439 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1440 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
1441#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1442 }
1443
1444 if (RT_SUCCESS(rc) && pThis->fMergePending)
1445 {
1446 rc = RTSemFastMutexCreate(&pThis->MergeCompleteMutex);
1447 if (RT_SUCCESS(rc))
1448 rc = RTSemRWCreate(&pThis->MergeLock);
1449 if (RT_SUCCESS(rc))
1450 {
1451 pThis->VDIThreadSyncCallbacks.cbSize = sizeof(VDINTERFACETHREADSYNC);
1452 pThis->VDIThreadSyncCallbacks.enmInterface = VDINTERFACETYPE_THREADSYNC;
1453 pThis->VDIThreadSyncCallbacks.pfnStartRead = drvvdThreadStartRead;
1454 pThis->VDIThreadSyncCallbacks.pfnFinishRead = drvvdThreadFinishRead;
1455 pThis->VDIThreadSyncCallbacks.pfnStartWrite = drvvdThreadStartWrite;
1456 pThis->VDIThreadSyncCallbacks.pfnFinishWrite = drvvdThreadFinishWrite;
1457
1458 rc = VDInterfaceAdd(&pThis->VDIThreadSync, "DrvVD_ThreadSync", VDINTERFACETYPE_THREADSYNC,
1459 &pThis->VDIThreadSyncCallbacks, pThis, &pThis->pVDIfsDisk);
1460 }
1461 else
1462 {
1463 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1464 N_("DrvVD: Failed to create semaphores for \"MergePending\""));
1465 }
1466 }
1467
1468 if (RT_SUCCESS(rc))
1469 {
1470 rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk);
1471 /* Error message is already set correctly. */
1472 }
1473 }
1474
1475 if (pThis->pDrvMediaAsyncPort && fUseNewIo)
1476 pThis->fAsyncIOSupported = true;
1477
1478 unsigned iImageIdx = 0;
1479 while (pCurNode && RT_SUCCESS(rc))
1480 {
1481 /* Allocate per-image data. */
1482 PVBOXIMAGE pImage = drvvdNewImage(pThis);
1483 if (!pImage)
1484 {
1485 rc = VERR_NO_MEMORY;
1486 break;
1487 }
1488
1489 /*
1490 * Read the image configuration.
1491 */
1492 rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
1493 if (RT_FAILURE(rc))
1494 {
1495 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1496 N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
1497 break;
1498 }
1499
1500 rc = CFGMR3QueryStringAlloc(pCurNode, "Format", &pszFormat);
1501 if (RT_FAILURE(rc))
1502 {
1503 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1504 N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
1505 break;
1506 }
1507
1508 bool fMergeSource;
1509 rc = CFGMR3QueryBoolDef(pCurNode, "MergeSource", &fMergeSource, false);
1510 if (RT_FAILURE(rc))
1511 {
1512 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1513 N_("DrvVD: Configuration error: Querying \"MergeSource\" as boolean failed"));
1514 break;
1515 }
1516 if (fMergeSource)
1517 {
1518 if (pThis->uMergeSource == VD_LAST_IMAGE)
1519 pThis->uMergeSource = iImageIdx;
1520 else
1521 {
1522 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1523 N_("DrvVD: Configuration error: Multiple \"MergeSource\" occurrences"));
1524 break;
1525 }
1526 }
1527
1528 bool fMergeTarget;
1529 rc = CFGMR3QueryBoolDef(pCurNode, "MergeTarget", &fMergeTarget, false);
1530 if (RT_FAILURE(rc))
1531 {
1532 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1533 N_("DrvVD: Configuration error: Querying \"MergeTarget\" as boolean failed"));
1534 break;
1535 }
1536 if (fMergeTarget)
1537 {
1538 if (pThis->uMergeTarget == VD_LAST_IMAGE)
1539 pThis->uMergeTarget = iImageIdx;
1540 else
1541 {
1542 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1543 N_("DrvVD: Configuration error: Multiple \"MergeTarget\" occurrences"));
1544 break;
1545 }
1546 }
1547
1548 PCFGMNODE pCfgVDConfig = CFGMR3GetChild(pCurNode, "VDConfig");
1549 rc = VDInterfaceAdd(&pImage->VDIConfig, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
1550 &pThis->VDIConfigCallbacks, pCfgVDConfig, &pImage->pVDIfsImage);
1551 AssertRC(rc);
1552
1553 /*
1554 * Open the image.
1555 */
1556 unsigned uOpenFlags;
1557 if (fReadOnly || pThis->fTempReadOnly || iLevel != 0)
1558 uOpenFlags = VD_OPEN_FLAGS_READONLY;
1559 else
1560 uOpenFlags = VD_OPEN_FLAGS_NORMAL;
1561 if (fHonorZeroWrites)
1562 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
1563 if (pThis->fAsyncIOSupported)
1564 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
1565
1566 /* Try to open backend in async I/O mode first. */
1567 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1568 if (rc == VERR_NOT_SUPPORTED)
1569 {
1570 pThis->fAsyncIOSupported = false;
1571 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
1572 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1573 }
1574
1575 if (RT_SUCCESS(rc))
1576 {
1577 Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
1578 iLevel, pszName,
1579 VDIsReadOnly(pThis->pDisk) ? "read-only" : "read-write"));
1580 if ( VDIsReadOnly(pThis->pDisk)
1581 && !fReadOnly
1582 && !pThis->fTempReadOnly
1583 && iLevel == 0)
1584 {
1585 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_VD_IMAGE_READ_ONLY, RT_SRC_POS,
1586 N_("Failed to open image '%s' for writing due to wrong permissions"),
1587 pszName);
1588 break;
1589 }
1590 }
1591 else
1592 {
1593 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1594 N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName,
1595 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc);
1596 break;
1597 }
1598
1599
1600 MMR3HeapFree(pszName);
1601 pszName = NULL;
1602 MMR3HeapFree(pszFormat);
1603 pszFormat = NULL;
1604
1605 /* next */
1606 iLevel--;
1607 iImageIdx--;
1608 pCurNode = CFGMR3GetParent(pCurNode);
1609 }
1610
1611 if ( RT_SUCCESS(rc)
1612 && pThis->fMergePending
1613 && ( pThis->uMergeSource == VD_LAST_IMAGE
1614 || pThis->uMergeTarget == VD_LAST_IMAGE))
1615 {
1616 rc = PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRIVER_INVALID_PROPERTIES,
1617 N_("DrvVD: Configuration error: Inconsistent image merge data"));
1618 }
1619
1620 /*
1621 * Register a load-done callback so we can undo TempReadOnly config before
1622 * we get to drvvdResume. Autoamtically deregistered upon destruction.
1623 */
1624 if (RT_SUCCESS(rc))
1625 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
1626 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
1627 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
1628 NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
1629
1630
1631 if (RT_FAILURE(rc))
1632 {
1633 if (VALID_PTR(pszName))
1634 MMR3HeapFree(pszName);
1635 if (VALID_PTR(pszFormat))
1636 MMR3HeapFree(pszFormat);
1637 /* drvvdDestruct does the rest. */
1638 }
1639
1640 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1641 return rc;
1642}
1643
1644/**
1645 * VBox disk container media driver registration record.
1646 */
1647const PDMDRVREG g_DrvVD =
1648{
1649 /* u32Version */
1650 PDM_DRVREG_VERSION,
1651 /* szName */
1652 "VD",
1653 /* szRCMod */
1654 "",
1655 /* szR0Mod */
1656 "",
1657 /* pszDescription */
1658 "Generic VBox disk media driver.",
1659 /* fFlags */
1660 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1661 /* fClass. */
1662 PDM_DRVREG_CLASS_MEDIA,
1663 /* cMaxInstances */
1664 ~0,
1665 /* cbInstance */
1666 sizeof(VBOXDISK),
1667 /* pfnConstruct */
1668 drvvdConstruct,
1669 /* pfnDestruct */
1670 drvvdDestruct,
1671 /* pfnRelocate */
1672 NULL,
1673 /* pfnIOCtl */
1674 NULL,
1675 /* pfnPowerOn */
1676 drvvdPowerOn,
1677 /* pfnReset */
1678 NULL,
1679 /* pfnSuspend */
1680 drvvdSuspend,
1681 /* pfnResume */
1682 drvvdResume,
1683 /* pfnAttach */
1684 NULL,
1685 /* pfnDetach */
1686 NULL,
1687 /* pfnPowerOff */
1688 drvvdPowerOff,
1689 /* pfnSoftReset */
1690 NULL,
1691 /* u32EndVersion */
1692 PDM_DRVREG_VERSION
1693};
1694
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