VirtualBox

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

Last change on this file since 7285 was 6312, checked in by vboxsync, 17 years ago

remove functions from PDMIMEDIAASYNC and PCMIBLOCKASYNC. PDMIMEDIA and PDMIBLOCK are mandatory now and the async versions are optional extensions which can be implemented. Removed duplicated code

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