Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1167 lines
52 KiB

/*++
Module Name:
frsexts.cxx
Abstract:
Author:
Sudarshan Chitre (sudarc) 12-May-1999
Revision History:
12-May-1999 sudarc
--*/
#include "frsexts.h"
WINDBG_EXTENSION_APIS ExtensionApis;
HANDLE ProcessHandle = 0;
BOOL fKD = 0;
#define MAX_ARGS 4
//
// stuff not common to kernel-mode and user-mode DLLs
//
#undef DECLARE_API
#define DECLARE_API(s) \
VOID \
s( \
HANDLE hCurrentProcess, \
HANDLE hCurrentThread, \
DWORD dwCurrentPc, \
PWINDBG_EXTENSION_APIS pExtensionApis, \
LPSTR lpArgumentString \
)
#define INIT_DPRINTF() { if (!fKD) ExtensionApis = *pExtensionApis; ProcessHandle = hCurrentProcess; }
#define MIN(x, y) ((x) < (y)) ? x:y
// define our own operators new and delete, so that we do not have to include the crt
void * __cdecl
::operator new(size_t dwBytes)
{
void *p;
p = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytes);
return (p);
}
void __cdecl
::operator delete (void *p)
{
HeapFree(GetProcessHeap(), 0, p);
}
BOOL
GetData(IN ULONG_PTR dwAddress, IN LPVOID ptr, IN ULONG size, IN PCSTR type )
{
BOOL b;
ULONG BytesRead;
ULONG count;
if (fKD == 0)
{
return ReadProcessMemory(ProcessHandle, (LPVOID) dwAddress, ptr, size, 0);
}
while( size > 0 )
{
count = MIN( size, 3000 );
b = ReadMemory((ULONG) dwAddress, ptr, count, &BytesRead );
if (!b || BytesRead != count )
{
if (NULL == type)
{
type = "unspecified" ;
}
return FALSE;
}
dwAddress += count;
size -= count;
ptr = (LPVOID)((ULONG_PTR)ptr + count);
}
return TRUE;
}
char *Days[] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
char *Months[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
VOID
FileTimeToString(
FILETIME *FileTime,
PCHAR Buffer
)
/*++
Routine Description:
Convert a FileTime (UTC time) to an ANSI date/time string in the
local time zone.
Arguments:
Time - ptr to a FILETIME
Str - a string of at least TIME_STRING_LENGTH bytes to receive the time.
Return Value:
None
--*/
{
FILETIME LocalFileTime;
SYSTEMTIME SystemTime;
Buffer[0] = '\0';
strcpy(Buffer, "Time???");
if (FileTime->dwHighDateTime != 0 || FileTime->dwLowDateTime != 0)
{
if (!FileTimeToLocalFileTime(FileTime, &LocalFileTime) ||
!FileTimeToSystemTime(&LocalFileTime, &SystemTime))
{
return;
}
sprintf(
Buffer,
"%s %s %2d, %4d %02d:%02d:%02d",
Days[SystemTime.wDayOfWeek],
Months[SystemTime.wMonth - 1],
SystemTime.wDay,
SystemTime.wYear,
SystemTime.wHour,
SystemTime.wMinute,
SystemTime.wSecond);
}
return;
}
#define DMPGUID(_TEXT_,_Guid_) \
{ \
dprintf((_TEXT_)); \
dprintf("%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x\n", \
(_Guid_).Data1, \
(_Guid_).Data2, \
(_Guid_).Data3, \
(_Guid_).Data4[0], \
(_Guid_).Data4[1], \
(_Guid_).Data4[2], \
(_Guid_).Data4[3], \
(_Guid_).Data4[4], \
(_Guid_).Data4[5], \
(_Guid_).Data4[6], \
(_Guid_).Data4[7]); \
}
#define DMPPGUID(_TEXT_,_pGuid_) \
{ \
BOOL bDmpGuid; \
BYTE bufDmpGuid[sizeof(GUID)]; \
dprintf((_TEXT_)); \
bDmpGuid = GetData((ULONG)(_pGuid_), &bufDmpGuid, sizeof(bufDmpGuid), NULL);\
if ( !bDmpGuid ) { \
dprintf("<Error reading memory>\n"); \
} else { \
dprintf("%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x\n", \
((GUID *)(bufDmpGuid))->Data1, \
((GUID *)(bufDmpGuid))->Data2, \
((GUID *)(bufDmpGuid))->Data3, \
((GUID *)(bufDmpGuid))->Data4[0], \
((GUID *)(bufDmpGuid))->Data4[1], \
((GUID *)(bufDmpGuid))->Data4[2], \
((GUID *)(bufDmpGuid))->Data4[3], \
((GUID *)(bufDmpGuid))->Data4[4], \
((GUID *)(bufDmpGuid))->Data4[5], \
((GUID *)(bufDmpGuid))->Data4[6], \
((GUID *)(bufDmpGuid))->Data4[7]); \
\
} \
}
#define DMPGNAME(_TEXT_,_pGname_) \
{ \
BOOL bDmpGname; \
BYTE bufDmpGname[sizeof(GNAME)];\
BYTE DmpName[MAX_PATH * 2]; \
UINT count = 0; \
bDmpGname = GetData((ULONG)(_pGname_), &bufDmpGname, sizeof(bufDmpGname), NULL);\
if ( !bDmpGname ) { \
dprintf((_TEXT_)); \
dprintf("<Error reading memory>\n"); \
} else { \
DMPPGUID((_TEXT_),((GNAME *)bufDmpGname)->Guid); \
dprintf((_TEXT_)); \
if (((GNAME *)bufDmpGname)->Name == NULL) { \
dprintf("<null>\n"); \
} else { \
while (count < MAX_PATH * 2 && bDmpGname) { \
bDmpGname = GetData((ULONG)(((GNAME *)bufDmpGname)->Name) + count, &DmpName[count], sizeof(BYTE), NULL);\
count++; \
} \
\
dprintf("%ws\n",(WCHAR *)DmpName); \
} \
} \
}
#define DMPQUAD(_TEXT_,_Fid_) \
{ \
dprintf((_TEXT_)); \
dprintf("%08x %08x\n",(ULONG)((_Fid_)>>32) ,(ULONG)(_Fid_)); \
}
#define DMPTIME(_TEXT_,_Time_) \
{ \
CHAR TimeStr[TIME_STRING_LENGTH]; \
FileTimeToString((FILETIME *)&(_Time_),TimeStr); \
dprintf((_TEXT_)); \
dprintf("%s\n",TimeStr); \
}
#define DMPSTRW(_TEXT_,_pStr_) \
{ \
UINT count = 0; \
BOOL bDmpStrW = TRUE; \
BYTE DmpStr[MAX_PATH * 2]; \
while (count < MAX_PATH * 2 && bDmpStrW) { \
bDmpStrW = GetData((ULONG)(_pStr_) + count, &DmpStr[count], sizeof(BYTE), NULL);\
count++; \
} \
dprintf((_TEXT_)); \
dprintf("%ws\n",(WCHAR *)DmpStr); \
}
//
// Common print functions for all the data structures.
//
VOID
do_coe(
PCHANGE_ORDER_ENTRY ChangeOrder
)
/*
typedef struct _CHANGE_ORDER_ENTRY_ {
GENERIC_HASH_ENTRY_HEADER HashEntryHeader; // Change Order hash Table support
UNICODE_STRING UFileName; // Used in renames to make file name bigger
ULONG EntryFlags; // misc state flags. See below.
ULONG CoMorphGenCount; // for debugging.
//
// Change order process list management.
//
LIST_ENTRY ProcessList; // Link on the change order process list.
ULONG TimeToRun; // Time to process the change order.
ULONG EntryCreateTime; // Tick Count at entry create time.
SINGLE_LIST_ENTRY DupCoList; // Duplicate change order list.
//
//
ULONG DirNestingLevel; // Number levels file is down in tree.
ULONGLONG FileReferenceNumber; // File's FID
ULONGLONG ParentFileReferenceNumber; // File's parent FID
ULONGLONG OriginalParentFid; // For rename processing
ULONGLONG NewParentFid; // For rename processing
ULONGLONG NameConflictHashValue; // Key value for NameConflict table cleanup.
ULONG StreamLastMergeSeqNum; // Stream seq num of last Usn record merged with this CO.
PREPLICA_THREAD_CTX RtCtx; // For DB access during CO processing.
GUID *pParentGuid; // ptr to the File's parent Guid in CoCmd.
//
// The joinguid is a cxtion's session id and, in this case,
// is used to retry change orders that were accepted by
// the change order accept thread for a cxtion that has since
// unjoined from its partner. The change orders for previous
// sessions are retried because they are out-of-order wrt the
// change orders for the current session id. In other words,
// order is maintained per session by coordinating the partners
// at join time.
GUID JoinGuid; // Cxtion's session id
// undefined if local co
//
// Remote and control change orders are associated with a cxtion.
// If this field is non-null, then the field
// ChangeOrderCount has been incremente for this change
// order. The count should be decremented when the
// change order is freed in ChgOrdIssueCleanup().
//
PCXTION Cxtion; // NULL if local co
//
// Issue cleanup flags -- As a change order is processed it acquires
// various resources that must be released when it retires or goes thru
// retry. The ISCU flag bits below are used to set these bits. Note:
// Not all bits may be set here. Some may get set just before the CO goes
// thru cleanup.
//
ULONG IssueCleanup;
//
// Needed to dampen basic info changes (e.g., resetting the archive bit)
// Copied from the idtable entry when the change order is created and
// used to update the change order when the change order is retired.
//
ULONG FileAttributes;
LARGE_INTEGER FileCreateTime;
LARGE_INTEGER FileWriteTime;
//
// Change order command parameters.
// (must be last since it ends with FileName)
//
CHANGE_ORDER_COMMAND Cmd;
} CHANGE_ORDER_ENTRY, *PCHANGE_ORDER_ENTRY;
*/
{
PWCHAR FileName = NULL;
dprintf("Dumping CHANGE_ORDER_ENTRY.\n\n");
dprintf("HashEntryHeader : Address( 0x%x )\n",ChangeOrder->HashEntryHeader);
dprintf("FileNameLength : %d\n",ChangeOrder->UFileName.Length);
FileName = new WCHAR((ChangeOrder->UFileName.Length)/2 + 1);
GetData((ULONG)(ChangeOrder->UFileName.Buffer),(BYTE*)FileName,ChangeOrder->UFileName.Length,NULL);
FileName[(ChangeOrder->UFileName.Length)/2] = L'\0';
dprintf("FileName : Address( 0x%x )\n",ChangeOrder->UFileName.Buffer);
dprintf("FileName : %ws\n",FileName);
delete FileName;
dprintf("EntryFlags : 0x%x\n",ChangeOrder->EntryFlags);
dprintf("CoMorphGenCount : %d\n",ChangeOrder->CoMorphGenCount);
dprintf("ProcessList : Address( 0x%x )\n",ChangeOrder->ProcessList);
dprintf("TimeToRun : %d\n",ChangeOrder->TimeToRun);
dprintf("EntryCreateTime : %d\n",ChangeOrder->EntryCreateTime);
dprintf("DupCoList : Address( 0x%x )\n",ChangeOrder->DupCoList);
dprintf("DirNestingLevel : %d\n",ChangeOrder->DirNestingLevel);
DMPQUAD("FileReferenceNumber : ",ChangeOrder->FileReferenceNumber);
DMPQUAD("ParentFileReferenceNumber : ",ChangeOrder->ParentFileReferenceNumber);
DMPQUAD("OriginalParentFid : ",ChangeOrder->OriginalParentFid);
DMPQUAD("NewParentFid : ",ChangeOrder->NewParentFid);
DMPQUAD("NameConflictHashValue : ",ChangeOrder->NameConflictHashValue);
dprintf("StreamLastMergeSeqNum : %d\n",ChangeOrder->StreamLastMergeSeqNum);
dprintf("RtCtx : Address( 0x%x )\n",ChangeOrder->RtCtx);
DMPPGUID("pParentGuid : ",ChangeOrder->pParentGuid);
DMPGUID("JoinGuid : ",ChangeOrder->JoinGuid);
dprintf("Cxtion : Address( 0x%x )\n",ChangeOrder->Cxtion);
dprintf("IssueCleanup : 0x%x\n",ChangeOrder->IssueCleanup);
dprintf("FileAttributes : 0x%x\n",ChangeOrder->FileAttributes);
DMPTIME("FileCreateTime : ",ChangeOrder->FileCreateTime);
DMPTIME("FileWriteTime : ",ChangeOrder->FileWriteTime);
dprintf("Cmd : Address( 0x%x )\n",ChangeOrder->Cmd);
}
VOID
do_coc(
PCHANGE_ORDER_COMMAND Cmd
)
/*
typedef struct _CHANGE_ORDER_RECORD_ {
ULONG SequenceNumber; // Unique sequence number for change order.
ULONG Flags; // Change order flags
ULONG IFlags; // These flags can ONLY be updated with interlocked exchange.
ULONG State; // State is sep DWORD to avoid locking.
ULONG ContentCmd; // File content changes from UsnReason
union {
ULONG LocationCmd;
CO_LOCATION_CMD Field; // File Location command
} Lcmd;
ULONG FileAttributes;
ULONG FileVersionNumber; // The file version number, inc on each close.
ULONG PartnerAckSeqNumber; // Save seq number for Partner Ack.
ULONGLONG FileSize;
ULONGLONG FileOffset; // The current committed progress for staging file.
ULONGLONG FrsVsn; // Originator Volume sequence number
bugbug("perf: FileUsn and JrnlUsn can probably be combined")
USN FileUsn; // The USN of the file must match on the Fetch request.
USN JrnlUsn; // USN of last journal record contributing to this CO.
USN JrnlFirstUsn; // USN of first journal record contributing to this CO.
struct _REPLICA *OriginalReplica; // Contains Replica ID when in DB
struct _REPLICA *NewReplica; // Contains Replica ID when in DB
GUID ChangeOrderGuid; // Guid that identifies the change order everywhere.
GUID OriginatorGuid; // The GUID of the originating member
GUID FileGuid; // The obj ID of the file
GUID OldParentGuid; // The Obj ID of the file's original parent directory
GUID NewParentGuid; // The Obj ID of the file's current parent directory
GUID CxtionGuid; // The obj ID of remote CO connection.
ULONGLONG Spare1Ull;
ULONGLONG Spare2Ull;
GUID Spare1Guid;
GUID Spare2Guid;
PWCHAR Spare1Wcs;
PWCHAR Spare2Wcs;
PVOID Spare1Bin;
PVOID Spare2Bin;
LARGE_INTEGER EventTime; // The USN Journal Entry Timestamp.
USHORT FileNameLength;
WCHAR FileName[MAX_PATH+1]; // The file name. (Must be Last)
} CHANGE_ORDER_COMMAND, *PCHANGE_ORDER_COMMAND,
*/
{
PWCHAR FileName = NULL;
dprintf("Dumping CHANGE_ORDER_COMMAND.\n\n");
dprintf("SequenceNumber : %d\n",Cmd->SequenceNumber);
dprintf("Flags : 0x%x\n",Cmd->Flags);
dprintf("IFlags : 0x%x\n",Cmd->IFlags);
dprintf("State : %d\n",Cmd->State);
dprintf("ContentCmd : 0x%x\n",Cmd->ContentCmd);
dprintf("LocationCmd : 0x%x\n",Cmd->Lcmd.LocationCmd);
dprintf("FileAttributes : 0x%x\n",Cmd->FileAttributes);
dprintf("FileVersionNumber : %d\n",Cmd->FileVersionNumber);
dprintf("PartnerAckSeqNumber : %d\n",Cmd->PartnerAckSeqNumber);
DMPQUAD("FileSize : ",Cmd->FileSize);
DMPQUAD("FileOffset : ",Cmd->FileOffset);
DMPQUAD("FrsVsn : ",Cmd->FrsVsn);
DMPQUAD("FileUsn : ",Cmd->FileUsn);
DMPQUAD("JrnlUsn : ",Cmd->JrnlUsn);
DMPQUAD("JrnlFirstUsn : ",Cmd->JrnlFirstUsn);
dprintf("OriginalReplicaNum : %d\n",Cmd->OriginalReplicaNum);
dprintf("NewReplicaNum : %d\n",Cmd->NewReplicaNum);
DMPGUID("ChangeOrderGuid : ",Cmd->ChangeOrderGuid);
DMPGUID("OriginatorGuid : ",Cmd->OriginatorGuid);
DMPGUID("FileGuid : ",Cmd->FileGuid);
DMPGUID("OldParentGuid : ",Cmd->OldParentGuid);
DMPGUID("NewParentGuid : ",Cmd->NewParentGuid);
DMPGUID("CxtionGuid : ",Cmd->CxtionGuid);
DMPTIME("EventTime : ",Cmd->EventTime);
dprintf("FileNameLength : %d\n",Cmd->FileNameLength);
dprintf("FileName : %ws\n",Cmd->FileName);
}
VOID
do_cxt(
PCXTION pCxtion
)
/*
typedef struct _CXTION CXTION, *PCXTION;
struct _CXTION {
FRS_NODE_HEADER Header; // memory management
ULONG State; // Incore state
ULONG Flags; // misc flags
BOOL Inbound; // TRUE if inbound cxtion *
BOOL JrnlCxtion; // TRUE if this Cxtion struct is for the local NTFS Journal
PGNAME Name; // Cxtion name/guid from the DS *
PGNAME Partner; // Partner's name/guid from the DS *
PWCHAR PartnerDnsName; // partner's DNS name from the DS *
PWCHAR PartnerPrincName; // partner's server principle name *
PWCHAR PartnerSid; // partner's sid (string) *
PWCHAR PartSrvName; // Partner's server name
ULONG PartnerAuthLevel; // Authentication level *
PGEN_TABLE VVector; // partner's version vector
PSCHEDULE Schedule; // schedule *
ULONG TerminationCoSeqNum;// The Seq Num of most recent Termination CO inserted.
PCOMMAND_SERVER VvJoinCs; // command server for vvjoins
struct _COMMAND_PACKET *JoinCmd; // check join status; rejoin if needed
// NULL == no delayed cmd outstanding
ULONGLONG LastJoinTime; // The time of the last successful join on this cxtion.
GUID JoinGuid; // Unique id for this join
GUID ReplicaVersionGuid; // partner's originator guid
DWORD CommQueueIndex; // Comm layer queue for sending pkts
DWORD ChangeOrderCount; // remote/control change orders pending
PGEN_TABLE CoeTable; // table of idle change orders
struct _COMMAND_PACKET *CommTimeoutCmd; // Timeout (waitable timer) packet
DWORD UnjoinTrigger; // DBG force unjoin in # remote cos
DWORD UnjoinReset; // reset force unjoin trigger
PFRS_QUEUE CoProcessQueue; // If non-null then Unidle the queue when
// JOIN succeeds or fails.
ULONG CommPkts; // Number of comm pkts
ULONG Penalty; // Penalty in Milliseconds
PCOMM_PACKET ActiveJoinCommPkt; // Don't flood Q w/many join pkts
ULONG PartnerMajor; // From comm packet
ULONG PartnerMinor; // From comm packet
struct _OUT_LOG_PARTNER_ *OLCtx; // Outbound Log Context for this connection.
struct _HASHTABLEDATA_REPLICACONN *PerfRepConnData; // PERFMON counter data structure
};
*/
{
dprintf("Dumping CXTION.\n\n");
dprintf("Header : Address ( 0x%x )\n",pCxtion->Header);
dprintf("State : %d\n",pCxtion->State);
dprintf("Flags : 0x%x\n",pCxtion->Flags);
dprintf("Inbound : %d\n",pCxtion->Inbound);
dprintf("JrnlCxtion : %d\n",pCxtion->JrnlCxtion);
DMPGNAME("Name : ",pCxtion->Name);
DMPGNAME("Partner : ",pCxtion->Partner);
dprintf("PartnerDnsName : %ws\n",pCxtion->PartnerDnsName);
dprintf("PartnerPrincName : %ws\n",pCxtion->PartnerPrincName);
dprintf("PartnerSid : %ws\n",pCxtion->PartnerSid);
dprintf("PartSrvName : %ws\n",pCxtion->PartSrvName);
dprintf("PartnerAuthLevel : %d\n",pCxtion->PartnerAuthLevel);
dprintf("VVector : Address ( 0x%x )\n",pCxtion->VVector);
dprintf("Schedule : Address ( 0x%x )\n",pCxtion->Schedule);
dprintf("TerminationCoSeqNum : %d\n",pCxtion->TerminationCoSeqNum);
dprintf("VvJoinCs : Address ( 0x%x )\n",pCxtion->VvJoinCs);
dprintf("JoinCmd : Address ( 0x%x )\n",pCxtion->JoinCmd);
DMPTIME("LastJoinTime : ",pCxtion->LastJoinTime);
DMPGUID("JoinGuid : ",pCxtion->JoinGuid);
DMPGUID("ReplicaVersionGuid : ",pCxtion->ReplicaVersionGuid);
dprintf("CommQueueIndex : %d\n",pCxtion->CommQueueIndex);
dprintf("ChangeOrderCount : %d\n",pCxtion->ChangeOrderCount);
dprintf("CoeTable : Address ( 0x%x )\n",pCxtion->CoeTable);
dprintf("CommTimeoutCmd : Address ( 0x%x )\n",pCxtion->CommTimeoutCmd);
dprintf("UnjoinTrigger : %d\n",pCxtion->UnjoinTrigger);
dprintf("UnjoinReset : %d\n",pCxtion->UnjoinReset);
dprintf("CoProcessQueue : Address ( 0x%x )\n",pCxtion->CoProcessQueue);
dprintf("CommPkts : %d\n",pCxtion->CommPkts);
dprintf("Penalty : %d\n",pCxtion->Penalty);
dprintf("ActiveJoinCommPkt : Address ( 0x%x )\n",pCxtion->ActiveJoinCommPkt);
dprintf("PartnerMajor : %d\n",pCxtion->PartnerMajor);
dprintf("PartnerMinor : %d\n",pCxtion->PartnerMinor);
dprintf("OLCtx : Address ( 0x%x )\n",pCxtion->OLCtx);
dprintf("PerfRepConnData : Address ( 0x%x )\n",pCxtion->PerfRepConnData);
}
VOID
do_olp(
POUT_LOG_PARTNER pOlp
)
/*
typedef struct _OUT_LOG_PARTNER_ {
FRS_NODE_HEADER Header; // Memory alloc
LIST_ENTRY List; // Link on the change order set list. (DONT MOVE)
ULONG Flags; // misc state flags. see below.
ULONG State; // Current state of this outbound partner.
SINGLE_LIST_ENTRY SaveList; // The link for the DB save list.
ULONG COLxRestart; // Restart point for Leading change order index.
ULONG COLxVVJoinDone; // COLx where VVJoin Finished and was rolled back.
ULONG COLx; // Leading change order index / sequence number.
ULONG COTx; // Trailing change order index / sequence number.
ULONG COTxLastSaved; // COTx value last saved in DB.
ULONG COTxNormalModeSave;// Saved Normal Mode COTx while in VV Join Mode.
ULONG COTslot; // Slot in Ack Vector corresponding to COTx.
ULONG OutstandingCos; // The current number of change orders outstanding.
ULONG OutstandingQuota; // The maximum number of COs outstanding.
ULONG AckVector[ACK_VECTOR_LONGS]; // The partner ack vector.
PCXTION Cxtion; // The partner connection. Has Guid and VVector.
} OUT_LOG_PARTNER, *POUT_LOG_PARTNER;
*/
{
dprintf("Dumping OUT_LOG_PARTNER.\n\n");
dprintf("Header : Address ( 0x%x )\n",pOlp->Header);
dprintf("List : Address ( 0x%x )\n",pOlp->List);
dprintf("Flags : 0x%x\n",pOlp->Flags);
dprintf("State : %d\n",pOlp->State);
dprintf("SaveList : Address ( 0x%x )\n",pOlp->SaveList);
dprintf("COLxRestart : %d\n",pOlp->COLxRestart);
dprintf("COLxVVJoinDone : %d\n",pOlp->COLxVVJoinDone);
dprintf("COLx : %d\n",pOlp->COLx);
dprintf("COTx : %d\n",pOlp->COTx);
dprintf("COTxLastSaved : %d\n",pOlp->COTxLastSaved);
dprintf("COTxNormalModeSave : %d\n",pOlp->COTxNormalModeSave);
dprintf("COTslot : %d\n",pOlp->COTslot);
dprintf("OutstandingCos : %d\n",pOlp->OutstandingCos);
dprintf("OutstandingQuota : %d\n",pOlp->OutstandingQuota);
}
VOID
do_rep(
PREPLICA pReplica
)
/*
typedef struct _REPLICA {
FRS_NODE_HEADER Header; // memory management
CRITICAL_SECTION ReplicaLock; // protects filter list (for now)
ULONG ReferenceCount;
ULONG CnfFlags; // From the config record
ULONG ReplicaSetType; // Type of replica set
BOOL Consistent; // replica is consistent
BOOL IsOpen; // database table is open
BOOL IsJournaling; // journal has been started
BOOL IsAccepting; // accepting comm requests
BOOL NeedsUpdate; // needs updating in the database
BOOL IsSeeding; // Seeding thread is deployed
BOOL IsSysvolReady; // SysvolReady is set to 1
LIST_ENTRY ReplicaList; // Link all replicas together
ULONG ServiceState; // stop, started, ...
FRS_ERROR_CODE FStatus; // error
PFRS_QUEUE Queue; // controlled by the command server
PGNAME ReplicaName; // Set name/Server guid from the DS
ULONG ReplicaNumber; // Internal id (name)
PGNAME MemberName; // Member name/guid from the DS
PGNAME SetName; // Set/guid name from the DS
GUID *ReplicaRootGuid; // guid assigned to Root dir
GUID ReplicaVersionGuid; // originator guid for version vector
PSCHEDULE Schedule; // schedule
PGEN_TABLE VVector; // Version vector
PGEN_TABLE Cxtions; // in/outbound cxtions
PWCHAR Root; // Root path
PWCHAR Stage; // Staging path
PWCHAR NewStage; // This maps to the current staging path in the
// DS. NewStage will be the one written to
// the config record but Stage will be used until
// next reboot.
PWCHAR Volume; // Volume??? bugbug
ULONGLONG MembershipExpires;// membership tombstone
ULONGLONG PreInstallFid; // For journal filtering.
TABLE_CTX ConfigTable; // Db table context
FRS_LIST ReplicaCtxListHead; // Links all open contexts on this replica set.
PWCHAR FileFilterList; // Raw file filter
PWCHAR DirFilterList; // Raw directory filter
LIST_ENTRY FileNameFilterHead; // Head of file name filter list.
LIST_ENTRY DirNameFilterHead; // Head of directory name filter list.
PQHASH_TABLE NameConflictTable; // Sequence COs using the same file name.
LONG InLogRetryCount; // Count of number CO needing a Retry.
ULONG InLogSeqNumber; // The last sequence number used in Inlog
//
//
// The inlog retry table tracks which retry change orders are currently
// active so we don't reissue the same change order until current
// invocation completes. This can happen when the system gets backed up
// and the change order retry thread kicks off again to issue retry COs
// before the last batch are able to finish. This state could be kept in
// the Inlog record but then it means extra writes to the DB.
// The sequence number is used to detect changes in the table when we don't
// have the lock. It is per-replica because it uses the change order
// sequence number of the inlog record and they aren't unique across
// replicas.
//
PQHASH_TABLE ActiveInlogRetryTable;
union {
struct {
ULONG AIRSequenceNum;
ULONG AIRSequenceNumSample;
};
ULONGLONG QuadChunkA;
};
//
// Status of sysvol seeding.
// Returned for NtFrsApi_Rpc_PromotionStatusW().
//
DWORD NtFrsApi_ServiceState;
DWORD NtFrsApi_ServiceWStatus;
#ifndef NOVVJOINHACK
DWORD NtFrsApi_HackCount; // temporary hack
#endif NOVVJOINHACK
PWCHAR NtFrsApi_ServiceDisplay;
//
// The Outbound log process state for this replica.
//
CRITICAL_SECTION OutLogLock; // protects the OutLog state
LIST_ENTRY OutLogEligible; // Eligible outbound log partners
LIST_ENTRY OutLogStandBy; // Partners ready to join eligible list
LIST_ENTRY OutLogActive; // Active outbound log partners
LIST_ENTRY OutLogInActive; // Inactive outbound log partners
PQHASH_TABLE OutLogRecordLock; // Sync access to outlog records.
ULONG OutLogSeqNumber; // The last sequence number used in Outlog
ULONG OutLogJLx; // The Joint Leading Index
ULONG OutLogJTx; // The Joint Trailing Index
ULONG OutLogCOMax; // The index of the Max change order in the log.
ULONG OutLogWorkState; // The output log current processing state.
struct _COMMAND_PACKET *OutLogCmdPkt; // Cmd pkt to queue when idle and have work.
PTABLE_CTX OutLogTableCtx; // Output Log Table context.
ULONG OutLogCountVVJoins; // Count of number of VVJoins in progress.
BOOL OutLogDoCleanup; // True means give log cleanup a run.
//
// The handle to the preinstall directory
//
HANDLE PreInstallHandle;
//
// The volume journal state for this replica.
//
GUID JrnlCxtionGuid; // Used as the Cxtion Guid for Local Cos
USN InlogCommitUsn; // Our current USN Journal commit point.
//USN JournalUsn; // The Journal USN for this replica.
USN JrnlRecoveryStart; // Point to start recovery.
USN JrnlRecoveryEnd; // Point where recovery is complete.
LIST_ENTRY RecoveryRefreshList; // List of file refresh req change orders.
LIST_ENTRY VolReplicaList; // Links all REPLICA structs on volume together.
USN LastUsnRecordProcessed; // Current Journal subsystem read USN.
LONG LocalCoQueueCount; // Count of number local COs in process queue
struct _VOLUME_MONITOR_ENTRY *pVme; // Ref to the VME for this Replica.
struct _HASHTABLEDATA_REPLICASET *PerfRepSetData; // PERFMON counter data structure
} REPLICA, *PREPLICA;
*/
{
dprintf("Dumping REPLICA.\n\n");
dprintf("Header : Address ( 0x%x )\n",pReplica->Header);
dprintf("ReplicaLock : Address ( 0x%x )\n",pReplica->ReplicaLock);
dprintf("ReferenceCount : %d\n",pReplica->ReferenceCount);
dprintf("CnfFlags : 0x%x\n",pReplica->CnfFlags);
dprintf("ReplicaSetType : %d\n",pReplica->ReplicaSetType);
dprintf("Consistent : %d\n",pReplica->Consistent);
dprintf("IsOpen : %d\n",pReplica->IsOpen);
dprintf("IsJournaling : %d\n",pReplica->IsJournaling);
dprintf("IsAccepting : %d\n",pReplica->IsAccepting);
dprintf("NeedsUpdate : %d\n",pReplica->NeedsUpdate);
dprintf("IsSeeding : %d\n",pReplica->IsSeeding);
dprintf("IsSysvolReady : %d\n",pReplica->IsSysvolReady);
dprintf("ReplicaList : Address ( 0x%x )\n",pReplica->ReplicaList);
dprintf("ServiceState : %d\n",pReplica->ServiceState);
dprintf("FStatus : %d\n",pReplica->FStatus);
dprintf("Queue : Address ( 0x%x )\n",pReplica->Queue);
DMPGNAME("ReplicaName : ",pReplica->ReplicaName);
dprintf("ReplicaNumber : %d\n",pReplica->ReplicaNumber);
DMPGNAME("MemberName : ",pReplica->MemberName);
DMPGNAME("SetName : ",pReplica->SetName);
DMPPGUID("ReplicaRootGuid : ",pReplica->ReplicaRootGuid);
DMPGUID("ReplicaVersionGuid : ",pReplica->ReplicaVersionGuid);
dprintf("Schedule : Address ( 0x%x )\n",pReplica->Schedule);
dprintf("VVector : Address ( 0x%x )\n",pReplica->VVector);
dprintf("Cxtions : Address ( 0x%x )\n",pReplica->Cxtions);
DMPSTRW("Root : ",pReplica->Root);
DMPSTRW("Stage : ",pReplica->Stage);
DMPSTRW("NewStage : ",pReplica->NewStage);
DMPSTRW("Volume : ",pReplica->Volume);
DMPTIME("MembershipExpires : ",pReplica->MembershipExpires);
DMPQUAD("PreInstallFid : ",pReplica->PreInstallFid);
dprintf("ConfigTable : Address ( 0x%x )\n",pReplica->ConfigTable);
dprintf("ReplicaCtxListHead : Address ( 0x%x )\n",pReplica->ReplicaCtxListHead);
DMPSTRW("FileFilterList : ",pReplica->FileFilterList);
DMPSTRW("DirFilterList : ",pReplica->DirFilterList);
dprintf("FileNameFilterHead : Address ( 0x%x )\n",pReplica->FileNameFilterHead);
dprintf("DirNameFilterHead : Address ( 0x%x )\n",pReplica->DirNameFilterHead);
dprintf("NameConflictTable : Address ( 0x%x )\n",pReplica->NameConflictTable);
dprintf("InLogRetryCount : %d\n",pReplica->InLogRetryCount);
dprintf("InLogSeqNumber : %d\n",pReplica->InLogSeqNumber);
dprintf("ActiveInlogRetryTable : Address ( 0x%x )\n",pReplica->ActiveInlogRetryTable);
dprintf("NtFrsApi_ServiceState : %d\n",pReplica->NtFrsApi_ServiceState);
dprintf("NtFrsApi_ServiceWStatus : %d\n",pReplica->NtFrsApi_ServiceWStatus);
DMPSTRW("NtFrsApi_ServiceDisplay : ",pReplica->NtFrsApi_ServiceDisplay);
dprintf("OutLogLock : Address ( 0x%x )\n",pReplica->OutLogLock);
dprintf("OutLogEligible : Address ( 0x%x )\n",pReplica->OutLogEligible);
dprintf("OutLogStandBy : Address ( 0x%x )\n",pReplica->OutLogStandBy);
dprintf("OutLogActive : Address ( 0x%x )\n",pReplica->OutLogActive);
dprintf("OutLogInActive : Address ( 0x%x )\n",pReplica->OutLogInActive);
dprintf("OutLogRecordLock : Address ( 0x%x )\n",pReplica->OutLogRecordLock);
dprintf("OutLogSeqNumber : %d\n",pReplica->OutLogSeqNumber);
dprintf("OutLogJLx : %d\n",pReplica->OutLogJLx);
dprintf("OutLogJTx : %d\n",pReplica->OutLogJTx);
dprintf("OutLogCOMax : %d\n",pReplica->OutLogCOMax);
dprintf("OutLogWorkState : %d\n",pReplica->OutLogWorkState);
dprintf("OutLogCmdPkt : Address ( 0x%x )\n",pReplica->OutLogCmdPkt);
dprintf("OutLogTableCtx : Address ( 0x%x )\n",pReplica->OutLogTableCtx);
dprintf("OutLogCountVVJoins : %d\n",pReplica->OutLogCountVVJoins);
dprintf("OutLogDoCleanup : %d\n",pReplica->OutLogDoCleanup);
dprintf("PreInstallHandle : Address ( 0x%x )\n",pReplica->PreInstallHandle);
DMPGUID("JrnlCxtionGuid : ",pReplica->JrnlCxtionGuid);
DMPQUAD("InlogCommitUsn : ",pReplica->InlogCommitUsn);
DMPQUAD("JrnlRecoveryStart : ",pReplica->JrnlRecoveryStart);
DMPQUAD("JrnlRecoveryEnd : ",pReplica->JrnlRecoveryEnd);
dprintf("RecoveryRefreshList : Address ( 0x%x )\n",pReplica->RecoveryRefreshList);
dprintf("VolReplicaList : Address ( 0x%x )\n",pReplica->VolReplicaList);
DMPQUAD("LastUsnRecordProcessed : ",pReplica->LastUsnRecordProcessed);
dprintf("LocalCoQueueCount : %d\n",pReplica->LocalCoQueueCount);
dprintf("pVme : Address ( 0x%x )\n",pReplica->pVme);
dprintf("PerfRepSetData : Address ( 0x%x )\n",pReplica->PerfRepSetData);
}
VOID
do_vme(
PVOLUME_MONITOR_ENTRY pVme
)
/*
typedef struct _VOLUME_MONITOR_ENTRY {
FRS_NODE_HEADER Header;
LIST_ENTRY ListEntry; // MUST FOLLOW HEADER
//
// This is the list head for all replica sets on the this volume. It links
// the REPLICA structs together.
//
FRS_LIST ReplicaListHead; // List of Replica Sets on Vol.
//
// The following USNs are for managing the NTFS USN journal on the volume.
//
USN JrnlRecoveryEnd; // Point where recovery is complete.
USN CurrentUsnRecord; // USN of record currently being processed.
USN CurrentUsnRecordDone; // USN of most recent record done processing.
USN LastUsnSavePoint; // USN of last vol wide save.
USN MonitorMaxProgressUsn; // Farthest progress made in this journal.
USN JrnlReadPoint; // The current active read point for journal.
USN_JOURNAL_DATA UsnJournalData; // FSCTL_QUERY_USN_JOURNAL data at journal open.
USN MonitorProgressUsn; // Start journal from here after pause.
USN ReplayUsn; // Start journal here after replica startup request
BOOL ReplayUsnValid; // above has valid data.
//
// The FrsVsn is a USN kept by FRS and exported by all replica sets on the
// volume. It is unaffected by disk reformats and is saved in the config
// record of each replica set. At startup we use the maximum value for all
// replica sets on a given volume. The only time they might differ is when
// service on a given replica set is not started.
//
ULONGLONG FrsVsn; // Private FRS volume seq num.
CRITICAL_SECTION Lock; // To sync access to VME.
CRITICAL_SECTION QuadWriteLock; // To sync updates to quadwords.
OVERLAPPED CancelOverlap; // Overlap struct for cancel req
ULONG WStatus; // Win32 status on error
ULONG ActiveReplicas; // Num replica sets active on journal
HANDLE Event; // Event handle for pause journal.
HANDLE VolumeHandle; // The vol handle for journal.
WCHAR DriveLetter[4]; // Drive letter for this volume.
//
// A change order table is kept on each volume to track the pending
// change orders. Tracking it for each replica set would be nice but
// that approach has a problem with renames that move files or dirs
// across replica sets on the volume. If there are prior change orders
// outstanding on a parent dir (MOVEOUT) in RS-A followed by a MOVEIN on
// a child file X to RS-B we must be sure the MOVEOUT on the parent happens
// before the MOVEIN on X. Similar problems arise with a MOVEOUT of file X
// followed by a MOVEIN to a different R.S. on the same volume. We need to
// locate the pending MOVEOUT change order on the volume or ensure it is
// processed first. One list per volume solves these problems.
//
PGENERIC_HASH_TABLE ChangeOrderTable;// The Replica Change Order table.
FRS_QUEUE ChangeOrderList; // Change order processing list head.
LIST_ENTRY UpdateList; // Link for the Replica Update Process Queue.
ULONG InitTime; // Time reference for the ChangeOrderList.
//
// THe Active Inbound Change Order table holds the change order structs
// indexed by File ID. An entry in the table means that we have an
// inbound (either local or remote) change order active on this file.
//
PGENERIC_HASH_TABLE ActiveInboundChangeOrderTable;
//
// The ActiveChildren hash table is used to record the parent FID of each
// active change order. This is used to prevent a change order from starting
// on the parent while a change order is active on one or more children.
// For example if the child change order was a create and the parent change
// order was an ACL change to prevent further creates, we must ensure the
// child completes before starting the parent change order. Each entry has
// a count of the number of active children and a flag that is set if the
// change order process queue is blocked because of a pending change order
// on the parent. When the count goes to zero the queue is unblocked.
//
PQHASH_TABLE ActiveChildren;
//
// The Parent Table is a simple hash table used to keep the parent File ID
// for each file and dir in any Replica Set on the volume. It is used in
// renames to find the old parent.
//
PQHASH_TABLE ParentFidTable;
//
// The FRS Write Filter table filters out journal entries caused
// by file system write from the File Replication Service (Us) when we
// install files in the replica tree.
//
PQHASH_TABLE FrsWriteFilter;
//
// The Recovery Conflict Table contains the FIDs of files that were in
// the inbound log when we crashed. At the start of recovery the inbound
// log for the given replica set is scanned and the FIDs are entered into
// the table. During journal processing any USN records with a matching
// FID are deemed to caused by FRS so we skip the record. (This is because
// the FrsWriteFilter table was lost in the crash).
PQHASH_TABLE RecoveryConflictTable;
//
// The name space table controls the merging of USN records into COs
// that use the same file name. If a name usage conflict exists in the
// USN record stream then we can't merge the USN record into a previous
// change order on the same file.
//
PQHASH_TABLE NameSpaceTable;
ULONG StreamSequenceNumberFetched;
ULONG StreamSequenceNumberClean;
ULONG StreamSequenceNumber;
//
// The Filter Table contains an entry for each direcctory that is within a
// replica set on this volume. It is used to filter out Journal records for
// files/dirs that are not in a Replica set. For those Journal records that
// are in a replica set, a lookup on the parent FileId tells us which one.
//
PGENERIC_HASH_TABLE FilterTable; // THe directory filter table.
BOOL StopIo; // True means StopIo requested.
BOOL IoActive; // True means I/O active on volume.
ULONG JournalState; // Current journal state.
ULONG ReferenceCount; // Free all hash tables when it hits 0.
LONG ActiveIoRequests;// Number of Journal reads currently outstanding.
FILE_OBJECTID_BUFFER RootDirObjectId; // Object ID for volume
FILE_FS_VOLUME_INFORMATION FSVolInfo; // NT volume info.
CHAR FSVolLabel[MAXIMUM_VOLUME_LABEL_LENGTH];
} VOLUME_MONITOR_ENTRY, *PVOLUME_MONITOR_ENTRY;
*/
{
dprintf("Dumping OUT_LOG_PARTNER.\n\n");
dprintf("Header : Address ( 0x%x )\n",pVme->Header);
dprintf("ListEntry : Address ( 0x%x )\n",pVme->ListEntry);
dprintf("WStatus : 0x%x\n",pVme->WStatus);
dprintf("ActiveReplicas : %d\n" ,pVme->ActiveReplicas);
dprintf("Event Handle for pause : 0x%x\n",pVme->Event);
dprintf("VolumeHandle : 0x%x\n",pVme->VolumeHandle);
dprintf("DriveLetter : %ws\n" ,pVme->DriveLetter);
dprintf("StopIo (bool) : 0x%x\n",pVme->StopIo);
dprintf("IoActive (bool) : 0x%x\n",pVme->IoActive);
dprintf("JournalState : 0x%x\n",pVme->JournalState);
dprintf("ReferenceCount : %d\n" ,pVme->ReferenceCount);
dprintf("ActiveIoRequests : %d\n" ,pVme->ActiveIoRequests);
dprintf("FSVolLabel : %s\n" ,pVme->FSVolLabel);
}
//
// Version info
//
#if DBG
USHORT SavedMajorVersion = 0x0c;
#else
USHORT SavedMajorVersion;
#endif
EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 };
USHORT SavedMinorVersion = VER_PRODUCTBUILD;
BOOL ChkTarget; // is debuggee a CHK build?
VOID
WinDbgExtensionDllInit(
PWINDBG_EXTENSION_APIS lpExtensionApis,
USHORT MajorVersion,
USHORT MinorVersion
)
{
fKD = 1;
ExtensionApis = *lpExtensionApis ;
SavedMajorVersion = MajorVersion;
SavedMinorVersion = MinorVersion;
ChkTarget = SavedMajorVersion == 0x0c ? TRUE : FALSE;
}
DECLARE_API( help )
{
INIT_DPRINTF();
if (lpArgumentString[0] == '\0') {
dprintf("\n");
dprintf("FRS Debugger extensions help:\n\n");
dprintf("%20s - CHANGE_ORDER_ENTRY\n","coe");
dprintf("%20s - CHANGE_ORDER_COMMAND\n","coc");
dprintf("%20s - CXTION\n","cxt");
dprintf("%20s - OUT_LOG_PARTNER\n","olp");
dprintf("%20s - REPLICA\n","rep");
dprintf("%20s - VME\n","vme");
dprintf("\n");
}
}
DECLARE_API( version )
{
INIT_DPRINTF();
if (fKD)
{
dprintf(
"FRS Extension dll for Build %d debugging %s kernel for Build %d\n",
VER_PRODUCTBUILD,
SavedMajorVersion == 0x0c ? "Checked" : "Free",
SavedMinorVersion
);
}
else
{
dprintf(
"FRS Extension dll for Build %d\n",
VER_PRODUCTBUILD
);
}
}
DECLARE_API( coe )
{
ULONG_PTR dwAddr;
INIT_DPRINTF();
dwAddr = GetExpression(lpArgumentString);
if ( !dwAddr ) {
dprintf("Error: can't evaluate '%s'\n", lpArgumentString);
return;
}
BOOL b;
char block[sizeof(CHANGE_ORDER_ENTRY)];
b = GetData(dwAddr, &block, sizeof(block), NULL);
if ( !b ) {
dprintf("can't read %p, error 0x%lx\n", dwAddr, GetLastError());
return;
}
do_coe((CHANGE_ORDER_ENTRY *) block);
}
DECLARE_API( coc )
{
ULONG_PTR dwAddr;
INIT_DPRINTF();
dwAddr = GetExpression(lpArgumentString);
if ( !dwAddr ) {
dprintf("Error: can't evaluate '%s'\n", lpArgumentString);
return;
}
BOOL b;
char block[sizeof(CHANGE_ORDER_COMMAND)];
b = GetData(dwAddr, &block, sizeof(block), NULL);
if ( !b ) {
dprintf("can't read %p, error 0x%lx\n", dwAddr, GetLastError());
return;
}
do_coc((CHANGE_ORDER_COMMAND *) block);
}
DECLARE_API( cxt )
{
ULONG_PTR dwAddr;
INIT_DPRINTF();
dwAddr = GetExpression(lpArgumentString);
if ( !dwAddr ) {
dprintf("Error: can't evaluate '%s'\n", lpArgumentString);
return;
}
BOOL b;
char block[sizeof(CXTION)];
b = GetData(dwAddr, &block, sizeof(block), NULL);
if ( !b ) {
dprintf("can't read %p, error 0x%lx\n", dwAddr, GetLastError());
return;
}
do_cxt((CXTION *) block);
}
DECLARE_API( olp )
{
ULONG_PTR dwAddr;
INIT_DPRINTF();
dwAddr = GetExpression(lpArgumentString);
if ( !dwAddr ) {
dprintf("Error: can't evaluate '%s'\n", lpArgumentString);
return;
}
BOOL b;
char block[sizeof(OUT_LOG_PARTNER)];
b = GetData(dwAddr, &block, sizeof(block), NULL);
if ( !b ) {
dprintf("can't read %p, error 0x%lx\n", dwAddr, GetLastError());
return;
}
do_olp((OUT_LOG_PARTNER *) block);
}
DECLARE_API( vme )
{
ULONG_PTR dwAddr;
INIT_DPRINTF();
dwAddr = GetExpression(lpArgumentString);
if ( !dwAddr ) {
dprintf("Error: can't evaluate '%s'\n", lpArgumentString);
return;
}
BOOL b;
char block[sizeof(VOLUME_MONITOR_ENTRY)];
b = GetData(dwAddr, &block, sizeof(block), NULL);
if ( !b ) {
dprintf("can't read %p, error 0x%lx\n", dwAddr, GetLastError());
return;
}
do_vme((VOLUME_MONITOR_ENTRY *) block);
}
DECLARE_API( rep )
{
ULONG_PTR dwAddr;
INIT_DPRINTF();
dwAddr = GetExpression(lpArgumentString);
if ( !dwAddr ) {
dprintf("Error: can't evaluate '%s'\n", lpArgumentString);
return;
}
BOOL b;
char block[sizeof(REPLICA)];
b = GetData(dwAddr, &block, sizeof(block), NULL);
if ( !b ) {
dprintf("can't read %p, error 0x%lx\n", dwAddr, GetLastError());
return;
}
do_rep((REPLICA *) block);
}
LPEXT_API_VERSION
ExtensionApiVersion(
VOID
)
{
return &ApiVersion;
}