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.
781 lines
16 KiB
781 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Debug.c
|
|
|
|
Abstract:
|
|
|
|
This module declares the Debug only code used by the NetWare redirector
|
|
file system.
|
|
|
|
Author:
|
|
|
|
Colin Watson [ColinW] 05-Jan-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "procs.h"
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
|
|
#define LINE_SIZE 511
|
|
#define BUFFER_LINES 50
|
|
|
|
|
|
#ifdef NWDBG
|
|
|
|
#include <stdlib.h> // rand()
|
|
int FailAllocateMdl = 0;
|
|
|
|
ULONG MaxDump = 256;
|
|
CHAR DBuffer[BUFFER_LINES*LINE_SIZE+1];
|
|
PCHAR DBufferPtr = DBuffer;
|
|
|
|
//
|
|
// The reference count debug buffer.
|
|
//
|
|
|
|
CHAR RBuffer[BUFFER_LINES*LINE_SIZE+1];
|
|
PCHAR RBufferPtr = RBuffer;
|
|
|
|
LIST_ENTRY MdlList;
|
|
|
|
VOID
|
|
HexDumpLine (
|
|
PCHAR pch,
|
|
ULONG len,
|
|
PCHAR s,
|
|
PCHAR t,
|
|
USHORT flag
|
|
);
|
|
|
|
ULONG
|
|
NwMemDbg (
|
|
IN PCH Format,
|
|
...
|
|
)
|
|
|
|
//++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// Effectively DbgPrint to the debugging console.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Same as for DbgPrint
|
|
//
|
|
//--
|
|
|
|
{
|
|
va_list arglist;
|
|
int Length;
|
|
|
|
//
|
|
// Format the output into a buffer and then print it.
|
|
//
|
|
|
|
va_start(arglist, Format);
|
|
|
|
Length = _vsnprintf(DBufferPtr, LINE_SIZE, Format, arglist);
|
|
|
|
if (Length < 0) {
|
|
DbgPrint( "NwRdr: Message is too long for NwMemDbg\n");
|
|
return 0;
|
|
}
|
|
|
|
va_end(arglist);
|
|
|
|
ASSERT( Length <= LINE_SIZE );
|
|
ASSERT( Length != 0 );
|
|
ASSERT( DBufferPtr < &DBuffer[BUFFER_LINES*LINE_SIZE+1]);
|
|
ASSERT( DBufferPtr >= DBuffer);
|
|
|
|
DBufferPtr += Length;
|
|
DBufferPtr[0] = '\0';
|
|
|
|
// Avoid running off the end of the buffer and exit
|
|
|
|
if (DBufferPtr >= (DBuffer+((BUFFER_LINES-1) * LINE_SIZE))) {
|
|
DBufferPtr = DBuffer;
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
RefDbgTrace (
|
|
PVOID Resource,
|
|
DWORD Count,
|
|
BOOLEAN Reference,
|
|
PBYTE FileName,
|
|
UINT Line
|
|
)
|
|
/**
|
|
|
|
Routine Description:
|
|
|
|
NwRefDebug logs reference count operations to expose
|
|
reference count errors or leaks in the redirector.
|
|
|
|
Arguments:
|
|
|
|
Resource - The object we're adjusting the reference count on.
|
|
Count - The current count on the object.
|
|
Reference - If TRUE we are doing a REFERENCE.
|
|
Otherwise, we are doing a DEREFERENCE.
|
|
FileName - The callers file name.
|
|
Line - The callers line number.
|
|
|
|
**/
|
|
{
|
|
int Length;
|
|
int NextCount;
|
|
|
|
//
|
|
// Format the output into a buffer and then print it.
|
|
//
|
|
|
|
if ( Reference )
|
|
NextCount = Count + 1;
|
|
else
|
|
NextCount = Count - 1;
|
|
|
|
Length = sprintf( RBufferPtr,
|
|
"%p: R=%p, %lu -> %lu (%s, line %d)\n",
|
|
(PVOID)PsGetCurrentThread(),
|
|
Resource,
|
|
Count,
|
|
NextCount,
|
|
FileName,
|
|
Line );
|
|
|
|
if (Length < 0) {
|
|
DbgPrint( "NwRdr: Message is too long for NwRefDbg\n");
|
|
return;
|
|
}
|
|
|
|
ASSERT( Length <= LINE_SIZE );
|
|
ASSERT( Length != 0 );
|
|
ASSERT( RBufferPtr < &RBuffer[BUFFER_LINES*LINE_SIZE+1]);
|
|
ASSERT( RBufferPtr >= RBuffer);
|
|
|
|
RBufferPtr += Length;
|
|
RBufferPtr[0] = '\0';
|
|
|
|
// Avoid running off the end of the buffer and exit
|
|
|
|
if (RBufferPtr >= (RBuffer+((BUFFER_LINES-1) * LINE_SIZE))) {
|
|
RBufferPtr = RBuffer;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
RealDebugTrace(
|
|
LONG Indent,
|
|
ULONG Level,
|
|
PCH Message,
|
|
PVOID Parameter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( (Level == 0) || (NwMemDebug & Level )) {
|
|
NwMemDbg( Message, PsGetCurrentThread(), 1, "", Parameter );
|
|
}
|
|
|
|
if ( (Level == 0) || (NwDebug & Level )) {
|
|
|
|
if ( Indent < 0) {
|
|
NwDebugTraceIndent += Indent;
|
|
}
|
|
|
|
DbgPrint( Message, PsGetCurrentThread(), NwDebugTraceIndent, "", Parameter );
|
|
|
|
if ( Indent > 0) {
|
|
NwDebugTraceIndent += Indent;
|
|
}
|
|
|
|
if (NwDebugTraceIndent < 0) {
|
|
NwDebugTraceIndent = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
dump(
|
|
IN ULONG Level,
|
|
IN PVOID far_p,
|
|
IN ULONG len
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Dump Min(len, MaxDump) bytes in classic hex dump style if debug
|
|
output is turned on for this level.
|
|
|
|
Arguments:
|
|
|
|
IN Level - 0 if always display. Otherwise only display if a
|
|
corresponding bit is set in NwDebug.
|
|
|
|
IN far_p - address of buffer to start dumping from.
|
|
|
|
IN len - length in bytes of buffer.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG l;
|
|
char s[80], t[80];
|
|
PCHAR far_pchar = (PCHAR)far_p;
|
|
|
|
if ( (Level == 0) || (NwDebug & Level )) {
|
|
if (len > MaxDump)
|
|
len = MaxDump;
|
|
|
|
while (len) {
|
|
l = len < 16 ? len : 16;
|
|
|
|
DbgPrint("\n%lx ", far_pchar);
|
|
HexDumpLine (far_pchar, l, s, t, 0);
|
|
DbgPrint("%s%.*s%s", s, 1 + ((16 - l) * 3), "", t);
|
|
NwMemDbg ( "%lx: %s%.*s%s\n",
|
|
far_pchar, s, 1 + ((16 - l) * 3), "", t);
|
|
|
|
len -= l;
|
|
far_pchar += l;
|
|
}
|
|
DbgPrint("\n");
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
dumpMdl(
|
|
IN ULONG Level,
|
|
IN PMDL Mdl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Dump the memory described by each part of a chained Mdl.
|
|
|
|
Arguments:
|
|
|
|
IN Level - 0 if always display. Otherwise only display if a
|
|
corresponding bit is set in NwDebug.
|
|
|
|
Mdl - Supplies the addresses of the memory to be dumped.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PMDL Next;
|
|
ULONG len;
|
|
|
|
|
|
if ( (Level == 0) || (NwDebug & Level )) {
|
|
Next = Mdl; len = 0;
|
|
do {
|
|
|
|
dump(Level, MmGetSystemAddressForMdlSafe(Next, LowPagePriority), MIN(MmGetMdlByteCount(Next), MaxDump-len));
|
|
|
|
len += MmGetMdlByteCount(Next);
|
|
} while ( (Next = Next->Next) != NULL &&
|
|
len <= MaxDump);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HexDumpLine (
|
|
PCHAR pch,
|
|
ULONG len,
|
|
PCHAR s,
|
|
PCHAR t,
|
|
USHORT flag
|
|
)
|
|
{
|
|
static UCHAR rghex[] = "0123456789ABCDEF";
|
|
|
|
UCHAR c;
|
|
UCHAR *hex, *asc;
|
|
|
|
|
|
hex = s;
|
|
asc = t;
|
|
|
|
*(asc++) = '*';
|
|
while (len--) {
|
|
c = *(pch++);
|
|
*(hex++) = rghex [c >> 4] ;
|
|
*(hex++) = rghex [c & 0x0F];
|
|
*(hex++) = ' ';
|
|
*(asc++) = (c < ' ' || c > '~') ? (CHAR )'.' : c;
|
|
}
|
|
*(asc++) = '*';
|
|
*asc = 0;
|
|
*hex = 0;
|
|
|
|
flag;
|
|
}
|
|
|
|
typedef struct _NW_POOL_HEADER {
|
|
ULONG Signature;
|
|
ULONG BufferSize;
|
|
ULONG BufferType;
|
|
LIST_ENTRY ListEntry;
|
|
ULONG Pad; // Pad to Q-word align
|
|
} NW_POOL_HEADER, *PNW_POOL_HEADER;
|
|
|
|
typedef struct _NW_POOL_TRAILER {
|
|
ULONG Signature;
|
|
} NW_POOL_TRAILER;
|
|
|
|
typedef NW_POOL_TRAILER UNALIGNED *PNW_POOL_TRAILER;
|
|
|
|
PVOID
|
|
NwAllocatePool(
|
|
ULONG Type,
|
|
ULONG Size,
|
|
BOOLEAN RaiseStatus
|
|
)
|
|
{
|
|
PCHAR Buffer;
|
|
PNW_POOL_HEADER PoolHeader;
|
|
PNW_POOL_TRAILER PoolTrailer;
|
|
|
|
if ( RaiseStatus ) {
|
|
Buffer = FsRtlAllocatePoolWithTag(
|
|
Type,
|
|
sizeof( NW_POOL_HEADER ) + sizeof( NW_POOL_TRAILER ) + Size,
|
|
'scwn' );
|
|
} else {
|
|
#ifndef QFE_BUILD
|
|
Buffer = ExAllocatePoolWithTag(
|
|
Type,
|
|
sizeof( NW_POOL_HEADER )+sizeof( NW_POOL_TRAILER )+Size,
|
|
'scwn' );
|
|
#else
|
|
Buffer = ExAllocatePool(
|
|
Type,
|
|
sizeof( NW_POOL_HEADER )+sizeof( NW_POOL_TRAILER )+Size );
|
|
#endif
|
|
|
|
if ( Buffer == NULL ) {
|
|
return( NULL );
|
|
}
|
|
}
|
|
|
|
PoolHeader = (PNW_POOL_HEADER)Buffer;
|
|
PoolTrailer = (PNW_POOL_TRAILER)(Buffer + sizeof( NW_POOL_HEADER ) + Size);
|
|
|
|
PoolHeader->Signature = 0x11111111;
|
|
PoolHeader->BufferSize = Size;
|
|
PoolHeader->BufferType = Type;
|
|
|
|
PoolTrailer->Signature = 0x99999999;
|
|
|
|
if ( Type == PagedPool ) {
|
|
ExAcquireResourceExclusive( &NwDebugResource, TRUE );
|
|
InsertTailList( &NwPagedPoolList, &PoolHeader->ListEntry );
|
|
ExReleaseResource( &NwDebugResource );
|
|
} else if ( Type == NonPagedPool ) {
|
|
ExInterlockedInsertTailList( &NwNonpagedPoolList, &PoolHeader->ListEntry, &NwDebugInterlock );
|
|
} else {
|
|
KeBugCheck( RDR_FILE_SYSTEM );
|
|
}
|
|
|
|
return( Buffer + sizeof( NW_POOL_HEADER ) );
|
|
}
|
|
|
|
VOID
|
|
NwFreePool(
|
|
PVOID Buffer
|
|
)
|
|
{
|
|
PNW_POOL_HEADER PoolHeader;
|
|
PNW_POOL_TRAILER PoolTrailer;
|
|
KIRQL OldIrql;
|
|
|
|
PoolHeader = (PNW_POOL_HEADER)((PCHAR)Buffer - sizeof( NW_POOL_HEADER ));
|
|
ASSERT( PoolHeader->Signature == 0x11111111 );
|
|
ASSERT( PoolHeader->BufferType == PagedPool ||
|
|
PoolHeader->BufferType == NonPagedPool );
|
|
|
|
PoolTrailer = (PNW_POOL_TRAILER)((PCHAR)Buffer + PoolHeader->BufferSize );
|
|
ASSERT( PoolTrailer->Signature == 0x99999999 );
|
|
|
|
if ( PoolHeader->BufferType == PagedPool ) {
|
|
ExAcquireResourceExclusive( &NwDebugResource, TRUE );
|
|
RemoveEntryList( &PoolHeader->ListEntry );
|
|
ExReleaseResource( &NwDebugResource );
|
|
} else {
|
|
KeAcquireSpinLock( &NwDebugInterlock, &OldIrql );
|
|
RemoveEntryList( &PoolHeader->ListEntry );
|
|
KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
|
|
}
|
|
|
|
ExFreePool( PoolHeader );
|
|
}
|
|
|
|
//
|
|
// Debug functions for allocating and deallocating IRPs and MDLs
|
|
//
|
|
|
|
PIRP
|
|
NwAllocateIrp(
|
|
CCHAR Size,
|
|
BOOLEAN ChargeQuota
|
|
)
|
|
{
|
|
ExInterlockedIncrementLong( &IrpCount, &NwDebugInterlock );
|
|
return IoAllocateIrp( Size, ChargeQuota );
|
|
}
|
|
|
|
VOID
|
|
NwFreeIrp(
|
|
PIRP Irp
|
|
)
|
|
{
|
|
ExInterlockedDecrementLong( &IrpCount, &NwDebugInterlock );
|
|
IoFreeIrp( Irp );
|
|
}
|
|
|
|
typedef struct _NW_MDL {
|
|
LIST_ENTRY Next;
|
|
PUCHAR File;
|
|
int Line;
|
|
PMDL pMdl;
|
|
} NW_MDL, *PNW_MDL;
|
|
|
|
//int DebugLine = 2461;
|
|
|
|
PMDL
|
|
NwAllocateMdl(
|
|
PVOID Va,
|
|
ULONG Length,
|
|
BOOLEAN Secondary,
|
|
BOOLEAN ChargeQuota,
|
|
PIRP Irp,
|
|
PUCHAR FileName,
|
|
int Line
|
|
)
|
|
{
|
|
PNW_MDL Buffer;
|
|
|
|
static BOOLEAN MdlSetup = FALSE;
|
|
|
|
if (MdlSetup == FALSE) {
|
|
|
|
InitializeListHead( &MdlList );
|
|
|
|
MdlSetup = TRUE;
|
|
}
|
|
|
|
if ( FailAllocateMdl != 0 ) {
|
|
if ( ( rand() % FailAllocateMdl ) == 0 ) {
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
#ifndef QFE_BUILD
|
|
Buffer = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof( NW_MDL),
|
|
'scwn' );
|
|
#else
|
|
Buffer = ExAllocatePool(
|
|
NonPagedPool,
|
|
sizeof( NW_MDL));
|
|
#endif
|
|
|
|
if ( Buffer == NULL ) {
|
|
return( NULL );
|
|
}
|
|
|
|
ExInterlockedIncrementLong( &MdlCount, &NwDebugInterlock );
|
|
|
|
Buffer->File = FileName;
|
|
Buffer->Line = Line;
|
|
Buffer->pMdl = IoAllocateMdl( Va, Length, Secondary, ChargeQuota, Irp );
|
|
|
|
ExInterlockedInsertTailList( &MdlList, &Buffer->Next, &NwDebugInterlock );
|
|
|
|
/*
|
|
if (DebugLine == Line) {
|
|
DebugTrace( 0, DEBUG_TRACE_MDL, "AllocateMdl -> %08lx\n", Buffer->pMdl );
|
|
DebugTrace( 0, DEBUG_TRACE_MDL, "AllocateMdl -> %08lx\n", Line );
|
|
}
|
|
*/
|
|
return(Buffer->pMdl);
|
|
}
|
|
|
|
VOID
|
|
NwFreeMdl(
|
|
PMDL Mdl
|
|
)
|
|
{
|
|
PLIST_ENTRY MdlEntry;
|
|
PNW_MDL Buffer;
|
|
KIRQL OldIrql;
|
|
|
|
ExInterlockedDecrementLong( &MdlCount, &NwDebugInterlock );
|
|
|
|
KeAcquireSpinLock( &NwDebugInterlock, &OldIrql );
|
|
// Find the Mdl in the list and remove it.
|
|
|
|
for (MdlEntry = MdlList.Flink ;
|
|
MdlEntry != &MdlList ;
|
|
MdlEntry = MdlEntry->Flink ) {
|
|
|
|
Buffer = CONTAINING_RECORD( MdlEntry, NW_MDL, Next );
|
|
|
|
if (Buffer->pMdl == Mdl) {
|
|
|
|
RemoveEntryList( &Buffer->Next );
|
|
|
|
KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
|
|
|
|
IoFreeMdl( Mdl );
|
|
DebugTrace( 0, DEBUG_TRACE_MDL, "FreeMDL - %08lx\n", Mdl );
|
|
/*
|
|
if (DebugLine == Buffer->Line) {
|
|
DebugTrace( 0, DEBUG_TRACE_MDL, "FreeMdl -> %08lx\n", Mdl );
|
|
DebugTrace( 0, DEBUG_TRACE_MDL, "FreeMdl -> %08lx\n", Buffer->Line );
|
|
}
|
|
*/
|
|
ExFreePool(Buffer);
|
|
|
|
return;
|
|
}
|
|
}
|
|
ASSERT( FALSE );
|
|
|
|
KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
|
|
}
|
|
|
|
/*
|
|
VOID
|
|
NwLookForMdl(
|
|
)
|
|
{
|
|
PLIST_ENTRY MdlEntry;
|
|
PNW_MDL Buffer;
|
|
KIRQL OldIrql;
|
|
|
|
KeAcquireSpinLock( &NwDebugInterlock, &OldIrql );
|
|
// Find the Mdl in the list and remove it.
|
|
|
|
for (MdlEntry = MdlList.Flink ;
|
|
MdlEntry != &MdlList ;
|
|
MdlEntry = MdlEntry->Flink ) {
|
|
|
|
Buffer = CONTAINING_RECORD( MdlEntry, NW_MDL, Next );
|
|
|
|
if (Buffer->Line == DebugLine) {
|
|
|
|
DebugTrace( 0, DEBUG_TRACE_MDL, "LookForMdl -> %08lx\n", Buffer );
|
|
DbgBreakPoint();
|
|
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinLock( &NwDebugInterlock, OldIrql );
|
|
}
|
|
*/
|
|
|
|
//
|
|
// Function version of resource macro, to make debugging easier.
|
|
//
|
|
|
|
VOID
|
|
NwAcquireExclusiveRcb(
|
|
PRCB Rcb,
|
|
BOOLEAN Wait )
|
|
{
|
|
ExAcquireResourceExclusive( &((Rcb)->Resource), Wait );
|
|
}
|
|
|
|
VOID
|
|
NwAcquireSharedRcb(
|
|
PRCB Rcb,
|
|
BOOLEAN Wait )
|
|
{
|
|
ExAcquireResourceShared( &((Rcb)->Resource), Wait );
|
|
}
|
|
|
|
VOID
|
|
NwReleaseRcb(
|
|
PRCB Rcb )
|
|
{
|
|
ExReleaseResource( &((Rcb)->Resource) );
|
|
}
|
|
|
|
VOID
|
|
NwAcquireExclusiveFcb(
|
|
PNONPAGED_FCB pFcb,
|
|
BOOLEAN Wait )
|
|
{
|
|
ExAcquireResourceExclusive( &((pFcb)->Resource), Wait );
|
|
}
|
|
|
|
VOID
|
|
NwAcquireSharedFcb(
|
|
PNONPAGED_FCB pFcb,
|
|
BOOLEAN Wait )
|
|
{
|
|
ExAcquireResourceShared( &((pFcb)->Resource), Wait );
|
|
}
|
|
|
|
VOID
|
|
NwReleaseFcb(
|
|
PNONPAGED_FCB pFcb )
|
|
{
|
|
ExReleaseResource( &((pFcb)->Resource) );
|
|
}
|
|
|
|
VOID
|
|
NwAcquireOpenLock(
|
|
VOID
|
|
)
|
|
{
|
|
ExAcquireResourceExclusive( &NwOpenResource, TRUE );
|
|
}
|
|
|
|
VOID
|
|
NwReleaseOpenLock(
|
|
VOID
|
|
)
|
|
{
|
|
ExReleaseResource( &NwOpenResource );
|
|
}
|
|
|
|
|
|
//
|
|
// code to dump ICBs
|
|
//
|
|
|
|
VOID DumpIcbs(VOID)
|
|
{
|
|
PVCB Vcb;
|
|
PFCB Fcb;
|
|
PICB Icb;
|
|
PLIST_ENTRY VcbListEntry;
|
|
PLIST_ENTRY FcbListEntry;
|
|
PLIST_ENTRY IcbListEntry;
|
|
KIRQL OldIrql;
|
|
|
|
NwAcquireExclusiveRcb( &NwRcb, TRUE );
|
|
KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
|
|
|
|
DbgPrint("\nICB Pid State Scb/Fcb Name\n", 0);
|
|
for ( VcbListEntry = GlobalVcbList.Flink;
|
|
VcbListEntry != &GlobalVcbList ;
|
|
VcbListEntry = VcbListEntry->Flink ) {
|
|
|
|
Vcb = CONTAINING_RECORD( VcbListEntry, VCB, GlobalVcbListEntry );
|
|
|
|
for ( FcbListEntry = Vcb->FcbList.Flink;
|
|
FcbListEntry != &(Vcb->FcbList) ;
|
|
FcbListEntry = FcbListEntry->Flink ) {
|
|
|
|
Fcb = CONTAINING_RECORD( FcbListEntry, FCB, FcbListEntry );
|
|
|
|
for ( IcbListEntry = Fcb->IcbList.Flink;
|
|
IcbListEntry != &(Fcb->IcbList) ;
|
|
IcbListEntry = IcbListEntry->Flink ) {
|
|
|
|
Icb = CONTAINING_RECORD( IcbListEntry, ICB, ListEntry );
|
|
|
|
DbgPrint("%08lx", Icb);
|
|
DbgPrint(" %08lx",(DWORD)Icb->Pid);
|
|
DbgPrint(" %08lx",Icb->State);
|
|
DbgPrint(" %08lx",Icb->SuperType.Scb);
|
|
DbgPrint(" %wZ\n",
|
|
&(Icb->FileObject->FileName) );
|
|
}
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinLock( &ScbSpinLock, OldIrql );
|
|
NwReleaseRcb( &NwRcb );
|
|
}
|
|
|
|
#endif // ifdef NWDBG
|
|
|
|
//
|
|
// Ref counting debug routines.
|
|
//
|
|
|
|
#ifdef NWDBG
|
|
|
|
VOID
|
|
ChkNwReferenceScb(
|
|
PNONPAGED_SCB pNpScb,
|
|
PBYTE FileName,
|
|
UINT Line,
|
|
BOOLEAN Silent
|
|
) {
|
|
|
|
if ( (pNpScb)->NodeTypeCode != NW_NTC_SCBNP ) {
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
if ( !Silent) {
|
|
RefDbgTrace( pNpScb, pNpScb->Reference, TRUE, FileName, Line );
|
|
}
|
|
|
|
ExInterlockedIncrementLong( &(pNpScb)->Reference, &(pNpScb)->NpScbInterLock );
|
|
}
|
|
|
|
VOID
|
|
ChkNwDereferenceScb(
|
|
PNONPAGED_SCB pNpScb,
|
|
PBYTE FileName,
|
|
UINT Line,
|
|
BOOLEAN Silent
|
|
) {
|
|
|
|
if ( (pNpScb)->Reference == 0 ) {
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
if ( (pNpScb)->NodeTypeCode != NW_NTC_SCBNP ) {
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
if ( !Silent ) {
|
|
RefDbgTrace( pNpScb, pNpScb->Reference, FALSE, FileName, Line );
|
|
}
|
|
|
|
ExInterlockedDecrementLong( &(pNpScb)->Reference, &(pNpScb)->NpScbInterLock );
|
|
}
|
|
|
|
#endif
|
|
|