VirtualBox

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

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

pdmifs.h: another batch of _IID changes.

  • 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 25974 2010-01-22 14:49:05Z 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 if (RTUuidCompare2Strs(pszIID, PDMIBASE_IID) == 0)
822 return &pDrvIns->IBase;
823 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, &pThis->IMedia);
824 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNC, pThis->fAsyncIOSupported ? &pThis->IMediaAsync : NULL);
825 return NULL;
826}
827
828
829/*******************************************************************************
830* Saved state notification methods *
831*******************************************************************************/
832
833/**
834 * Load done callback for re-opening the image writable during teleportation.
835 *
836 * This is called both for successful and failed load runs, we only care about
837 * successfull ones.
838 *
839 * @returns VBox status code.
840 * @param pDrvIns The driver instance.
841 * @param pSSM The saved state handle.
842 */
843static DECLCALLBACK(int) drvvdLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
844{
845 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
846 Assert(!pThis->fErrorUseRuntime);
847
848 /* Drop out if we don't have any work to do or if it's a failed load. */
849 if ( !pThis->fTempReadOnly
850 || RT_FAILURE(SSMR3HandleGetStatus(pSSM)))
851 return VINF_SUCCESS;
852
853 int rc = drvvdSetWritable(pThis);
854 if (RT_FAILURE(rc)) /** @todo does the bugger set any errors? */
855 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
856 N_("Failed to write lock the images"));
857 return VINF_SUCCESS;
858}
859
860
861/*******************************************************************************
862* Driver methods *
863*******************************************************************************/
864
865static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
866{
867 LogFlow(("%s:\n", __FUNCTION__));
868 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
869
870 /*
871 * We must close the disk here to ensure that
872 * the backend closes all files before the
873 * async transport driver is destructed.
874 */
875 int rc = VDCloseAll(pThis->pDisk);
876 AssertRC(rc);
877}
878
879/**
880 * VM resume notification that we use to undo what the temporary read-only image
881 * mode set by drvvdSuspend.
882 *
883 * Also switch to runtime error mode if we're resuming after a state load
884 * without having been powered on first.
885 *
886 * @param pDrvIns The driver instance data.
887 *
888 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
889 * we're making assumptions about Main behavior here!
890 */
891static DECLCALLBACK(void) drvvdResume(PPDMDRVINS pDrvIns)
892{
893 LogFlow(("%s:\n", __FUNCTION__));
894 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
895 drvvdSetWritable(pThis);
896 pThis->fErrorUseRuntime = true;
897}
898
899/**
900 * The VM is being suspended, temporarily change to read-only image mode.
901 *
902 * This is important for several reasons:
903 * -# It makes sure that there are no pending writes to the image. Most
904 * backends implements this by closing and reopening the image in read-only
905 * mode.
906 * -# It allows Main to read the images during snapshotting without having
907 * to account for concurrent writes.
908 * -# This is essential for making teleportation targets sharing images work
909 * right. Both with regards to caching and with regards to file sharing
910 * locks (RTFILE_O_DENY_*). (See also drvvdLoadDone.)
911 *
912 * @param pDrvIns The driver instance data.
913 */
914static DECLCALLBACK(void) drvvdSuspend(PPDMDRVINS pDrvIns)
915{
916 LogFlow(("%s:\n", __FUNCTION__));
917 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
918 if (!VDIsReadOnly(pThis->pDisk))
919 {
920 unsigned uOpenFlags;
921 int rc = VDGetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, &uOpenFlags);
922 AssertRC(rc);
923 uOpenFlags |= VD_OPEN_FLAGS_READONLY;
924 rc = VDSetOpenFlags(pThis->pDisk, VD_LAST_IMAGE, uOpenFlags);
925 AssertRC(rc);
926 pThis->fTempReadOnly = true;
927 }
928}
929
930/**
931 * VM PowerOn notification for undoing the TempReadOnly config option and
932 * changing to runtime error mode.
933 *
934 * @param pDrvIns The driver instance data.
935 *
936 * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere,
937 * we're making assumptions about Main behavior here!
938 */
939static DECLCALLBACK(void) drvvdPowerOn(PPDMDRVINS pDrvIns)
940{
941 LogFlow(("%s:\n", __FUNCTION__));
942 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
943 drvvdSetWritable(pThis);
944 pThis->fErrorUseRuntime = true;
945}
946
947/**
948 * @copydoc FNPDMDRVDESTRUCT
949 */
950static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
951{
952 PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
953 LogFlow(("%s:\n", __FUNCTION__));
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
980 /*
981 * Init the static parts.
982 */
983 pDrvIns->IBase.pfnQueryInterface = drvvdQueryInterface;
984 pThis->pDrvIns = pDrvIns;
985 pThis->fTempReadOnly = false;
986 pThis->pDisk = NULL;
987 pThis->fAsyncIOSupported = false;
988
989 /* IMedia */
990 pThis->IMedia.pfnRead = drvvdRead;
991 pThis->IMedia.pfnWrite = drvvdWrite;
992 pThis->IMedia.pfnFlush = drvvdFlush;
993 pThis->IMedia.pfnGetSize = drvvdGetSize;
994 pThis->IMedia.pfnIsReadOnly = drvvdIsReadOnly;
995 pThis->IMedia.pfnBiosGetPCHSGeometry = drvvdBiosGetPCHSGeometry;
996 pThis->IMedia.pfnBiosSetPCHSGeometry = drvvdBiosSetPCHSGeometry;
997 pThis->IMedia.pfnBiosGetLCHSGeometry = drvvdBiosGetLCHSGeometry;
998 pThis->IMedia.pfnBiosSetLCHSGeometry = drvvdBiosSetLCHSGeometry;
999 pThis->IMedia.pfnGetUuid = drvvdGetUuid;
1000
1001 /* IMediaAsync */
1002 pThis->IMediaAsync.pfnStartRead = drvvdStartRead;
1003 pThis->IMediaAsync.pfnStartWrite = drvvdStartWrite;
1004
1005 /* Initialize supported VD interfaces. */
1006 pThis->pVDIfsDisk = NULL;
1007
1008 pThis->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1009 pThis->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1010 pThis->VDIErrorCallbacks.pfnError = drvvdErrorCallback;
1011 pThis->VDIErrorCallbacks.pfnMessage = NULL;
1012
1013 rc = VDInterfaceAdd(&pThis->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
1014 &pThis->VDIErrorCallbacks, pDrvIns, &pThis->pVDIfsDisk);
1015 AssertRC(rc);
1016
1017 /* This is just prepared here, the actual interface is per-image, so it's
1018 * added later. No need to have separate callback tables. */
1019 pThis->VDIConfigCallbacks.cbSize = sizeof(VDINTERFACECONFIG);
1020 pThis->VDIConfigCallbacks.enmInterface = VDINTERFACETYPE_CONFIG;
1021 pThis->VDIConfigCallbacks.pfnAreKeysValid = drvvdCfgAreKeysValid;
1022 pThis->VDIConfigCallbacks.pfnQuerySize = drvvdCfgQuerySize;
1023 pThis->VDIConfigCallbacks.pfnQuery = drvvdCfgQuery;
1024
1025 /* List of images is empty now. */
1026 pThis->pImages = NULL;
1027
1028 /* Try to attach async media port interface above.*/
1029 pThis->pDrvMediaAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAASYNCPORT);
1030
1031 /*
1032 * Validate configuration and find all parent images.
1033 * It's sort of up side down from the image dependency tree.
1034 */
1035 bool fHostIP = false;
1036 bool fUseNewIo = false;
1037 unsigned iLevel = 0;
1038 PCFGMNODE pCurNode = pCfgHandle;
1039
1040 for (;;)
1041 {
1042 bool fValid;
1043
1044 if (pCurNode == pCfgHandle)
1045 {
1046 /* Toplevel configuration additionally contains the global image
1047 * open flags. Some might be converted to per-image flags later. */
1048 fValid = CFGMR3AreValuesValid(pCurNode,
1049 "Format\0Path\0"
1050 "ReadOnly\0TempReadOnly\0HonorZeroWrites\0"
1051 "HostIPStack\0UseNewIo\0");
1052 }
1053 else
1054 {
1055 /* All other image configurations only contain image name and
1056 * the format information. */
1057 fValid = CFGMR3AreValuesValid(pCurNode, "Format\0Path\0");
1058 }
1059 if (!fValid)
1060 {
1061 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1062 RT_SRC_POS, N_("DrvVD: Configuration error: keys incorrect at level %d"), iLevel);
1063 break;
1064 }
1065
1066 if (pCurNode == pCfgHandle)
1067 {
1068 rc = CFGMR3QueryBoolDef(pCurNode, "HostIPStack", &fHostIP, true);
1069 if (RT_FAILURE(rc))
1070 {
1071 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1072 N_("DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
1073 break;
1074 }
1075
1076 rc = CFGMR3QueryBoolDef(pCurNode, "HonorZeroWrites", &fHonorZeroWrites, false);
1077 if (RT_FAILURE(rc))
1078 {
1079 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1080 N_("DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
1081 break;
1082 }
1083
1084 rc = CFGMR3QueryBoolDef(pCurNode, "ReadOnly", &fReadOnly, false);
1085 if (RT_FAILURE(rc))
1086 {
1087 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1088 N_("DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
1089 break;
1090 }
1091
1092 rc = CFGMR3QueryBoolDef(pCurNode, "TempReadOnly", &pThis->fTempReadOnly, false);
1093 if (RT_FAILURE(rc))
1094 {
1095 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1096 N_("DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
1097 break;
1098 }
1099 if (fReadOnly && pThis->fTempReadOnly)
1100 {
1101 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1102 N_("DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
1103 break;
1104 }
1105 rc = CFGMR3QueryBoolDef(pCurNode, "UseNewIo", &fUseNewIo, false);
1106 if (RT_FAILURE(rc))
1107 {
1108 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1109 N_("DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
1110 break;
1111 }
1112 }
1113
1114 PCFGMNODE pParent = CFGMR3GetChild(pCurNode, "Parent");
1115 if (!pParent)
1116 break;
1117 pCurNode = pParent;
1118 iLevel++;
1119 }
1120
1121 /*
1122 * Open the images.
1123 */
1124 if (RT_SUCCESS(rc))
1125 {
1126 /* First of all figure out what kind of TCP networking stack interface
1127 * to use. This is done unconditionally, as backends which don't need
1128 * it will just ignore it. */
1129 if (fHostIP)
1130 {
1131 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1132 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1133 pThis->VDITcpNetCallbacks.pfnClientConnect = RTTcpClientConnect;
1134 pThis->VDITcpNetCallbacks.pfnClientClose = RTTcpClientClose;
1135 pThis->VDITcpNetCallbacks.pfnSelectOne = RTTcpSelectOne;
1136 pThis->VDITcpNetCallbacks.pfnRead = RTTcpRead;
1137 pThis->VDITcpNetCallbacks.pfnWrite = RTTcpWrite;
1138 pThis->VDITcpNetCallbacks.pfnFlush = RTTcpFlush;
1139 }
1140 else
1141 {
1142#ifndef VBOX_WITH_INIP
1143 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1144 RT_SRC_POS, N_("DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
1145#else /* VBOX_WITH_INIP */
1146 pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
1147 pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
1148 pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
1149 pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
1150 pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
1151 pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
1152 pThis->VDITcpNetCallbacks.pfnWrite = drvvdINIPWrite;
1153 pThis->VDITcpNetCallbacks.pfnFlush = drvvdINIPFlush;
1154#endif /* VBOX_WITH_INIP */
1155 }
1156 if (RT_SUCCESS(rc))
1157 {
1158 rc = VDInterfaceAdd(&pThis->VDITcpNet, "DrvVD_INIP",
1159 VDINTERFACETYPE_TCPNET,
1160 &pThis->VDITcpNetCallbacks, NULL,
1161 &pThis->pVDIfsDisk);
1162 }
1163
1164 if (RT_SUCCESS(rc) && fUseNewIo)
1165 {
1166#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1167 pThis->VDIAsyncIOCallbacks.cbSize = sizeof(VDINTERFACEASYNCIO);
1168 pThis->VDIAsyncIOCallbacks.enmInterface = VDINTERFACETYPE_ASYNCIO;
1169 pThis->VDIAsyncIOCallbacks.pfnOpen = drvvdAsyncIOOpen;
1170 pThis->VDIAsyncIOCallbacks.pfnClose = drvvdAsyncIOClose;
1171 pThis->VDIAsyncIOCallbacks.pfnGetSize = drvvdAsyncIOGetSize;
1172 pThis->VDIAsyncIOCallbacks.pfnSetSize = drvvdAsyncIOSetSize;
1173 pThis->VDIAsyncIOCallbacks.pfnReadSync = drvvdAsyncIOReadSync;
1174 pThis->VDIAsyncIOCallbacks.pfnWriteSync = drvvdAsyncIOWriteSync;
1175 pThis->VDIAsyncIOCallbacks.pfnFlushSync = drvvdAsyncIOFlushSync;
1176 pThis->VDIAsyncIOCallbacks.pfnReadAsync = drvvdAsyncIOReadAsync;
1177 pThis->VDIAsyncIOCallbacks.pfnWriteAsync = drvvdAsyncIOWriteAsync;
1178 pThis->VDIAsyncIOCallbacks.pfnFlushAsync = drvvdAsyncIOFlushAsync;
1179
1180 rc = VDInterfaceAdd(&pThis->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
1181 &pThis->VDIAsyncIOCallbacks, pThis, &pThis->pVDIfsDisk);
1182#else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1183 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
1184 RT_SRC_POS, N_("DrvVD: Configuration error: Async Completion Framework not compiled in"));
1185#endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */
1186 }
1187
1188 if (RT_SUCCESS(rc))
1189 {
1190 rc = VDCreate(pThis->pVDIfsDisk, &pThis->pDisk);
1191 /* Error message is already set correctly. */
1192 }
1193 }
1194
1195 if (pThis->pDrvMediaAsyncPort)
1196 pThis->fAsyncIOSupported = true;
1197
1198 while (pCurNode && RT_SUCCESS(rc))
1199 {
1200 /* Allocate per-image data. */
1201 PVBOXIMAGE pImage = drvvdNewImage(pThis);
1202 if (!pImage)
1203 {
1204 rc = VERR_NO_MEMORY;
1205 break;
1206 }
1207
1208 /*
1209 * Read the image configuration.
1210 */
1211 rc = CFGMR3QueryStringAlloc(pCurNode, "Path", &pszName);
1212 if (RT_FAILURE(rc))
1213 {
1214 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1215 N_("DrvVD: Configuration error: Querying \"Path\" as string failed"));
1216 break;
1217 }
1218
1219 rc = CFGMR3QueryStringAlloc(pCurNode, "Format", &pszFormat);
1220 if (RT_FAILURE(rc))
1221 {
1222 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
1223 N_("DrvVD: Configuration error: Querying \"Format\" as string failed"));
1224 break;
1225 }
1226
1227 PCFGMNODE pCfg = CFGMR3GetChild(pCurNode, "VDConfig");
1228 rc = VDInterfaceAdd(&pImage->VDIConfig, "DrvVD_Config", VDINTERFACETYPE_CONFIG,
1229 &pThis->VDIConfigCallbacks, pCfg, &pImage->pVDIfsImage);
1230 AssertRC(rc);
1231
1232 /*
1233 * Open the image.
1234 */
1235 unsigned uOpenFlags;
1236 if (fReadOnly || pThis->fTempReadOnly || iLevel != 0)
1237 uOpenFlags = VD_OPEN_FLAGS_READONLY;
1238 else
1239 uOpenFlags = VD_OPEN_FLAGS_NORMAL;
1240 if (fHonorZeroWrites)
1241 uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
1242 if (pThis->fAsyncIOSupported)
1243 uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
1244
1245 /* Try to open backend in async I/O mode first. */
1246 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1247 if (rc == VERR_NOT_SUPPORTED)
1248 {
1249 /* Seems async I/O is not supported by the backend, open in normal mode. */
1250 pThis->fAsyncIOSupported = false;
1251 uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
1252 rc = VDOpen(pThis->pDisk, pszFormat, pszName, uOpenFlags, pImage->pVDIfsImage);
1253 }
1254
1255 if (RT_SUCCESS(rc))
1256 {
1257 Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
1258 iLevel, pszName,
1259 VDIsReadOnly(pThis->pDisk) ? "read-only" : "read-write"));
1260 if ( VDIsReadOnly(pThis->pDisk)
1261 && !fReadOnly
1262 && !pThis->fTempReadOnly
1263 && iLevel == 0)
1264 {
1265 rc = PDMDrvHlpVMSetError(pDrvIns, VERR_VD_IMAGE_READ_ONLY, RT_SRC_POS,
1266 N_("Failed to open image '%s' for writing due to wrong permissions"),
1267 pszName);
1268 break;
1269 }
1270 }
1271 else
1272 {
1273 rc = PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1274 N_("Failed to open image '%s' in %s mode rc=%Rrc"), pszName,
1275 (uOpenFlags & VD_OPEN_FLAGS_READONLY) ? "read-only" : "read-write", rc);
1276 break;
1277 }
1278
1279
1280 MMR3HeapFree(pszName);
1281 pszName = NULL;
1282 MMR3HeapFree(pszFormat);
1283 pszFormat = NULL;
1284
1285 /* next */
1286 iLevel--;
1287 pCurNode = CFGMR3GetParent(pCurNode);
1288 }
1289
1290 /*
1291 * Register a load-done callback so we can undo TempReadOnly config before
1292 * we get to drvvdResume. Autoamtically deregistered upon destruction.
1293 */
1294 if (RT_SUCCESS(rc))
1295 rc = PDMDrvHlpSSMRegisterEx(pDrvIns, 0 /* version */, 0 /* cbGuess */,
1296 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
1297 NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/,
1298 NULL /*pfnDonePrep*/, NULL /*pfnLoadExec*/, drvvdLoadDone);
1299
1300
1301 if (RT_FAILURE(rc))
1302 {
1303 if (VALID_PTR(pszName))
1304 MMR3HeapFree(pszName);
1305 if (VALID_PTR(pszFormat))
1306 MMR3HeapFree(pszFormat);
1307 /* drvvdDestruct does the rest. */
1308 }
1309
1310 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
1311 return rc;
1312}
1313
1314/**
1315 * VBox disk container media driver registration record.
1316 */
1317const PDMDRVREG g_DrvVD =
1318{
1319 /* u32Version */
1320 PDM_DRVREG_VERSION,
1321 /* szDriverName */
1322 "VD",
1323 /* szRCMod */
1324 "",
1325 /* szR0Mod */
1326 "",
1327 /* pszDescription */
1328 "Generic VBox disk media driver.",
1329 /* fFlags */
1330 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1331 /* fClass. */
1332 PDM_DRVREG_CLASS_MEDIA,
1333 /* cMaxInstances */
1334 ~0,
1335 /* cbInstance */
1336 sizeof(VBOXDISK),
1337 /* pfnConstruct */
1338 drvvdConstruct,
1339 /* pfnDestruct */
1340 drvvdDestruct,
1341 /* pfnRelocate */
1342 NULL,
1343 /* pfnIOCtl */
1344 NULL,
1345 /* pfnPowerOn */
1346 drvvdPowerOn,
1347 /* pfnReset */
1348 NULL,
1349 /* pfnSuspend */
1350 drvvdSuspend,
1351 /* pfnResume */
1352 drvvdResume,
1353 /* pfnAttach */
1354 NULL,
1355 /* pfnDetach */
1356 NULL,
1357 /* pfnPowerOff */
1358 drvvdPowerOff,
1359 /* pfnSoftReset */
1360 NULL,
1361 /* u32EndVersion */
1362 PDM_DRVREG_VERSION
1363};
1364
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