VirtualBox

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

Last change on this file since 35753 was 35560, checked in by vboxsync, 14 years ago

PDM: introduced fEject parameter to PDMIMOUNT::pfnUnmount which is false if we don't need to eject the medium during unmount

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