You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1407 lines
40 KiB
1407 lines
40 KiB
/*++
|
|
|
|
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_LOOKUP 'lSoV' // VoSl - Snasphot lookup table entry
|
|
#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 VOLSNAP_TAG_COPY 'CSoV' // VoSx - Copy On Write Structures
|
|
|
|
#define NUMBER_OF_THREAD_POOLS (3)
|
|
|
|
struct _VSP_CONTEXT;
|
|
typedef struct _VSP_CONTEXT VSP_CONTEXT, *PVSP_CONTEXT;
|
|
|
|
class FILTER_EXTENSION;
|
|
typedef FILTER_EXTENSION* PFILTER_EXTENSION;
|
|
|
|
class VOLUME_EXTENSION;
|
|
typedef VOLUME_EXTENSION* PVOLUME_EXTENSION;
|
|
|
|
//
|
|
// Write context buffer.
|
|
//
|
|
|
|
typedef struct _VSP_WRITE_CONTEXT {
|
|
LIST_ENTRY ListEntry;
|
|
PFILTER_EXTENSION Filter;
|
|
PVOLUME_EXTENSION Extension;
|
|
PIRP Irp;
|
|
LIST_ENTRY CompletionRoutines;
|
|
} VSP_WRITE_CONTEXT, *PVSP_WRITE_CONTEXT;
|
|
|
|
//
|
|
// Copy On Write List Entry.
|
|
//
|
|
|
|
typedef struct _VSP_COPY_ON_WRITE {
|
|
LIST_ENTRY ListEntry;
|
|
LONGLONG RoundedStart;
|
|
PVOID Buffer;
|
|
} VSP_COPY_ON_WRITE, *PVSP_COPY_ON_WRITE;
|
|
|
|
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;
|
|
|
|
//
|
|
// Low-Priority Queue for sending stuff to the DelayedWorkQueue in a
|
|
// single threaded manner. Protect with 'ESpinLock'.
|
|
//
|
|
|
|
LIST_ENTRY LowPriorityQueue;
|
|
BOOLEAN WorkerItemInUse;
|
|
WORK_QUEUE_ITEM LowPriorityWorkItem;
|
|
PWORK_QUEUE_ITEM ActualLowPriorityWorkItem;
|
|
|
|
//
|
|
// 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 write context buffers.
|
|
//
|
|
|
|
NPAGED_LOOKASIDE_LIST WriteContextLookasideList;
|
|
|
|
//
|
|
// Emergency Write Context Buffer. Protect with 'ESpinLock'.
|
|
//
|
|
|
|
PVSP_WRITE_CONTEXT EmergencyWriteContext;
|
|
BOOLEAN EmergencyWriteContextInUse;
|
|
LIST_ENTRY WriteContextIrpWaitingList;
|
|
LONG WriteContextIrpWaitingListNeedsChecking;
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// Are we past re-init?
|
|
//
|
|
|
|
LONG PastReinit;
|
|
|
|
//
|
|
// Are we part boot-re-init?
|
|
//
|
|
|
|
KEVENT PastBootReinit;
|
|
|
|
//
|
|
// Keep a table of persistent information to facilitate matching
|
|
// up a snapshot with its diff area. Protect with 'LookupTableMutex'.
|
|
//
|
|
|
|
RTL_GENERIC_TABLE PersistentSnapshotLookupTable;
|
|
KMUTEX LookupTableMutex;
|
|
|
|
//
|
|
// Remember whether or not this is SETUP.
|
|
//
|
|
|
|
BOOLEAN IsSetup;
|
|
|
|
//
|
|
// Indicates that the volumes in the system are safe for write access.
|
|
//
|
|
|
|
LONG VolumesSafeForWriteAccess;
|
|
|
|
//
|
|
// Supplies the next volume number to be used for a snapshot.
|
|
// Protect with InterlockedIncrement.
|
|
//
|
|
|
|
LONG NextVolumeNumber;
|
|
|
|
//
|
|
// Keep a table of used devnode numbers. Protect with 'Semaphore'.
|
|
//
|
|
|
|
RTL_GENERIC_TABLE UsedDevnodeNumbers;
|
|
|
|
} 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;
|
|
|
|
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'.
|
|
// Protect 'IsOffline' with 'InterlockedExchange'.
|
|
//
|
|
|
|
LONG IsStarted;
|
|
LONG DeadToPnp;
|
|
LONG DeviceDeleted;
|
|
LONG IsDead;
|
|
LONG AliveToPnp;
|
|
LONG IsOffline;
|
|
|
|
//
|
|
// 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;
|
|
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 this is a persistent snapshot.
|
|
//
|
|
|
|
BOOLEAN IsPersistent;
|
|
|
|
//
|
|
// Indicates that this persistent snapshot was detected, not created.
|
|
//
|
|
|
|
BOOLEAN IsDetected;
|
|
|
|
//
|
|
// Indicates that there we a need to grow the diff area found when
|
|
// the snapshot was detected.
|
|
//
|
|
|
|
BOOLEAN DetectedNeedForGrow;
|
|
|
|
//
|
|
// Indicates that the persistent on disk structure has been
|
|
// committed. Protect with 'NonPagedResource'.
|
|
//
|
|
|
|
BOOLEAN OnDiskNotCommitted;
|
|
|
|
//
|
|
// Indicates that the device is visible. Protect with
|
|
// 'Root->Semaphore'.
|
|
//
|
|
|
|
BOOLEAN IsVisible;
|
|
|
|
//
|
|
// Indicates that no diff area fill is necessary for this persistent
|
|
// snapshot.
|
|
|
|
BOOLEAN NoDiffAreaFill;
|
|
|
|
//
|
|
// Indicates that the root semaphore is held.
|
|
//
|
|
|
|
BOOLEAN RootSemaphoreHeld;
|
|
|
|
//
|
|
// Indicates that this device object is a pre-exposure.
|
|
// Protect with 'Root->Semaphore'.
|
|
//
|
|
|
|
BOOLEAN IsPreExposure;
|
|
|
|
//
|
|
// Indictates that this snapshot is keeping a reference to
|
|
// 'IgnoreCopyData'. Protect with 'Root->Semaphore'.
|
|
//
|
|
|
|
BOOLEAN IgnoreCopyDataReference;
|
|
|
|
//
|
|
// Indicates that the grow failed and whether or not the limit
|
|
// was user imposed.
|
|
//
|
|
|
|
BOOLEAN UserImposedLimit;
|
|
LONG GrowFailed;
|
|
|
|
//
|
|
// Keep an event here for waiting for the pre-exposure.
|
|
//
|
|
|
|
KEVENT PreExposureEvent;
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// The devnode number.
|
|
//
|
|
|
|
ULONG DevnodeNumber;
|
|
|
|
//
|
|
// The volume snapshot GUID.
|
|
//
|
|
|
|
GUID SnapshotGuid;
|
|
|
|
//
|
|
// The snapshot order number. Set at commit time.
|
|
//
|
|
|
|
LONGLONG SnapshotOrderNumber;
|
|
|
|
//
|
|
// A table to translate volume offset to backing store offset.
|
|
// Protect with 'PagedResource'.
|
|
//
|
|
|
|
RTL_GENERIC_TABLE VolumeBlockTable;
|
|
RTL_GENERIC_TABLE CopyBackPointerTable;
|
|
|
|
//
|
|
// A table to store entries in flight. This table is non-paged.
|
|
// Protect with 'NonPagedResource'.
|
|
//
|
|
|
|
RTL_GENERIC_TABLE TempVolumeBlockTable;
|
|
ULONG MaximumNumberOfTempEntries;
|
|
ULONG DiffAreaFileIncrease;
|
|
|
|
//
|
|
// The Diff Area File for this snapshot.
|
|
// Write protect 'DiffAreaFile' pointer with 'NonPagedResource',
|
|
// 'Root->Semaphore', 'RefCount == 0', and
|
|
// 'extension->Filter->RefCount == 0'.
|
|
//
|
|
|
|
PVSP_DIFF_AREA_FILE DiffAreaFile;
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// Mounted device interface name.
|
|
//
|
|
|
|
UNICODE_STRING MountedDeviceInterfaceName;
|
|
|
|
//
|
|
// These fields are there to help with the lag in creating new
|
|
// diff area space. If the diff area volume does not have any
|
|
// snapshots present on it, then a copy on write can block
|
|
// on the arrival on new diff area space.
|
|
//
|
|
|
|
BOOLEAN GrowDiffAreaFilePending;
|
|
BOOLEAN PastFileSystemOperations;
|
|
LIST_ENTRY WaitingForDiffAreaSpace;
|
|
|
|
//
|
|
// States whether or not this snapshot has the crashdump file.
|
|
//
|
|
|
|
BOOLEAN ContainsCrashdumpFile;
|
|
|
|
//
|
|
// States whether or not this snapshot has copy on writed the hiber
|
|
// file. Protect with 'InterlockedExchange'.
|
|
//
|
|
|
|
LONG HiberFileCopied;
|
|
LONG PageFileCopied;
|
|
|
|
//
|
|
// Keep a list of Write Contexts. Protect with 'SpinLock'.
|
|
//
|
|
|
|
LIST_ENTRY WriteContextList;
|
|
|
|
//
|
|
// List entry for deleting the device objects.
|
|
//
|
|
|
|
LIST_ENTRY AnotherListEntry;
|
|
|
|
};
|
|
|
|
typedef
|
|
VOID
|
|
(*ZERO_REF_CALLBACK)(
|
|
IN PFILTER_EXTENSION Filter
|
|
);
|
|
|
|
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;
|
|
BOOLEAN IsCopyTarget;
|
|
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;
|
|
PIRP Irp;
|
|
} Filter;
|
|
|
|
struct {
|
|
PVOLUME_EXTENSION Extension;
|
|
LIST_ENTRY ExtentList;
|
|
LONGLONG Current;
|
|
ULONG Increase;
|
|
KSPIN_LOCK SpinLock;
|
|
PLIST_ENTRY CurrentEntry;
|
|
ULONG CurrentEntryOffset;
|
|
PDEVICE_OBJECT TargetObject;
|
|
NTSTATUS ResultStatus;
|
|
KEVENT Event;
|
|
LONG RefCount;
|
|
} 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;
|
|
|
|
struct {
|
|
PFILTER_EXTENSION Filter;
|
|
PKTIMER Timer;
|
|
PKDPC Dpc;
|
|
} DeleteDiffAreaFiles;
|
|
|
|
struct {
|
|
PFILTER_EXTENSION Filter;
|
|
BOOLEAN KeepOnDisk;
|
|
BOOLEAN SynchronousCall;
|
|
} DestroyAllSnapshots;
|
|
|
|
struct {
|
|
PVOLUME_EXTENSION Extension;
|
|
PIRP Irp;
|
|
LIST_ENTRY ExtentList;
|
|
BOOLEAN HiberfileIncluded;
|
|
BOOLEAN PagefileIncluded;
|
|
} CopyExtents;
|
|
|
|
struct {
|
|
PFILTER_EXTENSION Filter;
|
|
HANDLE Handle1;
|
|
HANDLE Handle2;
|
|
} CloseHandles;
|
|
|
|
struct {
|
|
PFILTER_EXTENSION Filter;
|
|
PIRP Irp;
|
|
} DismountCleanupOnWrite;
|
|
|
|
struct {
|
|
PFILTER_EXTENSION Filter;
|
|
KDPC TimerDpc;
|
|
PKTIMER Timer;
|
|
} PnpWaitTimer;
|
|
|
|
struct {
|
|
PFILTER_EXTENSION Filter;
|
|
PIRP Irp;
|
|
LONGLONG RoundedStart;
|
|
LONGLONG RoundedEnd;
|
|
} CopyOnWrite;
|
|
};
|
|
};
|
|
|
|
#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)
|
|
#define VSP_CONTEXT_TYPE_DELETE_DA_FILES (11)
|
|
#define VSP_CONTEXT_TYPE_DESTROY_SNAPSHOTS (12)
|
|
#define VSP_CONTEXT_TYPE_COPY_EXTENTS (13)
|
|
#define VSP_CONTEXT_TYPE_CLOSE_HANDLES (14)
|
|
#define VSP_CONTEXT_TYPE_DISMOUNT_CLEANUP (15)
|
|
#define VSP_CONTEXT_TYPE_PNP_WAIT_TIMER (16)
|
|
#define VSP_CONTEXT_TYPE_COPY_ON_WRITE (17)
|
|
|
|
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? Are they persistent?
|
|
// Write protect with 'InterlockedExchange' and 'Root->Semaphore'.
|
|
//
|
|
|
|
LONG SnapshotsPresent;
|
|
LONG PersistentSnapshots;
|
|
|
|
//
|
|
// Persistent only fields.
|
|
// Protect 'FirstControlBlockVolumeOffset' with 'NonPagedResource'.
|
|
// Protect 'ControlBlockFileHandle' with 'InterlockedExchange'.
|
|
// Protect 'SnapshotOnDiskIrp' and control file contents with
|
|
// 'NonPagedResource'.
|
|
// Protect '*LookupTableEntries' with 'NonPagedResource'.
|
|
//
|
|
|
|
LONGLONG FirstControlBlockVolumeOffset;
|
|
HANDLE ControlBlockFileHandle;
|
|
KSEMAPHORE ControlBlockFileHandleSemaphore;
|
|
PIRP SnapshotOnDiskIrp;
|
|
LIST_ENTRY SnapshotLookupTableEntries;
|
|
LIST_ENTRY DiffAreaLookupTableEntries;
|
|
KEVENT ControlBlockFileHandleReady;
|
|
|
|
//
|
|
// Keep track of I/Os so that freeze/thaw is possible.
|
|
// Protect 'RefCount' with 'InterlockedIncrement/Decrement'.
|
|
// Write Protect 'HoldIncomingWrites' with InterlockedIncrement and
|
|
// 'SpinLock'.
|
|
// Protect 'HoldQueue' with 'SpinLock'.
|
|
// Protect 'ZeroRefCallback', 'ZeroRefContext' with the setting
|
|
// of 'ExternalWaiter' to 1 and 'SpinLock'.
|
|
//
|
|
|
|
LONG RefCount;
|
|
LONG HoldIncomingWrites;
|
|
LIST_ENTRY HoldQueue;
|
|
BOOLEAN ExternalWaiter;
|
|
ZERO_REF_CALLBACK ZeroRefCallback;
|
|
PVOID ZeroRefContext;
|
|
KEVENT ZeroRefEvent;
|
|
KSEMAPHORE ZeroRefSemaphore;
|
|
|
|
KTIMER HoldWritesTimer;
|
|
KDPC HoldWritesTimerDpc;
|
|
ULONG HoldWritesTimeout;
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// A semaphore preventing 2 simultaneous critical operations.
|
|
//
|
|
|
|
KSEMAPHORE CriticalOperationSemaphore;
|
|
|
|
//
|
|
// 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' and 'SpinLock'.
|
|
//
|
|
|
|
LIST_ENTRY DiffAreaFilesOnThisFilter;
|
|
|
|
//
|
|
// The designated diff area volume that makes up the Diff Area for this
|
|
// volume.
|
|
// Protect with 'Root->Semaphore'.
|
|
//
|
|
|
|
PFILTER_EXTENSION DiffAreaVolume;
|
|
|
|
//
|
|
// Diff area sizes information total for all diff area files.
|
|
// Protect with 'SpinLock'.
|
|
// Additionally protect 'MaximumVolumeSpace' with 'NonPagedResource'.
|
|
//
|
|
|
|
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;
|
|
|
|
//
|
|
// Indicates that a snapshot discovery is still pending. The
|
|
// snapshot discovery will end upon the first write if not
|
|
// all of the pieces make it in time. Protect with
|
|
// 'InterlockedExchange' and 'RefCount == 0'.
|
|
//
|
|
|
|
LONG SnapshotDiscoveryPending;
|
|
|
|
//
|
|
// Remember whether or not the underlying volume is online.
|
|
// Protect with 'Root->Semaphore'.
|
|
//
|
|
|
|
LONG IsOnline;
|
|
|
|
//
|
|
// Remember whether or not remove has been processed. Protect with
|
|
// 'Root->Semaphore'.
|
|
//
|
|
|
|
BOOLEAN IsRemoved;
|
|
|
|
//
|
|
// Remember whether or not this volume is used for crashdump.
|
|
// Protect with 'Root->Semaphore'.
|
|
//
|
|
|
|
BOOLEAN UsedForCrashdump;
|
|
|
|
//
|
|
// Protect with 'InterlockedExchange'.
|
|
//
|
|
|
|
LONG UsedForPaging;
|
|
|
|
//
|
|
// In the persistent snapshot case on the boot volume, keep a handle
|
|
// to \SystemRoot\bootstat.dat and pin it. Protect with
|
|
// 'InterlockedExchange'.
|
|
//
|
|
|
|
HANDLE BootStatHandle;
|
|
|
|
//
|
|
// Indicates that there is a hibernate action pending. Protect with
|
|
// 'InterlockedExchange'.
|
|
//
|
|
|
|
LONG HibernatePending;
|
|
|
|
//
|
|
// Indicates that COPY DATA ioctls should be ignored. Protect with
|
|
// 'InterlockedExchange'.
|
|
//
|
|
|
|
LONG IgnoreCopyData;
|
|
|
|
//
|
|
// Flag memory pressure to tweak commit and release error codes.
|
|
//
|
|
|
|
LONG LastReleaseDueToMemoryPressure;
|
|
|
|
//
|
|
// A bitmap that says, if a write comes here then delete all
|
|
// snapshots using this volume. Set value with 'InterlockedExchange'
|
|
// and protect with 'SpinLock'.
|
|
//
|
|
|
|
PRTL_BITMAP ProtectedBlocksBitmap;
|
|
|
|
//
|
|
// A list of copy on writes should be kept in non-paged pool
|
|
// for a spell until the diff area volumes all arrive.
|
|
// Protect 'FirstWriteProcessed' with 'SpinLock' and 'Interlocked'
|
|
// Protect 'CopyOnWriteList' with 'SpinLock'.
|
|
// Protect 'PnpWaitTimerContext' with 'SpinLock'.
|
|
// Protect 'ActivateStarted' with 'SpinLock'.
|
|
//
|
|
|
|
LONG FirstWriteProcessed;
|
|
LONG ActivateStarted;
|
|
LIST_ENTRY CopyOnWriteList;
|
|
PVSP_CONTEXT PnpWaitTimerContext;
|
|
|
|
//
|
|
// A ref count to keep track of pending file system operations
|
|
// on this filter.
|
|
//
|
|
|
|
LONG FSRefCount;
|
|
|
|
//
|
|
// The delete diff area files timer. Protect with Critical.
|
|
//
|
|
|
|
PKTIMER DeleteTimer;
|
|
|
|
//
|
|
// Epic number to avoid queries
|
|
//
|
|
|
|
LONG EpicNumber;
|
|
|
|
};
|
|
|
|
typedef struct _VSP_WAIT_BLOCK {
|
|
LONG RefCount;
|
|
KEVENT Event;
|
|
} VSP_WAIT_BLOCK, *PVSP_WAIT_BLOCK;
|
|
|
|
#define BLOCK_SIZE (0x4000)
|
|
#define BLOCK_SHIFT (14)
|
|
#define MINIMUM_TABLE_HEAP_SIZE (0x20000)
|
|
#define MEMORY_PRESSURE_CHECK_ALLOC_SIZE (0x40000)
|
|
#define LARGEST_NTFS_CLUSTER (0x10000)
|
|
#define SMALLEST_NTFS_CLUSTER (0x200)
|
|
#define VSP_HIGH_PRIORITY (20)
|
|
#define VSP_LOWER_PRIORITY (10)
|
|
#define VSP_MAX_SNAPSHOTS (512)
|
|
|
|
#define NOMINAL_DIFF_AREA_FILE_GROWTH (50*1024*1024)
|
|
#define MAXIMUM_DIFF_AREA_FILE_GROWTH (1000*1024*1024)
|
|
|
|
#define VSP_TRANSLATION_TABLE_ENTRY_FLAG_COPY_ENTRY (0x1)
|
|
|
|
typedef struct _TRANSLATION_TABLE_ENTRY {
|
|
LONGLONG VolumeOffset;
|
|
PDEVICE_OBJECT TargetObject;
|
|
ULONG Flags;
|
|
LONGLONG TargetOffset;
|
|
} TRANSLATION_TABLE_ENTRY, *PTRANSLATION_TABLE_ENTRY;
|
|
|
|
//
|
|
// The structure below is used in the non-paged temp table. 'IsComplete' and
|
|
// 'WaitingQueueDpc' 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;
|
|
BOOLEAN InTableUpdateQueue;
|
|
BOOLEAN IsMoveEntry;
|
|
PKEVENT WaitEvent;
|
|
LIST_ENTRY WaitingQueueDpc; // These can run in arbitrary context.
|
|
WORK_QUEUE_ITEM WorkItem;
|
|
|
|
//
|
|
// Fields used for the persistent implementation. Protect 'TableUpdate*'
|
|
// with 'Extension->SpinLock'.
|
|
//
|
|
|
|
LIST_ENTRY TableUpdateListEntry;
|
|
LONGLONG FileOffset;
|
|
};
|
|
|
|
//
|
|
// The structure below is used in the persistent snapshot lookup table.
|
|
// Protect everything with 'NonPagedResource'.
|
|
// Protect 'SnapshotFilter', 'DiffAreaFilter' with 'Root->LookupTableMutex'.
|
|
//
|
|
|
|
typedef struct _VSP_LOOKUP_TABLE_ENTRY {
|
|
GUID SnapshotGuid;
|
|
PFILTER_EXTENSION SnapshotFilter;
|
|
PFILTER_EXTENSION DiffAreaFilter;
|
|
LIST_ENTRY SnapshotFilterListEntry;
|
|
LIST_ENTRY DiffAreaFilterListEntry;
|
|
LONGLONG VolumeSnapshotSize;
|
|
LONGLONG SnapshotOrderNumber;
|
|
ULONGLONG SnapshotControlItemFlags;
|
|
LARGE_INTEGER SnapshotTime;
|
|
LONGLONG DiffAreaStartingVolumeOffset;
|
|
LONGLONG ApplicationInfoStartingVolumeOffset;
|
|
LONGLONG DiffAreaLocationDescriptionVolumeOffset;
|
|
LONGLONG InitialBitmapVolumeOffset;
|
|
HANDLE DiffAreaHandle;
|
|
} VSP_LOOKUP_TABLE_ENTRY, *PVSP_LOOKUP_TABLE_ENTRY;
|
|
|
|
//
|
|
// Write protect 'VolumeListEntry' with 'NonPagedResource' and
|
|
// 'Root->Semaphore'.
|
|
// Protect 'FilterListEntry*' with 'Root->Semaphore' and 'Filter->SpinLock'.
|
|
// Protect 'NextAvailable' with 'NonPagedResource'
|
|
// Write Protect 'AllocatedFileSize' with 'NonPagedResource' and
|
|
// 'Root->Semaphore'.
|
|
// Protect 'UnusedAllocationList' with 'NonPagedResource'.
|
|
//
|
|
|
|
struct _VSP_DIFF_AREA_FILE {
|
|
LIST_ENTRY FilterListEntry;
|
|
BOOLEAN FilterListEntryBeingUsed;
|
|
PVOLUME_EXTENSION Extension;
|
|
PFILTER_EXTENSION Filter;
|
|
HANDLE FileHandle;
|
|
LONGLONG NextAvailable;
|
|
LONGLONG AllocatedFileSize;
|
|
LIST_ENTRY UnusedAllocationList;
|
|
LIST_ENTRY ListEntry;
|
|
|
|
//
|
|
// Fields used for the persistent implementation. Protect
|
|
// 'TableUpdateQueue' and 'TableUpdateInProgress' with 'Extension->SpinLock'.
|
|
// Whoever sets 'TableUpdateInProgress' to TRUE owns 'TableUpdateIrp',
|
|
// 'NextFreeTableOffset', 'TableTargetOffset', and 'OldTableTargetOffset'.
|
|
// Protect 'IrpNeeded' with 'Extension->SpinLock'.
|
|
// Protect the initialization of 'IrpReady' with non-paged resource.
|
|
// Protect 'ValidateHandleNeeded' with 'Root->Semaphore'.
|
|
//
|
|
|
|
PIRP TableUpdateIrp;
|
|
ULONG NextFreeTableEntryOffset;
|
|
LONGLONG ApplicationInfoTargetOffset;
|
|
LONGLONG DiffAreaLocationDescriptionTargetOffset;
|
|
LONGLONG InitialBitmapVolumeOffset;
|
|
LONGLONG FirstTableTargetOffset;
|
|
LONGLONG TableTargetOffset;
|
|
LONGLONG NextTableTargetOffset;
|
|
LONGLONG NextTableFileOffset;
|
|
LIST_ENTRY TableUpdateQueue;
|
|
BOOLEAN TableUpdateInProgress;
|
|
BOOLEAN IrpNeeded;
|
|
BOOLEAN ValidateHandleNeeded;
|
|
BOOLEAN NextBlockAllocationInProgress;
|
|
BOOLEAN NextBlockAllocationComplete;
|
|
NTSTATUS StatusOfNextBlockAllocate;
|
|
LIST_ENTRY TableUpdatesInProgress;
|
|
WORK_QUEUE_ITEM WorkItem;
|
|
KEVENT IrpReady;
|
|
};
|
|
|
|
typedef struct _DIFF_AREA_FILE_ALLOCATION {
|
|
LIST_ENTRY ListEntry;
|
|
LONGLONG Offset;
|
|
LONGLONG NLength; // Negative values indicate that the length is unusable.
|
|
} DIFF_AREA_FILE_ALLOCATION, *PDIFF_AREA_FILE_ALLOCATION;
|
|
|
|
typedef struct _OLD_HEAP_ENTRY {
|
|
LIST_ENTRY ListEntry;
|
|
PVOID DiffAreaFileMap;
|
|
} OLD_HEAP_ENTRY, *POLD_HEAP_ENTRY;
|
|
|
|
//
|
|
// {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);
|
|
|
|
//
|
|
// The following definitions are for the persistent volume snapshot on disk
|
|
// data structures.
|
|
//
|
|
|
|
#define VOLSNAP_PERSISTENT_VERSION (1)
|
|
|
|
//
|
|
// Block type definitions.
|
|
//
|
|
|
|
#define VSP_BLOCK_TYPE_START (1)
|
|
#define VSP_BLOCK_TYPE_CONTROL (2)
|
|
#define VSP_BLOCK_TYPE_DIFF_AREA (3)
|
|
#define VSP_BLOCK_TYPE_APP_INFO (4)
|
|
#define VSP_BLOCK_TYPE_DIFF_AREA_LOCATION_DESCRIPTION (5)
|
|
#define VSP_BLOCK_TYPE_INITIAL_BITMAP (6)
|
|
|
|
//
|
|
// Common header for all block types.
|
|
//
|
|
|
|
typedef struct _VSP_BLOCK_HEADER {
|
|
GUID Signature; // Equal to VSP_DIFF_AREA_FILE_GUID.
|
|
ULONG Version; // Equal to VOLSNAP_PERSISTENT_VERSION.
|
|
ULONG BlockType; // The type of block.
|
|
LONGLONG ThisFileOffset; // The file offset of this block.
|
|
LONGLONG ThisVolumeOffset; // The volume offset of this block.
|
|
LONGLONG NextVolumeOffset; // The volume offset of the next block.
|
|
} VSP_BLOCK_HEADER, *PVSP_BLOCK_HEADER;
|
|
|
|
//
|
|
// Start block definition. This will be stored in the last sector of the
|
|
// NTFS boot file.
|
|
//
|
|
|
|
#define BYTES_IN_BOOT_AREA (0x2000)
|
|
#define VSP_START_BLOCK_OFFSET (0x1E00)
|
|
|
|
typedef struct _VSP_BLOCK_START {
|
|
VSP_BLOCK_HEADER Header;
|
|
LONGLONG FirstControlBlockVolumeOffset;
|
|
LONGLONG MaximumDiffAreaSpace;
|
|
} VSP_BLOCK_START, *PVSP_BLOCK_START;
|
|
|
|
//
|
|
// Control Item types definition.
|
|
//
|
|
|
|
#define VSP_CONTROL_ITEM_TYPE_END (0)
|
|
#define VSP_CONTROL_ITEM_TYPE_FREE (1)
|
|
#define VSP_CONTROL_ITEM_TYPE_SNAPSHOT (2)
|
|
#define VSP_CONTROL_ITEM_TYPE_DIFF_AREA (3)
|
|
|
|
//
|
|
// Snapshot flags.
|
|
//
|
|
|
|
#define VSP_SNAPSHOT_CONTROL_ITEM_FLAG_REVERT_MASTER (0x1)
|
|
#define VSP_SNAPSHOT_CONTROL_ITEM_FLAG_READ_WRITE (0x2)
|
|
#define VSP_SNAPSHOT_CONTROL_ITEM_FLAG_VISIBLE (0x4)
|
|
#define VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_CRASHDUMP (0x8)
|
|
#define VSP_SNAPSHOT_CONTROL_ITEM_FLAG_HIBERFIL_COPIED (0x10)
|
|
#define VSP_SNAPSHOT_CONTROL_ITEM_FLAG_PAGEFILE_COPIED (0x20)
|
|
#define VSP_SNAPSHOT_CONTROL_ITEM_FLAG_NO_DIFF_AREA_FILL (0x40)
|
|
#define VSP_SNAPSHOT_CONTROL_ITEM_FLAG_DIRTY_DETECTION (0x80)
|
|
#define VSP_SNAPSHOT_CONTROL_ITEM_FLAG_OFFLINE (0x100)
|
|
#define VSP_SNAPSHOT_CONTROL_ITEM_FLAG_ALL (0x1FC)
|
|
|
|
//
|
|
// Control Item for snapshot.
|
|
//
|
|
|
|
typedef struct _VSP_CONTROL_ITEM_SNAPSHOT {
|
|
ULONG ControlItemType; // Set to VSP_CONTROL_ITEM_TYPE_SNAPSHOT.
|
|
ULONG Reserved;
|
|
LONGLONG VolumeSnapshotSize;
|
|
GUID SnapshotGuid;
|
|
LONGLONG SnapshotOrderNumber;
|
|
ULONGLONG SnapshotControlItemFlags;
|
|
LARGE_INTEGER SnapshotTime;
|
|
} VSP_CONTROL_ITEM_SNAPSHOT, *PVSP_CONTROL_ITEM_SNAPSHOT;
|
|
|
|
//
|
|
// Control Item for diff area file.
|
|
//
|
|
|
|
typedef struct _VSP_CONTROL_ITEM_DIFF_AREA {
|
|
ULONG ControlItemType; // Set to VSP_CONTROL_ITEM_TYPE_DIFF_AREA.
|
|
ULONG Reserved;
|
|
LONGLONG DiffAreaStartingVolumeOffset;
|
|
GUID SnapshotGuid;
|
|
LONGLONG ApplicationInfoStartingVolumeOffset;
|
|
LONGLONG DiffAreaLocationDescriptionVolumeOffset;
|
|
LONGLONG InitialBitmapVolumeOffset;
|
|
} VSP_CONTROL_ITEM_DIFF_AREA, *PVSP_CONTROL_ITEM_DIFF_AREA;
|
|
|
|
//
|
|
// Number of bytes per control information structure.
|
|
//
|
|
|
|
#define VSP_BYTES_PER_CONTROL_ITEM (0x80)
|
|
|
|
//
|
|
// Global snapshot flags.
|
|
//
|
|
|
|
#define VSP_CONTROL_BLOCK_FLAG_REVERT_IN_PROGRESS (0x1)
|
|
|
|
//
|
|
// Control block definition. These will stored consecutively
|
|
// as clusters in "\System Volume Information\{VSP_DIFF_AREA_FILE_GUID}".
|
|
//
|
|
|
|
typedef struct _VSP_BLOCK_CONTROL {
|
|
VSP_BLOCK_HEADER Header;
|
|
} VSP_BLOCK_CONTROL, *PVSP_BLOCK_CONTROL;
|
|
|
|
//
|
|
// The following is the persistent table definition within a diff area file.
|
|
//
|
|
|
|
#define VSP_DIFF_AREA_TABLE_ENTRY_FLAG_MOVE_ENTRY (0x1)
|
|
|
|
typedef struct _VSP_BLOCK_DIFF_AREA_TABLE_ENTRY {
|
|
LONGLONG SnapshotVolumeOffset;
|
|
LONGLONG DiffAreaFileOffset;
|
|
LONGLONG DiffAreaVolumeOffset;
|
|
ULONGLONG Flags;
|
|
} VSP_BLOCK_DIFF_AREA_TABLE_ENTRY, *PVSP_BLOCK_DIFF_AREA_TABLE_ENTRY;
|
|
|
|
//
|
|
// Diff area block structure. The first of these will be stored as the
|
|
// second block of the diff area file named
|
|
// "\System Volume Information\{SnapshotGuid}{VSP_DIFF_AREA_FILE_GUID}".
|
|
//
|
|
|
|
#define VSP_OFFSET_TO_FIRST_TABLE_ENTRY (0x80)
|
|
|
|
typedef struct _VSP_BLOCK_DIFF_AREA {
|
|
VSP_BLOCK_HEADER Header;
|
|
} VSP_BLOCK_DIFF_AREA, *PVSP_BLOCK_DIFF_AREA;
|
|
|
|
//
|
|
// App info block structure. This block will be stored as a block
|
|
// of the diff area file named
|
|
// "\System Volume Information\{SnapshotGuid}{VSP_DIFF_AREA_FILE_GUID}".
|
|
//
|
|
|
|
#define VSP_OFFSET_TO_APP_INFO (0x80)
|
|
#define VSP_MAX_APP_INFO_SIZE (BLOCK_SIZE - VSP_OFFSET_TO_APP_INFO)
|
|
|
|
typedef struct _VSP_BLOCK_APP_INFO {
|
|
VSP_BLOCK_HEADER Header;
|
|
ULONG AppInfoSize;
|
|
} VSP_BLOCK_APP_INFO, *PVSP_BLOCK_APP_INFO;
|
|
|
|
//
|
|
// The following is the definition of a Diff Area Location Descriptor.
|
|
//
|
|
|
|
typedef struct _VSP_DIFF_AREA_LOCATION_DESCRIPTOR {
|
|
LONGLONG VolumeOffset;
|
|
LONGLONG FileOffset;
|
|
LONGLONG Length;
|
|
} VSP_DIFF_AREA_LOCATION_DESCRIPTOR, *PVSP_DIFF_AREA_LOCATION_DESCRIPTOR;
|
|
|
|
//
|
|
// Diff Area File Location Description block structure. This block will
|
|
// be stored as a block of the diff area file named
|
|
// "\System Volume Information\{SnapshotGuid}{VSP_DIFF_AREA_FILE_GUID}".
|
|
//
|
|
|
|
#define VSP_OFFSET_TO_FIRST_LOCATION_DESCRIPTOR (0x80)
|
|
|
|
typedef struct _VSP_BLOCK_DIFF_AREA_LOCATION_DESCRIPTION {
|
|
VSP_BLOCK_HEADER Header;
|
|
} VSP_BLOCK_DIFF_AREA_LOCATION_DESCRIPTION, *PVSP_BLOCK_DIFF_AREA_LOCATION_DESCRIPTION;
|
|
|
|
//
|
|
// Initial Bitmap block structure. This block will be stored as a block of
|
|
// the diff area file named
|
|
// "\System Volume Information\{SnapshotGuid}{VSP_DIFF_AREA_FILE_GUID}".
|
|
//
|
|
|
|
#define VSP_OFFSET_TO_START_OF_BITMAP (0x80)
|
|
|
|
typedef struct _VSP_BLOCK_INITIAL_BITMAP {
|
|
VSP_BLOCK_HEADER Header;
|
|
} VSP_BLOCK_INITIAL_BITMAP, *PVSP_BLOCK_INITIAL_BITMAP;
|