windows-nt/Source/XPSP1/NT/base/fs/ntfs/ntfslog.h

944 lines
25 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
NtfsLog.h
Abstract:
This module defines the Ntfs-specific log file structures.
Author:
Tom Miller [TomM] 21-Jul-1991
Revision History:
--*/
#ifndef _NTFSLOG_
#define _NTFSLOG_
//
// The following type defines the Ntfs log operations.
//
// The comment specifies the record type which follows the record.
// These record types are defined either here or in ntfs.h.
//
typedef enum _NTFS_LOG_OPERATION {
Noop = 0x00, //
CompensationLogRecord = 0x01, //
InitializeFileRecordSegment = 0x02, // FILE_RECORD_SEGMENT_HEADER
DeallocateFileRecordSegment = 0x03, //
WriteEndOfFileRecordSegment = 0x04, // ATTRIBUTE_RECORD_HEADER
CreateAttribute = 0x05, // ATTRIBUTE_RECORD_HEADER
DeleteAttribute = 0x06, //
UpdateResidentValue = 0x07, // (value)
UpdateNonresidentValue = 0x08, // (value)
UpdateMappingPairs = 0x09, // (value = mapping pairs bytes)
DeleteDirtyClusters = 0x0A, // array of LCN_RANGE
SetNewAttributeSizes = 0x0B, // NEW_ATTRIBUTE_SIZES
AddIndexEntryRoot = 0x0C, // INDEX_ENTRY
DeleteIndexEntryRoot = 0x0D, // INDEX_ENTRY
AddIndexEntryAllocation = 0x0E, // INDEX_ENTRY
DeleteIndexEntryAllocation = 0x0F, // INDEX_ENTRY
WriteEndOfIndexBuffer = 0x10, // INDEX_ENTRY
SetIndexEntryVcnRoot = 0x11, // VCN
SetIndexEntryVcnAllocation = 0x12, // VCN
UpdateFileNameRoot = 0x13, // DUPLICATED_INFORMATION
UpdateFileNameAllocation = 0x14, // DUPLICATED_INFORMATION
SetBitsInNonresidentBitMap = 0x15, // BITMAP_RANGE
ClearBitsInNonresidentBitMap = 0x16, // BITMAP_RANGE
HotFix = 0x17, //
EndTopLevelAction = 0x18, //
PrepareTransaction = 0x19, //
CommitTransaction = 0x1A, //
ForgetTransaction = 0x1B, //
OpenNonresidentAttribute = 0x1C, // OPEN_ATTRIBUTE_ENTRY+ATTRIBUTE_NAME_ENTRY
OpenAttributeTableDump = 0x1D, // OPEN_ATTRIBUTE_ENTRY array
AttributeNamesDump = 0x1E, // (all attribute names)
DirtyPageTableDump = 0x1F, // DIRTY_PAGE_ENTRY array
TransactionTableDump = 0x20, // TRANSACTION_ENTRY array
UpdateRecordDataRoot = 0x21, // (value)
UpdateRecordDataAllocation = 0x22 // (value)
} NTFS_LOG_OPERATION, *PNTFS_LOG_OPERATION;
//
// The Ntfs log record header precedes every log record written to
// disk by Ntfs.
//
//
// Log record header.
//
typedef struct _NTFS_LOG_RECORD_HEADER {
//
// Log Operations (LOG_xxx codes)
//
USHORT RedoOperation;
USHORT UndoOperation;
//
// Offset to Redo record, and its length
//
USHORT RedoOffset;
USHORT RedoLength;
//
// Offset to Undo record, and its length. Note, for some Redo/Undo
// combinations, the expected records may be the same, and thus
// these two values will be identical to the above values.
//
USHORT UndoOffset;
USHORT UndoLength;
//
// Open attribute table index to which this update applies. Index 0 is
// always reserved for the MFT itself. The value of this field
// essentially distinguishes two cases for this update, which will be
// referred to as MFT update and nonresident attribute update.
//
// MFT updates are for initialization and deletion of file record
// segments and updates to resident attributes.
//
// Nonresident attribute updates are used to update attributes which
// have been allocated externally to the MFT.
//
USHORT TargetAttribute;
//
// Number of Lcns in use at end of header.
//
USHORT LcnsToFollow;
//
// Byte offset and Vcn for which this update is to be applied. If the
// TargetAttribute is the MFT, then the Vcn will always be the exact
// Vcn of the start of the file record segment being modified, even
// if the modification happens to be in a subsequent cluster of the
// same file record. The byte offset in this case is the offset to
// the attribute being changed. For the Mft, AttributeOffset may be used
// to represent the offset from the start of the attribute record
// at which an update is to be applied.
//
// If the update is to some other (nonresident) attribute, then
// TargetVcn and RecordOffset may be used to calculate the reference
// point for the update. The ClusterBlockOffset refers to the number
// of 512 byte blocks this structure is from the beginning of the
// logged Vcn.
//
// As a bottom line, the exact use of these fields is up to the
// writer of this particular log operation, and the associated
// restart routines for this attribute.
//
USHORT RecordOffset;
USHORT AttributeOffset;
USHORT ClusterBlockOffset;
USHORT Reserved;
VCN TargetVcn;
//
// Run information. This is a variable-length array of LcnsToFollow
// entries, only the first of which is declared. Note that the writer
// always writes log records according to the physical page size on his
// machine, however whenever the log file is being read, no assumption
// is made about page size. This is to facilitate moving disks between
// systems with different page sizes.
//
LCN LcnsForPage[1];
//
// Immediately following the last run is a log-operation-specific record
// whose length may be calculated by subtracting the length of this header
// from the length of the entire record returned by LFS. These records
// are defined below.
//
} NTFS_LOG_RECORD_HEADER, *PNTFS_LOG_RECORD_HEADER;
//
// RESTART AREA STRUCTURES
//
// The following structures are present in the Restart Area.
//
//
// Generic Restart Table
//
// This is a generic table definition for the purpose of describing one
// of the three table structures used at Restart: the Open Attribute Table,
// the Dirty Pages Table, and the Transaction Table. This simple structure
// allows for common initialization and free list management. Allocation
// and Deallocation and lookup by index are extremely fast, while lookup
// by value (only performed in the Dirty Pages Table during Restart) is
// a little slower. I.e., all accesses to these tables during normal
// operation are extremely fast.
//
// If fast access to a table entry by value becomes an issue, then the
// table may be supplemented by an external Generic Table - it is probably
// not a good idea to make the Generic Table be part of the structure
// written to the Log File.
//
// Entries in a Restart Table should start with:
//
// ULONG AllocatedOrNextFree;
//
// An allocated entry will have the pattern RESTART_ENTRY_ALLOCATED
// in this field.
//
#define RESTART_ENTRY_ALLOCATED (0xFFFFFFFF)
typedef struct _RESTART_TABLE {
//
// Entry size, in bytes
//
USHORT EntrySize;
//
// Total number of entries in table
//
USHORT NumberEntries;
//
// Number entries that are allocated
//
USHORT NumberAllocated;
//
// Reserved for alignment
//
USHORT Reserved[3];
//
// Free goal - Offset after which entries should be freed to end of
// list, as opposed to front. At each checkpoint, the table may be
// truncated if there are enough free entries at the end of the list.
// Expressed as an offset from the start of this structure.
//
ULONG FreeGoal;
//
// First Free entry (head of list) and Last Free entry (used to deallocate
// beyond Free Goal). Expressed as an offset from the start of this
// structure.
//
ULONG FirstFree;
ULONG LastFree;
//
// The table itself starts here.
//
} RESTART_TABLE, *PRESTART_TABLE;
//
// Macro to get a pointer to an entry in a Restart Table, from the Table
// pointer and entry index. NOTE - Don't generate the index in a call
// to NtfsAllocateRestartTableIndex within this macro. The macro code
// tends to capture the Table pointer before generating the index. If the
// table needs to grow then the captured value may be invalid.
//
#define GetRestartEntryFromIndex(TBL,INDX) ( \
(PVOID)((PCHAR)(TBL)->Table + (INDX)) \
)
//
// Macro to get an index for an entry in a Restart Table, from the Table
// pointer and entry pointer.
//
#define GetIndexFromRestartEntry(TBL,ENTRY) ( \
(ULONG)((PCHAR)(ENTRY) - (PCHAR)(TBL)->Table) \
)
//
// Macro to see if an entry in a Restart Table is allocated.
//
#define IsRestartTableEntryAllocated(PTR) ( \
(BOOLEAN)(*(PULONG)(PTR) == RESTART_ENTRY_ALLOCATED) \
)
//
// Macro to retrieve the size of a Restart Table in bytes.
//
#define SizeOfRestartTable(TBL) ( \
(ULONG)(((TBL)->Table->NumberEntries * \
(TBL)->Table->EntrySize) + \
sizeof(RESTART_TABLE)) \
)
//
// Macro to see if Restart Table is empty. It is empty if the
// number allocated is zero.
//
#define IsRestartTableEmpty(TBL) (!(TBL)->Table->NumberAllocated)
//
// Macro to see if an index is within the currently allocated size
// for that table.
//
#define IsRestartIndexWithinTable(TBL,INDX) ( \
(BOOLEAN)((INDX) < SizeOfRestartTable(TBL)) \
)
//
// Macros to acquire and release a Restart Table.
//
#define NtfsAcquireExclusiveRestartTable(TBL,WAIT) { \
ExAcquireResourceExclusiveLite( &(TBL)->Resource,(WAIT)); \
}
#define NtfsAcquireSharedStartExRestartTable(TBL,WAIT) { \
ExAcquireSharedStarveExclusive( &(TBL)->Resource,(WAIT)); \
}
#define NtfsAcquireSharedRestartTable(TBL,WAIT) { \
ExAcquireResourceSharedLite( &(TBL)->Resource,(WAIT)); \
}
#define NtfsReleaseRestartTable(TBL) { \
ExReleaseResourceLite(&(TBL)->Resource); \
}
//
// Define some tuning parameters to keep the restart tables a
// reasonable size.
//
#define INITIAL_NUMBER_TRANSACTIONS (5)
#define HIGHWATER_TRANSACTION_COUNT (10)
#define INITIAL_NUMBER_ATTRIBUTES (8)
#define HIGHWATER_ATTRIBUTE_COUNT (16)
//
// Attribute Name Entry. This is a simple structure used to store
// all of the attribute names for the Open Attribute Table during
// checkpoint processing. The Attribute Names record written to the log
// is a series of Attribute Name Entries terminated by an entry with
// Index == NameLength == 0. The end of the table may be tested for by
// looking for either of these fields to be 0, as 0 is otherwise invalid
// for both.
//
// Note that the size of this structure is equal to the overhead for storing
// an attribute name in the table, including the UNICODE_NULL.
//
typedef struct _ATTRIBUTE_NAME_ENTRY {
//
// Index for Attibute with this name in the Open Attribute Table.
//
USHORT Index;
//
// Length of attribute name to follow in bytes, including a terminating
// UNICODE_NULL.
//
USHORT NameLength;
//
// Start of attribute name
//
WCHAR Name[1];
} ATTRIBUTE_NAME_ENTRY, *PATTRIBUTE_NAME_ENTRY;
//
// Open Attribute Table. This is the on-disk structure for version 0.
//
// One entry exists in the Open Attribute Table for each nonresident
// attribute of each file that is open with modify access.
//
// This table is initialized at Restart to the maximum of
// DEFAULT_ATTRIBUTE_TABLE_SIZE or the size of the table in the log file.
// It is maintained in the running system.
//
#pragma pack(4)
typedef struct _OPEN_ATTRIBUTE_ENTRY_V0 {
//
// Entry is allocated if this field contains RESTART_ENTRY_ALLOCATED.
// Otherwise, it is a free link.
//
ULONG AllocatedOrNextFree;
//
// Placeholder for Scb in V0. We use it to point to the index
// in the in-memory structure.
//
ULONG OatIndex;
//
// File Reference of file containing attribute.
//
FILE_REFERENCE FileReference;
//
// Lsn of OpenNonresidentAttribute log record, to distinguish reuses
// of this open file record. Log records referring to this Open
// Attribute Entry Index, but with Lsns older than this field, can
// only occur when the attribute was subsequently deleted - these
// log records can be ignored.
//
LSN LsnOfOpenRecord;
//
// Flag to say if dirty pages seen for this attribute during dirty
// page scan.
//
BOOLEAN DirtyPagesSeen;
//
// Flag to indicate if the pointer in Overlay above is to an Scb or
// attribute name. It is only used during restart when cleaning up
// the open attribute table.
//
BOOLEAN AttributeNamePresent;
//
// Reserved for alignment
//
UCHAR Reserved[2];
//
// The following two fields identify the actual attribute
// with respect to its file. We identify the attribute by
// its type code and name. When the Restart Area is written,
// all of the names for all of the open attributes are temporarily
// copied to the end of the Restart Area.
// The name is not used on disk but must be a 64-bit value.
//
ATTRIBUTE_TYPE_CODE AttributeTypeCode;
LONGLONG AttributeName;
//
// This field is only relevant to indices, i.e., if AttributeTypeCode
// above is $INDEX_ALLOCATION.
//
ULONG BytesPerIndexBuffer;
} OPEN_ATTRIBUTE_ENTRY_V0, *POPEN_ATTRIBUTE_ENTRY_V0;
#pragma pack()
#define SIZEOF_OPEN_ATTRIBUTE_ENTRY_V0 ( \
FIELD_OFFSET( OPEN_ATTRIBUTE_ENTRY_V0, BytesPerIndexBuffer ) + 4 \
)
//
// Auxiliary OpenAttribute data. This is the data that doesn't need to be
// logged.
//
typedef struct OPEN_ATTRIBUTE_DATA {
//
// Queue of these structures attached to the Vcb.
// NOTE - This must be the first entry in this structure.
//
LIST_ENTRY Links;
//
// Index for this entry in the On-disk open attribute table.
//
ULONG OnDiskAttributeIndex;
BOOLEAN AttributeNamePresent;
//
// The following overlay either contains an optional pointer to an
// Attribute Name Entry from the Analysis Phase of Restart, or a
// pointer to an Scb once attributes have been open and in the normal
// running system.
//
// Specifically, after the Analysis Phase of Restart:
//
// AttributeName == NULL if there is no attribute name, or the
// attribute name was captured in the Attribute
// Names Dump in the last successful checkpoint.
// AttributeName != NULL if an OpenNonresidentAttribute log record
// was encountered, and an Attribute Name Entry
// was allocated at that time (and must be
// deallocated when no longer needed).
//
// Once the Nonresident Attributes have been opened during Restart,
// and in the running system, this is an Scb pointer.
//
union {
PWSTR AttributeName;
PSCB Scb;
} Overlay;
//
// Store the unicode string for the attribute name.
//
UNICODE_STRING AttributeName;
} OPEN_ATTRIBUTE_DATA, *POPEN_ATTRIBUTE_DATA;
//
// Open Attribute Table. This is the on-disk structure for version 1 and
// it is the version we always use in-memory.
//
// One entry exists in the Open Attribute Table for each nonresident
// attribute of each file that is open with modify access.
//
// This table is initialized at Restart to the maximum of
// DEFAULT_ATTRIBUTE_TABLE_SIZE or the size of the table in the log file.
// It is maintained in the running system.
//
typedef struct _OPEN_ATTRIBUTE_ENTRY {
//
// Entry is allocated if this field contains RESTART_ENTRY_ALLOCATED.
// Otherwise, it is a free link.
//
ULONG AllocatedOrNextFree;
//
// This field is only relevant to indices, i.e., if AttributeTypeCode
// above is $INDEX_ALLOCATION.
//
ULONG BytesPerIndexBuffer;
//
// The following two fields identify the actual attribute
// with respect to its file. We identify the attribute by
// its type code and name. When the Restart Area is written,
// all of the names for all of the open attributes are temporarily
// copied to the end of the Restart Area.
//
ATTRIBUTE_TYPE_CODE AttributeTypeCode;
//
// Flag to say if dirty pages seen for this attribute during dirty
// page scan.
//
BOOLEAN DirtyPagesSeen;
CHAR Unused[3];
//
// File Reference of file containing attribute.
//
FILE_REFERENCE FileReference;
//
// Lsn of OpenNonresidentAttribute log record, to distinguish reuses
// of this open file record. Log records referring to this Open
// Attribute Entry Index, but with Lsns older than this field, can
// only occur when the attribute was subsequently deleted - these
// log records can be ignored.
//
LSN LsnOfOpenRecord;
//
// Point to the OpenAttribute data.
//
union {
POPEN_ATTRIBUTE_DATA OatData;
ULONGLONG Alignment;
};
} OPEN_ATTRIBUTE_ENTRY, *POPEN_ATTRIBUTE_ENTRY;
//
// VOID
// NtfsFreeAllOpenAttributeData (
// IN PVCB vCB
// );
//
#define NtfsFreeAllOpenAttributeData(V) { \
while (!IsListEmpty( &(V)->OpenAttributeData )) { \
POPEN_ATTRIBUTE_DATA _Next = CONTAINING_RECORD( (V)->OpenAttributeData.Flink, \
OPEN_ATTRIBUTE_DATA, \
Links ); \
NtfsFreeOpenAttributeData( _Next ); \
} \
}
//
// Dirty Pages Table - Version 0
//
// This entry is for restart version 0. It is inadvertently misaligned.
//
// One entry exists in the Dirty Pages Table for each page which is
// dirty at the time the Restart Area is written.
//
// This table is initialized at Restart to the maximum of
// DEFAULT_DIRTY_PAGES_TABLE_SIZE or the size of the table in the log file.
// It is *not* maintained in the running system.
//
#pragma pack(4)
typedef struct _DIRTY_PAGE_ENTRY_V0 {
//
// Entry is allocated if this field contains RESTART_ENTRY_ALLOCATED.
// Otherwise, it is a free link.
//
ULONG AllocatedOrNextFree;
//
// Target attribute index. This is the index into the Open Attribute
// Table to which this dirty page entry applies.
//
ULONG TargetAttribute;
//
// Length of transfer, in case this is the end of file, and we cannot
// write an entire page.
//
ULONG LengthOfTransfer;
//
// Number of Lcns in the array at end of this structure. See comment
// with this array.
//
ULONG LcnsToFollow;
//
// Reserved for alignment
//
ULONG Reserved;
//
// Vcn of dirty page.
//
VCN Vcn;
//
// OldestLsn for log record for which the update has not yet been
// written through to disk.
//
LSN OldestLsn;
//
// Run information. This is a variable-length array of LcnsToFollow
// entries, only the first of which is declared. Note that the writer
// always writes pages according to the physical page size on his
// machine, however whenever the log file is being read, no assumption
// is made about page size. This is to facilitate moving disks between
// systems with different page sizes.
//
LCN LcnsForPage[1];
} DIRTY_PAGE_ENTRY_V0, *PDIRTY_PAGE_ENTRY_V0;
#pragma pack()
//
// Dirty Pages Table - Version 1
//
// This version correctly aligns the 64-bit fields.
//
// One entry exists in the Dirty Pages Table for each page which is
// dirty at the time the Restart Area is written.
//
// This table is initialized at Restart to the maximum of
// DEFAULT_DIRTY_PAGES_TABLE_SIZE or the size of the table in the log file.
// It is *not* maintained in the running system.
//
typedef struct _DIRTY_PAGE_ENTRY {
//
// Entry is allocated if this field contains RESTART_ENTRY_ALLOCATED.
// Otherwise, it is a free link.
//
ULONG AllocatedOrNextFree;
//
// Target attribute index. This is the index into the Open Attribute
// Table to which this dirty page entry applies.
//
ULONG TargetAttribute;
//
// Length of transfer, in case this is the end of file, and we cannot
// write an entire page.
//
ULONG LengthOfTransfer;
//
// Number of Lcns in the array at end of this structure. See comment
// with this array.
//
ULONG LcnsToFollow;
//
// Vcn of dirty page.
//
VCN Vcn;
//
// OldestLsn for log record for which the update has not yet been
// written through to disk.
//
LSN OldestLsn;
//
// Run information. This is a variable-length array of LcnsToFollow
// entries, only the first of which is declared. Note that the writer
// always writes pages according to the physical page size on his
// machine, however whenever the log file is being read, no assumption
// is made about page size. This is to facilitate moving disks between
// systems with different page sizes.
//
LCN LcnsForPage[1];
} DIRTY_PAGE_ENTRY, *PDIRTY_PAGE_ENTRY;
//
// Transaction Table
//
// One transaction entry exists for each existing transaction at the time
// the Restart Area is written.
//
// Currently only local transactions are supported, and the transaction
// ID is simply used to index into this table.
//
// This table is initialized at Restart to the maximum of
// DEFAULT_TRANSACTION_TABLE_SIZE or the size of the table in the log file.
// It is maintained in the running system.
//
typedef struct _TRANSACTION_ENTRY {
//
// Entry is allocated if this field contains RESTART_ENTRY_ALLOCATED.
// Otherwise, it is a free link.
//
ULONG AllocatedOrNextFree;
//
// Transaction State
//
UCHAR TransactionState;
//
// Reserved for proper alignment
//
UCHAR Reserved[3];
//
// First Lsn for transaction. This tells us how far back in the log
// we may have to read to abort the transaction.
//
LSN FirstLsn;
//
// PreviousLsn written for the transaction and UndoNextLsn (next record
// which should be undone in the event of a rollback.
//
LSN PreviousLsn;
LSN UndoNextLsn;
//
// Number of of undo log records pending abort, and total undo size.
//
ULONG UndoRecords;
LONG UndoBytes;
} TRANSACTION_ENTRY, *PTRANSACTION_ENTRY;
//
// Restart record
//
// The Restart record used by NTFS is small, and it only describes where
// the above information has been written to the log. The above records
// may be considered logically part of NTFS's restart area.
//
typedef struct _RESTART_AREA {
//
// Version numbers of NTFS Restart Implementation
//
ULONG MajorVersion;
ULONG MinorVersion;
//
// Lsn of Start of Checkpoint. This is the Lsn at which the Analysis
// Phase of Restart must begin.
//
LSN StartOfCheckpoint;
//
// Lsns at which the four tables above plus the attribute names reside.
//
LSN OpenAttributeTableLsn;
LSN AttributeNamesLsn;
LSN DirtyPageTableLsn;
LSN TransactionTableLsn;
//
// Lengths of the above structures in bytes.
//
ULONG OpenAttributeTableLength;
ULONG AttributeNamesLength;
ULONG DirtyPageTableLength;
ULONG TransactionTableLength;
//
// Oldest Usn from which scan must occur to pickup all files which
// have not been through cleanup.
//
USN LowestOpenUsn;
LSN CurrentLsnAtMount;
ULONG BytesPerCluster;
ULONG Reserved;
//
// Keep some additional information about the Usn journal so we
// can reduce the amount of caching we do.
//
FILE_REFERENCE UsnJournalReference;
LONGLONG UsnCacheBias;
} RESTART_AREA, *PRESTART_AREA;
//
// This symbols is used to accept Restart Areas with or without the OldestUsn
//
#define SIZEOF_OLD_RESTART_AREA (FIELD_OFFSET( RESTART_AREA, LowestOpenUsn ))
//
// RECORD STRUCTURES USED BY LOG RECORDS
//
//
// Set new attribute sizes
//
typedef struct _NEW_ATTRIBUTE_SIZES {
LONGLONG AllocationSize;
LONGLONG ValidDataLength;
LONGLONG FileSize;
LONGLONG TotalAllocated;
} NEW_ATTRIBUTE_SIZES, *PNEW_ATTRIBUTE_SIZES;
#define SIZEOF_FULL_ATTRIBUTE_SIZES ( \
sizeof( NEW_ATTRIBUTE_SIZES ) \
)
#define SIZEOF_PARTIAL_ATTRIBUTE_SIZES ( \
FIELD_OFFSET( NEW_ATTRIBUTE_SIZES, TotalAllocated ) \
)
//
// Describe a bitmap range
//
typedef struct _BITMAP_RANGE {
ULONG BitMapOffset;
ULONG NumberOfBits;
} BITMAP_RANGE, *PBITMAP_RANGE;
//
// Describe a range of Lcns
//
typedef struct _LCN_RANGE {
LCN StartLcn;
LONGLONG Count;
} LCN_RANGE, *PLCN_RANGE;
#endif // _NTFSLOG_