413 lines
13 KiB
C
413 lines
13 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
lock.h
|
||
|
||
Abstract:
|
||
|
||
This module defines types and functions for the LAN Manager server
|
||
FSP's lock package. This package began as a modification and
|
||
streamlining of the executive resource package -- it allowed
|
||
recursive acquisition, but didn't provide shared locks. Later,
|
||
debugging support in the form of level checking was added.
|
||
|
||
Coming full circle, the package now serves as a wrapper around the
|
||
real resource package. It simply provides debugging support. The
|
||
reasons for reverting to using resources include:
|
||
|
||
1) The resource package now supports recursive acquisition.
|
||
|
||
2) There are a couple of places in the server where shared access
|
||
is desirable.
|
||
|
||
3) The resource package has a "no-wait" option that disables waiting
|
||
for a lock when someone else owns it. This feature is useful to
|
||
the server FSD.
|
||
|
||
Author:
|
||
|
||
Chuck Lenzmeier (chuckl) 29-Nov-1989
|
||
A modification of Gary Kimura's resource package. See lock.c.
|
||
David Treadwell (davidtr)
|
||
|
||
Chuck Lenzmeier (chuckl) 5-Apr-1991
|
||
Revert to using resource package.
|
||
|
||
Environment:
|
||
|
||
Kernel mode only, LAN Manager server FSP and FSD.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#ifndef _LOCK_
|
||
#define _LOCK_
|
||
|
||
//#include <ntos.h>
|
||
|
||
//
|
||
// Structure containing global spin locks. Used to isolate each spin
|
||
// lock into its own cache line.
|
||
//
|
||
|
||
typedef struct _SRV_GLOBAL_SPIN_LOCKS {
|
||
ULONG Reserved1[7];
|
||
KSPIN_LOCK Fsd;
|
||
ULONG Reserved2[7];
|
||
struct {
|
||
KSPIN_LOCK Lock;
|
||
ULONG Reserved3[7];
|
||
} Endpoint[ENDPOINT_LOCK_COUNT];
|
||
KSPIN_LOCK Statistics;
|
||
ULONG Reserved4[7];
|
||
KSPIN_LOCK Timer;
|
||
ULONG Reserved5[7];
|
||
#if SRVDBG || SRVDBG_HANDLES
|
||
KSPIN_LOCK Debug;
|
||
ULONG Reserved6[7];
|
||
#endif
|
||
} SRV_GLOBAL_SPIN_LOCKS, *PSRV_GLOBAL_SPIN_LOCKS;
|
||
|
||
//
|
||
// Macros for accessing spin locks.
|
||
//
|
||
|
||
#define ACQUIRE_SPIN_LOCK(lock,irql) { \
|
||
PAGED_CODE_CHECK(); \
|
||
ExAcquireSpinLock( (lock), (irql) ); \
|
||
}
|
||
#define RELEASE_SPIN_LOCK(lock,irql) { \
|
||
PAGED_CODE_CHECK(); \
|
||
ExReleaseSpinLock( (lock), (irql) ); \
|
||
}
|
||
#define ACQUIRE_DPC_SPIN_LOCK(lock) { \
|
||
PAGED_CODE_CHECK(); \
|
||
ExAcquireSpinLockAtDpcLevel( (lock) ); \
|
||
}
|
||
#define RELEASE_DPC_SPIN_LOCK(lock) { \
|
||
PAGED_CODE_CHECK(); \
|
||
ExReleaseSpinLockFromDpcLevel( (lock) ); \
|
||
}
|
||
|
||
#define INITIALIZE_SPIN_LOCK(lock) KeInitializeSpinLock( lock );
|
||
|
||
#define GLOBAL_SPIN_LOCK(lock) SrvGlobalSpinLocks.lock
|
||
#define ENDPOINT_SPIN_LOCK(index) SrvGlobalSpinLocks.Endpoint[index].Lock
|
||
|
||
#define INITIALIZE_GLOBAL_SPIN_LOCK(lock) INITIALIZE_SPIN_LOCK( &GLOBAL_SPIN_LOCK(lock) )
|
||
|
||
#define ACQUIRE_GLOBAL_SPIN_LOCK(lock,irql) ACQUIRE_SPIN_LOCK( &GLOBAL_SPIN_LOCK(lock), (irql) )
|
||
#define RELEASE_GLOBAL_SPIN_LOCK(lock,irql) RELEASE_SPIN_LOCK( &GLOBAL_SPIN_LOCK(lock), (irql) )
|
||
#define ACQUIRE_DPC_GLOBAL_SPIN_LOCK(lock) ACQUIRE_DPC_SPIN_LOCK( &GLOBAL_SPIN_LOCK(lock) )
|
||
#define RELEASE_DPC_GLOBAL_SPIN_LOCK(lock) RELEASE_DPC_SPIN_LOCK( &GLOBAL_SPIN_LOCK(lock) )
|
||
|
||
//
|
||
// Macros for initializing, deleting, acquiring, and releasing locks.
|
||
//
|
||
|
||
#if !SRVDBG_LOCK
|
||
|
||
//
|
||
// When debugging is disabled, the lock macros simply equate to calls to
|
||
// the corresponding resource package functions.
|
||
//
|
||
|
||
#define INITIALIZE_LOCK( lock, level, name ) ExInitializeResourceLite( (lock) )
|
||
#define DELETE_LOCK( lock ) ExDeleteResourceLite( (lock) )
|
||
|
||
#define ACQUIRE_LOCK( lock ) \
|
||
ExAcquireResourceExclusiveLite( (lock), TRUE )
|
||
#define ACQUIRE_LOCK_NO_WAIT( lock ) \
|
||
ExAcquireResourceExclusiveLite( (lock), FALSE )
|
||
|
||
#define ACQUIRE_LOCK_SHARED( lock ) \
|
||
ExAcquireResourceSharedLite( (lock), TRUE )
|
||
#define ACQUIRE_LOCK_SHARED_NO_WAIT( lock ) \
|
||
ExAcquireResourceSharedLite( (lock), FALSE )
|
||
|
||
#define RELEASE_LOCK(lock) ExReleaseResourceLite( (lock) )
|
||
|
||
#define LOCK_NUMBER_OF_ACTIVE( lock ) ((lock)->ActiveCount)
|
||
|
||
#else // !SRVDBG_LOCK
|
||
|
||
//
|
||
// When debugging is enabled, the lock macros equate to calls to
|
||
// functions in the server. These functions are implemented in lock.c.
|
||
//
|
||
|
||
#define INITIALIZE_LOCK( lock, level, name ) \
|
||
SrvInitializeLock( (lock), (level), (name) )
|
||
#define DELETE_LOCK( lock ) SrvDeleteLock( (lock) )
|
||
|
||
#define ACQUIRE_LOCK( lock ) \
|
||
SrvAcquireLock( (lock), TRUE, TRUE )
|
||
#define ACQUIRE_LOCK_NO_WAIT( lock ) \
|
||
SrvAcquireLock( (lock), FALSE, TRUE )
|
||
|
||
#define ACQUIRE_LOCK_SHARED( lock ) \
|
||
SrvAcquireLock( (lock), TRUE, FALSE )
|
||
#define ACQUIRE_LOCK_SHARED_NO_WAIT( lock ) \
|
||
SrvAcquireLock( (lock), FALSE, FALSE )
|
||
|
||
#define RELEASE_LOCK( lock ) SrvReleaseLock( (lock) )
|
||
|
||
#define LOCK_NUMBER_OF_ACTIVE( lock ) ((lock)->Resource.ActiveCount)
|
||
|
||
#define LOCK_NAME( lock ) ((lock)->Header.LockName)
|
||
#define LOCK_LEVEL( lock ) ((lock)->Header.LockLevel)
|
||
#define LOCK_THREAD_LIST( lock ) (&((lock)->Header.ThreadListEntry))
|
||
|
||
#endif // else !SRVDBG_LOCK
|
||
|
||
|
||
#if !SRVDBG_LOCK
|
||
|
||
//
|
||
// When debugging is disabled, a server lock is identical to an
|
||
// executive resource.
|
||
//
|
||
|
||
typedef ERESOURCE SRV_LOCK, *PSRV_LOCK;
|
||
|
||
#define RESOURCE_OF(_l_) (_l_)
|
||
|
||
#else // !SRVDBG_LOCK
|
||
|
||
//
|
||
// SRV_LOCK_HEADER is a structure that contains debugging information
|
||
// used by the server lock package. Server locks contain a
|
||
// SRV_LOCK_HEADER.
|
||
//
|
||
|
||
typedef struct _SRV_LOCK_HEADER {
|
||
|
||
//
|
||
// To prevent deadlocks, locks are assigned level numbers. If a
|
||
// thread holds a lock with level N, it may only acquire new locks
|
||
// with a level greater then N. Level numbers are assigned during
|
||
// lock initialization.
|
||
//
|
||
// *** Due to the problems involved in retaining the information
|
||
// necessary to do level checking for shared locks, the lock
|
||
// package only does level checking for exclusive locks.
|
||
//
|
||
|
||
ULONG LockLevel;
|
||
|
||
//
|
||
// A doubly-linked list of all the locks owned by a thread is stored
|
||
// in a thread's TEB. The list is in order of lock level (from
|
||
// highest to lowest), which is also, by definition of lock levels,
|
||
// the order in which the thread acquired the locks. This allows
|
||
// the thread to release the locks in any order while maintaining
|
||
// easy access to the highest-level lock that the thread owns,
|
||
// thereby providing a mechanism for ensuring that locks are
|
||
// acquired in increasing order.
|
||
//
|
||
|
||
LIST_ENTRY ThreadListEntry;
|
||
|
||
//
|
||
// The symbolic name of the lock is used in DbgPrint calls.
|
||
//
|
||
|
||
PSZ LockName;
|
||
|
||
} SRV_LOCK_HEADER, *PSRV_LOCK_HEADER;
|
||
|
||
//
|
||
// When debugging is enabled, a server lock is a wrapper around an
|
||
// executive resource.
|
||
//
|
||
|
||
typedef struct _SRV_LOCK {
|
||
|
||
//
|
||
// The SRV_LOCK_HEADER must appear first!
|
||
//
|
||
|
||
SRV_LOCK_HEADER Header;
|
||
|
||
//
|
||
// The actual "lock" is maintained by the resource package.
|
||
//
|
||
|
||
ERESOURCE Resource;
|
||
|
||
} SRV_LOCK, *PSRV_LOCK;
|
||
|
||
#define RESOURCE_OF(_sl_) (_sl_).Resource
|
||
|
||
//
|
||
// Lock functions used when debugging.
|
||
//
|
||
|
||
VOID
|
||
SrvInitializeLock(
|
||
IN PSRV_LOCK Lock,
|
||
IN ULONG LockLevel,
|
||
IN PSZ LockName
|
||
);
|
||
|
||
VOID
|
||
SrvDeleteLock (
|
||
IN PSRV_LOCK Lock
|
||
);
|
||
|
||
BOOLEAN
|
||
SrvAcquireLock(
|
||
IN PSRV_LOCK Lock,
|
||
IN BOOLEAN Wait,
|
||
IN BOOLEAN Exclusive
|
||
);
|
||
|
||
VOID
|
||
SrvReleaseLock(
|
||
IN PSRV_LOCK Lock
|
||
);
|
||
|
||
//
|
||
// Macros that define locations in the UserReserved field of the TEB
|
||
// where lock level information is stored.
|
||
//
|
||
|
||
#define SRV_TEB_LOCK_LIST 0
|
||
#define SRV_TEB_LOCK_INIT 2
|
||
#define SRV_TEB_USER_SIZE (3 * sizeof(ULONG))
|
||
|
||
//
|
||
// Max value for lock levels is 0x7FFFFFFF.
|
||
//
|
||
// Levels for locks used in the server. The following must be true:
|
||
//
|
||
// EndpointLock must be lower than ConnectionLock (really
|
||
// connection->Lock) because SrvCloseConnectionsFromClient holds
|
||
// EndpointLock when it acquires ConnectionLock to check a connection's
|
||
// client name, and because a number of callers hold EndpointLock when
|
||
// they call SrvCloseConnection, which acquires ConnectionLock. Note
|
||
// also that SrvDeleteServedNet and TerminateServer hold EndpointLock
|
||
// when they call SrvCloseEndpoint; any attempt to change
|
||
// SrvCloseEndpoint must take this into account.
|
||
// ExamineAndProcessConnections also depends on this ordering.
|
||
//
|
||
// EndpointLock must be lower than MfcbListLock and MfcbLock because
|
||
// EndpointLock is held while stopping the server and closing
|
||
// connections, thereby closing files on the connections.
|
||
//
|
||
// ShareLock must be lower than ConnectionLock because
|
||
// SrvCloseTreeConnectsOnShare holds ShareLock when it calls
|
||
// SrvCloseTreeConnect. Note that SrvSmbTreeConnect and
|
||
// SrvSmbTreeConnectAndX depend on this ordering, because they take out
|
||
// both locks concurrently.
|
||
//
|
||
// Similarly, ShareLock must be lower than MfcbListLock and MfcbLock
|
||
// because SrvCloseTreeConnectsOnShare holds ShareLock when it calls
|
||
// SrvCloseRfcbsOnTree.
|
||
//
|
||
// MfcbListLock must be lower than MfcbLock (really mfcb->Lock) because
|
||
// SrvMoveFile and DoDelete hold MfcbListLock to find an MFCB, then take
|
||
// MfcbLock before releasing MfcbListLock.
|
||
//
|
||
// MfcbLock must be lower than OrderedListLock and ConnectionLock
|
||
// because CompleteOpen acquires these locks while holding the MfcbLock.
|
||
//
|
||
// OrderedListLock must be lower than ConnectionLock because
|
||
// SrvFindEntryInOrderedList holds the ordered list lock when in calls
|
||
// the check-and-reference routine for sessions and tree connects. For
|
||
// other ordered lists, this is not a problem, because the other lists
|
||
// are either protected the same locks that the check-and-reference
|
||
// routine uses (endpoints, connections, and shares), or the
|
||
// check-and-reference routine uses a spin lock (files). Note also that
|
||
// OrderedListLock and ConnectionLock are acquired concurrently and in
|
||
// the proper order in SrvSmbSessionSetupAndX, SrvSmbTreeConnect, and
|
||
// CompleteOpen.
|
||
//
|
||
// *** WARNING: If the ordered RFCB list (SrvRfcbList) or the ordered
|
||
// session list (SrvSessionList) are changed to use a lock other
|
||
// than SrvOrderedListLock, the above requirement may change, and
|
||
// the routines listed above may need to change. Changing other
|
||
// ordered lists that currently use some other global lock also may
|
||
// change the requirements.
|
||
//
|
||
// DebugLock must be higher than MfcbLock because CompleteOpen holds
|
||
// the MfcbLock when it allocates the LFCB and RFCB. The DebugLock
|
||
// is held for all memory allocations. Note that because of the
|
||
// way DebugLock is currently used, it is impossible to acquire other
|
||
// locks while holding DebugLock.
|
||
//
|
||
// ConnectionLock must be higher than SearchLock because the scavenger
|
||
// thread holds the search lock while walking the search list looking
|
||
// for search blocks to time out, and if a block to time out is found it
|
||
// closes the search which acquires the the connection lock in order to
|
||
// dereference the session in by the search block.
|
||
//
|
||
// EndpointLock must be higher than SearchLock because in the above
|
||
// scenario, SrvDereferenceSession may call SrvDereferenceConnection
|
||
// which acquires the endpoint lock.
|
||
//
|
||
// SearchLock must be at a higher level than ShareLock because
|
||
// SrvCloseShare gets the ShareLock, but SrvCloseSessionsOnTreeConnect
|
||
// aquires the SearchLock.
|
||
//
|
||
// CommDeviceLock must be higher than MfcbLock because DoCommDeviceOpen
|
||
// acquires the CommDeviceLock while holding MfcbLock.
|
||
//
|
||
// OplockListLock needs to be lower than ShareLock as the server may
|
||
// need to call SrvDereferenceRfcb while holding the OplockListLock.
|
||
// This routine may call SrvDereferenceLfcb which may call
|
||
// SrvDereferenceShare which acquires the ShareLock.
|
||
//
|
||
// This is a summary of the above (the top lock is acquired first and
|
||
// therefore must have a lower level):
|
||
//
|
||
// endp endp endp share share share mfcbl mfcb mfcb order mfcb
|
||
// conn mfcbl mfcb conn mfcbl mfcb mfcb order conn conn debug
|
||
//
|
||
// search search share oplock oplock
|
||
// conn endp search mfcb share
|
||
//
|
||
// Merging this, we find the following "threads" of requirements:
|
||
//
|
||
// share mfcb mfcb oplock
|
||
// search debug comm share
|
||
// endp
|
||
// mfcbl
|
||
// mfcb
|
||
// order
|
||
// conn
|
||
//
|
||
// The following locks are not affected by the above requirements:
|
||
//
|
||
// configuration
|
||
// smbbufferlist
|
||
// Connection->LicenseLock
|
||
//
|
||
// The levels of all of these locks are made equal and high in an
|
||
// attempt to find level requirements not listed above.
|
||
//
|
||
|
||
#define OPLOCK_LIST_LOCK_LEVEL (ULONG)0x00000800
|
||
#define SHARE_LOCK_LEVEL (ULONG)0x00000900
|
||
#define SEARCH_LOCK_LEVEL (ULONG)0x00001000
|
||
#define ENDPOINT_LOCK_LEVEL (ULONG)0x00002000
|
||
#define MFCB_LIST_LOCK_LEVEL (ULONG)0x00003000
|
||
#define MFCB_LOCK_LEVEL (ULONG)0x00004000
|
||
#define COMM_DEVICE_LOCK_LEVEL (ULONG)0x00005000
|
||
#define ORDERED_LIST_LOCK_LEVEL (ULONG)0x00006000
|
||
#define CONNECTION_LOCK_LEVEL (ULONG)0x00007000
|
||
#define CONFIGURATION_LOCK_LEVEL (ULONG)0x00010000
|
||
#define UNLOCKABLE_CODE_LOCK_LEVEL (ULONG)0x00010000
|
||
#define STARTUPSHUTDOWN_LOCK_LEVEL (ULONG)0x00020000
|
||
#define DEBUG_LOCK_LEVEL (ULONG)0x00050000
|
||
#define LICENSE_LOCK_LEVEL (ULONG)0x00100000
|
||
#define FCBLIST_LOCK_LEVEL (ULONG)0x00200000
|
||
|
||
#endif // else !SRVDBG_LOCK
|
||
|
||
#endif // ndef _LOCK_
|