Changeset 26987 in vbox
- Timestamp:
- Mar 3, 2010 1:33:47 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/VBoxHDD.cpp
r26986 r26987 41 41 42 42 #include <VBox/VBoxHDD-Plugin.h> 43 #include "VBoxHDDInternal.h" 43 44 45 #define VBOXHDDDISK_SIGNATURE 0x6f0e2a7d 46 47 /** Buffer size used for merging images. */ 48 #define VD_MERGE_BUFFER_SIZE (16 * _1M) 49 50 /** 51 * VD async I/O interface storage descriptor. 52 */ 53 typedef struct VDIASYNCIOSTORAGE 54 { 55 /** File handle. */ 56 RTFILE File; 57 /** Completion callback. */ 58 PFNVDCOMPLETED pfnCompleted; 59 /** Thread for async access. */ 60 RTTHREAD ThreadAsync; 61 } VDIASYNCIOSTORAGE, *PVDIASYNCIOSTORAGE; 62 63 /** 64 * VBox HDD Container image descriptor. 65 */ 66 typedef struct VDIMAGE 67 { 68 /** Link to parent image descriptor, if any. */ 69 struct VDIMAGE *pPrev; 70 /** Link to child image descriptor, if any. */ 71 struct VDIMAGE *pNext; 72 /** Container base filename. (UTF-8) */ 73 char *pszFilename; 74 /** Data managed by the backend which keeps the actual info. */ 75 void *pvBackendData; 76 /** Cached sanitized image flags. */ 77 unsigned uImageFlags; 78 /** Image open flags (only those handled generically in this code and which 79 * the backends will never ever see). */ 80 unsigned uOpenFlags; 81 82 /** Function pointers for the various backend methods. */ 83 PCVBOXHDDBACKEND Backend; 84 85 /** Pointer to list of VD interfaces, per-image. */ 86 PVDINTERFACE pVDIfsImage; 87 } VDIMAGE, *PVDIMAGE; 88 89 /** 90 * uModified bit flags. 91 */ 92 #define VD_IMAGE_MODIFIED_FLAG RT_BIT(0) 93 #define VD_IMAGE_MODIFIED_FIRST RT_BIT(1) 94 #define VD_IMAGE_MODIFIED_DISABLE_UUID_UPDATE RT_BIT(2) 95 96 97 /** 98 * VBox HDD Container main structure, private part. 99 */ 100 struct VBOXHDD 101 { 102 /** Structure signature (VBOXHDDDISK_SIGNATURE). */ 103 uint32_t u32Signature; 104 105 /** Number of opened images. */ 106 unsigned cImages; 107 108 /** Base image. */ 109 PVDIMAGE pBase; 110 111 /** Last opened image in the chain. 112 * The same as pBase if only one image is used. */ 113 PVDIMAGE pLast; 114 115 /** Flags representing the modification state. */ 116 unsigned uModified; 117 118 /** Cached size of this disk. */ 119 uint64_t cbSize; 120 /** Cached PCHS geometry for this disk. */ 121 PDMMEDIAGEOMETRY PCHSGeometry; 122 /** Cached LCHS geometry for this disk. */ 123 PDMMEDIAGEOMETRY LCHSGeometry; 124 125 /** Pointer to list of VD interfaces, per-disk. */ 126 PVDINTERFACE pVDIfsDisk; 127 /** Pointer to the common interface structure for error reporting. */ 128 PVDINTERFACE pInterfaceError; 129 /** Pointer to the error interface we use if available. */ 130 PVDINTERFACEERROR pInterfaceErrorCallbacks; 131 132 /** Fallback async interface. */ 133 VDINTERFACE VDIAsyncIO; 134 /** Fallback async I/O interface callback table. */ 135 VDINTERFACEASYNCIO VDIAsyncIOCallbacks; 136 }; 137 138 139 /** 140 * VBox parent read descriptor, used internally for compaction. 141 */ 142 typedef struct VDPARENTSTATEDESC 143 { 144 /** Pointer to disk descriptor. */ 145 PVBOXHDD pDisk; 146 /** Pointer to image descriptor. */ 147 PVDIMAGE pImage; 148 } VDPARENTSTATEDESC, *PVDPARENTSTATEDESC; 44 149 45 150 … … 178 283 * internal: find image by index into the images list. 179 284 */ 180 PVDIMAGE vdGetImageByNumber(PVBOXHDD pDisk, unsigned nImage)285 static PVDIMAGE vdGetImageByNumber(PVBOXHDD pDisk, unsigned nImage) 181 286 { 182 287 PVDIMAGE pImage = pDisk->pBase; … … 268 373 * internal: mark the disk as modified. 269 374 */ 270 void vdSetModifiedFlag(PVBOXHDD pDisk)375 static void vdSetModifiedFlag(PVBOXHDD pDisk) 271 376 { 272 377 pDisk->uModified |= VD_IMAGE_MODIFIED_FLAG; … … 765 870 } 766 871 767 /**768 * internal: send output to the log (unconditionally).769 */770 void vdLogError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)771 {772 NOREF(pvUser);773 RTLogPrintf("Error occurred: %Rrc\n", rc);774 RTLogPrintf(pszFormat, va);775 }776 872 777 873 /** … … 948 1044 if (pDisk->pInterfaceError) 949 1045 pDisk->pInterfaceErrorCallbacks = VDGetInterfaceError(pDisk->pInterfaceError); 950 else951 {952 /* Provide our own interface */953 pDisk->VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);954 pDisk->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;955 pDisk->VDIErrorCallbacks.pfnMessage = vdLogMessage;956 pDisk->VDIErrorCallbacks.pfnError = vdLogError;957 rc = VDInterfaceAdd(&pDisk->VDIError, "VD_Error", VDINTERFACETYPE_ERROR,958 &pDisk->VDIErrorCallbacks, pDisk, &pDisk->pVDIfsDisk);959 AssertRC(rc);960 }961 1046 962 1047 /* Use the fallback async I/O interface if the caller doesn't provide one. */ … … 3640 3725 } 3641 3726 3727 /** 3728 * Query if asynchronous operations are supported for this disk. 3729 * 3730 * @returns VBox status code. 3731 * @returns VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. 3732 * @param pDisk Pointer to the HDD container. 3733 * @param nImage Image number, counts from 0. 0 is always base image of container. 3734 * @param pfAIOSupported Where to store if async IO is supported. 3735 */ 3736 VBOXDDU_DECL(int) VDImageIsAsyncIOSupported(PVBOXHDD pDisk, unsigned nImage, bool *pfAIOSupported) 3737 { 3738 int rc = VINF_SUCCESS; 3739 3740 LogFlowFunc(("pDisk=%#p nImage=%u pfAIOSupported=%#p\n", pDisk, nImage, pfAIOSupported)); 3741 do 3742 { 3743 /* sanity check */ 3744 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 3745 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 3746 3747 /* Check arguments. */ 3748 AssertMsgBreakStmt(VALID_PTR(pfAIOSupported), 3749 ("pfAIOSupported=%#p\n", pfAIOSupported), 3750 rc = VERR_INVALID_PARAMETER); 3751 3752 PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage); 3753 AssertPtrBreakStmt(pImage, rc = VERR_VD_IMAGE_NOT_FOUND); 3754 3755 if (pImage->Backend->uBackendCaps & VD_CAP_ASYNC) 3756 *pfAIOSupported = pImage->Backend->pfnIsAsyncIOSupported(pImage->pvBackendData); 3757 else 3758 *pfAIOSupported = false; 3759 } while (0); 3760 3761 LogFlowFunc(("returns %Rrc, fAIOSupported=%u\n", rc, *pfAIOSupported)); 3762 return rc; 3763 } 3764 3765 /** 3766 * Start a asynchronous read request. 3767 * 3768 * @returns VBox status code. 3769 * @param pDisk Pointer to the HDD container. 3770 * @param uOffset The offset of the virtual disk to read from. 3771 * @param cbRead How many bytes to read. 3772 * @param paSeg Pointer to an array of segments. 3773 * @param cSeg Number of segments in the array. 3774 * @param pvUser User data which is passed on completion 3775 */ 3776 VBOXDDU_DECL(int) VDAsyncRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead, 3777 PPDMDATASEG paSeg, unsigned cSeg, 3778 void *pvUser) 3779 { 3780 int rc = VERR_VD_BLOCK_FREE; 3781 3782 LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbRead=%zu\n", 3783 pDisk, uOffset, paSeg, cSeg, cbRead)); 3784 do 3785 { 3786 /* sanity check */ 3787 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 3788 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 3789 3790 /* Check arguments. */ 3791 AssertMsgBreakStmt(cbRead, 3792 ("cbRead=%zu\n", cbRead), 3793 rc = VERR_INVALID_PARAMETER); 3794 AssertMsgBreakStmt(uOffset + cbRead <= pDisk->cbSize, 3795 ("uOffset=%llu cbRead=%zu pDisk->cbSize=%llu\n", 3796 uOffset, cbRead, pDisk->cbSize), 3797 rc = VERR_INVALID_PARAMETER); 3798 AssertMsgBreakStmt(VALID_PTR(paSeg), 3799 ("paSeg=%#p\n", paSeg), 3800 rc = VERR_INVALID_PARAMETER); 3801 AssertMsgBreakStmt(cSeg, 3802 ("cSeg=%zu\n", cSeg), 3803 rc = VERR_INVALID_PARAMETER); 3804 3805 3806 PVDIMAGE pImage = pDisk->pLast; 3807 AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED); 3808 3809 /* @todo: This does not work for images which do not have all meta data in memory. */ 3810 for (PVDIMAGE pCurrImage = pImage; 3811 pCurrImage != NULL && rc == VERR_VD_BLOCK_FREE; 3812 pCurrImage = pCurrImage->pPrev) 3813 { 3814 rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pvBackendData, 3815 uOffset, cbRead, paSeg, cSeg, 3816 pvUser); 3817 } 3818 3819 /* No image in the chain contains the data for the block. */ 3820 if (rc == VERR_VD_BLOCK_FREE) 3821 { 3822 for (unsigned i = 0; i < cSeg && (cbRead > 0); i++) 3823 { 3824 memset(paSeg[i].pvSeg, '\0', paSeg[i].cbSeg); 3825 cbRead -= paSeg[i].cbSeg; 3826 } 3827 /* Request finished without the need to enqueue a async I/O request. Tell caller. */ 3828 rc = VINF_VD_ASYNC_IO_FINISHED; 3829 } 3830 3831 } while (0); 3832 3833 LogFlowFunc(("returns %Rrc\n", rc)); 3834 return rc; 3835 } 3836 3837 3838 /** 3839 * Start a asynchronous write request. 3840 * 3841 * @returns VBox status code. 3842 * @param pDisk Pointer to the HDD container. 3843 * @param uOffset The offset of the virtual disk to write to. 3844 * @param cbWrtie How many bytes to write. 3845 * @param paSeg Pointer to an array of segments. 3846 * @param cSeg Number of segments in the array. 3847 * @param pvUser User data which is passed on completion. 3848 */ 3849 VBOXDDU_DECL(int) VDAsyncWrite(PVBOXHDD pDisk, uint64_t uOffset, size_t cbWrite, 3850 PPDMDATASEG paSeg, unsigned cSeg, 3851 void *pvUser) 3852 { 3853 int rc; 3854 3855 LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbWrite=%zu\n", 3856 pDisk, uOffset, paSeg, cSeg, cbWrite)); 3857 do 3858 { 3859 /* sanity check */ 3860 AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER); 3861 AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature)); 3862 3863 /* Check arguments. */ 3864 AssertMsgBreakStmt(cbWrite, 3865 ("cbWrite=%zu\n", cbWrite), 3866 rc = VERR_INVALID_PARAMETER); 3867 AssertMsgBreakStmt(uOffset + cbWrite <= pDisk->cbSize, 3868 ("uOffset=%llu cbWrite=%zu pDisk->cbSize=%llu\n", 3869 uOffset, cbWrite, pDisk->cbSize), 3870 rc = VERR_INVALID_PARAMETER); 3871 AssertMsgBreakStmt(VALID_PTR(paSeg), 3872 ("paSeg=%#p\n", paSeg), 3873 rc = VERR_INVALID_PARAMETER); 3874 AssertMsgBreakStmt(cSeg, 3875 ("cSeg=%zu\n", cSeg), 3876 rc = VERR_INVALID_PARAMETER); 3877 3878 3879 PVDIMAGE pImage = pDisk->pLast; 3880 AssertPtrBreakStmt(pImage, rc = VERR_VD_NOT_OPENED); 3881 3882 vdSetModifiedFlag(pDisk); 3883 rc = pImage->Backend->pfnAsyncWrite(pImage->pvBackendData, 3884 uOffset, cbWrite, 3885 paSeg, cSeg, pvUser); 3886 } while (0); 3887 3888 LogFlowFunc(("returns %Rrc\n", rc)); 3889 return rc; 3890 3891 } 3892 3642 3893 #if 0 3643 3894 /** @copydoc VBOXHDDBACKEND::pfnComposeLocation */
Note:
See TracChangeset
for help on using the changeset viewer.