603 lines
13 KiB
C
603 lines
13 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
blktree.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements routines for managing tree connect blocks.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Chuck Lenzmeier (chuckl) 4-Oct-1989
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#include "blktree.tmh"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
#define BugCheckFileId SRV_FILE_BLKTREE
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text( PAGE, SrvAllocateTreeConnect )
|
|||
|
#pragma alloc_text( PAGE, SrvCheckAndReferenceTreeConnect )
|
|||
|
#pragma alloc_text( PAGE, SrvCloseTreeConnect )
|
|||
|
#pragma alloc_text( PAGE, SrvCloseTreeConnectsOnShare )
|
|||
|
#pragma alloc_text( PAGE, SrvDereferenceTreeConnect )
|
|||
|
#pragma alloc_text( PAGE, SrvFreeTreeConnect )
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SrvAllocateTreeConnect (
|
|||
|
OUT PTREE_CONNECT *TreeConnect,
|
|||
|
IN PUNICODE_STRING ServerName OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function allocates a TreeConnect Block from the FSP heap.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TreeConnect - Returns a pointer to the tree connect block, or NULL
|
|||
|
if no heap space was available.
|
|||
|
|
|||
|
ServerName - the name of the server to which the client is connecting
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PNONPAGED_HEADER header;
|
|||
|
PTREE_CONNECT treeConnect;
|
|||
|
CLONG numberOfBytes;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to allocate from the heap.
|
|||
|
//
|
|||
|
|
|||
|
numberOfBytes = sizeof( TREE_CONNECT );
|
|||
|
if( ARGUMENT_PRESENT( ServerName ) ) {
|
|||
|
numberOfBytes += ServerName->Length;
|
|||
|
}
|
|||
|
|
|||
|
treeConnect = ALLOCATE_HEAP( numberOfBytes, BlockTypeTreeConnect );
|
|||
|
*TreeConnect = treeConnect;
|
|||
|
|
|||
|
if ( treeConnect == NULL ) {
|
|||
|
INTERNAL_ERROR(
|
|||
|
ERROR_LEVEL_EXPECTED,
|
|||
|
"SrvAllocateTreeConnect: Unable to allocate %d bytes from heap",
|
|||
|
sizeof( TREE_CONNECT ),
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
// An error will be logged by the caller.
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
IF_DEBUG(HEAP) {
|
|||
|
SrvPrint1( "SrvAllocateTreeConnect: Allocated tree connect at %p\n",
|
|||
|
treeConnect );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the nonpaged header.
|
|||
|
//
|
|||
|
|
|||
|
header = ALLOCATE_NONPAGED_POOL(
|
|||
|
sizeof(NONPAGED_HEADER),
|
|||
|
BlockTypeNonpagedHeader
|
|||
|
);
|
|||
|
if ( header == NULL ) {
|
|||
|
INTERNAL_ERROR(
|
|||
|
ERROR_LEVEL_EXPECTED,
|
|||
|
"SrvAllocateTreeConnect: Unable to allocate %d bytes from pool.",
|
|||
|
sizeof( NONPAGED_HEADER ),
|
|||
|
NULL
|
|||
|
);
|
|||
|
FREE_HEAP( treeConnect );
|
|||
|
*TreeConnect = NULL;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
header->Type = BlockTypeTreeConnect;
|
|||
|
header->PagedBlock = treeConnect;
|
|||
|
|
|||
|
RtlZeroMemory( treeConnect, numberOfBytes );
|
|||
|
|
|||
|
treeConnect->NonpagedHeader = header;
|
|||
|
|
|||
|
SET_BLOCK_TYPE_STATE_SIZE( treeConnect, BlockTypeTreeConnect, BlockStateActive, sizeof( TREE_CONNECT) );
|
|||
|
header->ReferenceCount = 2; // allow for Active status and caller's pointer
|
|||
|
|
|||
|
//
|
|||
|
// Set up the time at which the tree connect block was allocated.
|
|||
|
//
|
|||
|
KeQuerySystemTime( &treeConnect->StartTime );
|
|||
|
|
|||
|
//
|
|||
|
// Save the ServerName, if supplied
|
|||
|
//
|
|||
|
if( ARGUMENT_PRESENT( ServerName ) ) {
|
|||
|
treeConnect->ServerName.Buffer = (PWCHAR)(treeConnect + 1);
|
|||
|
treeConnect->ServerName.MaximumLength = ServerName->Length;
|
|||
|
RtlCopyUnicodeString( &treeConnect->ServerName, ServerName );
|
|||
|
}
|
|||
|
|
|||
|
#if SRVDBG2
|
|||
|
treeConnect->BlockHeader.ReferenceCount = 2; // for INITIALIZE_REFERENCE_HISTORY
|
|||
|
#endif
|
|||
|
INITIALIZE_REFERENCE_HISTORY( treeConnect );
|
|||
|
|
|||
|
INCREMENT_DEBUG_STAT( SrvDbgStatistics.TreeConnectInfo.Allocations );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // SrvAllocateTreeConnect
|
|||
|
|
|||
|
|
|||
|
BOOLEAN SRVFASTCALL
|
|||
|
SrvCheckAndReferenceTreeConnect (
|
|||
|
PTREE_CONNECT TreeConnect
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function atomically verifies that a tree connect is active and
|
|||
|
increments the reference count on the tree connect if it is.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TreeConnect - Address of tree connect
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
BOOLEAN - Returns TRUE if the tree connect is active, FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
//
|
|||
|
// Acquire the lock that guards the tree connect's state field.
|
|||
|
//
|
|||
|
|
|||
|
ACQUIRE_LOCK( &TreeConnect->Connection->Lock );
|
|||
|
|
|||
|
//
|
|||
|
// If the tree connect is active, reference it and return TRUE.
|
|||
|
//
|
|||
|
|
|||
|
if ( GET_BLOCK_STATE(TreeConnect) == BlockStateActive ) {
|
|||
|
|
|||
|
SrvReferenceTreeConnect( TreeConnect );
|
|||
|
|
|||
|
RELEASE_LOCK( &TreeConnect->Connection->Lock );
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The tree connect isn't active. Return FALSE.
|
|||
|
//
|
|||
|
|
|||
|
RELEASE_LOCK( &TreeConnect->Connection->Lock );
|
|||
|
|
|||
|
return FALSE;
|
|||
|
|
|||
|
} // SrvCheckAndReferenceTreeConnect
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SrvCloseTreeConnect (
|
|||
|
IN PTREE_CONNECT TreeConnect
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine does the core of a tree disconnect. It sets the state
|
|||
|
of the tree connect to Closing, closes all files open on the tree
|
|||
|
connect, and dereferences the tree connect block. The block will be
|
|||
|
destroyed as soon as all other references to it are eliminated.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TreeConnect - Supplies a pointer to the tree connect block that is
|
|||
|
to be closed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
ACQUIRE_LOCK( &TreeConnect->Connection->Lock );
|
|||
|
|
|||
|
if ( GET_BLOCK_STATE(TreeConnect) == BlockStateActive ) {
|
|||
|
|
|||
|
IF_DEBUG(BLOCK1) SrvPrint1( "Closing tree at %p\n", TreeConnect );
|
|||
|
|
|||
|
SET_BLOCK_STATE( TreeConnect, BlockStateClosing );
|
|||
|
|
|||
|
RELEASE_LOCK( &TreeConnect->Connection->Lock );
|
|||
|
//
|
|||
|
// Close any open files or pending transactions on this tree
|
|||
|
// connect.
|
|||
|
//
|
|||
|
|
|||
|
SrvCloseRfcbsOnTree( TreeConnect );
|
|||
|
|
|||
|
SrvCloseTransactionsOnTree( TreeConnect );
|
|||
|
|
|||
|
//
|
|||
|
// Close any open DOS searches on this tree connect.
|
|||
|
//
|
|||
|
|
|||
|
SrvCloseSearches(
|
|||
|
TreeConnect->Connection,
|
|||
|
(PSEARCH_FILTER_ROUTINE)SrvSearchOnTreeConnect,
|
|||
|
(PVOID)TreeConnect,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Close any cached directories on this connection
|
|||
|
//
|
|||
|
SrvCloseCachedDirectoryEntries( TreeConnect->Connection );
|
|||
|
|
|||
|
//
|
|||
|
// Dereference the tree connect (to indicate that it's no longer
|
|||
|
// open).
|
|||
|
//
|
|||
|
|
|||
|
SrvDereferenceTreeConnect( TreeConnect );
|
|||
|
|
|||
|
INCREMENT_DEBUG_STAT( SrvDbgStatistics.TreeConnectInfo.Closes );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
RELEASE_LOCK( &TreeConnect->Connection->Lock );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // SrvCloseTreeConnect
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SrvCloseTreeConnectsOnShare (
|
|||
|
IN PSHARE Share
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function close all tree connects on a given share.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Share - A pointer to the share block.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PLIST_ENTRY treeConnectEntry, nextTreeConnectEntry;
|
|||
|
PTREE_CONNECT treeConnect;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
//
|
|||
|
// Acquire the lock that protects the share's tree connect list.
|
|||
|
//
|
|||
|
// *** Note that this routine can be called with this lock already
|
|||
|
// held by SrvCloseShare from SrvNetShareDel.
|
|||
|
//
|
|||
|
|
|||
|
ACQUIRE_LOCK( &SrvShareLock );
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the list of TreeConnects for the given share,
|
|||
|
// closing all of them. The share block and the list are guaranteed
|
|||
|
// to remain valid because we hold the share lock.
|
|||
|
//
|
|||
|
|
|||
|
treeConnectEntry = Share->TreeConnectList.Flink;
|
|||
|
|
|||
|
while ( treeConnectEntry != &Share->TreeConnectList ) {
|
|||
|
|
|||
|
//
|
|||
|
// Capture the address of the next tree connect now, because
|
|||
|
// we're about to close the current one, and we can look at it
|
|||
|
// after we've done that.
|
|||
|
//
|
|||
|
|
|||
|
nextTreeConnectEntry = treeConnectEntry->Flink;
|
|||
|
|
|||
|
//
|
|||
|
// Close the tree connect. This will close all files open on
|
|||
|
// this tree connect, and will stop blocked activity on the tree
|
|||
|
// connect. The tree connect itself will not be removed from
|
|||
|
// the share's TreeConnect list until its reference count
|
|||
|
// reaches zero.
|
|||
|
//
|
|||
|
|
|||
|
treeConnect = CONTAINING_RECORD(
|
|||
|
treeConnectEntry,
|
|||
|
TREE_CONNECT,
|
|||
|
ShareListEntry
|
|||
|
);
|
|||
|
|
|||
|
SrvCloseTreeConnect( treeConnect );
|
|||
|
|
|||
|
//
|
|||
|
// Point to the next tree connect.
|
|||
|
//
|
|||
|
|
|||
|
treeConnectEntry = nextTreeConnectEntry;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Release the share's tree connect list lock.
|
|||
|
//
|
|||
|
|
|||
|
RELEASE_LOCK( &SrvShareLock );
|
|||
|
|
|||
|
} // SrvCloseTreeConnectsOnShare
|
|||
|
|
|||
|
|
|||
|
VOID SRVFASTCALL
|
|||
|
SrvDereferenceTreeConnect (
|
|||
|
IN PTREE_CONNECT TreeConnect
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function decrements the reference count on a tree connect. If
|
|||
|
the reference count goes to zero, the tree connect block is deleted.
|
|||
|
|
|||
|
Since this routine may call SrvDereferenceConnection, the caller
|
|||
|
must be careful if he holds the connection lock that he also
|
|||
|
holds a referenced pointer to the connection.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TreeConnect - Address of tree connect
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCONNECTION connection;
|
|||
|
LONG result;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
//
|
|||
|
// Enter a critical section and decrement the reference count on the
|
|||
|
// block.
|
|||
|
//
|
|||
|
|
|||
|
connection = TreeConnect->Connection;
|
|||
|
|
|||
|
IF_DEBUG(REFCNT) {
|
|||
|
SrvPrint2( "Dereferencing tree connect %p; old refcnt %lx\n",
|
|||
|
TreeConnect, TreeConnect->NonpagedHeader->ReferenceCount );
|
|||
|
}
|
|||
|
|
|||
|
ASSERT( GET_BLOCK_TYPE( TreeConnect ) == BlockTypeTreeConnect );
|
|||
|
ASSERT( TreeConnect->NonpagedHeader->ReferenceCount > 0 );
|
|||
|
UPDATE_REFERENCE_HISTORY( TreeConnect, TRUE );
|
|||
|
|
|||
|
result = InterlockedDecrement(
|
|||
|
&TreeConnect->NonpagedHeader->ReferenceCount
|
|||
|
);
|
|||
|
|
|||
|
if ( result == 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// The new reference count is 0, meaning that it's time to
|
|||
|
// delete this block.
|
|||
|
//
|
|||
|
// Free the tree connect entry in the tree table. (Note that
|
|||
|
// the connection lock guards this table.)
|
|||
|
//
|
|||
|
|
|||
|
ACQUIRE_LOCK( &connection->Lock );
|
|||
|
|
|||
|
SrvRemoveEntryTable(
|
|||
|
&connection->PagedConnection->TreeConnectTable,
|
|||
|
TID_INDEX( TreeConnect->Tid )
|
|||
|
);
|
|||
|
|
|||
|
if( TreeConnect->Session )
|
|||
|
{
|
|||
|
DEBUG TreeConnect->Session = NULL;
|
|||
|
|
|||
|
RELEASE_LOCK( &connection->Lock );
|
|||
|
|
|||
|
SrvDereferenceSession( TreeConnect->Session );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
RELEASE_LOCK( &connection->Lock );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove the tree connect from the list of active tree connects
|
|||
|
// for the share.
|
|||
|
//
|
|||
|
|
|||
|
SrvRemoveEntryOrderedList( &SrvTreeConnectList, TreeConnect );
|
|||
|
|
|||
|
//
|
|||
|
// Take the tree connect off the list of tree connects for the
|
|||
|
// share and decrement the count of active uses of the share.
|
|||
|
//
|
|||
|
|
|||
|
ACQUIRE_LOCK( &SrvShareLock );
|
|||
|
|
|||
|
SrvRemoveEntryList(
|
|||
|
&TreeConnect->Share->TreeConnectList,
|
|||
|
&TreeConnect->ShareListEntry
|
|||
|
);
|
|||
|
|
|||
|
RELEASE_LOCK( &SrvShareLock );
|
|||
|
|
|||
|
//
|
|||
|
// Dereference the share and the connection.
|
|||
|
//
|
|||
|
|
|||
|
SrvDereferenceShareForTreeConnect( TreeConnect->Share );
|
|||
|
DEBUG TreeConnect->Share = NULL;
|
|||
|
|
|||
|
SrvDereferenceConnection( connection );
|
|||
|
DEBUG TreeConnect->Connection = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Free the tree connect block.
|
|||
|
//
|
|||
|
|
|||
|
SrvFreeTreeConnect( TreeConnect );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // SrvDereferenceTreeConnect
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SrvFreeTreeConnect (
|
|||
|
IN PTREE_CONNECT TreeConnect
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function returns a TreeConnect Block to the FSP heap.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TreeConnect - Address of tree connect
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
DEBUG SET_BLOCK_TYPE_STATE_SIZE( TreeConnect, BlockTypeGarbage, BlockStateDead, -1 );
|
|||
|
DEBUG TreeConnect->NonpagedHeader->ReferenceCount = -1;
|
|||
|
|
|||
|
TERMINATE_REFERENCE_HISTORY( TreeConnect );
|
|||
|
|
|||
|
DEALLOCATE_NONPAGED_POOL( TreeConnect->NonpagedHeader );
|
|||
|
FREE_HEAP( TreeConnect );
|
|||
|
IF_DEBUG(HEAP) {
|
|||
|
SrvPrint1( "SrvFreeTreeConnect: Freed tree connect block at %p\n",
|
|||
|
TreeConnect );
|
|||
|
}
|
|||
|
|
|||
|
INCREMENT_DEBUG_STAT( SrvDbgStatistics.TreeConnectInfo.Frees );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // SrvFreeTreeConnect
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SrvDisconnectTreeConnectsFromSession (
|
|||
|
PCONNECTION connection,
|
|||
|
PSESSION Session
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine removes the session association on all associated
|
|||
|
TreeConnects and dereferences the session, allowing the session
|
|||
|
to exit normally. The caller MUST have the Connection Lock acquired.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Connection - The connection we're walking
|
|||
|
Session - Supplies a pointer to the session block for which
|
|||
|
transactions are to be closed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PTABLE_HEADER tableHeader;
|
|||
|
PLIST_ENTRY entry;
|
|||
|
USHORT i;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
SrvReferenceSession( Session );
|
|||
|
|
|||
|
tableHeader = &connection->PagedConnection->SessionTable;
|
|||
|
|
|||
|
for ( i = 0; i < tableHeader->TableSize; i++ ) {
|
|||
|
|
|||
|
PTREE_CONNECT treeConnect =
|
|||
|
(PTREE_CONNECT)tableHeader->Table[i].Owner;
|
|||
|
|
|||
|
if ( treeConnect != NULL ) {
|
|||
|
|
|||
|
if( treeConnect->Session == Session )
|
|||
|
{
|
|||
|
SrvDereferenceSession( Session );
|
|||
|
treeConnect->Session = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SrvDereferenceSession( Session );
|
|||
|
|
|||
|
} // SrvDisconnectTreeConnectsFromSession
|