VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvBlock.cpp@ 28784

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

Interface changes for error reporting and async I/O

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.1 KB
Line 
1/* $Id: DrvBlock.cpp 28784 2010-04-26 23:59:42Z vboxsync $ */
2/** @file
3 * VBox storage devices: Generic block driver
4 */
5
6/*
7 * Copyright (C) 2006-2010 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_BLOCK
27#include <VBox/pdmdrv.h>
28#include <iprt/assert.h>
29#include <iprt/string.h>
30#include <iprt/uuid.h>
31
32#include "Builtins.h"
33
34
35/** @def VBOX_PERIODIC_FLUSH
36 * Enable support for periodically flushing the VDI to disk. This may prove
37 * useful for those nasty problems with the ultra-slow host filesystems.
38 * If this is enabled, it can be configured via the CFGM key
39 * "VBoxInternal/Devices/piix3ide/0/LUN#<x>/Config/FlushInterval". <x>
40 * must be replaced with the correct LUN number of the disk that should
41 * do the periodic flushes. The value of the key is the number of bytes
42 * written between flushes. A value of 0 (the default) denotes no flushes. */
43#define VBOX_PERIODIC_FLUSH
44
45/** @def VBOX_IGNORE_FLUSH
46 * Enable support for ignoring VDI flush requests. This can be useful for
47 * filesystems that show bad guest IDE write performance (especially with
48 * Windows guests). NOTE that this does not disable the flushes caused by
49 * the periodic flush cache feature above.
50 * If this feature is enabled, it can be configured via the CFGM key
51 * "VBoxInternal/Devices/piix3ide/0/LUN#<x>/Config/IgnoreFlush". <x>
52 * must be replaced with the correct LUN number of the disk that should
53 * ignore flush requests. The value of the key is a boolean. The default
54 * is to ignore flushes, i.e. true. */
55#define VBOX_IGNORE_FLUSH
56
57
58/*******************************************************************************
59* Structures and Typedefs *
60*******************************************************************************/
61/**
62 * Block driver instance data.
63 *
64 * @implements PDMIBLOCK
65 * @implements PDMIBLOCKBIOS
66 * @implements PDMIMOUNT
67 * @implements PDMIMEDIAASYNCPORT
68 * @implements PDMIBLOCKASYNC
69 */
70typedef struct DRVBLOCK
71{
72 /** Pointer driver instance. */
73 PPDMDRVINS pDrvIns;
74 /** Drive type. */
75 PDMBLOCKTYPE enmType;
76 /** Locked indicator. */
77 bool fLocked;
78 /** Mountable indicator. */
79 bool fMountable;
80 /** Visible to the BIOS. */
81 bool fBiosVisible;
82#ifdef VBOX_PERIODIC_FLUSH
83 /** HACK: Configuration value for number of bytes written after which to flush. */
84 uint32_t cbFlushInterval;
85 /** HACK: Current count for the number of bytes written since the last flush. */
86 uint32_t cbDataWritten;
87#endif /* VBOX_PERIODIC_FLUSH */
88#ifdef VBOX_IGNORE_FLUSH
89 /** HACK: Disable flushes for this drive. */
90 bool fIgnoreFlush;
91#endif /* VBOX_IGNORE_FLUSH */
92 /** Pointer to the media driver below us.
93 * This is NULL if the media is not mounted. */
94 PPDMIMEDIA pDrvMedia;
95 /** Pointer to the block port interface above us. */
96 PPDMIBLOCKPORT pDrvBlockPort;
97 /** Pointer to the mount notify interface above us. */
98 PPDMIMOUNTNOTIFY pDrvMountNotify;
99 /** Our block interface. */
100 PDMIBLOCK IBlock;
101 /** Our block interface. */
102 PDMIBLOCKBIOS IBlockBios;
103 /** Our mountable interface. */
104 PDMIMOUNT IMount;
105
106 /** Pointer to the async media driver below us.
107 * This is NULL if the media is not mounted. */
108 PPDMIMEDIAASYNC pDrvMediaAsync;
109 /** Our media async port. */
110 PDMIMEDIAASYNCPORT IMediaAsyncPort;
111 /** Pointer to the async block port interface above us. */
112 PPDMIBLOCKASYNCPORT pDrvBlockAsyncPort;
113 /** Our async block interface. */
114 PDMIBLOCKASYNC IBlockAsync;
115
116 /** Uuid of the drive. */
117 RTUUID Uuid;
118
119 /** BIOS PCHS Geometry. */
120 PDMMEDIAGEOMETRY PCHSGeometry;
121 /** BIOS LCHS Geometry. */
122 PDMMEDIAGEOMETRY LCHSGeometry;
123} DRVBLOCK, *PDRVBLOCK;
124
125
126/* -=-=-=-=- IBlock -=-=-=-=- */
127
128/** Makes a PDRVBLOCK out of a PPDMIBLOCK. */
129#define PDMIBLOCK_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlock)) )
130
131/** @copydoc PDMIBLOCK::pfnRead */
132static DECLCALLBACK(int) drvblockRead(PPDMIBLOCK pInterface, uint64_t off, void *pvBuf, size_t cbRead)
133{
134 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
135
136 /*
137 * Check the state.
138 */
139 if (!pThis->pDrvMedia)
140 {
141 AssertMsgFailed(("Invalid state! Not mounted!\n"));
142 return VERR_PDM_MEDIA_NOT_MOUNTED;
143 }
144
145 int rc = pThis->pDrvMedia->pfnRead(pThis->pDrvMedia, off, pvBuf, cbRead);
146 return rc;
147}
148
149
150/** @copydoc PDMIBLOCK::pfnWrite */
151static DECLCALLBACK(int) drvblockWrite(PPDMIBLOCK pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)
152{
153 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
154
155 /*
156 * Check the state.
157 */
158 if (!pThis->pDrvMedia)
159 {
160 AssertMsgFailed(("Invalid state! Not mounted!\n"));
161 return VERR_PDM_MEDIA_NOT_MOUNTED;
162 }
163
164 int rc = pThis->pDrvMedia->pfnWrite(pThis->pDrvMedia, off, pvBuf, cbWrite);
165#ifdef VBOX_PERIODIC_FLUSH
166 if (pThis->cbFlushInterval)
167 {
168 pThis->cbDataWritten += (uint32_t)cbWrite;
169 if (pThis->cbDataWritten > pThis->cbFlushInterval)
170 {
171 pThis->cbDataWritten = 0;
172 pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
173 }
174 }
175#endif /* VBOX_PERIODIC_FLUSH */
176
177 return rc;
178}
179
180
181/** @copydoc PDMIBLOCK::pfnFlush */
182static DECLCALLBACK(int) drvblockFlush(PPDMIBLOCK pInterface)
183{
184 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
185
186 /*
187 * Check the state.
188 */
189 if (!pThis->pDrvMedia)
190 {
191 AssertMsgFailed(("Invalid state! Not mounted!\n"));
192 return VERR_PDM_MEDIA_NOT_MOUNTED;
193 }
194
195#ifdef VBOX_IGNORE_FLUSH
196 if (pThis->fIgnoreFlush)
197 return VINF_SUCCESS;
198#endif /* VBOX_IGNORE_FLUSH */
199
200 int rc = pThis->pDrvMedia->pfnFlush(pThis->pDrvMedia);
201 if (rc == VERR_NOT_IMPLEMENTED)
202 rc = VINF_SUCCESS;
203 return rc;
204}
205
206
207/** @copydoc PDMIBLOCK::pfnMerge */
208static DECLCALLBACK(int) drvblockMerge(PPDMIBLOCK pInterface,
209 PFNSIMPLEPROGRESS pfnProgress,
210 void *pvUser)
211{
212 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
213
214 /*
215 * Check the state.
216 */
217 if (!pThis->pDrvMedia)
218 {
219 AssertMsgFailed(("Invalid state! Not mounted!\n"));
220 return VERR_PDM_MEDIA_NOT_MOUNTED;
221 }
222
223 if (!pThis->pDrvMedia->pfnMerge)
224 return VERR_NOT_SUPPORTED;
225
226 int rc = pThis->pDrvMedia->pfnMerge(pThis->pDrvMedia, pfnProgress, pvUser);
227 return rc;
228}
229
230
231/** @copydoc PDMIBLOCK::pfnIsReadOnly */
232static DECLCALLBACK(bool) drvblockIsReadOnly(PPDMIBLOCK pInterface)
233{
234 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
235
236 /*
237 * Check the state.
238 */
239 if (!pThis->pDrvMedia)
240 return false;
241
242 bool fRc = pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
243 return fRc;
244}
245
246
247/** @copydoc PDMIBLOCK::pfnGetSize */
248static DECLCALLBACK(uint64_t) drvblockGetSize(PPDMIBLOCK pInterface)
249{
250 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
251
252 /*
253 * Check the state.
254 */
255 if (!pThis->pDrvMedia)
256 return 0;
257
258 uint64_t cb = pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
259 LogFlow(("drvblockGetSize: returns %llu\n", cb));
260 return cb;
261}
262
263
264/** @copydoc PDMIBLOCK::pfnGetType */
265static DECLCALLBACK(PDMBLOCKTYPE) drvblockGetType(PPDMIBLOCK pInterface)
266{
267 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
268 LogFlow(("drvblockGetType: returns %d\n", pThis->enmType));
269 return pThis->enmType;
270}
271
272
273/** @copydoc PDMIBLOCK::pfnGetUuid */
274static DECLCALLBACK(int) drvblockGetUuid(PPDMIBLOCK pInterface, PRTUUID pUuid)
275{
276 PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
277
278 /*
279 * Copy the uuid.
280 */
281 *pUuid = pThis->Uuid;
282 return VINF_SUCCESS;
283}
284
285/* -=-=-=-=- IBlockAsync -=-=-=-=- */
286
287/** Makes a PDRVBLOCK out of a PPDMIBLOCKASYNC. */
288#define PDMIBLOCKASYNC_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlockAsync)) )
289
290/** @copydoc PDMIBLOCKASYNC::pfnStartRead */
291static DECLCALLBACK(int) drvblockAsyncReadStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PCRTSGSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser)
292{
293 PDRVBLOCK pThis = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
294
295 /*
296 * Check the state.
297 */
298 if (!pThis->pDrvMediaAsync)
299 {
300 AssertMsgFailed(("Invalid state! Not mounted!\n"));
301 return VERR_PDM_MEDIA_NOT_MOUNTED;
302 }
303
304 int rc = pThis->pDrvMediaAsync->pfnStartRead(pThis->pDrvMediaAsync, off, pSeg, cSeg, cbRead, pvUser);
305 return rc;
306}
307
308
309/** @copydoc PDMIBLOCKASYNC::pfnStartWrite */
310static DECLCALLBACK(int) drvblockAsyncWriteStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PCRTSGSEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser)
311{
312 PDRVBLOCK pThis = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
313
314 /*
315 * Check the state.
316 */
317 if (!pThis->pDrvMediaAsync)
318 {
319 AssertMsgFailed(("Invalid state! Not mounted!\n"));
320 return VERR_PDM_MEDIA_NOT_MOUNTED;
321 }
322
323 int rc = pThis->pDrvMediaAsync->pfnStartWrite(pThis->pDrvMediaAsync, off, pSeg, cSeg, cbWrite, pvUser);
324
325 return rc;
326}
327
328
329/** @copydoc PDMIBLOCKASYNC::pfnStartFLush */
330static DECLCALLBACK(int) drvblockAsyncFlushStart(PPDMIBLOCKASYNC pInterface, void *pvUser)
331{
332 PDRVBLOCK pThis = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
333
334 /*
335 * Check the state.
336 */
337 if (!pThis->pDrvMediaAsync)
338 {
339 AssertMsgFailed(("Invalid state! Not mounted!\n"));
340 return VERR_PDM_MEDIA_NOT_MOUNTED;
341 }
342
343#ifdef VBOX_IGNORE_FLUSH
344 if (pThis->fIgnoreFlush)
345 return VINF_VD_ASYNC_IO_FINISHED;
346#endif /* VBOX_IGNORE_FLUSH */
347
348 int rc = pThis->pDrvMediaAsync->pfnStartFlush(pThis->pDrvMediaAsync, pvUser);
349
350 return rc;
351}
352
353/* -=-=-=-=- IMediaAsyncPort -=-=-=-=- */
354
355/** Makes a PDRVBLOCKASYNC out of a PPDMIMEDIAASYNCPORT. */
356#define PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface) ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMediaAsyncPort))) )
357
358static DECLCALLBACK(int) drvblockAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser, int rcReq)
359{
360 PDRVBLOCK pThis = PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface);
361
362 return pThis->pDrvBlockAsyncPort->pfnTransferCompleteNotify(pThis->pDrvBlockAsyncPort, pvUser, rcReq);
363}
364
365/* -=-=-=-=- IBlockBios -=-=-=-=- */
366
367/** Makes a PDRVBLOCK out of a PPDMIBLOCKBIOS. */
368#define PDMIBLOCKBIOS_2_DRVBLOCK(pInterface) ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IBlockBios))) )
369
370
371/** @copydoc PDMIBLOCKBIOS::pfnGetPCHSGeometry */
372static DECLCALLBACK(int) drvblockGetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)
373{
374 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
375
376 /*
377 * Check the state.
378 */
379 if (!pThis->pDrvMedia)
380 return VERR_PDM_MEDIA_NOT_MOUNTED;
381
382 /*
383 * Use configured/cached values if present.
384 */
385 if ( pThis->PCHSGeometry.cCylinders > 0
386 && pThis->PCHSGeometry.cHeads > 0
387 && pThis->PCHSGeometry.cSectors > 0)
388 {
389 *pPCHSGeometry = pThis->PCHSGeometry;
390 LogFlow(("%s: returns VINF_SUCCESS {%d,%d,%d}\n", __FUNCTION__, pThis->PCHSGeometry.cCylinders, pThis->PCHSGeometry.cHeads, pThis->PCHSGeometry.cSectors));
391 return VINF_SUCCESS;
392 }
393
394 /*
395 * Call media.
396 */
397 int rc = pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, &pThis->PCHSGeometry);
398
399 if (RT_SUCCESS(rc))
400 {
401 *pPCHSGeometry = pThis->PCHSGeometry;
402 LogFlow(("%s: returns %Rrc {%d,%d,%d}\n", __FUNCTION__, rc, pThis->PCHSGeometry.cCylinders, pThis->PCHSGeometry.cHeads, pThis->PCHSGeometry.cSectors));
403 }
404 else if (rc == VERR_NOT_IMPLEMENTED)
405 {
406 rc = VERR_PDM_GEOMETRY_NOT_SET;
407 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
408 }
409 return rc;
410}
411
412
413/** @copydoc PDMIBLOCKBIOS::pfnSetPCHSGeometry */
414static DECLCALLBACK(int) drvblockSetPCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)
415{
416 LogFlow(("%s: cCylinders=%d cHeads=%d cSectors=%d\n", __FUNCTION__, pPCHSGeometry->cCylinders, pPCHSGeometry->cHeads, pPCHSGeometry->cSectors));
417 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
418
419 /*
420 * Check the state.
421 */
422 if (!pThis->pDrvMedia)
423 {
424 AssertMsgFailed(("Invalid state! Not mounted!\n"));
425 return VERR_PDM_MEDIA_NOT_MOUNTED;
426 }
427
428 /*
429 * Call media. Ignore the not implemented return code.
430 */
431 int rc = pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
432
433 if ( RT_SUCCESS(rc)
434 || rc == VERR_NOT_IMPLEMENTED)
435 {
436 pThis->PCHSGeometry = *pPCHSGeometry;
437 rc = VINF_SUCCESS;
438 }
439 return rc;
440}
441
442
443/** @copydoc PDMIBLOCKBIOS::pfnGetLCHSGeometry */
444static DECLCALLBACK(int) drvblockGetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)
445{
446 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
447
448 /*
449 * Check the state.
450 */
451 if (!pThis->pDrvMedia)
452 return VERR_PDM_MEDIA_NOT_MOUNTED;
453
454 /*
455 * Use configured/cached values if present.
456 */
457 if ( pThis->LCHSGeometry.cCylinders > 0
458 && pThis->LCHSGeometry.cHeads > 0
459 && pThis->LCHSGeometry.cSectors > 0)
460 {
461 *pLCHSGeometry = pThis->LCHSGeometry;
462 LogFlow(("%s: returns VINF_SUCCESS {%d,%d,%d}\n", __FUNCTION__, pThis->LCHSGeometry.cCylinders, pThis->LCHSGeometry.cHeads, pThis->LCHSGeometry.cSectors));
463 return VINF_SUCCESS;
464 }
465
466 /*
467 * Call media.
468 */
469 int rc = pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, &pThis->LCHSGeometry);
470
471 if (RT_SUCCESS(rc))
472 {
473 *pLCHSGeometry = pThis->LCHSGeometry;
474 LogFlow(("%s: returns %Rrc {%d,%d,%d}\n", __FUNCTION__, rc, pThis->LCHSGeometry.cCylinders, pThis->LCHSGeometry.cHeads, pThis->LCHSGeometry.cSectors));
475 }
476 else if (rc == VERR_NOT_IMPLEMENTED)
477 {
478 rc = VERR_PDM_GEOMETRY_NOT_SET;
479 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
480 }
481 return rc;
482}
483
484
485/** @copydoc PDMIBLOCKBIOS::pfnSetLCHSGeometry */
486static DECLCALLBACK(int) drvblockSetLCHSGeometry(PPDMIBLOCKBIOS pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)
487{
488 LogFlow(("%s: cCylinders=%d cHeads=%d cSectors=%d\n", __FUNCTION__, pLCHSGeometry->cCylinders, pLCHSGeometry->cHeads, pLCHSGeometry->cSectors));
489 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
490
491 /*
492 * Check the state.
493 */
494 if (!pThis->pDrvMedia)
495 {
496 AssertMsgFailed(("Invalid state! Not mounted!\n"));
497 return VERR_PDM_MEDIA_NOT_MOUNTED;
498 }
499
500 /*
501 * Call media. Ignore the not implemented return code.
502 */
503 int rc = pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
504
505 if ( RT_SUCCESS(rc)
506 || rc == VERR_NOT_IMPLEMENTED)
507 {
508 pThis->LCHSGeometry = *pLCHSGeometry;
509 rc = VINF_SUCCESS;
510 }
511 return rc;
512}
513
514
515/** @copydoc PDMIBLOCKBIOS::pfnIsVisible */
516static DECLCALLBACK(bool) drvblockIsVisible(PPDMIBLOCKBIOS pInterface)
517{
518 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
519 LogFlow(("drvblockIsVisible: returns %d\n", pThis->fBiosVisible));
520 return pThis->fBiosVisible;
521}
522
523
524/** @copydoc PDMIBLOCKBIOS::pfnGetType */
525static DECLCALLBACK(PDMBLOCKTYPE) drvblockBiosGetType(PPDMIBLOCKBIOS pInterface)
526{
527 PDRVBLOCK pThis = PDMIBLOCKBIOS_2_DRVBLOCK(pInterface);
528 LogFlow(("drvblockBiosGetType: returns %d\n", pThis->enmType));
529 return pThis->enmType;
530}
531
532
533
534/* -=-=-=-=- IMount -=-=-=-=- */
535
536/** Makes a PDRVBLOCK out of a PPDMIMOUNT. */
537#define PDMIMOUNT_2_DRVBLOCK(pInterface) ( (PDRVBLOCK)((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMount)) )
538
539
540/** @copydoc PDMIMOUNT::pfnMount */
541static DECLCALLBACK(int) drvblockMount(PPDMIMOUNT pInterface, const char *pszFilename, const char *pszCoreDriver)
542{
543 LogFlow(("drvblockMount: pszFilename=%p:{%s} pszCoreDriver=%p:{%s}\n", pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
544 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
545
546 /*
547 * Validate state.
548 */
549 if (pThis->pDrvMedia)
550 {
551 AssertMsgFailed(("Already mounted\n"));
552 return VERR_PDM_MEDIA_MOUNTED;
553 }
554
555 /*
556 * Prepare configuration.
557 */
558 if (pszFilename)
559 {
560 int rc = PDMDrvHlpMountPrepare(pThis->pDrvIns, pszFilename, pszCoreDriver);
561 if (RT_FAILURE(rc))
562 {
563 Log(("drvblockMount: Prepare failed for \"%s\" rc=%Rrc\n", pszFilename, rc));
564 return rc;
565 }
566 }
567
568 /*
569 * Attach the media driver and query it's interface.
570 */
571 uint32_t fTachFlags = 0; /** @todo figure attachment flags for mount. */
572 PPDMIBASE pBase;
573 int rc = PDMDrvHlpAttach(pThis->pDrvIns, fTachFlags, &pBase);
574 if (RT_FAILURE(rc))
575 {
576 Log(("drvblockMount: Attach failed rc=%Rrc\n", rc));
577 return rc;
578 }
579
580 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
581 if (pThis->pDrvMedia)
582 {
583 /** @todo r=klaus missing async handling, this is just a band aid to
584 * avoid using stale information */
585 pThis->pDrvMediaAsync = NULL;
586
587 /*
588 * Initialize state.
589 */
590 pThis->fLocked = false;
591 pThis->PCHSGeometry.cCylinders = 0;
592 pThis->PCHSGeometry.cHeads = 0;
593 pThis->PCHSGeometry.cSectors = 0;
594 pThis->LCHSGeometry.cCylinders = 0;
595 pThis->LCHSGeometry.cHeads = 0;
596 pThis->LCHSGeometry.cSectors = 0;
597#ifdef VBOX_PERIODIC_FLUSH
598 pThis->cbDataWritten = 0;
599#endif /* VBOX_PERIODIC_FLUSH */
600
601 /*
602 * Notify driver/device above us.
603 */
604 if (pThis->pDrvMountNotify)
605 pThis->pDrvMountNotify->pfnMountNotify(pThis->pDrvMountNotify);
606 Log(("drvblockMount: Success\n"));
607 return VINF_SUCCESS;
608 }
609 else
610 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
611
612 /*
613 * Failed, detatch the media driver.
614 */
615 AssertMsgFailed(("No media interface!\n"));
616 int rc2 = PDMDrvHlpDetach(pThis->pDrvIns, fTachFlags);
617 AssertRC(rc2);
618 pThis->pDrvMedia = NULL;
619 return rc;
620}
621
622
623/** @copydoc PDMIMOUNT::pfnUnmount */
624static DECLCALLBACK(int) drvblockUnmount(PPDMIMOUNT pInterface, bool fForce)
625{
626 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
627
628 /*
629 * Validate state.
630 */
631 if (!pThis->pDrvMedia)
632 {
633 Log(("drvblockUmount: Not mounted\n"));
634 return VERR_PDM_MEDIA_NOT_MOUNTED;
635 }
636 if (pThis->fLocked && !fForce)
637 {
638 Log(("drvblockUmount: Locked\n"));
639 return VERR_PDM_MEDIA_LOCKED;
640 }
641
642 /* Media is no longer locked even if it was previously. */
643 pThis->fLocked = false;
644
645 /*
646 * Detach the media driver and query it's interface.
647 */
648 int rc = PDMDrvHlpDetach(pThis->pDrvIns, 0 /*fFlags*/);
649 if (RT_FAILURE(rc))
650 {
651 Log(("drvblockUnmount: Detach failed rc=%Rrc\n", rc));
652 return rc;
653 }
654 Assert(!pThis->pDrvMedia);
655
656 /*
657 * Notify driver/device above us.
658 */
659 if (pThis->pDrvMountNotify)
660 pThis->pDrvMountNotify->pfnUnmountNotify(pThis->pDrvMountNotify);
661 Log(("drvblockUnmount: success\n"));
662 return VINF_SUCCESS;
663}
664
665
666/** @copydoc PDMIMOUNT::pfnIsMounted */
667static DECLCALLBACK(bool) drvblockIsMounted(PPDMIMOUNT pInterface)
668{
669 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
670 return pThis->pDrvMedia != NULL;
671}
672
673/** @copydoc PDMIMOUNT::pfnLock */
674static DECLCALLBACK(int) drvblockLock(PPDMIMOUNT pInterface)
675{
676 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
677 Log(("drvblockLock: %d -> %d\n", pThis->fLocked, true));
678 pThis->fLocked = true;
679 return VINF_SUCCESS;
680}
681
682/** @copydoc PDMIMOUNT::pfnUnlock */
683static DECLCALLBACK(int) drvblockUnlock(PPDMIMOUNT pInterface)
684{
685 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
686 Log(("drvblockUnlock: %d -> %d\n", pThis->fLocked, false));
687 pThis->fLocked = false;
688 return VINF_SUCCESS;
689}
690
691/** @copydoc PDMIMOUNT::pfnIsLocked */
692static DECLCALLBACK(bool) drvblockIsLocked(PPDMIMOUNT pInterface)
693{
694 PDRVBLOCK pThis = PDMIMOUNT_2_DRVBLOCK(pInterface);
695 return pThis->fLocked;
696}
697
698
699/* -=-=-=-=- IBase -=-=-=-=- */
700
701/**
702 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
703 */
704static DECLCALLBACK(void *) drvblockQueryInterface(PPDMIBASE pInterface, const char *pszIID)
705{
706 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
707 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
708
709 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
710 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCK, &pThis->IBlock);
711 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKBIOS, pThis->fBiosVisible ? &pThis->IBlockBios : NULL);
712 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNT, pThis->fMountable ? &pThis->IMount : NULL);
713 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKASYNC, pThis->pDrvMediaAsync ? &pThis->IBlockAsync : NULL);
714 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAASYNCPORT, pThis->pDrvBlockAsyncPort ? &pThis->IMediaAsyncPort : NULL);
715 return NULL;
716}
717
718
719/* -=-=-=-=- driver interface -=-=-=-=- */
720
721/** @copydoc FNPDMDRVDETACH. */
722static DECLCALLBACK(void) drvblockDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
723{
724 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
725 pThis->pDrvMedia = NULL;
726 pThis->pDrvMediaAsync = NULL;
727 NOREF(fFlags);
728}
729
730/**
731 * Reset notification.
732 *
733 * @returns VBox status.
734 * @param pDevIns The driver instance data.
735 */
736static DECLCALLBACK(void) drvblockReset(PPDMDRVINS pDrvIns)
737{
738 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
739
740 pThis->fLocked = false;
741}
742
743/**
744 * Construct a block driver instance.
745 *
746 * @copydoc FNPDMDRVCONSTRUCT
747 */
748static DECLCALLBACK(int) drvblockConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
749{
750 PDRVBLOCK pThis = PDMINS_2_DATA(pDrvIns, PDRVBLOCK);
751 LogFlow(("drvblockConstruct: iInstance=%d\n", pDrvIns->iInstance));
752 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
753
754 /*
755 * Validate configuration.
756 */
757#if defined(VBOX_PERIODIC_FLUSH) || defined(VBOX_IGNORE_FLUSH)
758 if (!CFGMR3AreValuesValid(pCfg, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Mountable\0FlushInterval\0IgnoreFlush\0"))
759#else /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
760 if (!CFGMR3AreValuesValid(pCfg, "Type\0Locked\0BIOSVisible\0AttachFailError\0Cylinders\0Heads\0Sectors\0Mountable\0"))
761#endif /* !(VBOX_PERIODIC_FLUSH || VBOX_IGNORE_FLUSH) */
762 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
763
764 /*
765 * Initialize most of the data members.
766 */
767 pThis->pDrvIns = pDrvIns;
768
769 /* IBase. */
770 pDrvIns->IBase.pfnQueryInterface = drvblockQueryInterface;
771
772 /* IBlock. */
773 pThis->IBlock.pfnRead = drvblockRead;
774 pThis->IBlock.pfnWrite = drvblockWrite;
775 pThis->IBlock.pfnFlush = drvblockFlush;
776 pThis->IBlock.pfnMerge = drvblockMerge;
777 pThis->IBlock.pfnIsReadOnly = drvblockIsReadOnly;
778 pThis->IBlock.pfnGetSize = drvblockGetSize;
779 pThis->IBlock.pfnGetType = drvblockGetType;
780 pThis->IBlock.pfnGetUuid = drvblockGetUuid;
781
782 /* IBlockBios. */
783 pThis->IBlockBios.pfnGetPCHSGeometry = drvblockGetPCHSGeometry;
784 pThis->IBlockBios.pfnSetPCHSGeometry = drvblockSetPCHSGeometry;
785 pThis->IBlockBios.pfnGetLCHSGeometry = drvblockGetLCHSGeometry;
786 pThis->IBlockBios.pfnSetLCHSGeometry = drvblockSetLCHSGeometry;
787 pThis->IBlockBios.pfnIsVisible = drvblockIsVisible;
788 pThis->IBlockBios.pfnGetType = drvblockBiosGetType;
789
790 /* IMount. */
791 pThis->IMount.pfnMount = drvblockMount;
792 pThis->IMount.pfnUnmount = drvblockUnmount;
793 pThis->IMount.pfnIsMounted = drvblockIsMounted;
794 pThis->IMount.pfnLock = drvblockLock;
795 pThis->IMount.pfnUnlock = drvblockUnlock;
796 pThis->IMount.pfnIsLocked = drvblockIsLocked;
797
798 /* IBlockAsync. */
799 pThis->IBlockAsync.pfnStartRead = drvblockAsyncReadStart;
800 pThis->IBlockAsync.pfnStartWrite = drvblockAsyncWriteStart;
801 pThis->IBlockAsync.pfnStartFlush = drvblockAsyncFlushStart;
802
803 /* IMediaAsyncPort. */
804 pThis->IMediaAsyncPort.pfnTransferCompleteNotify = drvblockAsyncTransferCompleteNotify;
805
806 /*
807 * Get the IBlockPort & IMountNotify interfaces of the above driver/device.
808 */
809 pThis->pDrvBlockPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIBLOCKPORT);
810 if (!pThis->pDrvBlockPort)
811 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
812 N_("No block port interface above"));
813
814 /* Try to get the optional async block port interface above. */
815 pThis->pDrvBlockAsyncPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIBLOCKASYNCPORT);
816 pThis->pDrvMountNotify = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMOUNTNOTIFY);
817
818 /*
819 * Query configuration.
820 */
821 /* type */
822 char *psz;
823 int rc = CFGMR3QueryStringAlloc(pCfg, "Type", &psz);
824 if (RT_FAILURE(rc))
825 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_BLOCK_NO_TYPE, N_("Failed to obtain the type"));
826 if (!strcmp(psz, "HardDisk"))
827 pThis->enmType = PDMBLOCKTYPE_HARD_DISK;
828 else if (!strcmp(psz, "DVD"))
829 pThis->enmType = PDMBLOCKTYPE_DVD;
830 else if (!strcmp(psz, "CDROM"))
831 pThis->enmType = PDMBLOCKTYPE_CDROM;
832 else if (!strcmp(psz, "Floppy 2.88"))
833 pThis->enmType = PDMBLOCKTYPE_FLOPPY_2_88;
834 else if (!strcmp(psz, "Floppy 1.44"))
835 pThis->enmType = PDMBLOCKTYPE_FLOPPY_1_44;
836 else if (!strcmp(psz, "Floppy 1.20"))
837 pThis->enmType = PDMBLOCKTYPE_FLOPPY_1_20;
838 else if (!strcmp(psz, "Floppy 720"))
839 pThis->enmType = PDMBLOCKTYPE_FLOPPY_720;
840 else if (!strcmp(psz, "Floppy 360"))
841 pThis->enmType = PDMBLOCKTYPE_FLOPPY_360;
842 else
843 {
844 PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_BLOCK_UNKNOWN_TYPE, RT_SRC_POS,
845 N_("Unknown type \"%s\""), psz);
846 MMR3HeapFree(psz);
847 return VERR_PDM_BLOCK_UNKNOWN_TYPE;
848 }
849 Log2(("drvblockConstruct: enmType=%d\n", pThis->enmType));
850 MMR3HeapFree(psz); psz = NULL;
851
852 /* Mountable */
853 rc = CFGMR3QueryBoolDef(pCfg, "Mountable", &pThis->fMountable, false);
854 if (RT_FAILURE(rc))
855 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Mountable\" from the config"));
856
857 /* Locked */
858 rc = CFGMR3QueryBoolDef(pCfg, "Locked", &pThis->fLocked, false);
859 if (RT_FAILURE(rc))
860 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Locked\" from the config"));
861
862 /* BIOS visible */
863 rc = CFGMR3QueryBoolDef(pCfg, "BIOSVisible", &pThis->fBiosVisible, true);
864 if (RT_FAILURE(rc))
865 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"BIOSVisible\" from the config"));
866
867 /** @todo AttachFailError is currently completely ignored. */
868
869 /* Cylinders */
870 rc = CFGMR3QueryU32Def(pCfg, "Cylinders", &pThis->LCHSGeometry.cCylinders, 0);
871 if (RT_FAILURE(rc))
872 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Cylinders\" from the config"));
873
874 /* Heads */
875 rc = CFGMR3QueryU32Def(pCfg, "Heads", &pThis->LCHSGeometry.cHeads, 0);
876 if (RT_FAILURE(rc))
877 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Heads\" from the config"));
878
879 /* Sectors */
880 rc = CFGMR3QueryU32Def(pCfg, "Sectors", &pThis->LCHSGeometry.cSectors, 0);
881 if (RT_FAILURE(rc))
882 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Sectors\" from the config"));
883
884 /* Uuid */
885 rc = CFGMR3QueryStringAlloc(pCfg, "Uuid", &psz);
886 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
887 RTUuidClear(&pThis->Uuid);
888 else if (RT_SUCCESS(rc))
889 {
890 rc = RTUuidFromStr(&pThis->Uuid, psz);
891 if (RT_FAILURE(rc))
892 {
893 PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, "%s",
894 N_("Uuid from string failed on \"%s\""), psz);
895 MMR3HeapFree(psz);
896 return rc;
897 }
898 MMR3HeapFree(psz); psz = NULL;
899 }
900 else
901 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"Uuid\" from the config"));
902
903#ifdef VBOX_PERIODIC_FLUSH
904 rc = CFGMR3QueryU32Def(pCfg, "FlushInterval", &pThis->cbFlushInterval, 0);
905 if (RT_FAILURE(rc))
906 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"FlushInterval\" from the config"));
907#endif /* VBOX_PERIODIC_FLUSH */
908
909#ifdef VBOX_IGNORE_FLUSH
910 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreFlush", &pThis->fIgnoreFlush, true);
911 if (RT_FAILURE(rc))
912 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Failed to query \"IgnoreFlush\" from the config"));
913#endif /* VBOX_IGNORE_FLUSH */
914
915 /*
916 * Try attach driver below and query it's media interface.
917 */
918 PPDMIBASE pBase;
919 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pBase);
920 if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
921 && pThis->enmType != PDMBLOCKTYPE_HARD_DISK)
922 return VINF_SUCCESS;
923 if (RT_FAILURE(rc))
924 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
925 N_("Failed to attach driver below us! %Rrf"), rc);
926
927 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIA);
928 if (!pThis->pDrvMedia)
929 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
930 N_("No media or async media interface below"));
931
932 /* Try to get the optional async interface. */
933 pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
934
935 if (RTUuidIsNull(&pThis->Uuid))
936 {
937 if (pThis->enmType == PDMBLOCKTYPE_HARD_DISK)
938 pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, &pThis->Uuid);
939 }
940
941 return VINF_SUCCESS;
942}
943
944
945/**
946 * Block driver registration record.
947 */
948const PDMDRVREG g_DrvBlock =
949{
950 /* u32Version */
951 PDM_DRVREG_VERSION,
952 /* szName */
953 "Block",
954 /* szRCMod */
955 "",
956 /* szR0Mod */
957 "",
958 /* pszDescription */
959 "Generic block driver.",
960 /* fFlags */
961 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
962 /* fClass. */
963 PDM_DRVREG_CLASS_BLOCK,
964 /* cMaxInstances */
965 ~0,
966 /* cbInstance */
967 sizeof(DRVBLOCK),
968 /* pfnConstruct */
969 drvblockConstruct,
970 /* pfnDestruct */
971 NULL,
972 /* pfnRelocate */
973 NULL,
974 /* pfnIOCtl */
975 NULL,
976 /* pfnPowerOn */
977 NULL,
978 /* pfnReset */
979 drvblockReset,
980 /* pfnSuspend */
981 NULL,
982 /* pfnResume */
983 NULL,
984 /* pfnAttach */
985 NULL,
986 /* pfnDetach */
987 drvblockDetach,
988 /* pfnPowerOff */
989 NULL,
990 /* pfnSoftReset */
991 NULL,
992 /* u32EndVersion */
993 PDM_DRVREG_VERSION
994};
995
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