VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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