~ubuntu-branches/ubuntu/trusty/virtualbox-ose/trusty

« back to all changes in this revision

Viewing changes to src/VBox/Devices/Storage/VBoxHDD.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2009-12-18 16:44:29 UTC
  • mfrom: (0.3.3 upstream) (0.4.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091218164429-jd34ccexpv5na11a
Tags: 3.1.2-dfsg-1ubuntu1
* Merge from Debian unstable (LP: #498219), remaining changes:
  - Disable update action
    - debian/patches/u01-disable-update-action.dpatch
  - VirtualBox should go in Accessories, not in System tools (LP: #288590)
    - debian/virtualbox-ose-qt.files/virtualbox-ose.desktop
  - Add Apport hook
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Add Launchpad integration
    - debian/control
    - debian/lpi-bug.xpm
    - debian/patches/u02-lp-integration.dpatch
* Fixes the following bugs:
  - Kernel module fails to build with Linux >= 2.6.32 (LP: #474625)
  - X.Org drivers need to be rebuilt against X-Server 1.7 (LP: #495935)
  - The *-source packages try to build the kernel modules even though the
    kernel headers aren't available (LP: #473334)
* Replace *-source packages with transitional packages for *-dkms.
* Adapt u01-disable-update-action.dpatch and u02-lp-integration.dpatch for
  new upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
#include <iprt/path.h>
40
40
#include <iprt/param.h>
41
41
 
42
 
#include "VBoxHDD-Internal.h"
 
42
#include <VBox/VBoxHDD-Plugin.h>
43
43
 
44
44
 
45
45
#define VBOXHDDDISK_SIGNATURE 0x6f0e2a7d
48
48
#define VD_MERGE_BUFFER_SIZE    (16 * _1M)
49
49
 
50
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
/**
51
64
 * VBox HDD Container image descriptor.
52
65
 */
53
66
typedef struct VDIMAGE
115
128
    PVDINTERFACE        pInterfaceError;
116
129
    /** Pointer to the error interface we use if available. */
117
130
    PVDINTERFACEERROR   pInterfaceErrorCallbacks;
 
131
 
 
132
    /** Fallback async interface. */
 
133
    VDINTERFACE         VDIAsyncIO;
 
134
    /** Fallback async I/O interface callback table. */
 
135
    VDINTERFACEASYNCIO  VDIAsyncIOCallbacks;
118
136
};
119
137
 
120
138
 
134
152
extern VBOXHDDBACKEND g_VmdkBackend;
135
153
extern VBOXHDDBACKEND g_VDIBackend;
136
154
extern VBOXHDDBACKEND g_VhdBackend;
 
155
extern VBOXHDDBACKEND g_ParallelsBackend;
137
156
#ifdef VBOX_WITH_ISCSI
138
157
extern VBOXHDDBACKEND g_ISCSIBackend;
139
158
#endif
145
164
    &g_RawBackend,
146
165
    &g_VmdkBackend,
147
166
    &g_VDIBackend,
148
 
    &g_VhdBackend
 
167
    &g_VhdBackend,
 
168
    &g_ParallelsBackend
149
169
#ifdef VBOX_WITH_ISCSI
150
170
    ,&g_ISCSIBackend
151
171
#endif
630
650
        goto out;
631
651
    }
632
652
 
633
 
    while ((rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING)) != VERR_NO_MORE_FILES)
 
653
    while ((rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK)) != VERR_NO_MORE_FILES)
634
654
    {
635
655
        RTLDRMOD hPlugin = NIL_RTLDRMOD;
636
656
        PFNVBOXHDDFORMATLOAD pfnHDDFormatLoad = NULL;
643
663
            RTMemFree(pPluginDirEntry);
644
664
            pPluginDirEntry = (PRTDIRENTRYEX)RTMemAllocZ(cbPluginDirEntry);
645
665
            /* Retry. */
646
 
            rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING);
 
666
            rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
647
667
            if (RT_FAILURE(rc))
648
668
                break;
649
669
        }
