VirtualBox

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

Last change on this file since 27653 was 27303, checked in by vboxsync, 15 years ago

DrvVD: Not yet

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