VirtualBox

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

Last change on this file since 26008 was 26001, checked in by vboxsync, 15 years ago

PDM,*: Redid the PDM structure versions. Check the instance and helper versions in every device and driver constructor.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.1 KB
Line 
1/* $Id: DrvVD.cpp 26001 2010-01-25 14:21:13Z 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 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 /* Wait */
364 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
365 AssertRC(rc);
366
367 if (pcbRead)
368 *pcbRead = cbRead;
369
370 return VINF_SUCCESS;
371}
372
373static DECLCALLBACK(int) drvvdAsyncIOWriteSync(void *pvUser, void *pStorage, uint64_t uOffset,
374 size_t cbWrite, const void *pvBuf, size_t *pcbWritten)
375{
376 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
377 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
378 PDMDATASEG DataSeg;
379 PPDMASYNCCOMPLETIONTASK pTask;
380
381 Assert(!pStorageBackend->fSyncIoPending);
382 pStorageBackend->fSyncIoPending = true;
383 DataSeg.cbSeg = cbWrite;
384 DataSeg.pvSeg = (void *)pvBuf;
385
386 int rc = PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, &DataSeg, 1, cbWrite, NULL, &pTask);
387 if (RT_FAILURE(rc))
388 return rc;
389
390 /* Wait */
391 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
392 AssertRC(rc);
393
394 if (pcbWritten)
395 *pcbWritten = cbWrite;
396
397 return VINF_SUCCESS;
398}
399
400static DECLCALLBACK(int) drvvdAsyncIOFlushSync(void *pvUser, void *pStorage)
401{
402 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
403 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
404 PPDMASYNCCOMPLETIONTASK pTask;
405
406 Assert(!pStorageBackend->fSyncIoPending);
407 pStorageBackend->fSyncIoPending = true;
408
409 int rc = PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, NULL, &pTask);
410 if (RT_FAILURE(rc))
411 return rc;
412
413 /* Wait */
414 rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
415 AssertRC(rc);
416
417 return VINF_SUCCESS;
418}
419
420static DECLCALLBACK(int) drvvdAsyncIOReadAsync(void *pvUser, void *pStorage, uint64_t uOffset,
421 PCPDMDATASEG paSegments, size_t cSegments,
422 size_t cbRead, void *pvCompletion,
423 void **ppTask)
424{
425 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
426 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
427
428 return PDMR3AsyncCompletionEpRead(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbRead,
429 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
430}
431
432static DECLCALLBACK(int) drvvdAsyncIOWriteAsync(void *pvUser, void *pStorage, uint64_t uOffset,
433 PCPDMDATASEG paSegments, size_t cSegments,
434 size_t cbWrite, void *pvCompletion,
435 void **ppTask)
436{
437 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
438 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
439
440 return PDMR3AsyncCompletionEpWrite(pStorageBackend->pEndpoint, uOffset, paSegments, cSegments, cbWrite,
441 pvCompletion, (PPPDMASYNCCOMPLETIONTASK)ppTask);
442}
443
444static DECLCALLBACK(int) drvvdAsyncIOFlushAsync(void *pvUser, void *pStorage,
445 void *pvCompletion, void **ppTask)
446{
447 PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
448 PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
449
450 return PDMR3AsyncCompletionEpFlush(pStorageBackend->pEndpoint, pvCompletion,
451 (PPPDMASYNCCOMPLETIONTASK)ppTask);
452}
453
454#endif /* VBOX_WITH_PDM_ASYNC_COMPLETION */
455
456
457/*******************************************************************************
458* VD Configuration interface implementation *
459*******************************************************************************/
460
461static bool drvvdCfgAreKeysValid(void *pvUser, const char *pszzValid)
462{
463 return CFGMR3AreValuesValid((PCFGMNODE)pvUser, pszzValid);
464}
465
466static int drvvdCfgQuerySize(void *pvUser, const char *pszName, size_t *pcb)
467{
468 return CFGMR3QuerySize((PCFGMNODE)pvUser, pszName, pcb);
469}
470
471static int drvvdCfgQuery(void *pvUser, const char *pszName, char *pszString, size_t cchString)
472{
473 return CFGMR3QueryString((PCFGMNODE)pvUser, pszName, pszString, cchString);
474}
475
476
477#ifdef VBOX_WITH_INIP
478/*******************************************************************************
479* VD TCP network stack interface implementation - INIP case *
480*******************************************************************************/
481
482/** @copydoc VDINTERFACETCPNET::pfnClientConnect */
483static DECLCALLBACK(int) drvvdINIPClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
484{
485 int rc = VINF_SUCCESS;
486 /* First check whether lwIP is set up in this VM instance. */
487 if (!DevINIPConfigured())
488 {
489 LogRelFunc(("no IP stack\n"));
490 return VERR_NET_HOST_UNREACHABLE;
491 }
492 /* Resolve hostname. As there is no standard resolver for lwIP yet,
493 * just accept numeric IP addresses for now. */
494 struct in_addr ip;
495 if (!lwip_inet_aton(pszAddress, &ip))
496 {
497 LogRelFunc(("cannot resolve IP %s\n", pszAddress));
498 return VERR_NET_HOST_UNREACHABLE;
499 }
500 /* Create socket and connect. */
501 RTSOCKET Sock = lwip_socket(PF_INET, SOCK_STREAM, 0);
502 if (Sock != -1)
503 {
504 struct sockaddr_in InAddr = {0};
505 InAddr.sin_family = AF_INET;
506 InAddr.sin_port = htons(uPort);
507 InAddr.sin_addr = ip;
508 if (!lwip_connect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr)))
509 {
510 *pSock = Sock;
511 return VINF_SUCCESS;
512 }
513 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
514 lwip_close(Sock);
515 }
516 else
517 rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
518 return rc;
519}
520
521/** @copydoc VDINTERFACETCPNET::pfnClientClose */
522static DECLCALLBACK(int) drvvdINIPClientClose(RTSOCKET Sock)
523{
524 lwip_close(Sock);
525 return VINF_SUCCESS; /** @todo real solution needed */
526}
527
528/** @copydoc VDINTERFACETCPNET::pfnSelectOne */
529static DECLCALLBACK(int) drvvdINIPSelectOne(RTSOCKET Sock, RTMSINTERVAL cMillies)
530{
531 fd_set fdsetR;
532 FD_ZERO(&fdsetR);
533 FD_SET(Sock, &fdsetR);
534 fd_set fdsetE = fdsetR;
535
536 int rc;
537 if (cMillies == RT_INDEFINITE_WAIT)
538 rc = lwip_select(Sock + 1, &fdsetR, NULL, &fdsetE, NULL);
539 else
540 {
541 struct timeval timeout;
542 timeout.tv_sec = cMillies / 1000;
543 timeout.tv_usec = (cMillies % 1000) * 1000;
544 rc = lwip_select(Sock + 1, &fdsetR, NULL, &fdsetE, &timeout);
545 }
546 if (rc > 0)
547 return VINF_SUCCESS;
548 if (rc == 0)
549 return VERR_TIMEOUT;
550 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
551}
552
553/** @copydoc VDINTERFACETCPNET::pfnRead */
554static DECLCALLBACK(int) drvvdINIPRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
555{
556 /* Do params checking */
557 if (!pvBuffer || !cbBuffer)
558 {
559 AssertMsgFailed(("Invalid params\n"));
560 return VERR_INVALID_PARAMETER;
561 }
562
563 /*
564 * Read loop.
565 * If pcbRead is NULL we have to fill the entire buffer!
566 */
567 size_t cbRead = 0;
568 size_t cbToRead = cbBuffer;
569 for (;;)
570 {
571 /** @todo this clipping here is just in case (the send function
572 * needed it, so I added it here, too). Didn't investigate if this
573 * really has issues. Better be safe than sorry. */
574 ssize_t cbBytesRead = lwip_recv(Sock, (char *)pvBuffer + cbRead,
575 RT_MIN(cbToRead, 32768), 0);
576 if (cbBytesRead < 0)
577 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
578 if (cbBytesRead == 0 && errno)
579 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution */
580 if (pcbRead)
581 {
582 /* return partial data */
583 *pcbRead = cbBytesRead;
584 break;
585 }
586
587 /* read more? */
588 cbRead += cbBytesRead;
589 if (cbRead == cbBuffer)
590 break;
591
592 /* next */
593 cbToRead = cbBuffer - cbRead;
594 }
595
596 return VINF_SUCCESS;
597}
598
599/** @copydoc VDINTERFACETCPNET::pfnWrite */
600static DECLCALLBACK(int) drvvdINIPWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
601{
602 do
603 {
604 /** @todo lwip send only supports up to 65535 bytes in a single
605 * send (stupid limitation buried in the code), so make sure we
606 * don't get any wraparounds. This should be moved to DevINIP
607 * stack interface once that's implemented. */
608 ssize_t cbWritten = lwip_send(Sock, (void *)pvBuffer,
609 RT_MIN(cbBuffer, 32768), 0);
610 if (cbWritten < 0)
611 return VERR_NET_CONNECTION_REFUSED; /** @todo real solution needed */
612 AssertMsg(cbBuffer >= (size_t)cbWritten, ("Wrote more than we requested!!! cbWritten=%d cbBuffer=%d\n",
613 cbWritten, cbBuffer));
614 cbBuffer -= cbWritten;
615 pvBuffer = (const char *)pvBuffer + cbWritten;
616 } while (cbBuffer);
617
618 return VINF_SUCCESS;
619}
620
621/** @copydoc VDINTERFACETCPNET::pfnFlush */
622static DECLCALLBACK(int) drvvdINIPFlush(RTSOCKET Sock)
623{
624 int fFlag = 1;
625 lwip_setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY,
626 (const char *)&fFlag, sizeof(fFlag));
627 fFlag = 0;
628 lwip_setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY,
629 (const char *)&fFlag, sizeof(fFlag));
630 return VINF_SUCCESS;
631}
632#endif /* VBOX_WITH_INIP */
633
634
635/*******************************************************************************
636* Media interface methods *
637*******************************************************************************/
638
639/** @copydoc PDMIMEDIA::pfnRead */
640static DECLCALLBACK(int) drvvdRead(PPDMIMEDIA pInterface,
641 uint64_t off, void *pvBuf, size_t cbRead)
642{
643 LogFlow(("%s: off=%#llx pvBuf=%p cbRead=%d\n", __FUNCTION__,
644 off, pvBuf, cbRead));
645 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
646 int rc = VDRead(pThis->pDisk, off, pvBuf, cbRead);
647 if (RT_SUCCESS(rc))
648 Log2(("%s: off=%#llx pvBuf=%p cbRead=%d %.*Rhxd\n", __FUNCTION__,
649 off, pvBuf, cbRead, cbRead, pvBuf));
650 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
651 return rc;
652}
653
654/** @copydoc PDMIMEDIA::pfnWrite */
655static DECLCALLBACK(int) drvvdWrite(PPDMIMEDIA pInterface,
656 uint64_t off, const void *pvBuf,
657 size_t cbWrite)
658{
659 LogFlow(("%s: off=%#llx pvBuf=%p cbWrite=%d\n", __FUNCTION__,
660 off, pvBuf, cbWrite));
661 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
662 Log2(("%s: off=%#llx pvBuf=%p cbWrite=%d %.*Rhxd\n", __FUNCTION__,
663 off, pvBuf, cbWrite, cbWrite, pvBuf));
664 int rc = VDWrite(pThis->pDisk, off, pvBuf, cbWrite);
665 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
666 return rc;
667}
668
669/** @copydoc PDMIMEDIA::pfnFlush */
670static DECLCALLBACK(int) drvvdFlush(PPDMIMEDIA pInterface)
671{
672 LogFlow(("%s:\n", __FUNCTION__));
673 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
674 int rc = VDFlush(pThis->pDisk);
675 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
676 return rc;
677}
678
679/** @copydoc PDMIMEDIA::pfnGetSize */
680static DECLCALLBACK(uint64_t) drvvdGetSize(PPDMIMEDIA pInterface)
681{
682 LogFlow(("%s:\n", __FUNCTION__));
683 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
684 uint64_t cb = VDGetSize(pThis->pDisk, VD_LAST_IMAGE);
685 LogFlow(("%s: returns %#llx (%llu)\n", __FUNCTION__, cb, cb));
686 return cb;
687}
688
689/** @copydoc PDMIMEDIA::pfnIsReadOnly */
690static DECLCALLBACK(bool) drvvdIsReadOnly(PPDMIMEDIA pInterface)
691{
692 LogFlow(("%s:\n", __FUNCTION__));
693 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
694 bool f = VDIsReadOnly(pThis->pDisk);
695 LogFlow(("%s: returns %d\n", __FUNCTION__, f));
696 return f;
697}
698
699/** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */
700static DECLCALLBACK(int) drvvdBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
701 PPDMMEDIAGEOMETRY pPCHSGeometry)
702{
703 LogFlow(("%s:\n", __FUNCTION__));
704 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
705 int rc = VDGetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
706 if (RT_FAILURE(rc))
707 {
708 Log(("%s: geometry not available.\n", __FUNCTION__));
709 rc = VERR_PDM_GEOMETRY_NOT_SET;
710 }
711 LogFlow(("%s: returns %Rrc (CHS=%d/%d/%d)\n", __FUNCTION__,
712 rc, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
713 return rc;
714}
715
716/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */
717static DECLCALLBACK(int) drvvdBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
718 PCPDMMEDIAGEOMETRY pPCHSGeometry)
719{
720 LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
721 pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
722 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
723 int rc = VDSetPCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pPCHSGeometry);
724 if (rc == VERR_VD_GEOMETRY_NOT_SET)
725 rc = VERR_PDM_GEOMETRY_NOT_SET;
726 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
727 return rc;
728}
729
730/** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */
731static DECLCALLBACK(int) drvvdBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
732 PPDMMEDIAGEOMETRY pLCHSGeometry)
733{
734 LogFlow(("%s:\n", __FUNCTION__));
735 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
736 int rc = VDGetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
737 if (RT_FAILURE(rc))
738 {
739 Log(("%s: geometry not available.\n", __FUNCTION__));
740 rc = VERR_PDM_GEOMETRY_NOT_SET;
741 }
742 LogFlow(("%s: returns %Rrc (CHS=%d/%d/%d)\n", __FUNCTION__,
743 rc, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
744 return rc;
745}
746
747/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */
748static DECLCALLBACK(int) drvvdBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
749 PCPDMMEDIAGEOMETRY pLCHSGeometry)
750{
751 LogFlow(("%s: CHS=%d/%d/%d\n", __FUNCTION__,
752 pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
753 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
754 int rc = VDSetLCHSGeometry(pThis->pDisk, VD_LAST_IMAGE, pLCHSGeometry);
755 if (rc == VERR_VD_GEOMETRY_NOT_SET)
756 rc = VERR_PDM_GEOMETRY_NOT_SET;
757 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
758 return rc;
759}
760
761/** @copydoc PDMIMEDIA::pfnGetUuid */
762static DECLCALLBACK(int) drvvdGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
763{
764 LogFlow(("%s:\n", __FUNCTION__));
765 PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
766 int rc = VDGetUuid(pThis->pDisk, 0, pUuid);
767 LogFlow(("%s: returns %Rrc ({%RTuuid})\n", __FUNCTION__, rc, pUuid));
768 return rc;
769}
770
771/*******************************************************************************
772* Async Media interface methods *
773*******************************************************************************/
774
775static DECLCALLBACK(int) drvvdStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
776 PPDMDATASEG paSeg, unsigned cSeg,
777 size_t cbRead, void *pvUser)
778{
779 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d\n pvUser=%#p", __FUNCTION__,
780 uOffset, paSeg, cSeg, cbRead, pvUser));
781 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
782 int rc = VDAsyncRead(pThis->pDisk, uOffset, cbRead, paSeg, cSeg, pvUser);
783 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
784 return rc;
785}
786
787static DECLCALLBACK(int) drvvdStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
788 PPDMDATASEG paSeg, unsigned cSeg,
789 size_t cbWrite, void *pvUser)
790{
791 LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d\n pvUser=%#p", __FUNCTION__,
792 uOffset, paSeg, cSeg, cbWrite, pvUser));
793 PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
794 int rc = VDAsyncWrite(pThis->pDisk, uOffset, cbWrite, paSeg, cSeg, pvUser);
795 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
796 return rc;
797}
798
799/*******************************************************************************
800* Async transport port interface methods *
801*******************************************************************************/
802
803static DECLCALLBACK(int) drvvdTasksCompleteNotify(PPDMDRVINS pDrvIns, void *pvUser)
804{
805 return VERR_NOT_IMPLEMENTED;
806}
807
808
809/*******************************************************************************
810* Base interface methods *
811*******************************************************************************/
812
813/**
814 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
815 */
816static DECLCALLBACK(void *) drvvdQueryInterface(PPDMIBASE pInterface, const char *pszIID)
817{
818 PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
819 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
820
821 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
822 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
823 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->fAsyncIOSupported ? &pThis->IMediaAsync : NULL);
824 return NULL;
825}
826
827
828/*******************************************************************************
829* Saved state notification methods *
830*******************************************************************************/
831
832/**
833 * Load done callback for re-opening the image writable during teleportation.
834 *
835 * This is called both for successful and failed load runs, we only care about
836 * successfull ones.
837 *
838 * @returns VBox status code.
839 * @param pDrvIns The driver instance.
840 * @param pSSM The saved state handle.
841 */
842static DECLCALLBACK(int) drvvdLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
843{
844 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
845 Assert(!pThis->fErrorUseRuntime);
846
847 /* Drop out if we don't have any work to do or if it's a failed load. */
848 if ( !pThis->fTempReadOnly
849 || RT_FAILURE(SSMR3HandleGetStatus(pSSM)))
850 return VINF_SUCCESS;
851
852 int rc = drvvdSetWritable(pThis);
853 if (RT_FAILURE(rc)) /** @todo does the bugger set any errors? */
854 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
855 N_("Failed to write lock the images"));
856 return VINF_SUCCESS;
857}
858
859
860/*******************************************************************************
861* Driver methods *
862*******************************************************************************/
863
864static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
865{
866 LogFlow(("%s:\n", __FUNCTION__));
867 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
868
869 /*
870 * We must close the disk here to ensure that
871 * the backend closes all files before the
872 * async transport driver is destructed.
873 */
874 int rc = VDCloseAll(pThis->pDisk);
875 AssertRC(rc);
876}
877
878/**
879 * VM resume notification that we use to undo what the temporary read-only image
880 * mode set by drvvdSuspend.
881 *
882 * Also switch to runtime error mode if we're resuming after a state load
883 * without having been powered on first.
884 *
885 * @param pDrvIns The driver instance data.
886 *
887 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
888 * we're making assumptions about Main behavior here!
889 */
890static DECLCALLBACK(void) drvvdResume(PPDMDRVINS pDrvIns)
891{
892 LogFlow(("%s:\n", __FUNCTION__));
893 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
894 drvvdSetWritable(pThis);
895 pThis->fErrorUseRuntime = true;
896}
897
898/**
899 * The VM is being suspended, temporarily change to read-only image mode.
900 *
901 * This is important for several reasons:
902 * -# It makes sure that there are no pending writes to the image. Most
903 * backends implements this by closing and reopening the image in read-only
904 * mode.
905 * -# It allows Main to read the images during snapshotting without having
906 * to account for concurrent writes.
907 * -# This is essential for making teleportation targets sharing images work
908 * right. Both with regards to caching and with regards to file sharing
909 * locks (RTFILE_O_DENY_*). (See also drvvdLoadDone.)
910 *
911 * @param pDrvIns The driver instance data.
912 */
913static DECLCALLBACK(void) drvvdSuspend(PPDMDRVINS pDrvIns)
914{
915 LogFlow(("%s:\n", __FUNCTION__));
916 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
917 if (!VDIsReadOnly(pThis->pDisk))
918 {
919 unsigned uOpenFlags;
920 int rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
921 AssertRC(rc);
922 uOpenFlags |= VD_OPEN_FLAGS_READONLY;
923 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
924 AssertRC(rc);
925 pThis->fTempReadOnly = true;
926 }
927}
928
929/**
930 * VM PowerOn notification for undoing the TempReadOnly config option and
931 * changing to runtime error mode.
932 *
933 * @param pDrvIns The driver instance data.
934 *
935 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
936 * we're making assumptions about Main behavior here!
937 */
938static DECLCALLBACK(void) drvvdPowerOn(PPDMDRVINS pDrvIns)
939{
940 LogFlow(("%s:\n", __FUNCTION__));
941 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
942 drvvdSetWritable(pThis);
943 pThis->fErrorUseRuntime = true;
944}
945
946/**
947 * @copydoc FNPDMDRVDESTRUCT
948 */
949static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
950{
951 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
952 LogFlow(("%s:\n", __FUNCTION__));
953 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
954
955 if (VALID_PTR(pThis->pDisk))
956 {
957 VDDestroy(pThis->pDisk);
958 pThis->pDisk = NULL;
959 }
960 drvvdFreeImages(pThis);
961}
962
963/**
964 * Construct a VBox disk media driver instance.
965 *
966 * @copydoc FNPDMDRVCONSTRUCT
967 */
968static DECLCALLBACK(int) drvvdConstruct(PPDMDRVINS pDrvIns,
969 PCFGMNODE pCfgHandle,
970 uint32_t fFlags)
971{
972 LogFlow(("%s:\n", __FUNCTION__));
973 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
974 int rc = VINF_SUCCESS;
975 char *pszName = NULL; /**< The path of the disk image file. */
976 char *pszFormat = NULL; /**< The format backed to use for this image. */
977 bool fReadOnly; /**< True if the media is read-only. */
978 bool fHonorZeroWrites; /**< True if zero blocks should be written. */
979 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
980
981 /*
982 * Init the static parts.
983 */
984 pDrvIns->IBase.pfnQueryInterface = drvvdQueryInterface;
985 pThis->pDrvIns = pDrvIns;
986 pThis->fTempReadOnly = false;
987 pThis->pDisk = NULL;
988 pThis->fAsyncIOSupported = false;
989
990 /* IMedia */
991 pThis->IMedia.pfnRead = drvvdRead;
992 pThis->IMedia.pfnWrite = drvvdWrite;
993 pThis->IMedia.pfnFlush = drvvdFlush;
994 pThis->IMedia.pfnGetSize = drvvdGetSize;
995 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly;
996 pThis->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
997 pThis->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
998 pThis->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
999 pThis->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
1000 pThis->IMedia.pfnGetUuid = drvvdGetUuid;
1001
1002 /* IMediaAsync */
1003 pThis->IMediaAsync.pfnStartRead = drvvdStartRead;
1004 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite;
1005
1006 /* Initialize supported VD interfaces. */
1007 pThis->pVDIfsDisk = NULL;
1008
1009 pThis->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1010 pThis->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1011 pThis->VDIErrorCallbacks.pfnError = drvvdErrorCallback;
1012 pThis->VDIErrorCallbacks.pfnMessage = NULL;
1013
1014 rc = VDInterfaceAdd(&pThis->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
1015 &pThis->VDIErrorCallbacks, pDrvIns, &pThis->pVDIfsDisk);
1016 AssertRC(rc);
1017
1018 /* This is just prepared here, the actual interface is per-image, so it's
1019 * added later. No need to have separate callback tables. */
1020 pThis->VDIConfigCallbacks.cbSize = sizeof(VDINTERFACECONFIG);
1021 pThis->VDIConfigCallbacks.enmInterface = VDINTERFACETYPE_CONFIG;
1022 pThis->VDIConfigCallbacks.pfnAreKeysValid = drvvdCfgAreKeysValid;
1023 pThis->VDIConfigCallbacks.pfnQuerySize = drvvdCfgQuerySize;
1024 pThis->VDIConfigCallbacks.pfnQuery = drvvdCfgQuery;
1025
1026 /* List of images is empty now. */
1027 pThis->pImages = NULL;
1028
1029 /* Try to attach async media port interface above.*/
1030 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1031
1032 /*
1033 * Validate configuration and find all parent images.
1034 * It's sort of up side down from the image dependency tree.
1035 */
1036 bool fHostIP = false;
1037 bool fUseNewIo = false;
1038 unsigned iLevel = 0;
1039 PCFGMNODE pCurNode = pCfgHandle;
1040
1041 for (;;)
1042 {
1043 bool fValid;
1044
1045 if (pCurNode == pCfgHandle)
1046 {
1047 /* Toplevel configuration additionally contains the global image
1048 * open flags. Some might be converted to per-image flags later. */
1049 fValid = CFGMR3AreValuesValid(pCurNode,
1050 "Format\0Path\0"
1051 "ReadOnly\0TempReadOnly\0HonorZeroWrites\0"
1052 "HostIPStack\0UseNewIo\0");
1053 }
1054 else
1055 {
1056 /* All other image configurations only contain image name and
1057 * the format information. */
1058 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0");
1059 }
1060 if (!fValid)
1061 {
1062 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1063 RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
1064 break;
1065 }
1066
1067 if (pCurNode == pCfgHandle)
1068 {
1069 rc = CFGMR3QueryBoolDef(pCurNode, "HostIPStack", &fHostIP, true);
1070 if (RT_FAILURE(rc))
1071 {
1072 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1073 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
1074 break;
1075 }
1076
1077 rc = CFGMR3QueryBoolDef(pCurNode, "HonorZeroWrites", &fHonorZeroWrites, false);
1078 if (RT_FAILURE(rc))
1079 {
1080 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1081 N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
1082 break;
1083 }
1084
1085 rc = CFGMR3QueryBoolDef(pCurNode, "ReadOnly", &fReadOnly, false);
1086 if (RT_FAILURE(rc))
1087 {
1088 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1089 N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
1090 break;
1091 }
1092
1093 rc = CFGMR3QueryBoolDef(pCurNode, "TempReadOnly", &pThis->fTempReadOnly, false);
1094 if (RT_FAILURE(rc))
1095 {
1096 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1097 N_("DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
1098 break;
1099 }
1100 if (fReadOnly && pThis->fTempReadOnly)
1101 {
1102 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1103 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
1104 break;
1105 }
1106 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
1107 if (RT_FAILURE(rc))
1108 {
1109 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1110 N_("DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
1111 break;
1112 }
1113 }
1114
1115 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
1116 if (!pParent)
1117 break;
1118 pCurNode = pParent;
1119 iLevel++;
1120 }
1121
1122 /*
1123 * Open the images.
1124 */
1125 if (RT_SUCCESS(rc))
1126 {
1127 /* First of all figure out what kind of TCP networking stack interface
1128 * to use. This is done unconditionally, as backends which don't need
1129 * it will just ignore it. */
1130 if (fHostIP)
1131 {
1132 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1133 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1134 pThis->VDITcpNetCallbacks.pfnClientConnect = RTTcpClientConnect;
1135 pThis->VDITcpNetCallbacks.pfnClientClose = RTTcpClientClose;
1136 pThis->VDITcpNetCallbacks.pfnSelectOne = RTTcpSelectOne;
1137 pThis->VDITcpNetCallbacks.pfnRead = RTTcpRead;
1138 pThis->VDITcpNetCallbacks.pfnWrite = RTTcpWrite;
1139 pThis->VDITcpNetCallbacks.pfnFlush = RTTcpFlush;
1140 }
1141 else
1142 {
1143#ifndef VBOX_WITH_INIP
1144 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1145 RT_SRC_POS, N_("DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
1146#else /* VBOX_WITH_INIP */
1147 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1148 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1149 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
1150 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
1151 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
1152 pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
1153 pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite;
1154 pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush;
1155#endif /* VBOX_WITH_INIP */
1156 }
1157 if (RT_SUCCESS(rc))
1158 {
1159 rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP",
1160 VDINTERFACETYPE_TCPNET,
1161 &pThis->VDITcpNetCallbacks, NULL,
1162 &pThis->pVDIfsDisk);
1163 }
1164
1165 if (RT_SUCCESS(rc) && fUseNewIo)
1166 {
1167#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1168 pThis->VDIAsyncIOCallbacks.cbSize = sizeof(VDINTERFACEASYNCIO);
1169 pThis->VDIAsyncIOCallbacks.enmInterface = VDINTERFACETYPE_ASYNCIO;
1170 pThis->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen;
1171 pThis->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose;
1172 pThis->VDIAsyncIOCallbacks.pfnGetSize = drvvdAsyncIOGetSize;
1173 pThis->VDIAsyncIOCallbacks.pfnSetSize = drvvdAsyncIOSetSize;
1174 pThis->VDIAsyncIOCallbacks.pfnReadSync = drvvdAsyncIOReadSync;
1175 pThis->VDIAsyncIOCallbacks.pfnWriteSync = drvvdAsyncIOWriteSync;
1176 pThis->VDIAsyncIOCallbacks.pfnFlushSync = drvvdAsyncIOFlushSync;
1177 pThis->VDIAsyncIOCallbacks.pfnReadAsync = drvvdAsyncIOReadAsync;
1178 pThis->VDIAsyncIOCallbacks.pfnWriteAsync = drvvdAsyncIOWriteAsync;
1179 pThis->VDIAsyncIOCallbacks.pfnFlushAsync = drvvdAsyncIOFlushAsync;
1180
1181 rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
1182 &pThis->VDIAsyncIOCallbacks, pThis, &pThis->pVDIfsDisk);
1183#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1184 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1185 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
1186#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1187 }
1188
1189 if (RT_SUCCESS(rc))
1190 {
1191 rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk);
1192 /* Error message is already set correctly. */
1193 }
1194 }
1195
1196 if (pThis->pDrvMediaAsyncPort)
1197 pThis->fAsyncIOSupported = true;
1198
1199 while (pCurNode && RT_SUCCESS(rc))
1200 {
1201 /* Allocate per-image data. */
1202 PVBOXIMAGE pImage = drvvdNewImage(pThis);
1203 if (!pImage)
1204 {
1205 rc = VERR_NO_MEMORY;
1206 break;
1207 }
1208
1209 /*
1210 * Read the image configuration.
1211 */
1212 rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
1213 if (RT_FAILURE(rc))
1214 {
1215 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1216 N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
1217 break;
1218 }
1219
1220 rc = CFGMR3QueryStringAlloc(pCurNode, "Format", &pszFormat);
1221 if (RT_FAILURE(rc))
1222 {
1223 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1224 N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
1225 break;
1226 }
1227
1228 PCFGMNODE pCfg = CFGMR3GetChild(pCurNode, "VDConfig");
1229 rc = VDInterfaceAdd(&pImage->VDIConfig, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
1230 &pThis->VDIConfigCallbacks, pCfg, &pImage->pVDIfsImage);
1231 AssertRC(rc);
1232
1233 /*
1234 * Open the image.
1235 */
1236 unsigned uOpenFlags;
1237 if (fReadOnly || pThis->fTempReadOnly || iLevel != 0)
1238 uOpenFlags = VD_OPEN_FLAGS_READONLY;
1239 else
1240 uOpenFlags = VD_OPEN_FLAGS_NORMAL;
1241 if (fHonorZeroWrites)
1242 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
1243 if (pThis->fAsyncIOSupported)
1244 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
1245
1246 /* Try to open backend in async I/O mode first. */
1247 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1248 if (rc == VERR_NOT_SUPPORTED)
1249 {
1250 /* Seems async I/O is not supported by the backend, open in normal mode. */
1251 pThis->fAsyncIOSupported = false;
1252 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
1253 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1254 }
1255
1256 if (RT_SUCCESS(rc))
1257 {
1258 Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
1259 iLevel, pszName,
1260 VDIsReadOnly(pThis->pDisk) ? "read-only" : "read-write"));
1261 if ( VDIsReadOnly(pThis->pDisk)
1262 && !fReadOnly
1263 && !pThis->fTempReadOnly
1264 && iLevel == 0)
1265 {
1266 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_VD_IMAGE_READ_ONLY, RT_SRC_POS,
1267 N_("Failed to open image '%s' for writing due to wrong permissions"),
1268 pszName);
1269 break;
1270 }
1271 }
1272 else
1273 {
1274 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1275 N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName,
1276 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc);
1277 break;
1278 }
1279
1280
1281 MMR3HeapFree(pszName);
1282 pszName = NULL;
1283 MMR3HeapFree(pszFormat);
1284 pszFormat = NULL;
1285
1286 /* next */
1287 iLevel--;
1288 pCurNode = CFGMR3GetParent(pCurNode);
1289 }
1290
1291 /*
1292 * Register a load-done callback so we can undo TempReadOnly config before
1293 * we get to drvvdResume. Autoamtically deregistered upon destruction.
1294 */
1295 if (RT_SUCCESS(rc))
1296 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
1297 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
1298 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
1299 NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
1300
1301
1302 if (RT_FAILURE(rc))
1303 {
1304 if (VALID_PTR(pszName))
1305 MMR3HeapFree(pszName);
1306 if (VALID_PTR(pszFormat))
1307 MMR3HeapFree(pszFormat);
1308 /* drvvdDestruct does the rest. */
1309 }
1310
1311 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1312 return rc;
1313}
1314
1315/**
1316 * VBox disk container media driver registration record.
1317 */
1318const PDMDRVREG g_DrvVD =
1319{
1320 /* u32Version */
1321 PDM_DRVREG_VERSION,
1322 /* szDriverName */
1323 "VD",
1324 /* szRCMod */
1325 "",
1326 /* szR0Mod */
1327 "",
1328 /* pszDescription */
1329 "Generic VBox disk media driver.",
1330 /* fFlags */
1331 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1332 /* fClass. */
1333 PDM_DRVREG_CLASS_MEDIA,
1334 /* cMaxInstances */
1335 ~0,
1336 /* cbInstance */
1337 sizeof(VBOXDISK),
1338 /* pfnConstruct */
1339 drvvdConstruct,
1340 /* pfnDestruct */
1341 drvvdDestruct,
1342 /* pfnRelocate */
1343 NULL,
1344 /* pfnIOCtl */
1345 NULL,
1346 /* pfnPowerOn */
1347 drvvdPowerOn,
1348 /* pfnReset */
1349 NULL,
1350 /* pfnSuspend */
1351 drvvdSuspend,
1352 /* pfnResume */
1353 drvvdResume,
1354 /* pfnAttach */
1355 NULL,
1356 /* pfnDetach */
1357 NULL,
1358 /* pfnPowerOff */
1359 drvvdPowerOff,
1360 /* pfnSoftReset */
1361 NULL,
1362 /* u32EndVersion */
1363 PDM_DRVREG_VERSION
1364};
1365
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