705
725
}
706
726
 
707
727
/**
 
728
 * VD async I/O interface open callback.
 
729
 */
 
730
static int vdAsyncIOOpen(void *pvUser, const char *pszLocation, unsigned uOpenFlags,
 
731
                         PFNVDCOMPLETED pfnCompleted, void **ppStorage)
 
732
{
 
733
    PVDIASYNCIOSTORAGE pStorage = (PVDIASYNCIOSTORAGE)RTMemAllocZ(sizeof(VDIASYNCIOSTORAGE));
 
734
 
 
735
    if (!pStorage)
 
736
        return VERR_NO_MEMORY;
 
737
 
 
738
    pStorage->pfnCompleted = pfnCompleted;
 
739
 
 
740
    uint32_t fOpen = 0;
 
741
 
 
742
    if (uOpenFlags & VD_INTERFACEASYNCIO_OPEN_FLAGS_READONLY)
 
743
        fOpen |= RTFILE_O_READ      | RTFILE_O_DENY_NONE;
 
744
    else
 
745
        fOpen |= RTFILE_O_READWRITE | RTFILE_O_DENY_WRITE;
 
746
 
 
747
    if (uOpenFlags & VD_INTERFACEASYNCIO_OPEN_FLAGS_CREATE)
 
748
        fOpen |= RTFILE_O_CREATE;
 
749
    else
 
750
        fOpen |= RTFILE_O_OPEN;
 
751
 
 
752
    /* Open the file. */
 
753
    int rc = RTFileOpen(&pStorage->File, pszLocation, fOpen);
 
754
    if (RT_SUCCESS(rc))
 
755
    {
 
756
        *ppStorage = pStorage;
 
757
        return VINF_SUCCESS;
 
758
    }
 
759
 
 
760
    RTMemFree(pStorage);
 
761
    return rc;
 
762
}
 
763
 
 
764
/**
 
765
 * VD async I/O interface close callback.
 
766
 */
 
767
static int vdAsyncIOClose(void *pvUser, void *pvStorage)
 
768
{
 
769
    PVDIASYNCIOSTORAGE pStorage = (PVDIASYNCIOSTORAGE)pvStorage;
 
770
 
 
771
    RTFileClose(pStorage->File);
 
772
    RTMemFree(pStorage);
 
773
    return VINF_SUCCESS;
 
774
}
 
775
 
 
776
/**
 
777
 * VD async I/O interface callback for retrieving the file size.
 
778
 */
 
779
static int vdAsyncIOGetSize(void *pvUser, void *pvStorage, uint64_t *pcbSize)
 
780
{
 
781
    PVDIASYNCIOSTORAGE pStorage = (PVDIASYNCIOSTORAGE)pvStorage;
 
782
 
 
783
    return RTFileGetSize(pStorage->File, pcbSize);
 
784
}
 
785
 
 
786
/**
 
787
 * VD async I/O interface callback for setting the file size.
 
788
 */
 
789
static int vdAsyncIOSetSize(void *pvUser, void *pvStorage, uint64_t cbSize)
 
790
{
 
791
    PVDIASYNCIOSTORAGE pStorage = (PVDIASYNCIOSTORAGE)pvStorage;
 
792
 
 
793
    return RTFileSetSize(pStorage->File, cbSize);
 
794
}
 
795
 
 
796
/**
 
797
 * VD async I/O interface callback for a synchronous write to the file.
 
798
 */
 
799
static int vdAsyncIOWriteSync(void *pvUser, void *pvStorage, uint64_t uOffset,
 
800
                             size_t cbWrite, const void *pvBuf, size_t *pcbWritten)
 
801
{
 
802
    PVDIASYNCIOSTORAGE pStorage = (PVDIASYNCIOSTORAGE)pvStorage;
 
803
 
 
804
    return RTFileWriteAt(pStorage->File, uOffset, pvBuf, cbWrite, pcbWritten);
 
805
}
 
