VD.cpp revision d71e5eeb2842985b3282968b8b9dda165b974801
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VBoxHDD - VBox HDD Container implementation.
c97989161fbe75bc14cea477a5443bbf474dd3advboxsync * Copyright (C) 2006-2014 Oracle Corporation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * available from http://www.virtualbox.org. This file is free software;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Header Files *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Disable dynamic backends on non x86 architectures. This feature
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * requires the SUPR3 library which is not available there.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#if !defined(VBOX_HDD_NO_DYNAMIC_BACKENDS) && !defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Buffer size used for merging images. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Maximum number of segments in one I/O task. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Threshold after not recently used blocks are removed from the list. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define VD_DISCARD_REMOVE_THRESHOLD (10 * _1M) /** @todo: experiment */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VD async I/O interface storage descriptor.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** File handle. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Completion callback. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Thread for async access. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Structure containing everything I/O related
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * for the image and cache descriptors.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct VDIO
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** I/O interface to the upper layer. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Per image internal I/O interface. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Fallback I/O interface, only used if the caller doesn't provide it. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Opaque backend data. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Disk this image is part of */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Flag whether to ignore flush requests. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Forward declaration of an I/O task */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VBox HDD Container image descriptor.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct VDIMAGE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Link to parent image descriptor, if any. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Link to child image descriptor, if any. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Container base filename. (UTF-8) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Data managed by the backend which keeps the actual info. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Cached sanitized image flags. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Image open flags (only those handled generically in this code and which
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the backends will never ever see). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Function pointers for the various backend methods. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to list of VD interfaces, per-image. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** I/O related things. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * uModified bit flags.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define VD_IMAGE_MODIFIED_DISABLE_UUID_UPDATE RT_BIT(2)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VBox HDD Cache image descriptor.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct VDCACHE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Cache base filename. (UTF-8) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Data managed by the backend which keeps the actual info. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Cached sanitized image flags. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Image open flags (only those handled generically in this code and which
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the backends will never ever see). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Function pointers for the various backend methods. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to list of VD interfaces, per-cache. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** I/O related things. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * A block waiting for a discard.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** AVL core. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** LRU list node. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of bytes to discard. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Bitmap of allocated sectors. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VD discard state.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of bytes waiting for a discard. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** AVL tree with blocks waiting for a discard.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The uOffset + cbDiscard range is the search key. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** LRU list of the least frequently discarded blocks.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If there are to many blocks waiting the least frequently used
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * will be removed and the range will be set to 0.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VD filter instance.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct VDFILTER
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the previous filter. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the next filter. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Opaque VD filter backend instance data. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the filter backend interface. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to list of VD interfaces, per-filter. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** I/O related things. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a VD filter instance. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VBox HDD Container main structure, private part.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Structure signature (VBOXHDDDISK_SIGNATURE). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Image type. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of opened images. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Base image. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Last opened image in the chain.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The same as pBase if only one image is used. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** If a merge to one of the parents is running this may be non-NULL
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * to indicate to what image the writes should be additionally relayed. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Flags representing the modification state. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Cached size of this disk. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Cached PCHS geometry for this disk. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Cached LCHS geometry for this disk. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to list of VD interfaces, per-disk. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the common interface structure for error reporting. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the optional thread synchronization callbacks. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Memory cache for I/O contexts */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Memory cache for I/O tasks. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** An I/O context is currently using the disk structures
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Every I/O context must be placed on one of the lists below. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync volatile bool fLocked;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Head of pending I/O tasks waiting for completion - LIFO order. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Head of newly queued I/O contexts - LIFO order. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Head of halted I/O contexts which are given back to generic
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * disk framework by the backend. - LIFO order. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Head of blocked I/O contexts, processed only
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * after pIoCtxLockOwner was freed - LIFO order. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** I/O context which locked the disk for a growing write or flush request.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Other flush or growing write requests need to wait until
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the current one completes. - NIL_VDIOCTX if unlocked. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** If the disk was locked by a growing write, flush or discard request this
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * contains the start offset to check for interfering I/O while it is in progress. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** If the disk was locked by a growing write, flush or discard request this contains
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the first non affected offset to check for interfering I/O while it is in progress. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the L2 disk cache if any. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the discard state if any. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the first filter in the chain. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the last filter in the chain. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ("Lock not held\n"));\
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VBox parent read descriptor, used internally for compaction.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to disk descriptor. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to image descriptor. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Transfer direction.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Read */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Write */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Flush */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Discard */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** 32bit hack */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Transfer function */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef DECLCALLBACK(int) FNVDIOCTXTRANSFER (PVDIOCTX pIoCtx);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a transfer function. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * I/O context
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct VDIOCTX
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the next I/O context. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Disk this is request is for. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Return code. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Various flags for the I/O context. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of data transfers currently pending. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** How many meta data transfers are pending. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Flag whether the request finished */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync volatile bool fComplete;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Temporary allocated memory which is freed
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * when the context completes. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Transfer function. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Next transfer part after the current one completed. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Transfer direction */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Request type dependent data. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** I/O request (read/write). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of bytes left until this context completes. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Current offset */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of bytes to transfer */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Current image in the chain. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Start image to read from. pImageCur is reset to this
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * value after it reached the first image in the chain. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** S/G buffer */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of bytes to clear in the buffer before the current read. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of images to read. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Override for the parent image to start reading from. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Original offset of the transfer - required for filtering read requests. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Original size of the transfer - required for fitlering read requests. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Discard requests. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the range descriptor array. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of ranges in the array. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Range descriptor index which is processed. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Start offset to discard currently. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** How many bytes left to discard in the current range. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** How many bytes to discard in the current block (<= cbDiscardLeft). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Discard block handled currently. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Parent I/O context if any. Sets the type of the context (root/child) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Type dependent data (root/child) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Root data */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Completion callback */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** User argument 1 passed on completion. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** User argument 2 passed on completion. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Child data */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Saved start offset */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Saved transfer size */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of bytes transferred from the parent if this context completes. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of bytes to pre read */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of bytes to post read. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of bytes to write left in the parent. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Write type dependent data. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Optimized */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Bytes to fill to satisfy the block size. Not part of the virtual disk. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Bytes to copy instead of reading from the parent */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Bytes to read from the image. */
344f8996b5cf3f8bbc2c361f9d526eb5b1350916vboxsync/** Default flags for an I/O context, i.e. unblocked and async. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Flag whether the context is blocked. */
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync/** Flag whether the I/O context is using synchronous I/O. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Flag whether the read should update the cache. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define VDIOCTX_FLAGS_READ_UPDATE_CACHE RT_BIT_32(2)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Flag whether free blocks should be zeroed.
344f8996b5cf3f8bbc2c361f9d526eb5b1350916vboxsync * If false and no image has data for sepcified
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * range VERR_VD_BLOCK_FREE is returned for the I/O context.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Note that unallocated blocks are still zeroed
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * if at least one image has valid data for a part
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * of the range.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Don't free the I/O context when complete because
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * it was alloacted elsewhere (stack, ...). */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Don't set the modified flag for this I/O context when writing. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define VDIOCTX_FLAGS_DONT_SET_MODIFIED_FLAG RT_BIT_32(5)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** The write filter was applied already and shouldn't be applied a second time.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Used at the beginning of vdWriteHelperAsync() because it might be called
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * multiple times.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define VDIOCTX_FLAGS_WRITE_FILTER_APPLIED RT_BIT_32(6)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** NIL I/O context pointer value. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * List node for deferred I/O contexts.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Node in the list of deferred requests.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * A request can be deferred if the image is growing
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * and the request accesses the same range or if
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the backend needs to read or write metadata from the disk
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * before it can continue. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** I/O context this entry points to. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * I/O task.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct VDIOTASK
a44cdd0b29504e3de7b8aa87f839ad62b6e66f51vboxsync /** Next I/O task waiting in the list. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Storage this task belongs to. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Optional completion callback. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Opaque user data. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Completion status code for the task. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Flag whether this is a meta data transfer. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Type dependent data. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** User data transfer. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of bytes this task transferred. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the I/O context the task belongs. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Meta data transfer. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Meta transfer this task is for. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Storage handle.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct VDIOSTORAGE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Image I/O state this storage handle belongs to. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** AVL tree for pending async metadata transfers. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Storage handle */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Metadata transfer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @note This entry can't be freed if either the list is not empty or
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the reference counter is not 0.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The assumption is that the backends don't need to read huge amounts of
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * metadata to complete a transfer so the additional memory overhead should
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * be relatively small.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct VDMETAXFER
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** AVL core for fast search (the file offset is the key) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** I/O storage for this transfer. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Flags. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** List of I/O contexts waiting for this metadata transfer to complete. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Number of references to this entry. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Size of the data stored with this entry. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Shadow buffer which is used in case a write is still active and other
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * writes update the shadow buffer. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** List of I/O contexts updating the shadow buffer while there is a write
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * in progress. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Data stored - variable size. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The transfer direction for the metadata.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define VDMETAXFER_TXDIR_GET(flags) ((flags) & VDMETAXFER_TXDIR_MASK)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#define VDMETAXFER_TXDIR_SET(flags, dir) ((flags) = (flags & ~VDMETAXFER_TXDIR_MASK) | (dir))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Plugin structure.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct VDPLUGIN
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Pointer to the next plugin structure. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Handle of loaded plugin library. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** Filename of the loaded plugin. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to a plugin structure. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Head of loaded plugin list. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Number of image backends supported. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic unsigned g_cBackends = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Array of pointers to the image backends. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Array of handles to the corresponding plugin. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Builtin image backends. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Number of supported cache backends. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic unsigned g_cCacheBackends = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Array of pointers to the cache backends. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Array of handles to the corresponding plugin. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Builtin cache backends. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Number of supported filter backends. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic unsigned g_cFilterBackends = 0;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Array of pointers to the filters backends. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic PCVDFILTERBACKEND *g_apFilterBackends = NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Array of handles to the corresponding plugin. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Forward declaration of the async discard helper. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void vdDiskProcessBlockedIoCtx(PVBOXHDD pDisk);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdDiskUnlock(PVBOXHDD pDisk, PVDIOCTX pIoCtxRc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic DECLCALLBACK(void) vdIoCtxSyncComplete(void *pvUser1, void *pvUser2, int rcReq);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: add several backends.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdAddBackends(RTLDRMOD hPlugin, PCVBOXHDDBACKEND *ppBackends, unsigned cBackends)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCVBOXHDDBACKEND *pTmp = (PCVBOXHDDBACKEND*)RTMemRealloc(g_apBackends,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (g_cBackends + cBackends) * sizeof(PCVBOXHDDBACKEND));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTLDRMOD *pTmpPlugins = (RTLDRMOD*)RTMemRealloc(g_ahBackendPlugins,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memcpy(&g_apBackends[g_cBackends], ppBackends, cBackends * sizeof(PCVBOXHDDBACKEND));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (unsigned i = g_cBackends; i < g_cBackends + cBackends; i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: add single backend.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(int) vdAddBackend(RTLDRMOD hPlugin, PCVBOXHDDBACKEND pBackend)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: add several cache backends.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdAddCacheBackends(RTLDRMOD hPlugin, PCVDCACHEBACKEND *ppBackends, unsigned cBackends)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCVDCACHEBACKEND *pTmp = (PCVDCACHEBACKEND*)RTMemRealloc(g_apCacheBackends,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (g_cCacheBackends + cBackends) * sizeof(PCVDCACHEBACKEND));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTLDRMOD *pTmpPlugins = (RTLDRMOD*)RTMemRealloc(g_ahCacheBackendPlugins,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (g_cCacheBackends + cBackends) * sizeof(RTLDRMOD));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memcpy(&g_apCacheBackends[g_cCacheBackends], ppBackends, cBackends * sizeof(PCVDCACHEBACKEND));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (unsigned i = g_cCacheBackends; i < g_cCacheBackends + cBackends; i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: add single cache backend.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(int) vdAddCacheBackend(RTLDRMOD hPlugin, PCVDCACHEBACKEND pBackend)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Add several filter backends.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param hPlugin Plugin handle to add.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param ppBackends Array of filter backends to add.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cBackends Number of backends to add.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdAddFilterBackends(RTLDRMOD hPlugin, PCVDFILTERBACKEND *ppBackends, unsigned cBackends)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PCVDFILTERBACKEND *pTmp = (PCVDFILTERBACKEND *)RTMemRealloc(g_apFilterBackends,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (g_cFilterBackends + cBackends) * sizeof(PCVDFILTERBACKEND));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTLDRMOD *pTmpPlugins = (RTLDRMOD*)RTMemRealloc(g_ahFilterBackendPlugins,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (g_cFilterBackends + cBackends) * sizeof(RTLDRMOD));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memcpy(&g_apFilterBackends[g_cFilterBackends], ppBackends, cBackends * sizeof(PCVDFILTERBACKEND));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (unsigned i = g_cFilterBackends; i < g_cFilterBackends + cBackends; i++)
571525c203930230b3ae9badba7c2d2d12f21d05vboxsync * Add a single filter backend to the list of supported filters.
a44cdd0b29504e3de7b8aa87f839ad62b6e66f51vboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param hPlugin Plugin handle to add.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pBackend The backend to add.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(int) vdAddFilterBackend(RTLDRMOD hPlugin, PCVDFILTERBACKEND pBackend)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: issue error message.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdError(PVBOXHDD pDisk, int rc, RT_SRC_POS_DECL,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync const char *pszFormat, ...)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pDisk->pInterfaceError->pfnError(pDisk->pInterfaceError->Core.pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: thread synchronization, start read.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pDisk->pInterfaceThreadSync->pfnStartRead(pDisk->pInterfaceThreadSync->Core.pvUser);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: thread synchronization, finish read.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pDisk->pInterfaceThreadSync->pfnFinishRead(pDisk->pInterfaceThreadSync->Core.pvUser);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: thread synchronization, start write.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pDisk->pInterfaceThreadSync->pfnStartWrite(pDisk->pInterfaceThreadSync->Core.pvUser);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: thread synchronization, finish write.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pDisk->pInterfaceThreadSync->pfnFinishWrite(pDisk->pInterfaceThreadSync->Core.pvUser);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: find image format backend.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdFindBackend(const char *pszBackend, PCVBOXHDDBACKEND *ppBackend)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (unsigned i = 0; i < g_cBackends; i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!RTStrICmp(pszBackend, g_apBackends[i]->pszBackendName))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: find cache format backend.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdFindCacheBackend(const char *pszBackend, PCVDCACHEBACKEND *ppBackend)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (unsigned i = 0; i < g_cCacheBackends; i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!RTStrICmp(pszBackend, g_apCacheBackends[i]->pszBackendName))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: find filter backend.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdFindFilterBackend(const char *pszFilter, PCVDFILTERBACKEND *ppBackend)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync for (unsigned i = 0; i < g_cFilterBackends; i++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!RTStrICmp(pszFilter, g_apFilterBackends[i]->pszBackendName))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: add image structure to the end of images list.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void vdAddImageToList(PVBOXHDD pDisk, PVDIMAGE pImage)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: remove image structure from the images list.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void vdRemoveImageFromList(PVBOXHDD pDisk, PVDIMAGE pImage)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: add filter structure to the end of filter list.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void vdAddFilterToList(PVBOXHDD pDisk, PVDFILTER pFilter)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: Remove last filter structure from the filter list.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void vdRemoveFilterFromList(PVBOXHDD pDisk, PVDFILTER pFilter)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pDisk->pFilterHead != NULL && pDisk->pFilterTail != NULL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * internal: find image by index into the images list.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic PVDIMAGE vdGetImageByNumber(PVBOXHDD pDisk, unsigned nImage)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Applies the filter chain to the given write request.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pDisk The HDD container.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param uOffset The start offset of the write.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cbWrite Number of bytes to write.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pIoCtx The I/O context associated with the request.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdFilterChainApplyWrite(PVBOXHDD pDisk, uint64_t uOffset, size_t cbWrite,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pFilterCurr->pBackend->pfnFilterWrite(pFilterCurr->pvBackendData, uOffset, cbWrite, pIoCtx);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Reset S/G buffer for the next filter. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Applies the filter chain to the given read request.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pDisk The HDD container.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param uOffset The start offset of the read.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cbRead Number of bytes read.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pIoCtx The I/O context associated with the request.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdFilterChainApplyRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Reset buffer before starting. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pFilterCurr->pBackend->pfnFilterRead(pFilterCurr->pvBackendData, uOffset, cbRead, pIoCtx);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Reset S/G buffer for the next filter. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(void) vdIoCtxRootComplete(PVBOXHDD pDisk, PVDIOCTX pIoCtx)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoCtx->rcReq = vdFilterChainApplyRead(pDisk, pIoCtx->Req.Io.uOffsetXferOrig,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoCtx->Type.Root.pfnComplete(pIoCtx->Type.Root.pvUser1,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Initialize the structure members of a given I/O context.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(void) vdIoCtxInit(PVDIOCTX pIoCtx, PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t uOffset, size_t cbTransfer, PVDIMAGE pImageStart,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PFNVDIOCTXTRANSFER pfnIoCtxTransfer, uint32_t fFlags)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoCtx->Req.Io.cbTransferLeft = (uint32_t)cbTransfer; Assert((uint32_t)cbTransfer == cbTransfer);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* There is no S/G list for a flush request. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Internal: Tries to read the desired range from the given cache.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @retval VERR_VD_BLOCK_FREE if the block is not in the cache.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * pcbRead will be set to the number of bytes not in the cache.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Everything thereafter might be in the cache.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCache The cache to read from.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param uOffset Offset of the virtual disk to read.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cbRead How much to read.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pIoCtx The I/O context to read into.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pcbRead Where to store the number of bytes actually read.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * On success this indicates the number of bytes read from the cache.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If VERR_VD_BLOCK_FREE is returned this gives the number of bytes
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * which are not in the cache.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * In both cases everything beyond this value
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * might or might not be in the cache.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdCacheReadHelper(PVDCACHE pCache, uint64_t uOffset,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowFunc(("pCache=%#p uOffset=%llu pIoCtx=%p cbRead=%zu pcbRead=%#p\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pCache->Backend->pfnRead(pCache->pBackendData, uOffset, cbRead,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowFunc(("returns rc=%Rrc pcbRead=%zu\n", rc, *pcbRead));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Internal: Writes data for the given block into the cache.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pCache The cache to write to.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param uOffset Offset of the virtual disk to write to the cache.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cbWrite How much to write.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pIoCtx The I/O context to ẃrite from.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pcbWritten How much data could be written, optional.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdCacheWriteHelper(PVDCACHE pCache, uint64_t uOffset, size_t cbWrite,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowFunc(("pCache=%#p uOffset=%llu pIoCtx=%p cbWrite=%zu pcbWritten=%#p\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pCache->Backend->pfnWrite(pCache->pBackendData, uOffset, cbWrite,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pCache->Backend->pfnWrite(pCache->pBackendData, uOffset, cbWrite,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Creates a new empty discard state.
389b9f89a42b9efcb0d843a6a45c54418dd02e11vboxsync * @returns Pointer to the new discard state or NULL if out of memory.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVDDISCARDSTATE pDiscard = (PVDDISCARDSTATE)RTMemAllocZ(sizeof(VDDISCARDSTATE));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pDiscard->pTreeBlocks = (PAVLRU64TREE)RTMemAllocZ(sizeof(AVLRU64TREE));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Removes the least recently used blocks from the waiting list until
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the new value is reached.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pDisk VD disk container.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pDiscard The discard state.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cbDiscardingNew How many bytes should be waiting on success.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The number of bytes waiting can be less.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdDiscardRemoveBlocks(PVBOXHDD pDisk, PVDDISCARDSTATE pDiscard, size_t cbDiscardingNew)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowFunc(("pDisk=%#p pDiscard=%#p cbDiscardingNew=%zu\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVDDISCARDBLOCK pBlock = RTListGetLast(&pDiscard->ListLru, VDDISCARDBLOCK, NodeLru);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Go over the allocation bitmap and mark all discarded sectors as unused. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync bool fAllocated = ASMBitTest(pBlock->pbmAllocated, idxStart);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint32_t cSectors = (uint32_t)(pBlock->cbDiscard / 512);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Check for the first unallocated bit. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync idxEnd = ASMBitNextClear(pBlock->pbmAllocated, cSectors, idxStart);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Mark as unused and check for the first set bit. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync idxEnd = ASMBitNextSet(pBlock->pbmAllocated, cSectors, idxStart);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync vdIoCtxInit(&IoCtx, pDisk, VDIOCTXTXDIR_DISCARD, 0, 0, NULL,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = pDisk->pLast->Backend->pfnDiscard(pDisk->pLast->pBackendData,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVDDISCARDBLOCK pBlockRemove = (PVDDISCARDBLOCK)RTAvlrU64RangeRemove(pDiscard->pTreeBlocks, pBlock->Core.Key);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(RT_FAILURE(rc) || pDiscard->cbDiscarding <= cbDiscardingNew);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Destroys the current discard state, writing any waiting blocks to the image.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pDisk VD disk container.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = vdDiscardRemoveBlocks(pDisk, pDisk->pDiscard, 0 /* Remove all blocks. */);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Marks the given range as allocated in the image.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Required if there are discards in progress and a write to a block which can get discarded
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * is written to.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pDisk VD container data.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param uOffset First byte to mark as allocated.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cbRange Number of bytes to mark as allocated.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdDiscardSetRangeAllocated(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRange)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVDDISCARDBLOCK pBlock = (PVDDISCARDBLOCK)RTAvlrU64RangeGet(pDiscard->pTreeBlocks, uOffset);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cbThisRange = RT_MIN(cbThisRange, pBlock->Core.KeyLast - uOffset + 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASMBitSetRange(pBlock->pbmAllocated, idxStart, idxEnd);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pBlock = (PVDDISCARDBLOCK)RTAvlrU64GetBestFit(pDiscard->pTreeBlocks, uOffset, true);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cbThisRange = RT_MIN(cbThisRange, pBlock->Core.Key - uOffset);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync } while (cbRange != 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(PVDIOCTX) vdIoCtxAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync void *pvAllocation, PFNVDIOCTXTRANSFER pfnIoCtxTransfer,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoCtx = (PVDIOCTX)RTMemCacheAlloc(pDisk->hMemCacheIoCtx);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync vdIoCtxInit(pIoCtx, pDisk, enmTxDir, uOffset, cbTransfer, pImageStart,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(PVDIOCTX) vdIoCtxRootAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer, pImageStart,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("Allocated root I/O context %#p\n", pIoCtx));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(void) vdIoCtxDiscardInit(PVDIOCTX pIoCtx, PVBOXHDD pDisk, PCRTRANGE paRanges,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync unsigned cRanges, PFNVDASYNCTRANSFERCOMPLETE pfnComplete,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PFNVDIOCTXTRANSFER pfnIoCtxTransfer, uint32_t fFlags)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(PVDIOCTX) vdIoCtxDiscardAlloc(PVBOXHDD pDisk, PCRTRANGE paRanges,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoCtx = (PVDIOCTX)RTMemCacheAlloc(pDisk->hMemCacheIoCtx);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync vdIoCtxDiscardInit(pIoCtx, pDisk, paRanges, cRanges, pfnComplete, pvUser1,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("Allocated discard I/O context %#p\n", pIoCtx));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(PVDIOCTX) vdIoCtxChildAlloc(PVBOXHDD pDisk, VDIOCTXTXDIR enmTxDir,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVDIOCTX pIoCtx = vdIoCtxAlloc(pDisk, enmTxDir, uOffset, cbTransfer, pImageStart,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pcSgBuf, pvAllocation, pfnIoCtxTransfer, pIoCtxParent->fFlags & ~VDIOCTX_FLAGS_DONT_FREE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoCtx->Type.Child.cbTransferLeftSaved = cbTransfer;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoCtx->Type.Child.cbTransferParent = cbTransferParent;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("Allocated child I/O context %#p\n", pIoCtx));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(PVDIOTASK) vdIoTaskUserAlloc(PVDIOSTORAGE pIoStorage, PFNVDXFERCOMPLETED pfnComplete, void *pvUser, PVDIOCTX pIoCtx, uint32_t cbTransfer)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoTask = (PVDIOTASK)RTMemCacheAlloc(pIoStorage->pVDIo->pDisk->hMemCacheIoTask);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(PVDIOTASK) vdIoTaskMetaAlloc(PVDIOSTORAGE pIoStorage, PFNVDXFERCOMPLETED pfnComplete, void *pvUser, PVDMETAXFER pMetaXfer)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoTask = (PVDIOTASK)RTMemCacheAlloc(pIoStorage->pVDIo->pDisk->hMemCacheIoTask);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(void) vdIoCtxFree(PVBOXHDD pDisk, PVDIOCTX pIoCtx)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(void) vdIoTaskFree(PVBOXHDD pDisk, PVDIOTASK pIoTask)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoCtx->Req.Io.uOffset = pIoCtx->Type.Child.uOffsetSaved;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoCtx->Req.Io.cbTransferLeft = (uint32_t)pIoCtx->Type.Child.cbTransferLeftSaved;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert((uint32_t)pIoCtx->Type.Child.cbTransferLeftSaved == pIoCtx->Type.Child.cbTransferLeftSaved);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(PVDMETAXFER) vdMetaXferAlloc(PVDIOSTORAGE pIoStorage, uint64_t uOffset, size_t cb)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVDMETAXFER pMetaXfer = (PVDMETAXFER)RTMemAlloc(RT_OFFSETOF(VDMETAXFER, abData[cb]));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(void) vdIoCtxAddToWaitingList(volatile PVDIOCTX *ppList, PVDIOCTX pIoCtx)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Put it on the waiting list. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVDIOCTX pNext = ASMAtomicUoReadPtrT(ppList, PVDIOCTX);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while (!ASMAtomicCmpXchgExPtr(ppList, pIoCtx, pNext, &pHeadOld))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncDECLINLINE(void) vdIoCtxDefer(PVBOXHDD pDisk, PVDIOCTX pIoCtx)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowFunc(("Deferring I/O context pIoCtx=%#p\n", pIoCtx));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(!pIoCtx->pIoCtxParent && !(pIoCtx->fFlags & VDIOCTX_FLAGS_BLOCKED));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync vdIoCtxAddToWaitingList(&pDisk->pIoCtxBlockedHead, pIoCtx);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic size_t vdIoCtxCopy(PVDIOCTX pIoCtxDst, PVDIOCTX pIoCtxSrc, size_t cbData)
571525c203930230b3ae9badba7c2d2d12f21d05vboxsync return RTSgBufCopy(&pIoCtxDst->Req.Io.SgBuf, &pIoCtxSrc->Req.Io.SgBuf, cbData);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdIoCtxCmp(PVDIOCTX pIoCtx1, PVDIOCTX pIoCtx2, size_t cbData)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return RTSgBufCmp(&pIoCtx1->Req.Io.SgBuf, &pIoCtx2->Req.Io.SgBuf, cbData);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic size_t vdIoCtxCopyTo(PVDIOCTX pIoCtx, const uint8_t *pbData, size_t cbData)
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync return RTSgBufCopyFromBuf(&pIoCtx->Req.Io.SgBuf, pbData, cbData);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic size_t vdIoCtxCopyFrom(PVDIOCTX pIoCtx, uint8_t *pbData, size_t cbData)
a82df5167acec0c75d741d08c1d05a4007e3d50evboxsync return RTSgBufCopyToBuf(&pIoCtx->Req.Io.SgBuf, pbData, cbData);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic size_t vdIoCtxSet(PVDIOCTX pIoCtx, uint8_t ch, size_t cbData)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return RTSgBufSet(&pIoCtx->Req.Io.SgBuf, ch, cbData);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Process the I/O context, core method which assumes that the I/O context
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * acquired the lock.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pIoCtx I/O context to process.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * We complete the I/O context in case of an error
be2589a6f7086676e45b18d204bb1064889dc586vboxsync * if there is no I/O task pending.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Don't change anything if there is a metadata transfer pending or we are blocked. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Call the transfer function advancing to the next while there is no error. */
a82df5167acec0c75d741d08c1d05a4007e3d50evboxsync LogFlowFunc(("calling transfer function %#p\n", pIoCtx->pfnIoCtxTransfer));
a82df5167acec0c75d741d08c1d05a4007e3d50evboxsync /* Advance to the next part of the transfer if the current one succeeded. */
a82df5167acec0c75d741d08c1d05a4007e3d50evboxsync pIoCtx->pfnIoCtxTransfer = pIoCtx->pfnIoCtxTransferNext;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ASMAtomicCmpXchgS32(&pIoCtx->rcReq, rc, VINF_SUCCESS);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The I/O context completed if we have an error and there is no data
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * or meta data transfer pending.
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync LogFlowFunc(("pIoCtx=%#p rc=%Rrc cDataTransfersPending=%u cMetaTransfersPending=%u fComplete=%RTbool\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pIoCtx, rc, pIoCtx->cDataTransfersPending, pIoCtx->cMetaTransfersPending,
be2589a6f7086676e45b18d204bb1064889dc586vboxsync * Processes the list of waiting I/O contexts.
a82df5167acec0c75d741d08c1d05a4007e3d50evboxsync * @returns VBox status code, only valid if pIoCtxRc is not NULL, treat as void
be2589a6f7086676e45b18d204bb1064889dc586vboxsync * function otherwise.
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync * @param pDisk The disk structure.
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync * @param pIoCtxRc An I/O context handle which waits on the list. When processed
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync * The status code is returned. NULL if there is no I/O context
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync * to return the status code for.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdDiskProcessWaitingIoCtx(PVBOXHDD pDisk, PVDIOCTX pIoCtxRc)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowFunc(("pDisk=%#p pIoCtxRc=%#p\n", pDisk, pIoCtxRc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Get the waiting list and process it in FIFO order. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVDIOCTX pIoCtxHead = ASMAtomicXchgPtrT(&pDisk->pIoCtxHead, NULL, PVDIOCTX);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Reverse it. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Process now. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Need to clear the sync flag here if there is a new I/O context
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * with it set and the context is not given in pIoCtxRc.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This happens most likely on a different thread and that one shouldn't
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync * process the context synchronously.
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync * The thread who issued the context will wait on the event semaphore
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * anyway which is signalled when the completion handler is called.
a82df5167acec0c75d741d08c1d05a4007e3d50evboxsync int rc2 = vdFilterChainApplyRead(pDisk, pTmp->Req.Io.uOffsetXferOrig,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* The given I/O context was processed, pass the return code to the caller. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && ASMAtomicCmpXchgBool(&pTmp->fComplete, true, false))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowFunc(("Waiting I/O context completed pTmp=%#p\n", pTmp));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Processes the list of blocked I/O contexts.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns nothing.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pDisk The disk structure.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic void vdDiskProcessBlockedIoCtx(PVBOXHDD pDisk)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Get the waiting list and process it in FIFO order. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PVDIOCTX pIoCtxHead = ASMAtomicXchgPtrT(&pDisk->pIoCtxBlockedHead, NULL, PVDIOCTX);
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync /* Reverse it. */
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync /* Process now. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && ASMAtomicCmpXchgBool(&pTmp->fComplete, true, false))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowFunc(("Waiting I/O context completed pTmp=%#p\n", pTmp));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Processes the I/O context trying to lock the criticial section.
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync * The context is deferred if the critical section is busy.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns VBox status code.
d8df004f4caf4f71e78f0be1cc2e2a918358ae9fvboxsync * @param pIoCtx The I/O context to process.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int vdIoCtxProcessTryLockDefer(PVDIOCTX pIoCtx)
return rc;
return rc;
return rc;
if (fProcessBlockedReqs)
*pcbThisRead = 0;
&cbThisRead);
&cbThisRead);
return rc;
int rc;
return VERR_VD_ASYNC_IO_IN_PROGRESS;
&& !pImageParentOverride)
&cbThisRead);
else if (cImagesToProcess > 0)
ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, (uint32_t)cbThisRead); Assert(cbThisRead == (uint32_t)cbThisRead);
: rc;
return rc;
return rc;
if (fZeroFreeBlocks)
if (fUpdateCache)
return rc;
&Uuid);
&Uuid);
return rc;
return rc;
fFlags, 0);
int rc2;
bool fLockReadFrom = false;
bool fLockWriteTo = false;
unsigned uProgressOld = 0;
LogFlowFunc(("pDiskFrom=%#p pImageFrom=%#p pDiskTo=%#p cbSize=%llu cImagesFromRead=%u cImagesToRead=%u fSuppressRedundantIo=%RTbool pIfProgress=%#p pDstIfProgress=%#p\n",
pDiskFrom, pImageFrom, pDiskTo, cbSize, cImagesFromRead, cImagesToRead, fSuppressRedundantIo, pDstIfProgress, pDstIfProgress));
if (!pvBuf)
return rc;
fLockReadFrom = true;
if (fBlockwiseCopy)
&cbThisRead);
else if (cImagesToProcess > 0)
fLockReadFrom = false;
fLockWriteTo = true;
fLockWriteTo = false;
if (fLockReadFrom)
if (fLockWriteTo)
return rc;
return rc;
if (pIoCtxFlush)
return rc;
return rc;
return VINF_VD_ASYNC_IO_FINISHED;
if (cbPostRead)
if (cbWriteCopy)
if (cbFill)
return rc;
return rc;
* All backends which support differential/growing images support this - async version.
if (cbPostRead)
return VINF_SUCCESS;
if (cbFill)
return rc;
if (cbPostRead)
if (cbWriteCopy)
if (cbReadImage)
pIoCtx->Req.Io.cbTransferLeft = (uint32_t)cbReadImage; Assert(cbReadImage == (uint32_t)cbReadImage);
if (cbFill)
return rc;
return rc;
if (cbPostRead)
cbWriteCopy = 0;
if (cbPreRead)
return VINF_SUCCESS;
int rc;
unsigned fWrite;
return rc;
return rc;
return rc;
? 0 : VD_WRITE_NO_ALLOC;
fWrite);
PRTSGBUF pTmp = (PRTSGBUF)RTMemAlloc(cbPreRead + cbThisWrite + cbPostRead + sizeof(RTSGSEG) + sizeof(RTSGBUF));
pTmp,
pTmp,
if ( !cbWrite
return rc;
return rc;
PVDDISCARDBLOCK pBlockRemove = (PVDDISCARDBLOCK)RTAvlrU64RangeRemove(pDiscard->pTreeBlocks, pBlock->Core.Key);
return rc;
while (cbLeft > 0)
if (fAllocated)
fAllocated = false;
fAllocated = true;
PVDDISCARDBLOCK pBlockRemove = (PVDDISCARDBLOCK)RTAvlrU64RangeRemove(pDiscard->pTreeBlocks, pBlock->Core.Key);
return rc;
&pbmAllocated, 0);
if (pBlock)
return rc;
return VINF_SUCCESS;
if (!pDiscard)
return VERR_NO_MEMORY;
PVDDISCARDBLOCK pBlock = (PVDDISCARDBLOCK)RTAvlrU64GetBestFit(pDiscard->pTreeBlocks, offStart, false);
PVDDISCARDBLOCK pBlockAbove = (PVDDISCARDBLOCK)RTAvlrU64GetBestFit(pDiscard->pTreeBlocks, offStart, true);
if (pBlockAbove)
if (ASMBitFirstSet((volatile void *)pBlock->pbmAllocated, (uint32_t)(pBlock->cbDiscard / 512)) == -1)
return rc;
#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
return rc;
return rc;
return rc;
if (pPlugin)
return rc;
if (!pIt)
return VINF_SUCCESS;
for (unsigned i = 0; i < g_cBackends; i++)
memcpy(&g_ahBackendPlugins[i], &g_ahBackendPlugins[i + 1], (g_cBackends - i - 1) * sizeof(RTLDRMOD));
g_cBackends--;
for (unsigned i = 0; i < g_cCacheBackends; i++)
memcpy(&g_apCacheBackends[i], &g_apCacheBackends[i + 1], (g_cCacheBackends - i - 1) * sizeof(PCVBOXHDDBACKEND));
memcpy(&g_ahCacheBackendPlugins[i], &g_ahCacheBackendPlugins[i + 1], (g_cCacheBackends - i - 1) * sizeof(RTLDRMOD));
for (unsigned i = 0; i < g_cFilterBackends; i++)
memcpy(&g_apFilterBackends[i], &g_apFilterBackends[i + 1], (g_cFilterBackends - i - 1) * sizeof(PCVBOXHDDBACKEND));
memcpy(&g_ahFilterBackendPlugins[i], &g_ahFilterBackendPlugins[i + 1], (g_cFilterBackends - i - 1) * sizeof(RTLDRMOD));
return VINF_SUCCESS;
#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
return VINF_SUCCESS;
return rc;
return VERR_NOT_IMPLEMENTED;
#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
if (!pszPluginFilter)
return VERR_NO_STR_MEMORY;
goto out;
if (!pPluginDirEntry)
goto out;
while ((rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK)) != VERR_NO_MORE_FILES)
if (!pPluginDirEntry)
rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
if (!pszPluginPath)
out:
if (pPluginDirEntry)
if (pPluginDir)
return rc;
return VERR_NOT_IMPLEMENTED;
static int vdLoadDynamicBackends()
#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
return rc;
return VINF_SUCCESS;
#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
return VERR_NOT_IMPLEMENTED;
#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
if (!pszPluginFilter)
return VERR_NO_STR_MEMORY;
goto out;
if (!pPluginDirEntry)
goto out;
while ((rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK)) != VERR_NO_MORE_FILES)
if (!pPluginDirEntry)
rc = RTDirReadEx(pPluginDir, pPluginDirEntry, &cbPluginDirEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
if (!pszPluginPath)
out:
if (pPluginDirEntry)
if (pPluginDir)
return rc;
return VERR_NOT_IMPLEMENTED;
void **ppStorage)
if (!pStorage)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
static int vdIOGetModificationTimeFallback(void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)
return rc;
void **ppTask)
return VERR_NOT_IMPLEMENTED;
void **ppTask)
return VERR_NOT_IMPLEMENTED;
return VERR_NOT_IMPLEMENTED;
ASMAtomicSubU32(&pIoCtxParent->Req.Io.cbTransferLeft, (uint32_t)pIoCtx->Type.Child.cbTransferParent);
LogFlowFunc(("Parent I/O context completed pIoCtxParent=%#p rcReq=%Rrc\n", pIoCtxParent, pIoCtxParent->rcReq));
return VINF_SUCCESS;
bool fIoCtxContinue = true;
ASMAtomicSubU32(&pIoCtx->Req.Io.cbTransferLeft, (uint32_t)cbTransfer); Assert(cbTransfer == (uint32_t)cbTransfer);
if (pfnComplete)
return rc;
if (pfnComplete)
static int vdMetaXferCompleted(PVDIOSTORAGE pIoStorage, PFNVDXFERCOMPLETED pfnComplete, void *pvUser,
bool fFlush;
if (!fFlush)
/* Increase the reference counter to make sure it doesn't go away before the last context is processed. */
rcReq = pIoStorage->pVDIo->pInterfaceIo->pfnWriteAsync(pIoStorage->pVDIo->pInterfaceIo->Core.pvUser,
&pvTask);
vdIoCtxContinueDeferredList(pIoStorage, &pMetaXfer->ListIoCtxShwWrites, pfnComplete, pvUser, rcReq);
if (!fFlush)
else if (fFlush)
return VINF_SUCCESS;
while (pCur)
while (pHead)
while (pCur)
while (pCur)
return rc;
ASMNopPause();
return VINF_SUCCESS;
if (!pIoStorage)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
return rc;
unsigned fMove)
while (cbRead)
#ifdef RT_STRICT
for (unsigned i = 0; i < cSegments; i++)
if (!pIoTask)
return VERR_NO_MEMORY;
void *pvTask;
&pvTask);
return rc;
void *pvCompleteUser)
while (cbWrite)
#ifdef DEBUG
for (unsigned i = 0; i < cSegments; i++)
PVDIOTASK pIoTask = vdIoTaskUserAlloc(pIoStorage, pfnComplete, pvCompleteUser, pIoCtx, (uint32_t)cbTaskWrite);
if (!pIoTask)
return VERR_NO_MEMORY;
void *pvTask;
return rc;
void *pvCompleteUser)
if ( pIoCtx
if ( !pIoCtx
if (ppMetaXfer)
if (!pMetaXfer)
#ifdef RT_STRICT
pMetaXfer = (PVDMETAXFER)RTAvlrFileOffsetGetBestFit(pIoStorage->pTreeMetaXfers, uOffset, false /* fAbove */);
if (!pMetaXfer)
return VERR_NO_MEMORY;
if (!pIoTask)
return VERR_NO_MEMORY;
return rc;
bool fInTree = false;
if ( pIoCtx
if ( !pIoCtx
if (!pMetaXfer)
if (!pMetaXfer)
return VERR_NO_MEMORY;
fInTree = true;
if (!pIoTask)
return VERR_NO_MEMORY;
&pvTask);
if (!fInTree)
if (pDeferred)
return rc;
if (!pMetaXfer)
if ( pIoCtx
return VINF_SUCCESS;
if ( !pIoCtx
if (!pMetaXfer)
return VERR_NO_MEMORY;
if (!pIoTask)
return VERR_NO_MEMORY;
return rc;
/// @todo Assert(pIoCtx->Req.Io.cbTransferLeft >= cbCopied); - triggers with vdCopyHelper/dmgRead.
return cbCopied;
/// @todo Assert(pIoCtx->Req.Io.cbTransferLeft > cbCopied); - triggers with vdCopyHelper/dmgRead.
return cbCopied;
/// @todo Assert(pIoCtx->Req.Io.cbTransferLeft >= cbSet); - triggers with vdCopyHelper/dmgRead.
return cbSet;
return cbCreated;
bool fAdvance)
return fIsZero;
if (!pIoStorage)
return VERR_NO_MEMORY;
return rc;
return rc;
const char *pcszFilename,
void *pvCompleteUser)
void *pvCompleteUser)
void *pvCompleteUser)
return VINF_SUCCESS;
void *pvCompleteUser)
return VINF_SUCCESS;
return rc;
Assert(!(RT_MIN(cbSize / 512 / pLCHS->cHeads / pLCHS->cSectors, 1024) - (uint32_t)RT_MIN(cbSize / 512 / pLCHS->cHeads / pLCHS->cSectors, 1024)));
return rc;
if (!g_apBackends)
return VERR_INTERNAL_ERROR;
if (g_apCacheBackends)
g_cBackends = 0;
g_cCacheBackends = 0;
#ifndef VBOX_HDD_NO_DYNAMIC_BACKENDS
return VINF_SUCCESS;
if (!g_apBackends)
return rc;
if (!g_apBackends)
return rc;
if (!g_apBackends)
return rc;
if (!g_apBackends)
return rc;
unsigned *pcEntriesUsed)
unsigned cEntries = 0;
LogFlowFunc(("cEntriesAlloc=%u pEntries=%#p pcEntriesUsed=%#p\n", cEntriesAlloc, pEntries, pcEntriesUsed));
if (!g_apBackends)
VDInit();
return VERR_BUFFER_OVERFLOW;
for (unsigned i = 0; i < g_cBackends; i++)
return rc;
if (!g_apBackends)
VDInit();
for (unsigned i = 0; i < g_cBackends; i++)
return VINF_SUCCESS;
return VERR_NOT_FOUND;
unsigned *pcEntriesUsed)
unsigned cEntries = 0;
LogFlowFunc(("cEntriesAlloc=%u pEntries=%#p pcEntriesUsed=%#p\n", cEntriesAlloc, pEntries, pcEntriesUsed));
if (!g_apBackends)
VDInit();
return VERR_BUFFER_OVERFLOW;
for (unsigned i = 0; i < g_cFilterBackends; i++)
return rc;
if (!g_apBackends)
VDInit();
for (unsigned i = 0; i < g_cFilterBackends; i++)
return VINF_SUCCESS;
return VERR_NOT_FOUND;
if (pDisk)
&& pDisk)
return rc;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
return rc;
if (!g_apBackends)
VDInit();
if (!pInterfaceIo)
for (unsigned i = 0; i < g_cBackends; i++)
if (!pszFormat)
for (unsigned i = 0; i < g_cCacheBackends; i++)
if (!pszFormat)
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
fLockWrite = false;
if (!pImage)
pImage->uOpenFlags = uOpenFlags & (VD_OPEN_FLAGS_HONOR_SAME | VD_OPEN_FLAGS_DISCARD | VD_OPEN_FLAGS_IGNORE_FLUSH | VD_OPEN_FLAGS_INFORM_ABOUT_ZERO_BLOCKS);
uOpenFlags & ~(VD_OPEN_FLAGS_HONOR_SAME | VD_OPEN_FLAGS_IGNORE_FLUSH | VD_OPEN_FLAGS_INFORM_ABOUT_ZERO_BLOCKS),
rc = pImage->Backend->pfnRepair(pszFilename, pDisk->pVDIfsDisk, pImage->pVDIfsImage, 0 /* fFlags */);
uOpenFlags & ~(VD_OPEN_FLAGS_HONOR_SAME | VD_OPEN_FLAGS_IGNORE_FLUSH | VD_OPEN_FLAGS_INFORM_ABOUT_ZERO_BLOCKS),
fLockWrite = true;
unsigned uImageFlags;
unsigned uOpenFlagsPrevImg;
if (pImage)
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
if (!pCache)
fLockWrite = true;
&UuidCache);
&UuidImage);
if (pCache)
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
if (!pFilter)
fLockWrite = true;
if (pFilter)
return rc;
int rc2;
LogFlowFunc(("pDisk=%#p pszBackend=\"%s\" pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" PCHS=%u/%u/%u LCHS=%u/%u/%u Uuid=%RTuuid uOpenFlags=%#x pVDIfsImage=%#p pVDIfsOperation=%#p\n",
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
fLockRead = false;
if (!pImage)
if (!pUuid)
fLockWrite = true;
if (pImage)
return rc;
int rc2;
LogFlowFunc(("pDisk=%#p pszBackend=\"%s\" pszFilename=\"%s\" uImageFlags=%#x pszComment=\"%s\" Uuid=%RTuuid uOpenFlags=%#x pVDIfsImage=%#p pVDIfsOperation=%#p\n",
pDisk, pszBackend, pszFilename, uImageFlags, pszComment, pUuid, uOpenFlags, pVDIfsImage, pVDIfsOperation));
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
fLockRead = false;
fLockWrite = true;
fLockWrite = false;
if (!pImage)
if (!pUuid)
fLockWrite = true;
unsigned uOpenFlagsPrevImg;
&Uuid);
&Uuid);
&Uuid);
&ts);
if (pImage)
return rc;
int rc2;
LogFlowFunc(("pDisk=%#p pszBackend=\"%s\" pszFilename=\"%s\" cbSize=%llu uImageFlags=%#x pszComment=\"%s\" Uuid=%RTuuid uOpenFlags=%#x pVDIfsImage=%#p pVDIfsOperation=%#p\n",
pDisk, pszBackend, pszFilename, cbSize, uImageFlags, pszComment, pUuid, uOpenFlags, pVDIfsCache, pVDIfsOperation));
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
fLockRead = false;
if (!pCache)
if (!pUuid)
fLockWrite = true;
if (pCache)
return rc;
int rc2;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
fLockWrite = false;
if (!pvBuf)
fLockWrite = true;
fLockWrite = false;
fLockWrite = true;
fLockWrite = false;
fLockWrite = true;
fLockWrite = false;
fLockWrite = true;
fLockWrite = false;
fLockWrite = true;
fLockWrite = false;
fLockWrite = true;
&Uuid);
&Uuid);
&Uuid);
&Uuid);
&Uuid);
&Uuid);
&& pImageChild
if (pvBuf)
return rc;
* @param pszBackend Name of the image file backend to use (may be NULL to use the same as the source, case insensitive).
* @param fMoveByRename If true, attempt to perform a move by renaming (if successful the new size is ignored).
int rc2;
LogFlowFunc(("pDiskFrom=%#p nImage=%u pDiskTo=%#p pszBackend=\"%s\" pszFilename=\"%s\" fMoveByRename=%d cbSize=%llu nImageFromSame=%u nImageToSame=%u uImageFlags=%#x pDstUuid=%#p uOpenFlags=%#x pVDIfsOperation=%#p pDstVDIfsImage=%#p pDstVDIfsOperation=%#p\n",
pDiskFrom, nImage, pDiskTo, pszBackend, pszFilename, fMoveByRename, cbSize, nImageFromSame, nImageToSame, uImageFlags, pDstUuid, uOpenFlags, pVDIfsOperation, pDstVDIfsImage, pDstVDIfsOperation));
fLockReadFrom = true;
if ( fMoveByRename
fLockReadFrom = false;
fLockWriteFrom = true;
rc = pImageFrom->Backend->pfnRename(pImageFrom->pBackendData, pszFilename ? pszFilename : pImageFrom->pszFilename);
if (cbSizeFrom == 0)
if (pDstUuid)
fLockReadFrom = false;
if (pszFilename)
if (cbSize == 0)
/** @todo replace the VDCreateDiff/VDCreateBase calls by direct
if (cImagesTo > 0)
fLockWriteTo = true;
fLockWriteTo = true;
if (cbSizeTo == 0)
if (cbSize == 0)
fLockWriteTo = false;
cImagesFromReadBack = 0;
cImagesToReadBack = 0;
fLockWriteTo = true;
fLockWriteTo = true;
return rc;
* @param fMoveByRename If true, attempt to perform a move by renaming (if successful the new size is ignored).
int rc2;
fLockRead = true;
fLockRead = false;
fLockWrite = true;
if (pvBuf)
if (pvTmp)
return rc;
/** @todo r=klaus resizing was designed to be part of VDCopy, so having a separate function is not desirable. */
int rc2;
fLockRead = true;
fLockRead = false;
fLockWrite = true;
PCHSGeometryOld.cCylinders = RT_MIN(cbSize / 512 / PCHSGeometryOld.cHeads / PCHSGeometryOld.cSectors, 16383);
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
if (!pImage)
if (!pImage)
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
if (pCache)
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
return rc;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
return rc;
unsigned cImages;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return cImages;
bool fReadOnly;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
unsigned uOpenFlags;
return fReadOnly;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return cbSector;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return cbSize;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return cbSize;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
&PCHS);
return rc;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
&LCHS);
return rc;
unsigned *puVersion)
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
unsigned *puImageFlags)
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
unsigned *puOpenFlags)
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
unsigned uOpenFlags)
int rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
uOpenFlags & ~(VD_OPEN_FLAGS_HONOR_SAME | VD_OPEN_FLAGS_IGNORE_FLUSH | VD_OPEN_FLAGS_INFORM_ABOUT_ZERO_BLOCKS));
pImage->uOpenFlags = uOpenFlags & (VD_OPEN_FLAGS_HONOR_SAME | VD_OPEN_FLAGS_DISCARD | VD_OPEN_FLAGS_IGNORE_FLUSH | VD_OPEN_FLAGS_INFORM_ABOUT_ZERO_BLOCKS);
return rc;
int rc;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
int rc;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
const char *pszComment)
int rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
return rc;
int rc;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
int rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
if (!pUuid)
return rc;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
pUuid);
return rc;
int rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
if (!pUuid)
pUuid);
return rc;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
return rc;
int rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
if (!pUuid)
return rc;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
int rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
return rc;
int rc2;
bool fLockRead = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockRead = true;
if (!pIoCtx)
return rc;
int rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
if (!pIoCtx)
return rc;
int rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
if (!pIoCtx)
return rc;
int rc;
int rc2;
bool fLockWrite = false;
AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
fLockWrite = true;
if (!pIoCtx)
return rc;
if (!pInterfaceIo)
return rc;