VirtualBox

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

Last change on this file since 26270 was 26206, checked in by vboxsync, 15 years ago

Don't enable new I/O by default yet

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