VirtualBox

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

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

pdmifs.h: the final batch of refactored interface ID code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.0 KB
Line 
1/* $Id: DrvVD.cpp 25985 2010-01-23 00:51:04Z 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.215389.xyz. 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
954 if (VALID_PTR(pThis->pDisk))
955 {
956 VDDestroy(pThis->pDisk);
957 pThis->pDisk = NULL;
958 }
959 drvvdFreeImages(pThis);
960}
961
962/**
963 * Construct a VBox disk media driver instance.
964 *
965 * @copydoc FNPDMDRVCONSTRUCT
966 */
967static DECLCALLBACK(int) drvvdConstruct(PPDMDRVINS pDrvIns,
968 PCFGMNODE pCfgHandle,
969 uint32_t fFlags)
970{
971 LogFlow(("%s:\n", __FUNCTION__));
972 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
973 int rc = VINF_SUCCESS;
974 char *pszName = NULL; /**< The path of the disk image file. */
975 char *pszFormat = NULL; /**< The format backed to use for this image. */
976 bool fReadOnly; /**< True if the media is read-only. */
977 bool fHonorZeroWrites; /**< True if zero blocks should be written. */
978
979 /*
980 * Init the static parts.
981 */
982 pDrvIns->IBase.pfnQueryInterface = drvvdQueryInterface;
983 pThis->pDrvIns = pDrvIns;
984 pThis->fTempReadOnly = false;
985 pThis->pDisk = NULL;
986 pThis->fAsyncIOSupported = false;
987
988 /* IMedia */
989 pThis->IMedia.pfnRead = drvvdRead;
990 pThis->IMedia.pfnWrite = drvvdWrite;
991 pThis->IMedia.pfnFlush = drvvdFlush;
992 pThis->IMedia.pfnGetSize = drvvdGetSize;
993 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly;
994 pThis->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
995 pThis->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
996 pThis->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
997 pThis->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
998 pThis->IMedia.pfnGetUuid = drvvdGetUuid;
999
1000 /* IMediaAsync */
1001 pThis->IMediaAsync.pfnStartRead = drvvdStartRead;
1002 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite;
1003
1004 /* Initialize supported VD interfaces. */
1005 pThis->pVDIfsDisk = NULL;
1006
1007 pThis->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1008 pThis->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1009 pThis->VDIErrorCallbacks.pfnError = drvvdErrorCallback;
1010 pThis->VDIErrorCallbacks.pfnMessage = NULL;
1011
1012 rc = VDInterfaceAdd(&pThis->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
1013 &pThis->VDIErrorCallbacks, pDrvIns, &pThis->pVDIfsDisk);
1014 AssertRC(rc);
1015
1016 /* This is just prepared here, the actual interface is per-image, so it's
1017 * added later. No need to have separate callback tables. */
1018 pThis->VDIConfigCallbacks.cbSize = sizeof(VDINTERFACECONFIG);
1019 pThis->VDIConfigCallbacks.enmInterface = VDINTERFACETYPE_CONFIG;
1020 pThis->VDIConfigCallbacks.pfnAreKeysValid = drvvdCfgAreKeysValid;
1021 pThis->VDIConfigCallbacks.pfnQuerySize = drvvdCfgQuerySize;
1022 pThis->VDIConfigCallbacks.pfnQuery = drvvdCfgQuery;
1023
1024 /* List of images is empty now. */
1025 pThis->pImages = NULL;
1026
1027 /* Try to attach async media port interface above.*/
1028 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1029
1030 /*
1031 * Validate configuration and find all parent images.
1032 * It's sort of up side down from the image dependency tree.
1033 */
1034 bool fHostIP = false;
1035 bool fUseNewIo = false;
1036 unsigned iLevel = 0;
1037 PCFGMNODE pCurNode = pCfgHandle;
1038
1039 for (;;)
1040 {
1041 bool fValid;
1042
1043 if (pCurNode == pCfgHandle)
1044 {
1045 /* Toplevel configuration additionally contains the global image
1046 * open flags. Some might be converted to per-image flags later. */
1047 fValid = CFGMR3AreValuesValid(pCurNode,
1048 "Format\0Path\0"
1049 "ReadOnly\0TempReadOnly\0HonorZeroWrites\0"
1050 "HostIPStack\0UseNewIo\0");
1051 }
1052 else
1053 {
1054 /* All other image configurations only contain image name and
1055 * the format information. */
1056 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0");
1057 }
1058 if (!fValid)
1059 {
1060 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1061 RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
1062 break;
1063 }
1064
1065 if (pCurNode == pCfgHandle)
1066 {
1067 rc = CFGMR3QueryBoolDef(pCurNode, "HostIPStack", &fHostIP, true);
1068 if (RT_FAILURE(rc))
1069 {
1070 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1071 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
1072 break;
1073 }
1074
1075 rc = CFGMR3QueryBoolDef(pCurNode, "HonorZeroWrites", &fHonorZeroWrites, false);
1076 if (RT_FAILURE(rc))
1077 {
1078 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1079 N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
1080 break;
1081 }
1082
1083 rc = CFGMR3QueryBoolDef(pCurNode, "ReadOnly", &fReadOnly, false);
1084 if (RT_FAILURE(rc))
1085 {
1086 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1087 N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
1088 break;
1089 }
1090
1091 rc = CFGMR3QueryBoolDef(pCurNode, "TempReadOnly", &pThis->fTempReadOnly, false);
1092 if (RT_FAILURE(rc))
1093 {
1094 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1095 N_("DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
1096 break;
1097 }
1098 if (fReadOnly && pThis->fTempReadOnly)
1099 {
1100 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1101 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
1102 break;
1103 }
1104 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
1105 if (RT_FAILURE(rc))
1106 {
1107 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1108 N_("DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
1109 break;
1110 }
1111 }
1112
1113 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
1114 if (!pParent)
1115 break;
1116 pCurNode = pParent;
1117 iLevel++;
1118 }
1119
1120 /*
1121 * Open the images.
1122 */
1123 if (RT_SUCCESS(rc))
1124 {
1125 /* First of all figure out what kind of TCP networking stack interface
1126 * to use. This is done unconditionally, as backends which don't need
1127 * it will just ignore it. */
1128 if (fHostIP)
1129 {
1130 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1131 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1132 pThis->VDITcpNetCallbacks.pfnClientConnect = RTTcpClientConnect;
1133 pThis->VDITcpNetCallbacks.pfnClientClose = RTTcpClientClose;
1134 pThis->VDITcpNetCallbacks.pfnSelectOne = RTTcpSelectOne;
1135 pThis->VDITcpNetCallbacks.pfnRead = RTTcpRead;
1136 pThis->VDITcpNetCallbacks.pfnWrite = RTTcpWrite;
1137 pThis->VDITcpNetCallbacks.pfnFlush = RTTcpFlush;
1138 }
1139 else
1140 {
1141#ifndef VBOX_WITH_INIP
1142 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1143 RT_SRC_POS, N_("DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
1144#else /* VBOX_WITH_INIP */
1145 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1146 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1147 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
1148 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
1149 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
1150 pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
1151 pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite;
1152 pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush;
1153#endif /* VBOX_WITH_INIP */
1154 }
1155 if (RT_SUCCESS(rc))
1156 {
1157 rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP",
1158 VDINTERFACETYPE_TCPNET,
1159 &pThis->VDITcpNetCallbacks, NULL,
1160 &pThis->pVDIfsDisk);
1161 }
1162
1163 if (RT_SUCCESS(rc) && fUseNewIo)
1164 {
1165#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1166 pThis->VDIAsyncIOCallbacks.cbSize = sizeof(VDINTERFACEASYNCIO);
1167 pThis->VDIAsyncIOCallbacks.enmInterface = VDINTERFACETYPE_ASYNCIO;
1168 pThis->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen;
1169 pThis->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose;
1170 pThis->VDIAsyncIOCallbacks.pfnGetSize = drvvdAsyncIOGetSize;
1171 pThis->VDIAsyncIOCallbacks.pfnSetSize = drvvdAsyncIOSetSize;
1172 pThis->VDIAsyncIOCallbacks.pfnReadSync = drvvdAsyncIOReadSync;
1173 pThis->VDIAsyncIOCallbacks.pfnWriteSync = drvvdAsyncIOWriteSync;
1174 pThis->VDIAsyncIOCallbacks.pfnFlushSync = drvvdAsyncIOFlushSync;
1175 pThis->VDIAsyncIOCallbacks.pfnReadAsync = drvvdAsyncIOReadAsync;
1176 pThis->VDIAsyncIOCallbacks.pfnWriteAsync = drvvdAsyncIOWriteAsync;
1177 pThis->VDIAsyncIOCallbacks.pfnFlushAsync = drvvdAsyncIOFlushAsync;
1178
1179 rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
1180 &pThis->VDIAsyncIOCallbacks, pThis, &pThis->pVDIfsDisk);
1181#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1182 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1183 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
1184#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1185 }
1186
1187 if (RT_SUCCESS(rc))
1188 {
1189 rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk);
1190 /* Error message is already set correctly. */
1191 }
1192 }
1193
1194 if (pThis->pDrvMediaAsyncPort)
1195 pThis->fAsyncIOSupported = true;
1196
1197 while (pCurNode && RT_SUCCESS(rc))
1198 {
1199 /* Allocate per-image data. */
1200 PVBOXIMAGE pImage = drvvdNewImage(pThis);
1201 if (!pImage)
1202 {
1203 rc = VERR_NO_MEMORY;
1204 break;
1205 }
1206
1207 /*
1208 * Read the image configuration.
1209 */
1210 rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
1211 if (RT_FAILURE(rc))
1212 {
1213 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1214 N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
1215 break;
1216 }
1217
1218 rc = CFGMR3QueryStringAlloc(pCurNode, "Format", &pszFormat);
1219 if (RT_FAILURE(rc))
1220 {
1221 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1222 N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
1223 break;
1224 }
1225
1226 PCFGMNODE pCfg = CFGMR3GetChild(pCurNode, "VDConfig");
1227 rc = VDInterfaceAdd(&pImage->VDIConfig, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
1228 &pThis->VDIConfigCallbacks, pCfg, &pImage->pVDIfsImage);
1229 AssertRC(rc);
1230
1231 /*
1232 * Open the image.
1233 */
1234 unsigned uOpenFlags;
1235 if (fReadOnly || pThis->fTempReadOnly || iLevel != 0)
1236 uOpenFlags = VD_OPEN_FLAGS_READONLY;
1237 else
1238 uOpenFlags = VD_OPEN_FLAGS_NORMAL;
1239 if (fHonorZeroWrites)
1240 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
1241 if (pThis->fAsyncIOSupported)
1242 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
1243
1244 /* Try to open backend in async I/O mode first. */
1245 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1246 if (rc == VERR_NOT_SUPPORTED)
1247 {
1248 /* Seems async I/O is not supported by the backend, open in normal mode. */
1249 pThis->fAsyncIOSupported = false;
1250 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
1251 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1252 }
1253
1254 if (RT_SUCCESS(rc))
1255 {
1256 Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
1257 iLevel, pszName,
1258 VDIsReadOnly(pThis->pDisk) ? "read-only" : "read-write"));
1259 if ( VDIsReadOnly(pThis->pDisk)
1260 && !fReadOnly
1261 && !pThis->fTempReadOnly
1262 && iLevel == 0)
1263 {
1264 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_VD_IMAGE_READ_ONLY, RT_SRC_POS,
1265 N_("Failed to open image '%s' for writing due to wrong permissions"),
1266 pszName);
1267 break;
1268 }
1269 }
1270 else
1271 {
1272 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1273 N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName,
1274 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc);
1275 break;
1276 }
1277
1278
1279 MMR3HeapFree(pszName);
1280 pszName = NULL;
1281 MMR3HeapFree(pszFormat);
1282 pszFormat = NULL;
1283
1284 /* next */
1285 iLevel--;
1286 pCurNode = CFGMR3GetParent(pCurNode);
1287 }
1288
1289 /*
1290 * Register a load-done callback so we can undo TempReadOnly config before
1291 * we get to drvvdResume. Autoamtically deregistered upon destruction.
1292 */
1293 if (RT_SUCCESS(rc))
1294 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
1295 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
1296 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
1297 NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
1298
1299
1300 if (RT_FAILURE(rc))
1301 {
1302 if (VALID_PTR(pszName))
1303 MMR3HeapFree(pszName);
1304 if (VALID_PTR(pszFormat))
1305 MMR3HeapFree(pszFormat);
1306 /* drvvdDestruct does the rest. */
1307 }
1308
1309 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1310 return rc;
1311}
1312
1313/**
1314 * VBox disk container media driver registration record.
1315 */
1316const PDMDRVREG g_DrvVD =
1317{
1318 /* u32Version */
1319 PDM_DRVREG_VERSION,
1320 /* szDriverName */
1321 "VD",
1322 /* szRCMod */
1323 "",
1324 /* szR0Mod */
1325 "",
1326 /* pszDescription */
1327 "Generic VBox disk media driver.",
1328 /* fFlags */
1329 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1330 /* fClass. */
1331 PDM_DRVREG_CLASS_MEDIA,
1332 /* cMaxInstances */
1333 ~0,
1334 /* cbInstance */
1335 sizeof(VBOXDISK),
1336 /* pfnConstruct */
1337 drvvdConstruct,
1338 /* pfnDestruct */
1339 drvvdDestruct,
1340 /* pfnRelocate */
1341 NULL,
1342 /* pfnIOCtl */
1343 NULL,
1344 /* pfnPowerOn */
1345 drvvdPowerOn,
1346 /* pfnReset */
1347 NULL,
1348 /* pfnSuspend */
1349 drvvdSuspend,
1350 /* pfnResume */
1351 drvvdResume,
1352 /* pfnAttach */
1353 NULL,
1354 /* pfnDetach */
1355 NULL,
1356 /* pfnPowerOff */
1357 drvvdPowerOff,
1358 /* pfnSoftReset */
1359 NULL,
1360 /* u32EndVersion */
1361 PDM_DRVREG_VERSION
1362};
1363
Note: See TracBrowser for help on using the repository browser.

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