806
 
 
807
/**
 
808
 * VD async I/O interface callback for a synchronous read from the file.
 
809
 */
 
810
static int vdAsyncIOReadSync(void *pvUser, void *pvStorage, uint64_t uOffset,
 
811
                             size_t cbRead, void *pvBuf, size_t *pcbRead)
 
812
{
 
813
    PVDIASYNCIOSTORAGE pStorage = (PVDIASYNCIOSTORAGE)pvStorage;
 
814
 
 
815
    return RTFileReadAt(pStorage->File, uOffset, pvBuf, cbRead, pcbRead);
 
816
}
 
817
 
 
818
/**
 
819
 * VD async I/O interface callback for a synchronous flush of the file data.
 
820
 */
 
821
static int vdAsyncIOFlushSync(void *pvUser, void *pvStorage)
 
822
{
 
823
    PVDIASYNCIOSTORAGE pStorage = (PVDIASYNCIOSTORAGE)pvStorage;
 
824
 
 
825
    return RTFileFlush(pStorage->File);
 
826
}
 
827
 
 
828
/**
 
829
 * VD async I/O interface callback for a asynchronous read from the file.
 
830
 */
 
831
static int vdAsyncIOReadAsync(void *pvUser, void *pStorage, uint64_t uOffset,
 
832
                              PCPDMDATASEG paSegments, size_t cSegments,
 
833
                              size_t cbRead, void *pvCompletion,
 
834
                              void **ppTask)
 
835
{
 
836
    return VERR_NOT_IMPLEMENTED;
 
837
}
 
838
 
 
839
/**
 
840
 * VD async I/O interface callback for a asynchronous write to the file.
 
841
 */
 
842
static int vdAsyncIOWriteAsync(void *pvUser, void *pStorage, uint64_t uOffset,
 
843
                               PCPDMDATASEG paSegments, size_t cSegments,
 
844
                               size_t cbWrite, void *pvCompletion,
 
845
                               void **ppTask)
 
846
{
 
847
    return VERR_NOT_IMPLEMENTED;
 
848
}
 
849
 
 
850
/**
 
851
 * VD async I/O interface callback for a asynchronous flush of the file data.
 
852
 */
 
853
static int vdAsyncIOFlushAsync(void *pvUser, void *pStorage,
 
854
                               void *pvCompletion, void **ppTask)
 
855
{
 
856
    return VERR_NOT_IMPLEMENTED;
 
857
}
 
858
 
 
859
/**
 
860
 * internal: send output to the log (unconditionally).
 
861
 */
 
862
int vdLogMessage(void *pvUser, const char *pszFormat, ...)
 
863
{
 
864
    NOREF(pvUser);
 
865
    va_list args;
 
866
    va_start(args, pszFormat);
 
867
    RTLogPrintf(pszFormat, args);
 
868
    va_end(args);
 
869
    return VINF_SUCCESS;
 
870
}
 
871
 
 
872
 
 
873
/**
708
874
 * Initializes HDD backends.
709
875
 *
710
876
 * @returns VBox status code.
877
1043
            pDisk->pInterfaceError = VDInterfaceGet(pVDIfsDisk, VDINTERFACETYPE_ERROR);
878
1044
            if (pDisk->pInterfaceError)
879
1045
                pDisk->pInterfaceErrorCallbacks = VDGetInterfaceError(pDisk->pInterfaceError);
 
1046
 
 
1047
            /* Use the fallback async I/O interface if the caller doesn't provide one. */
 
1048
            PVDINTERFACE pVDIfAsyncIO = VDInterfaceGet(pVDIfsDisk, VDINTERFACETYPE_ASYNCIO);
 
1049
            if (!pVDIfAsyncIO)
 
