|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
volsnap.h
Abstract:
This file provides the internal data structures for the volume snapshot driver.
Author:
Norbert P. Kusters (norbertk) 22-Jan-1999
Environment:
kernel mode only
Notes:
Revision History:
--*/
#ifdef POOL_TAGGING
#undef ExAllocatePool
#undef ExAllocatePoolWithQuota
#define ExAllocatePool #assert(FALSE)
#define ExAllocatePoolWithQuota #assert(FALSE)
#endif
#define VOLSNAP_TAG_APP_INFO 'aSoV' // VoSa - Application information allocations
#define VOLSNAP_TAG_BUFFER 'bSoV' // VoSb - Buffer allocations
#define VOLSNAP_TAG_CONTEXT 'cSoV' // VoSc - Snapshot context allocations
#define VOLSNAP_TAG_DIFF_VOLUME 'dSoV' // VoSd - Diff area volume allocations
#define VOLSNAP_TAG_DIFF_FILE 'fSoV' // VoSf - Diff area file allocations
#define VOLSNAP_TAG_BIT_HISTORY 'hSoV' // VoSh - Bit history allocations
#define VOLSNAP_TAG_IO_STATUS 'iSoV' // VoSi - Io status block allocations
#define VOLSNAP_TAG_BITMAP 'mSoV' // VoSm - Bitmap allocations
#define VOLSNAP_TAG_OLD_HEAP 'oSoV' // VoSo - Old heap entry allocations
#define VOLSNAP_TAG_PNP_ID 'pSoV' // VoSp - Pnp id allocations
#define VOLSNAP_TAG_RELATIONS 'rSoV' // VoSr - Device relations allocations
#define VOLSNAP_TAG_SHORT_TERM 'sSoV' // VoSs - Short term allocations
#define VOLSNAP_TAG_TEMP_TABLE 'tSoV' // VoSt - Temp table allocations
#define VOLSNAP_TAG_WORK_QUEUE 'wSoV' // VoSw - Work queue allocations
#define VOLSNAP_TAG_DISPATCH 'xSoV' // VoSx - Dispatch context allocations
#define NUMBER_OF_THREAD_POOLS (3)
struct _VSP_CONTEXT; typedef struct _VSP_CONTEXT VSP_CONTEXT, *PVSP_CONTEXT;
struct _TEMP_TRANSLATION_TABLE_ENTRY; typedef struct _TEMP_TRANSLATION_TABLE_ENTRY TEMP_TRANSLATION_TABLE_ENTRY, *PTEMP_TRANSLATION_TABLE_ENTRY;
typedef struct _DO_EXTENSION {
//
// Pointer to the driver object.
//
PDRIVER_OBJECT DriverObject;
//
// List of volume filters in they system. Protect with 'Semaphore'.
//
LIST_ENTRY FilterList;
//
// HOLD/RELEASE Data. Protect with cancel spin lock.
//
LONG HoldRefCount; GUID HoldInstanceGuid; ULONG SecondsToHoldFsTimeout; ULONG SecondsToHoldIrpTimeout; LIST_ENTRY HoldIrps; KTIMER HoldTimer; KDPC HoldTimerDpc;
//
// A semaphore for synchronization.
//
KSEMAPHORE Semaphore;
//
// Worker Thread. Protect with 'SpinLock'.
// Protect 'WorkerThreadObjects' and 'Wait*' with
// 'ThreadsRefCountSemaphore'.
//
LIST_ENTRY WorkerQueue[NUMBER_OF_THREAD_POOLS]; KSEMAPHORE WorkerSemaphore[NUMBER_OF_THREAD_POOLS]; KSPIN_LOCK SpinLock[NUMBER_OF_THREAD_POOLS]; PVOID* WorkerThreadObjects; BOOLEAN WaitForWorkerThreadsToExitWorkItemInUse; WORK_QUEUE_ITEM WaitForWorkerThreadsToExitWorkItem;
//
// The threads ref count. Protect with 'ThreadsRefCountSemaphore'.
//
LONG ThreadsRefCount; KSEMAPHORE ThreadsRefCountSemaphore;
//
// Notification entry.
//
PVOID NotificationEntry;
//
// Lookaside list for contexts.
//
NPAGED_LOOKASIDE_LIST ContextLookasideList;
//
// Emergency Context. Protect with 'ESpinLock'.
//
PVSP_CONTEXT EmergencyContext; BOOLEAN EmergencyContextInUse; LIST_ENTRY IrpWaitingList; LONG IrpWaitingListNeedsChecking; KSPIN_LOCK ESpinLock;
//
// Lookaside list for temp table entries.
//
NPAGED_LOOKASIDE_LIST TempTableEntryLookasideList;
//
// Emergency Temp Table Entry. Protect with 'ESpinLock'.
//
PVOID EmergencyTableEntry; BOOLEAN EmergencyTableEntryInUse; LIST_ENTRY WorkItemWaitingList; LONG WorkItemWaitingListNeedsChecking;
//
// Stack count for allocating IRPs. Use InterlockedExchange to update
// along with Root->Semaphore. Then, can be read for use in allocating
// copy irps.
//
LONG StackSize;
//
// Is the code locked? Protect with interlocked and 'Semaphore'.
//
LONG IsCodeLocked;
//
// Copy of registry path input to DriverEntry.
//
UNICODE_STRING RegistryPath;
//
// Queue for AdjustBitmap operations. Just one at at time in the delayed
// work queue. Protect with 'ESpinLock'.
//
LIST_ENTRY AdjustBitmapQueue; BOOLEAN AdjustBitmapInProgress;
} DO_EXTENSION, *PDO_EXTENSION;
#define DEVICE_EXTENSION_VOLUME (0)
#define DEVICE_EXTENSION_FILTER (1)
struct DEVICE_EXTENSION {
//
// Pointer to the device object for this extension.
//
PDEVICE_OBJECT DeviceObject;
//
// Pointer to the root device extension.
//
PDO_EXTENSION Root;
//
// The type of device extension.
//
ULONG DeviceExtensionType;
//
// A spinlock for synchronization.
//
KSPIN_LOCK SpinLock;
};
typedef DEVICE_EXTENSION* PDEVICE_EXTENSION;
class FILTER_EXTENSION; typedef FILTER_EXTENSION* PFILTER_EXTENSION;
struct _VSP_DIFF_AREA_FILE; typedef struct _VSP_DIFF_AREA_FILE VSP_DIFF_AREA_FILE, *PVSP_DIFF_AREA_FILE;
class VOLUME_EXTENSION : public DEVICE_EXTENSION {
public:
//
// A pointer to the filter for the volume that we are snapshotting.
//
PFILTER_EXTENSION Filter;
//
// Local state to handle PNP's START and REMOVE.
// Protect 'IsStarted' with 'InterlockedExchange'.
// Protect 'DeadToPnp' with 'InterlockedExchange'.
// Protect 'DeviceDeleted' with 'InterlockedExchange'.
// Write protect 'IsDead' with 'InterlockedExchange' and
// 'Root->Semaphore.'. 'IsDead' indicates that this device is really
// dead now. It is illegal to turn IsStarted to TRUE.
// Protect 'AliveToPnp' with 'InterlockedExchange'.
//
LONG IsStarted; LONG DeadToPnp; LONG DeviceDeleted; LONG IsDead; LONG AliveToPnp;
//
// Keep track of all requests outstanding in order to support
// remove.
// Protect 'RefCount' with 'InterlockedIncrement/Decrement'.
// Write protect 'HoldIncomingRequests' with 'SpinLock' and
// 'InterlockedExchange'.
// Protect 'HoldQueue' with 'SpinLock'.
// Protect 'ZeroRefEvent' with the setting of 'HoldIncomingRequests'
// from 0 to 1.
//
LONG RefCount; LONG HoldIncomingRequests; LIST_ENTRY HoldIrpQueue; LIST_ENTRY HoldWorkerQueue; KEVENT ZeroRefEvent;
//
// Post Commit Processing has occurred. Protect with 'Root->Semaphore'.
// Don't return this device in BusRelations until this is TRUE.
//
BOOLEAN HasEndCommit;
//
// Indicates that this device has been installed. Protect with
// 'Root->Semaphore'.
//
BOOLEAN IsInstalled;
//
// Indicates that growing the diff area file is now safe.
// Protect with 'InterlockedExchange'.
//
LONG OkToGrowDiffArea;
//
// Time stamp when commit took place.
//
LARGE_INTEGER CommitTimeStamp;
//
// A list entry for 'Filter->VolumeList'.
// Write protect with 'Filter->SpinLock', 'Root->Semaphore', and
// 'Filter->RefCount == 0'.
// Blink points to an older snapshot.
// Flink points to a newer snapshot.
//
LIST_ENTRY ListEntry;
//
// The volume number.
//
ULONG VolumeNumber;
//
// A table to translate volume offset to backing store offset.
// Protect with 'PagedResource'.
//
RTL_GENERIC_TABLE VolumeBlockTable;
//
// A table to store entries in flight. This table is non-paged.
// Protect with 'NonPagedResource'.
//
RTL_GENERIC_TABLE TempVolumeBlockTable; ULONG MaximumNumberOfTempEntries; ULONG DiffAreaFileIncrease;
//
// A list of Diff Area Files that are used.
// Write protect 'ListOfDiffAreaFiles' with 'NonPagedResource',
// 'Root->Semaphore', 'RefCount == 0', and
// 'extension->Filter->RefCount == 0'.
// Protect 'NextDiffAreaFile' with 'NonPagedResource'.
//
LIST_ENTRY ListOfDiffAreaFiles; PVSP_DIFF_AREA_FILE NextDiffAreaFile;
//
// Memory mapped section of a diff area file to be used for a heap.
// Protect with 'PagedResource'.
//
PVOID DiffAreaFileMap; ULONG DiffAreaFileMapSize; PVOID DiffAreaFileMapProcess; ULONG NextAvailable; PVOID NextDiffAreaFileMap; ULONG NextDiffAreaFileMapSize; LIST_ENTRY OldHeaps;
//
// A bitmap of blocks that do not need to be copy on writed.
// Protect with 'SpinLock'.
//
PRTL_BITMAP VolumeBlockBitmap;
//
// A bitmap product of ignorable blocks from previous snapshots.
// Protect with 'SpinLock'.
//
PRTL_BITMAP IgnorableProduct;
//
// Application Information. Protect with 'PagedResource'.
//
ULONG ApplicationInformationSize; PVOID ApplicationInformation;
//
// Volume size.
//
LONGLONG VolumeSize;
//
// Emergency copy irp. Protect with 'SpinLock'.
//
PIRP EmergencyCopyIrp; LONG EmergencyCopyIrpInUse; LIST_ENTRY EmergencyCopyIrpQueue;
//
// This field is used to pass a buffer to the TempTableAllocateRoutine.
// Protect with 'NonPagedResource'.
//
PVOID TempTableEntry;
//
// These fields are there to help with the lag in creating new
// page file space. Non paged pool can be used until the page file
// space can be acquired. Protect 'PageFileSpaceCreatePending' and
// 'WaitingForPageFileSpace' with 'SpinLock'.
//
LONG PageFileSpaceCreatePending; LIST_ENTRY WaitingForPageFileSpace;
};
typedef VOID (*ZERO_REF_CALLBACK)( IN PFILTER_EXTENSION Filter );
typedef VOLUME_EXTENSION* PVOLUME_EXTENSION;
struct _VSP_CONTEXT {
ULONG Type; WORK_QUEUE_ITEM WorkItem;
union { struct { PVOLUME_EXTENSION Extension; PIRP OriginalReadIrp; ULONG_PTR OriginalReadIrpOffset; LONGLONG OriginalVolumeOffset; ULONG BlockOffset; ULONG Length; PDEVICE_OBJECT TargetObject; LONGLONG TargetOffset; } ReadSnapshot;
struct { PDO_EXTENSION RootExtension; ULONG QueueNumber; } ThreadCreation;
struct { PIO_WORKITEM IoWorkItem; PIRP Irp; } Dispatch;
struct { PVOLUME_EXTENSION Extension; PIRP Irp; } Extension;
struct { PFILTER_EXTENSION Filter; } Filter;
struct { PVOLUME_EXTENSION Extension; PVSP_DIFF_AREA_FILE DiffAreaFile; } GrowDiffArea;
struct { KEVENT Event; } Event;
struct { PVOLUME_EXTENSION Extension; PFILTER_EXTENSION DiffAreaFilter; NTSTATUS SpecificIoStatus; NTSTATUS FinalStatus; ULONG UniqueErrorValue; } ErrorLog;
struct { PDO_EXTENSION RootExtension; } RootExtension;
struct { PVOLUME_EXTENSION Extension; PIRP Irp; LONGLONG RoundedStart; } WriteVolume; }; };
#define VSP_CONTEXT_TYPE_READ_SNAPSHOT (1)
#define VSP_CONTEXT_TYPE_THREAD_CREATION (2)
#define VSP_CONTEXT_TYPE_DISPATCH (3)
#define VSP_CONTEXT_TYPE_EXTENSION (4)
#define VSP_CONTEXT_TYPE_FILTER (5)
#define VSP_CONTEXT_TYPE_GROW_DIFF_AREA (6)
#define VSP_CONTEXT_TYPE_EVENT (7)
#define VSP_CONTEXT_TYPE_ERROR_LOG (8)
#define VSP_CONTEXT_TYPE_ROOT_EXTENSION (9)
#define VSP_CONTEXT_TYPE_WRITE_VOLUME (10)
class FILTER_EXTENSION : public DEVICE_EXTENSION {
public:
//
// The target object for this filter.
//
PDEVICE_OBJECT TargetObject;
//
// The PDO for this filter.
//
PDEVICE_OBJECT Pdo;
//
// Do we have any snapshots?
// Write protect with 'InterlockedExchange' and 'Root->Semaphore'.
//
LONG SnapshotsPresent;
//
// Keep track of I/Os so that freeze/thaw is possible.
// Protect 'RefCount' with 'InterlockedIncrement/Decrement'.
// Write Protect 'HoldIncomingWrites' with InterlockedExchange and
// 'SpinLock'.
// Protect 'HoldQueue' with 'SpinLock'.
// Protect 'ZeroRefCallback', 'ZeroRefContext',
// and 'TimerIsSet' are for use by the thread that sets
// 'HoldIncomingWrites' to 1 from 0.
// Write protect 'ZeroRefCallback' with 'SpinLock'.
// Protect 'TimerIsSet' with InterlockedExchange.
//
LONG RefCount; LONG HoldIncomingWrites; LIST_ENTRY HoldQueue; ZERO_REF_CALLBACK ZeroRefCallback; PVOID ZeroRefContext;
KTIMER HoldWritesTimer; KDPC HoldWritesTimerDpc; ULONG HoldWritesTimeout; LONG TimerIsSet;
//
// The flush and hold irp is kept here while it is cancellable.
// Protect with the cancel spin lock.
//
PIRP FlushAndHoldIrp;
//
// This event indicates that the end commit process is completed.
// This means that PNP has kicked into gear and that the ignorable
// bitmap computation has taken place.
//
KEVENT EndCommitProcessCompleted;
//
// Keep a notification entry on this object to watch for a
// dismount. Protect with 'Root->Semaphore'.
//
PVOID TargetDeviceNotificationEntry;
//
// A list entry for 'Root->FilterList'.
// Protect these with 'Root->Semaphore'.
//
LIST_ENTRY ListEntry; BOOLEAN NotInFilterList;
//
// Keep a list of snapshot volumes.
// Write protect with 'Root->Semaphore', 'RefCount == 0', and
// 'SpinLock'.
// Flink points to the oldest snapshot.
// Blink points to the newest snapshot.
//
LIST_ENTRY VolumeList;
//
// Cache the prepared snapshot for committing later.
// Write protect with 'SpinLock' and 'Root->Semaphore'.
//
PVOLUME_EXTENSION PreparedSnapshot;
//
// List of dead snapshot volumes. Protect with 'Root->Semaphore'.
//
LIST_ENTRY DeadVolumeList;
//
// List of volume snapshots which depend on this filter for
// diff area support. This will serve as removal relations.
// Protect with 'Root->Semaphore'.
//
LIST_ENTRY DiffAreaFilesOnThisFilter;
//
// List of volumes that make up the Diff Area for this volume.
// Protect with 'Root->Semaphore'.
//
LIST_ENTRY DiffAreaVolumes;
//
// Diff area sizes information total for all diff area files.
// Protect with 'SpinLock'.
//
LONGLONG UsedVolumeSpace; LONGLONG AllocatedVolumeSpace; LONGLONG MaximumVolumeSpace;
//
// Timer for completing END_COMMIT if device doesn't install.
//
KTIMER EndCommitTimer; KDPC EndCommitTimerDpc;
//
// File object for AUTO_CLEANUP. Protect with cancel spin lock.
//
PFILE_OBJECT AutoCleanupFileObject;
//
// Is a delete all snapshots pending. Protect with
// InterlockedExchange.
//
LONG DestroyAllSnapshotsPending; VSP_CONTEXT DestroyContext;
//
// Resource to use for protection. Don't page when holding this
// resource. Protect the queueing with 'SpinLock'.
//
LIST_ENTRY NonPagedResourceList; BOOLEAN NonPagedResourceInUse;
//
// Page resource to use for protection. It is ok to page when
// holding this resource. Protect the queueing with 'SpinLock'.
//
LIST_ENTRY PagedResourceList; BOOLEAN PagedResourceInUse;
};
#define BLOCK_SIZE (0x4000)
#define BLOCK_SHIFT (14)
#define MINIMUM_TABLE_HEAP_SIZE (0x20000)
#define MEMORY_PRESSURE_CHECK_ALLOC_SIZE (0x40000)
#define NOMINAL_DIFF_AREA_FILE_GROWTH (50*1024*1024)
#define MAXIMUM_DIFF_AREA_FILE_GROWTH (1000*1024*1024)
typedef struct _TRANSLATION_TABLE_ENTRY { LONGLONG VolumeOffset; PDEVICE_OBJECT TargetObject; LONGLONG TargetOffset; } TRANSLATION_TABLE_ENTRY, *PTRANSLATION_TABLE_ENTRY;
//
// The structure below is used in the non-paged temp table. 'IsComplete' and
// 'WaitingQueue*' are protected with 'extension->SpinLock'.
//
struct _TEMP_TRANSLATION_TABLE_ENTRY { LONGLONG VolumeOffset; PVOLUME_EXTENSION Extension; PIRP WriteIrp; PIRP CopyIrp; PDEVICE_OBJECT TargetObject; LONGLONG TargetOffset; BOOLEAN IsComplete; LIST_ENTRY WaitingQueueDpc; // These can run in arbitrary context.
WORK_QUEUE_ITEM WorkItem; };
//
// Write protect 'VolumeListEntry' with 'NonPagedResource' and
// 'Root->Semaphore'.
// Protect 'FilterListEntry*' with 'Root->Semaphore'.
// Protect 'NextAvailable' with 'NonPagedResource'
// Write Protect 'AllocatedFileSize' with 'NonPagedResource' and
// 'Root->Semaphore'.
// Protect 'UnusedAllocationList' with 'NonPagedResource'.
//
struct _VSP_DIFF_AREA_FILE { LIST_ENTRY VolumeListEntry; LIST_ENTRY FilterListEntry; BOOLEAN FilterListEntryBeingUsed; PVOLUME_EXTENSION Extension; PFILTER_EXTENSION Filter; HANDLE FileHandle; LONGLONG NextAvailable; LONGLONG AllocatedFileSize; LIST_ENTRY UnusedAllocationList; };
typedef struct _DIFF_AREA_FILE_ALLOCATION { LIST_ENTRY ListEntry; LONGLONG Offset; LONGLONG Length; } DIFF_AREA_FILE_ALLOCATION, *PDIFF_AREA_FILE_ALLOCATION;
typedef struct _OLD_HEAP_ENTRY { LIST_ENTRY ListEntry; PVOID DiffAreaFileMap; } OLD_HEAP_ENTRY, *POLD_HEAP_ENTRY;
typedef struct _VSP_DIFF_AREA_VOLUME { LIST_ENTRY ListEntry; PFILTER_EXTENSION Filter; } VSP_DIFF_AREA_VOLUME, *PVSP_DIFF_AREA_VOLUME;
//
// {3808876B-C176-4e48-B7AE-04046E6CC752}
// This GUID is used to decorate the names of the diff area files for
// uniqueness. This GUID has been included in the list of files not to be
// backed up by NTBACKUP. If this GUID is changed, or if other GUIDs are
// added, then this change should also be reflected in the NTBACKUP file
// not to be backed up.
//
DEFINE_GUID(VSP_DIFF_AREA_FILE_GUID, 0x3808876b, 0xc176, 0x4e48, 0xb7, 0xae, 0x4, 0x4, 0x6e, 0x6c, 0xc7, 0x52);
#if DBG
//
// Tracing definitions.
//
typedef struct _VSP_TRACE_STRUCTURE { ULONG EventNumber; ULONG_PTR Arg1; ULONG_PTR Arg2; ULONG_PTR Arg3; } VSP_TRACE_STRUCTURE, *PVSP_TRACE_STRUCTURE;
PVSP_TRACE_STRUCTURE VspAllocateTraceStructure( );
#define VSP_TRACE_IT(A0, A1, A2, A3) \
{ PVSP_TRACE_STRUCTURE moo; \ moo = VspAllocateTraceStructure(); \ moo->EventNumber = (A0); \ moo->Arg1 = (ULONG_PTR) (A1); \ moo->Arg2 = (ULONG_PTR) (A2); \ moo->Arg3 = (ULONG_PTR) (A3); }
#else // DBG
#define VSP_TRACE_IT(A0, A1, A2, A3)
#endif // DBG
|