VirtualBox

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

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

DrvVD: Fix stupid bug which masks errors while opening a file

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

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