1050
            {
 
1051
                pDisk->VDIAsyncIOCallbacks.cbSize        = sizeof(VDINTERFACEASYNCIO);
 
1052
                pDisk->VDIAsyncIOCallbacks.enmInterface  = VDINTERFACETYPE_ASYNCIO;
 
1053
                pDisk->VDIAsyncIOCallbacks.pfnOpen       = vdAsyncIOOpen;
 
1054
                pDisk->VDIAsyncIOCallbacks.pfnClose      = vdAsyncIOClose;
 
1055
                pDisk->VDIAsyncIOCallbacks.pfnGetSize    = vdAsyncIOGetSize;
 
1056
                pDisk->VDIAsyncIOCallbacks.pfnSetSize    = vdAsyncIOSetSize;
 
1057
                pDisk->VDIAsyncIOCallbacks.pfnReadSync   = vdAsyncIOReadSync;
 
1058
                pDisk->VDIAsyncIOCallbacks.pfnWriteSync  = vdAsyncIOWriteSync;
 
1059
                pDisk->VDIAsyncIOCallbacks.pfnFlushSync  = vdAsyncIOFlushSync;
 
1060
                pDisk->VDIAsyncIOCallbacks.pfnReadAsync  = vdAsyncIOReadAsync;
 
1061
                pDisk->VDIAsyncIOCallbacks.pfnWriteAsync = vdAsyncIOWriteAsync;
 
1062
                pDisk->VDIAsyncIOCallbacks.pfnFlushAsync = vdAsyncIOFlushAsync;
 
1063
                rc = VDInterfaceAdd(&pDisk->VDIAsyncIO, "VD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
 
1064
                                    &pDisk->VDIAsyncIOCallbacks, pDisk, &pDisk->pVDIfsDisk);
 
1065
                AssertRC(rc);
 
1066
            }
 
1067
 
880
1068
            *ppDisk = pDisk;
881
1069
        }
882
1070
        else
917
1105
 *          VINF_SUCCESS if a plugin was found.
918
1106
 *                       ppszFormat contains the string which can be used as backend name.
919
1107
 *          VERR_NOT_SUPPORTED if no backend was found.
 
1108
 * @param   pVDIfsDisk      Pointer to the per-disk VD interface list.
920
1109
 * @param   pszFilename     Name of the image file for which the backend is queried.
921
1110
 * @param   ppszFormat      Receives pointer of the UTF-8 string which contains the format name.
922
1111
 *                          The returned pointer must be freed using RTStrFree().
923
1112
 */
924
 
VBOXDDU_DECL(int) VDGetFormat(const char *pszFilename, char **ppszFormat)
 
