VirtualBox

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

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

DrvBlock: Async flushes are not ignored by default

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