windows-nt/Source/XPSP1/NT/base/fs/srv/lock.h

413 lines
13 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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_