1113
VBOXDDU_DECL(int) VDGetFormat(PVDINTERFACE pVDIfsDisk, const char *pszFilename, char **ppszFormat)
925
1114
{
926
1115
    int rc = VERR_NOT_SUPPORTED;
 
1116
    PVDINTERFACE pVDIfAsyncIO;
 
1117
    VDINTERFACEASYNCIO VDIAsyncIOCallbacks;
 
1118
    VDINTERFACE        VDIAsyncIO;
927
1119
 
928
1120
    LogFlowFunc(("pszFilename=\"%s\"\n", pszFilename));
929
1121
    /* Check arguments. */
937
1129
    if (!g_apBackends)
938
1130
        VDInit();
939
1131
 
 
1132
    /* Use the fallback async I/O interface if the caller doesn't provide one. */
 
1133
    pVDIfAsyncIO = VDInterfaceGet(pVDIfsDisk, VDINTERFACETYPE_ASYNCIO);
 
1134
    if (!pVDIfAsyncIO)
 
1135
    {
 
1136
        VDIAsyncIOCallbacks.cbSize        = sizeof(VDINTERFACEASYNCIO);
 
1137
        VDIAsyncIOCallbacks.enmInterface  = VDINTERFACETYPE_ASYNCIO;
 
1138
        VDIAsyncIOCallbacks.pfnOpen       = vdAsyncIOOpen;
 
1139
        VDIAsyncIOCallbacks.pfnClose      = vdAsyncIOClose;
 
1140
        VDIAsyncIOCallbacks.pfnGetSize    = vdAsyncIOGetSize;
 
1141
        VDIAsyncIOCallbacks.pfnSetSize    = vdAsyncIOSetSize;
 
1142
        VDIAsyncIOCallbacks.pfnReadSync   = vdAsyncIOReadSync;
 
1143
        VDIAsyncIOCallbacks.pfnWriteSync  = vdAsyncIOWriteSync;
 
1144
        VDIAsyncIOCallbacks.pfnFlushSync  = vdAsyncIOFlushSync;
 
1145
        VDIAsyncIOCallbacks.pfnReadAsync  = vdAsyncIOReadAsync;
 
1146
        VDIAsyncIOCallbacks.pfnWriteAsync = vdAsyncIOWriteAsync;
 
1147
        VDIAsyncIOCallbacks.pfnFlushAsync = vdAsyncIOFlushAsync;
 
1148
        rc = VDInterfaceAdd(&VDIAsyncIO, "VD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
 
1149
                            &VDIAsyncIOCallbacks, NULL, &pVDIfsDisk);
 
1150
        AssertRC(rc);
 
1151
    }
 
1152
 
940
1153
    /* Find the backend supporting this file format. */
941
1154
    for (unsigned i = 0; i < g_cBackends; i++)
942
1155
    {
943
1156
        if (g_apBackends[i]->pfnCheckIfValid)
944
1157
        {
945
 
            rc = g_apBackends[i]->pfnCheckIfValid(pszFilename);
 
1158
            rc = g_apBackends[i]->pfnCheckIfValid(pszFilename, pVDIfsDisk);
946
1159
            if (    RT_SUCCESS(rc)
947
1160
                /* The correct backend has been found, but there is a small
948
1161
                 * incompatibility so that the file cannot be used. Stop here
1055
1268
        if (RT_FAILURE(rc))
1056
1269
        {
1057
1270
            if (!(uOpenFlags & VD_OPEN_FLAGS_READONLY)
1058
 
                &&  (rc == VERR_ACCESS_DENIED
 
1271
                &&  (   rc == VERR_ACCESS_DENIED
1059
1272
                     || rc == VERR_PERMISSION_DENIED
1060
1273
                     || rc == VERR_WRITE_PROTECT
1061
1274
                     || rc == VERR_SHARING_VIOLATION
1069
1282
            if (RT_FAILURE(rc))
1070
1283
            {
1071
1284
                rc = vdError(pDisk, rc, RT_SRC_POS,
1072
 
                             N_("VD: error opening image file '%s'"), pszFilename);
 
1285
                             N_("VD: error %Rrc opening image file '%s'"), rc, pszFilename);
1073
1286
                break;
1074
1287
            }
1075
1288
        }
1530
1743
        }
1531
1744
 
1532
1745
        pImage->uOpenFlags = uOpenFlags & VD_OPEN_FLAGS_HONOR_SAME;
 
1746
        uImageFlags |= VD_IMAGE_FLAGS_DIFF;
1533
1747
        rc = pImage->Backend->pfnCreate(pImage->pszFilename, pDisk->cbSize,
1534
 
                                        uImageFlags, pszComment,
1535
 
                                        &pDisk->PCHSGeometry,
 
1748
                                        uImageFlags | VD_IMAGE_FLAGS_DIFF,
 
1749
                                        pszComment, &pDisk->PCHSGeometry,
1536
1750
                                        &pDisk->LCHSGeometry, pUuid,
1537
1751
                                        uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME,
1538
1752
                                        0, 99,
1543
1757
 
1544
1758
        if (RT_SUCCESS(rc) && pDisk->cImages != 0)
1545
1759
        {
1546
 
            pImage->uImageFlags |= VD_IMAGE_FLAGS_DIFF;
 
1760
            pImage->uImageFlags = uImageFlags;
1547
1761
 
1548
1762
            /* Switch previous image to read-only mode. */
1549
1763
            unsigned uOpenFlagsPrevImg;
2029
2243
                if (!RTStrICmp(pszBackend, "RAW"))
2030
2244
                    uImageFlags |= VD_IMAGE_FLAGS_FIXED;
2031
2245
 
 
2246
                /* Fix broken PCHS geometry. Can happen for two reasons: either
 
2247
                 * the backend mixes up PCHS and LCHS, or the application used
 
2248
                 * to create the source image has put garbage in it. */
 
2249
                /** @todo double-check if the VHD backend correctly handles
 
2250
                 * PCHS and LCHS geometry. also reconsider our current paranoia
 
2251
                 * level when it comes to geometry settings here and in the
 
2252
                 * backends. */
 
2253
                if (PCHSGeometryFrom.cHeads > 16 || PCHSGeometryFrom.cSectors > 63)
 
2254
                {
 
2255
                    Assert(RT_MIN(cbSize / 512 / 16 / 63, 16383) - (uint32_t)RT_MIN(cbSize / 512 / 16 / 63, 16383));
 
2256
                    PCHSGeometryFrom.cCylinders = (uint32_t)RT_MIN(cbSize / 512 / 16 / 63, 16383);
 
2257
                    PCHSGeometryFrom.cHeads = 16;
 
2258
                    PCHSGeometryFrom.cSectors = 63;
 
2259
                }
 
2260
 
2032
2261
                rc = VDCreateBase(pDiskTo, pszBackend, pszFilename, cbSize,
2033
2262
                                  uImageFlags, szComment,
2034
2263
                                  &PCHSGeometryFrom, &LCHSGeometryFrom,
2112
2341
 
2113
2342
        if (RT_SUCCESS(rc))
2114
2343
        {
2115
 
            pImageTo->Backend->pfnSetModificationUuid(pImageTo->pvBackendData, &ImageModificationUuid);
 
2344
            /* Only set modification UUID if it is non-null, since the source
 
2345
             * backend might not provide a valid modification UUID. */
 
2346
            if (!RTUuidIsNull(&ImageModificationUuid))
 
2347
                pImageTo->Backend->pfnSetModificationUuid(pImageTo->pvBackendData, &ImageModificationUuid);
2116
2348
            /** @todo double-check this - it makes little sense to copy over the parent modification uuid,
2117
2349
             * as the destination image can have a totally different parent. */
2118
2350
#if 0
3472
3704
        AssertPtrBreak(pDisk);
3473
3705
        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
3474
3706
 
3475
 
        RTLogPrintf("--- Dumping VD Disk, Images=%u\n", pDisk->cImages);
 
3707
        int (*pfnMessage)(void *, const char *, ...) = NULL;
 
3708
        void *pvUser = pDisk->pInterfaceError->pvUser;
 
3709
 
 
3710
        if (pDisk->pInterfaceErrorCallbacks && VALID_PTR(pDisk->pInterfaceErrorCallbacks->pfnMessage))
 
3711
            pfnMessage = pDisk->pInterfaceErrorCallbacks->pfnMessage;
 
3712
        else
 
3713
        {
 
3714
            pDisk->pInterfaceErrorCallbacks->pfnMessage = vdLogMessage;
 
3715
            pfnMessage = vdLogMessage;
 
3716
        }
 
3717
 
 
3718
        pfnMessage(pvUser, "--- Dumping VD Disk, Images=%u\n", pDisk->cImages);
3476
3719
        for (PVDIMAGE pImage = pDisk->pBase; pImage; pImage = pImage->pNext)
3477
3720
        {
3478
 
            RTLogPrintf("Dumping VD image \"%s\" (Backend=%s)\n",
3479
 
                        pImage->pszFilename, pImage->Backend->pszBackendName);
 
3721
            pfnMessage(pvUser, "Dumping VD image \"%s\" (Backend=%s)\n",
 
3722
                       pImage->pszFilename, pImage->Backend->pszBackendName);
3480
3723
            pImage->Backend->pfnDump(pImage->pvBackendData);
3481
3724
        }
3482
3725
    } while (0);