VirtualBox

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

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

Storage: Convert from PDMDATASEG to RTSGSEG to avoid casting between those two in VBoxHDD and more async I/O updates

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