DrvVD.cpp revision f4fd9b62ec1cb6bb79fc7432a2d1a4c5f7c63bfc
#
endif /* VBOX_WITH_INIP *//* Small hack to get at lwIP initialized status */ #
endif /* VBOX_WITH_INIP *//******************************************************************************* * Defined types, constants and macros * *******************************************************************************/ /** Converts a pointer to VBOXDISK::IMedia to a PVBOXDISK. */ /** Converts a pointer to VBOXDISK::IMediaAsync to a PVBOXDISK. */ * VBox disk container, image information, private part. /** Pointer to next image. */ /** Pointer to list of VD interfaces. Per-image. */ /** Configuration information interface. */ /** TCP network stack interface. */ /** PDM async completion end point. */ /** Event semaphore for synchronous operations. */ /** Flag whether a synchronous operation is currently pending. */ /** Return code of the last completed request. */ * VBox disk container media main structure, private part. * @implements PDMIMEDIAASYNC * @implements VDINTERFACEERROR * @implements VDINTERFACETCPNET * @implements VDINTERFACEASYNCIO * @implements VDINTERFACECONFIG /** The VBox disk container. */ /** The media interface. */ /** Pointer to the driver instance. */ /** Flag whether suspend has changed image open mode to read only. */ /** Flag whether to use the runtime (true) or startup error facility. */ /** Pointer to list of VD interfaces. Per-disk. */ /** Thread synchronization interface. */ /** Flag whether opened disk supports async I/O operations. */ /** The async media interface. */ /** The async media port interface above. */ /** Pointer to the list of data we need to keep per image. */ /** Flag whether the media should allow concurrent open for writing. */ /** Flag whether a merge operation has been set up. */ /** Synchronization to prevent destruction before merge finishes. */ /** Synchronization between merge and other image accesses. */ /** Source image index for merging. */ /** Target image index for merging. */ /** Flag whether boot acceleration is enabled. */ /** Flag whether boot acceleration is currently active. */ /** Size of the disk, used for read truncation. */ /** Size of the configured buffer. */ /** Start offset for which the buffer holds data. */ /** Number of valid bytes in the buffer. */ /** Bandwidth group the disk is assigned to. */ /** Flag whether async I/O using the host cache is enabled. */ /** I/O interface for a cache image. */ /** Interface list for the cache image. */ /** The block cache handle if configured. */ /** Cryptographic support /** Pointer to the CFGM node containing the config of the crypto filter /** Config interface for the encryption filter. */ /** Crypto interface for the encryption filter. */ /** The secret key interface used to retrieve keys. */ /** The secret key helper interface used to notify about missing keys. */ /******************************************************************************* *******************************************************************************/ * Internal: allocate new image descriptor and put it in the list * Internal: free the list of images descriptors. * Make the image temporarily read-only. * @returns VBox status code. * @param pThis The driver instance data. * Undo the temporary read-only status of the image. * @returns VBox status code. * @param pThis The driver instance data. /******************************************************************************* * Error reporting callback * *******************************************************************************/ /* We must not pass VMSETRTERR_FLAGS_FATAL as it could lead to a * deadlock: We are probably executed in a thread context != EMT * and the EM thread would wait until every thread is suspended * but we would wait for the EM thread ... */ /******************************************************************************* * VD Async I/O interface implementation * *******************************************************************************/ LogFlowFunc((
"pDrvIns=%#p pvTemplateUser=%#p pvUser=%#p rcReq=%d\n",
LogFlow((
"drvvdAsyncIOOpen: Successfully opened '%s'; fOpen=%#x pStorage=%p\n",
#
endif /* VBOX_WITH_PDM_ASYNC_COMPLETION *//******************************************************************************* * VD Thread Synchronization interface implementation * *******************************************************************************/ /******************************************************************************* * VD Configuration interface implementation * *******************************************************************************/ /******************************************************************************* * VD Crypto interface implementation for the encryption support * *******************************************************************************/ /******************************************************************************* * VD TCP network stack interface implementation - INIP case * *******************************************************************************/ * vvl: this structure duplicate meaning of sockaddr, * perhaps it'd be better to get rid of it. /** @copydoc VDINTERFACETCPNET::pfnSocketCreate */ * The extended select method is not supported because it is impossible to wakeup /** @copydoc VDINTERFACETCPNET::pfnSocketCreate */ /** @copydoc VDINTERFACETCPNET::pfnClientConnect */ /* Check whether lwIP is set up in this VM instance. */ /* Resolve hostname. As there is no standard resolver for lwIP yet, * just accept numeric IP addresses for now. */ else /* concatination with if */ /* Create socket and connect. */ /** @copydoc VDINTERFACETCPNET::pfnClientClose */ /** @copydoc VDINTERFACETCPNET::pfnIsClientConnected */ /** @copydoc VDINTERFACETCPNET::pfnSelectOne */ /** @copydoc VDINTERFACETCPNET::pfnRead */ * If pcbRead is NULL we have to fill the entire buffer! /** @todo this clipping here is just in case (the send function * needed it, so I added it here, too). Didn't investigate if this * really has issues. Better be safe than sorry. */ if (
cbBytesRead == 0 &&
errno)
/** @todo r=bird: lwip_recv will not touch errno on Windows. This may apply to other hosts as well */ /* return partial data */ /** @copydoc VDINTERFACETCPNET::pfnWrite */ /** @todo lwip send only supports up to 65535 bytes in a single * send (stupid limitation buried in the code), so make sure we * don't get any wraparounds. This should be moved to DevINIP * stack interface once that's implemented. */ /** @copydoc VDINTERFACETCPNET::pfnSgWrite */ /* This is an extremely crude emulation, however it's good enough * for our iSCSI code. INIP has no sendmsg(). */ /** @copydoc VDINTERFACETCPNET::pfnFlush */ /** @copydoc VDINTERFACETCPNET::pfnSetSendCoalescing */ /** @copydoc VDINTERFACETCPNET::pfnGetLocalAddress */ /** @copydoc VDINTERFACETCPNET::pfnGetPeerAddress */ /** @copydoc VDINTERFACETCPNET::pfnSelectOneEx */ /** @copydoc VDINTERFACETCPNET::pfnPoke */ #
endif /* VBOX_WITH_INIP *//******************************************************************************* * VD TCP network stack interface implementation - Host TCP case * *******************************************************************************/ /** IPRT socket handle. */ /** Pollset with the wakeup pipe and socket. */ /** Pipe endpoint - read (in the pollset). */ /** Pipe endpoint - write. */ /** Flag whether the thread was woken up. */ /** Flag whether the thread is waiting in the select call. */ /** Pollset id of the socket. */ /** Pollset id of the pipe. */ /** @copydoc VDINTERFACETCPNET::pfnSocketCreate */ /* Init pipe and pollset. */ /** @copydoc VDINTERFACETCPNET::pfnSocketDestroy */ /* Destroy the pipe and pollset if necessary. */ /** @copydoc VDINTERFACETCPNET::pfnClientConnect */ /* Add to the pollset if required. */ /** @copydoc VDINTERFACETCPNET::pfnClientClose */ /** @copydoc VDINTERFACETCPNET::pfnIsClientConnected */ /** @copydoc VDINTERFACETCPNET::pfnSelectOne */ /** @copydoc VDINTERFACETCPNET::pfnRead */ /** @copydoc VDINTERFACETCPNET::pfnWrite */ /** @copydoc VDINTERFACETCPNET::pfnSgWrite */ /** @copydoc VDINTERFACETCPNET::pfnReadNB */ /** @copydoc VDINTERFACETCPNET::pfnWriteNB */ /** @copydoc VDINTERFACETCPNET::pfnSgWriteNB */ /** @copydoc VDINTERFACETCPNET::pfnFlush */ /** @copydoc VDINTERFACETCPNET::pfnSetSendCoalescing */ /** @copydoc VDINTERFACETCPNET::pfnGetLocalAddress */ /** @copydoc VDINTERFACETCPNET::pfnGetPeerAddress */ /* We got interrupted, drain the pipe. */ /** @copydoc VDINTERFACETCPNET::pfnSelectOneEx */ * Only the pipe is configured or the caller doesn't wait for a socket event, * wait until there is something to read from the pipe. /* Make sure the socket is not in the pollset. */ /* We got interrupted, drain the pipe. */ else /* The caller waits for a socket event. */ /* Loop until we got woken up or a socket event occurred. */ /** @todo find an adaptive wait algorithm based on the * number of wakeups in the past. */ /* Check if there is an event pending. */ /** @copydoc VDINTERFACETCPNET::pfnPoke */ * Checks the prerequisites for encrypted I/O. * @returns VBox status code. * @param pThis The VD driver instance data. N_(
"VD: The DEK for this disk is missing"));
/******************************************************************************* * Media interface methods * *******************************************************************************/ /** @copydoc PDMIMEDIA::pfnRead */ /* Can we serve the request from the buffer? */ /* Increase request to the buffer size and read. */ /** @copydoc PDMIMEDIA::pfnRead */ /* Can we serve the request from the buffer? */ /* Increase request to the buffer size and read. */ /** @copydoc PDMIMEDIA::pfnWrite */ /* Invalidate any buffer if boot acceleration is enabled. */ /** @copydoc PDMIMEDIA::pfnFlush */ /** @copydoc PDMIMEDIA::pfnMerge */ /* Note: There is an unavoidable race between destruction and another * thread invoking this function. This is handled safely and gracefully by * atomically invalidating the lock handle in drvvdDestruct. */ /* Take shortcut: PFNSIMPLEPROGRESS is exactly the same type as * PFNVDPROGRESS, so there's no need for a conversion function. */ /** @todo maybe introduce a conversion which limits update frequency. */ /** @copydoc PDMIMEDIA::pfnSetKey */ /* Unload the crypto filter first to make sure it doesn't access the keys anymore. */ /* Load the crypt filter plugin. */ /** @copydoc PDMIMEDIA::pfnGetSize */ /** @copydoc PDMIMEDIA::pfnGetSectorSize */ /** @copydoc PDMIMEDIA::pfnIsReadOnly */ /** @copydoc PDMIMEDIA::pfnBiosGetPCHSGeometry */ LogFunc((
"geometry not available.\n"));
/** @copydoc PDMIMEDIA::pfnBiosSetPCHSGeometry */ /** @copydoc PDMIMEDIA::pfnBiosGetLCHSGeometry */ LogFunc((
"geometry not available.\n"));
/** @copydoc PDMIMEDIA::pfnBiosSetLCHSGeometry */ /** @copydoc PDMIMEDIA::pfnGetUuid */ /** @copydoc PDMIMEDIA::pfnIoBufAlloc */ /* Configured encryption requires locked down memory. */ /** @copydoc PDMIMEDIA::pfnIoBufFree */ /******************************************************************************* * Async Media interface methods * *******************************************************************************/ LogFlowFunc((
"uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d pvUser=%#p\n",
LogFlowFunc((
"uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d pvUser=%#p\n",
/** @copydoc FNPDMBLKCACHEXFERCOMPLETEDRV */ /** @copydoc FNPDMBLKCACHEXFERENQUEUEDRV */ /** @copydoc FNPDMBLKCACHEXFERENQUEUEDISCARDDRV */ * Loads all configured plugins. * @returns VBox status code. * @param pThis The disk instance. * @param pCfg CFGM node holding plugin list. * Sets up the disk filter chain. * @returns VBox status code. * @param pThis The disk instance. * @param pCfg CFGM node holding the filter parameters. /******************************************************************************* * Base interface methods * *******************************************************************************/ * @interface_method_impl{PDMIBASE,pfnQueryInterface} /******************************************************************************* * Saved state notification methods * *******************************************************************************/ * Load done callback for re-opening the image writable during teleportation. * This is called both for successful and failed load runs, we only care about * @returns VBox status code. * @param pDrvIns The driver instance. * @param pSSM The saved state handle. /* Drop out if we don't have any work to do or if it's a failed load. */ if (
RT_FAILURE(
rc))
/** @todo does the bugger set any errors? */ N_(
"Failed to write lock the images"));
/******************************************************************************* *******************************************************************************/ * VM resume notification that we use to undo what the temporary read-only image * mode set by drvvdSuspend. * Also switch to runtime error mode if we're resuming after a state load * without having been powered on first. * @param pDrvIns The driver instance data. * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere, * we're making assumptions about Main behavior here! * The VM is being suspended, temporarily change to read-only image mode. * This is important for several reasons: * -# It makes sure that there are no pending writes to the image. Most * backends implements this by closing and reopening the image in read-only * -# It allows Main to read the images during snapshotting without having * to account for concurrent writes. * -# This is essential for making teleportation targets sharing images work * right. Both with regards to caching and with regards to file sharing * locks (RTFILE_O_DENY_*). (See also drvvdLoadDone.) * @param pDrvIns The driver instance data. * VM PowerOn notification for undoing the TempReadOnly config option and * changing to runtime error mode. * @param pDrvIns The driver instance data. * @todo The VMSetError vs VMSetRuntimeError mess must be fixed elsewhere, * we're making assumptions about Main behavior here! * @copydoc FNPDMDRVDESTRUCT /* Request the semaphore to wait until a potentially running merge * operation has been finished. */ * Construct a VBox disk media driver instance. * @copydoc FNPDMDRVCONSTRUCT char *
pszName =
NULL;
/**< The path of the disk image file. */ char *
pszFormat =
NULL;
/**< The format backed to use for this image. */ bool fReadOnly;
/**< True if the media is read-only. */ bool fMaybeReadOnly;
/**< True if the media may or may not be read-only. */ /* Initialize supported VD interfaces. */ /* List of images is empty now. */ N_(
"No media port interface above"));
/* Try to attach async media port interface above.*/ /* Before we access any VD API load all given plugins. */ * Validate configuration and find all parent images. * It's sort of up side down from the image dependency tree. /* Toplevel configuration additionally contains the global image * open flags. Some might be converted to per-image flags later. */ "ReadOnly\0MaybeReadOnly\0TempReadOnly\0Shareable\0HonorZeroWrites\0" "HostIPStack\0UseNewIo\0BootAcceleration\0BootAccelerationBuffer\0" "SetupMerge\0MergeSource\0MergeTarget\0BwGroup\0Type\0BlockCache\0" "CachePath\0CacheFormat\0Discard\0InformAboutZeroBlocks\0" "SkipConsistencyChecks\0");
/* All other image configurations only contain image name and * the format information. */ "MergeSource\0MergeTarget\0");
N_(
"DrvVD: Configuration error: Querying \"HostIPStack\" as boolean failed"));
N_(
"DrvVD: Configuration error: Querying \"HonorZeroWrites\" as boolean failed"));
N_(
"DrvVD: Configuration error: Querying \"ReadOnly\" as boolean failed"));
N_(
"DrvVD: Configuration error: Querying \"MaybeReadOnly\" as boolean failed"));
N_(
"DrvVD: Configuration error: Querying \"TempReadOnly\" as boolean failed"));
N_(
"DrvVD: Configuration error: Both \"ReadOnly\" and \"TempReadOnly\" are set"));
N_(
"DrvVD: Configuration error: Querying \"Shareable\" as boolean failed"));
N_(
"DrvVD: Configuration error: Querying \"UseNewIo\" as boolean failed"));
N_(
"DrvVD: Configuration error: Querying \"SetupMerge\" as boolean failed"));
N_(
"DrvVD: Configuration error: Both \"ReadOnly\" and \"MergePending\" are set"));
N_(
"DrvVD: Configuration error: Querying \"BootAcceleration\" as boolean failed"));
N_(
"DrvVD: Configuration error: Querying \"BootAccelerationBuffer\" as integer failed"));
N_(
"DrvVD: Configuration error: Querying \"BlockCache\" as boolean failed"));
N_(
"DrvVD: Configuration error: Querying \"BwGroup\" as string failed"));
N_(
"DrvVD: Configuration error: Querying \"Discard\" as boolean failed"));
N_(
"DrvVD: Configuration error: Both \"ReadOnly\" and \"Discard\" are set"));
N_(
"DrvVD: Configuration error: Querying \"InformAboutZeroBlocks\" as boolean failed"));
N_(
"DrvVD: Configuration error: Querying \"SKipConsistencyChecks\" as boolean failed"));
N_(
"Unknown type \"%s\""),
psz);
N_(
"DrvVD: Configuration error: Querying \"CachePath\" as string failed"));
N_(
"DrvVD: Configuration error: Querying \"CacheFormat\" as string failed"));
* Create the image container and the necessary interfaces. * The image has a bandwidth group but the host cache is enabled. * Use the async I/O framework but tell it to enable the host cache. /** @todo quick hack to work around problems in the async I/O * implementation (rw semaphore thread ownership problem) * while a merge is running. Remove once this is fixed. */ N_(
"DrvVD: Failed to create semaphores for \"MergePending\""));
/* Error message is already set correctly. */ /* Allocate per-image data. */ * Read the image configuration. N_(
"DrvVD: Configuration error: Querying \"Path\" as string failed"));
N_(
"DrvVD: Configuration error: Querying \"Format\" as string failed"));
N_(
"DrvVD: Configuration error: Querying \"MergeSource\" as boolean failed"));
N_(
"DrvVD: Configuration error: Multiple \"MergeSource\" occurrences"));
N_(
"DrvVD: Configuration error: Querying \"MergeTarget\" as boolean failed"));
N_(
"DrvVD: Configuration error: Multiple \"MergeTarget\" occurrences"));
/* Check VDConfig for encryption config. */ /* Setup VDConfig interface for disk encryption support. */ /* Unconditionally insert the TCPNET interface, don't bother to check * if an image really needs it. Will be ignored. Since the TCPNET * interface is per image we could make this more flexible in the * future if we want to. */ /* Construct TCPNET callback table depending on the config. This is * done unconditionally, as uninterested backends will ignore it. */ * There is a 15ms delay between receiving the data and marking the socket * as readable on Windows XP which hurts async I/O performance of * TCP backends badly. Provide a different select method without * This is only used on XP because it is not as efficient as the one using poll * and all other Windows versions are working fine. LogRel((
"VD: Detected Windows XP, disabled poll based waiting for TCP\n"));
RT_SRC_POS,
N_(
"DrvVD: Configuration error: TCP over Internal Networking not compiled in"));
#
else /* VBOX_WITH_INIP */#
endif /* VBOX_WITH_INIP */ /* Insert the custom I/O interface only if we're told to use new IO. * Since the I/O interface is per image we could make this more * flexible in the future if we want to. */ #
else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */ RT_SRC_POS,
N_(
"DrvVD: Configuration error: Async Completion Framework not compiled in"));
#
endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */ /* Try to open backend in async I/O mode first. */ LogFunc((
"%d - Opened '%s' in %s mode\n",
N_(
"Failed to open image '%s' for writing due to wrong permissions"),
N_(
"Failed to open image '%s' in %s mode rc=%Rrc"),
pszName,
/* Open the cache image if set. */ /* Insert the custom I/O interface only if we're told to use new IO. * Since the I/O interface is per image we could make this more * flexible in the future if we want to. */ #
else /* !VBOX_WITH_PDM_ASYNC_COMPLETION */ RT_SRC_POS,
N_(
"DrvVD: Configuration error: Async Completion Framework not compiled in"));
#
endif /* !VBOX_WITH_PDM_ASYNC_COMPLETION */ N_(
"DrvVD: Configuration error: Inconsistent image merge data"));
/* Create the block cache if enabled. */ && !
pThis->
pCfgCrypto /* Disk encryption disables the block cache for security reasons */ * We need a unique ID for the block cache (to identify the owner of data * blocks in a saved state). UUIDs are not really suitable because * there are image formats which don't support them. Furthermore it is * possible that a new diff image was attached after a saved state * which changes the UUID. * However the device "name + device instance + LUN" triple the disk is * attached to is always constant for saved states. N_(
"DrvVD: Configuration error: Could not query device data"));
LogRel((
"VD: Block cache is not supported\n"));
N_(
"DrvVD: Out of memory when creating block cache"));
* Register a load-done callback so we can undo TempReadOnly config before * we get to drvvdResume. Autoamtically deregistered upon destruction. NULL /*pfnLivePrep*/,
NULL /*pfnLiveExec*/,
NULL /*pfnLiveVote*/,
NULL /*pfnSavePrep*/,
NULL /*pfnSaveExec*/,
NULL /*pfnSaveDone*/,
/* Setup the boot acceleration stuff if enabled. */ LogRel((
"VD: Boot acceleration enabled\n"));
LogRel((
"VD: Boot acceleration, out of memory, disabled\n"));
/* drvvdDestruct does the rest. */ * VBox disk container media driver registration record. "Generic VBox disk media driver.",