/*++ Copyright (c) 1999 Microsoft Corporation Module Name: blklock.c Abstract: This module implements routines for managing byte range lock blocks. Author: Andy Herron (andyhe) 15-Nov-1999 Revision History: --*/ #include "precomp.h" #include "blklock.tmh" #pragma hdrstop #ifdef INCLUDE_SMB_PERSISTENT #define BugCheckFileId SRV_FILE_BLKLOCK #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, SrvAllocateLock ) #pragma alloc_text( PAGE, SrvFindAndReferenceLock ) #pragma alloc_text( PAGE, SrvCloseLock ) #pragma alloc_text( PAGE, SrvCloseLocksOnRfcb ) #pragma alloc_text( PAGE, SrvDereferenceLock ) #endif VOID SrvAllocateLock ( OUT PBYTELOCK *Lock, IN PRFCB Rfcb, IN LARGE_INTEGER Offset, IN LARGE_INTEGER Length, IN BOOLEAN Exclusive ) /*++ Routine Description: This function allocates a lock block from the FSP heap. Arguments: Lock - Returns a pointer to the lock block, or NULL if no heap space was available. Rfcb - file which owns this lock. MFCB lock will be taken to insert lock into list. Offset - offset of lock in file. Length - lock length. Exclusive - is this a shared or exclusive lock? Return Value: None. --*/ { PBYTELOCK lock; PNONPAGED_MFCB npMfcb; PAGED_CODE( ); if ( ! Rfcb->PersistentHandle ) { *Lock = NULL; return; } // // Attempt to allocate from the heap. // lock = ALLOCATE_HEAP( sizeof(BYTELOCK), BlockTypeByteRangeLock ); *Lock = lock; if ( lock == NULL ) { INTERNAL_ERROR( ERROR_LEVEL_EXPECTED, "SrvAllocateLock: Unable to allocate %d bytes from heap", sizeof(BYTELOCK), NULL ); return; } IF_DEBUG(HEAP) { SrvPrint1( "SrvAllocateLock: Allocated byte range lock at %lx\n", lock ); } RtlZeroMemory( lock, sizeof(BYTELOCK) ); SET_BLOCK_TYPE_STATE_SIZE( lock, BlockTypeByteRangeLock, BlockStateActive, BlockTypeByteRangeLock ); lock->BlockHeader.ReferenceCount = 2; // allow for Active status and caller's pointer lock->Rfcb = Rfcb; lock->LockOffset.QuadPart = Offset.QuadPart; lock->LockLength.QuadPart = Length.QuadPart; lock->Exclusive = Exclusive; INITIALIZE_REFERENCE_HISTORY( lock ); npMfcb = Rfcb->Lfcb->Mfcb->NonpagedMfcb; ACQUIRE_LOCK( &npMfcb->Lock ); SrvInsertHeadList( &Rfcb->PagedRfcb->ByteRangeLocks, &lock->RfcbListEntry ); RELEASE_LOCK( &npMfcb->Lock ); // INCREMENT_DEBUG_STAT( SrvDbgStatistics.SessionInfo.Allocations ); return; } // SrvAllocateLock PBYTELOCK SrvFindAndReferenceLock ( IN PRFCB Rfcb, IN LARGE_INTEGER Offset, IN LARGE_INTEGER Length, IN BOOLEAN Exclusive ) /*++ Routine Description: This function finds a lock, references it and returns it. Arguments: Rfcb - file which owns this lock. MFCB lock will be taken to insert lock into list. Offset - offset of lock in file. Length - lock length. Exclusive - is this a shared or exclusive lock? Return Value: PBYTELOCK - pointer to lock structure, null if doesn't exist. --*/ { PBYTELOCK lock = NULL; PLIST_ENTRY listEntry; PLIST_ENTRY listHead; PNONPAGED_MFCB npMfcb; PAGED_CODE( ); if (! Rfcb->PersistentHandle ) { return NULL; } npMfcb = Rfcb->Lfcb->Mfcb->NonpagedMfcb; ACQUIRE_LOCK( &npMfcb->Lock ); listHead = &Rfcb->PagedRfcb->ByteRangeLocks; listEntry = listHead->Flink; while (listEntry != listHead) { lock = CONTAINING_RECORD( listEntry, BYTELOCK, RfcbListEntry ); if ( GET_BLOCK_STATE(lock) == BlockStateActive && lock->LockOffset.QuadPart == Offset.QuadPart && lock->LockLength.QuadPart == Length.QuadPart && lock->Exclusive == Exclusive ) { IF_DEBUG(REFCNT) { SrvPrint2( "Referencing byte lock 0x%lx; old refcnt %lx\n", lock, lock->BlockHeader.ReferenceCount ); } ASSERT( GET_BLOCK_TYPE( lock ) == BlockTypeByteRangeLock ); ASSERT( lock->BlockHeader.ReferenceCount > 0 ); InterlockedIncrement( &lock->BlockHeader.ReferenceCount ); break; } lock = NULL; listEntry = listEntry->Flink; } RELEASE_LOCK( &npMfcb->Lock ); return lock; } // SrvFindAndReferenceLock VOID SrvCloseLock ( IN PBYTELOCK Lock, IN BOOLEAN HaveLock ) /*++ Routine Description: This routine closes out the byte range lock block. Arguments: Lock - Supplies a pointer to the lock block that is to be closed. Return Value: None. --*/ { PNONPAGED_MFCB npMfcb; PAGED_CODE( ); ASSERT( Lock->Rfcb != NULL ); if (!HaveLock) { npMfcb = Lock->Rfcb->Lfcb->Mfcb->NonpagedMfcb; ACQUIRE_LOCK( &npMfcb->Lock ); } if ( GET_BLOCK_STATE(Lock) == BlockStateActive ) { IF_DEBUG(BLOCK1) SrvPrint1( "Closing byte lock at 0x%lx\n", Lock ); SET_BLOCK_STATE( Lock, BlockStateClosing ); SrvRemoveEntryList( &Rfcb->PagedRfcb->ByteRangeLocks, &Lock->RfcbListEntry ); if (!HaveLock) { RELEASE_LOCK( &npMfcb->Lock ); } // if ( we're in the state file ) { // // remove us from state file. // } Lock->Rfcb = NULL; // // Dereference the lock (to indicate that it's no longer // open). // SrvDereferenceLock( Lock ); } else { if (!HaveLock) { RELEASE_LOCK( &npMfcb->Lock ); } } return; } // SrvCloseLock VOID SrvCloseLocksOnRfcb ( IN PRFCB Rfcb ) /*++ Routine Description: This function closes all locks on an RFCB. It walks the RFCB's list of locks, calling SrvCloseLock as appropriate. Arguments: Rfcb - Supplies a pointer to a Rfcb Block Return Value: None. --*/ { PBYTELOCK lock; PLIST_ENTRY listEntry; PLIST_ENTRY listHead; PNONPAGED_MFCB npMfcb; PAGED_CODE( ); if (! Rfcb->PersistentHandle ) { return; } npMfcb = Rfcb->Lfcb->Mfcb->NonpagedMfcb; ACQUIRE_LOCK( &npMfcb->Lock ); listHead = &Rfcb->PagedRfcb->ByteRangeLocks; listEntry = listHead->Flink; while (listEntry != listHead) { lock = CONTAINING_RECORD( listEntry, BYTELOCK, RfcbListEntry ); listEntry = listEntry->Flink; SrvCloseLock( lock, TRUE ); } RELEASE_LOCK( &npMfcb->Lock ); return; } // SrvCloseLocksOnRfcb VOID SRVFASTCALL SrvDereferenceLock ( IN PBYTELOCK Lock ) /*++ Routine Description: This function decrements the reference count on a lock. If the reference count goes to zero, the lock block is deleted. Arguments: Lock - Address of lock Return Value: None. --*/ { LONG result; PAGED_CODE( ); // // Enter a critical section and decrement the reference count on the // block. // IF_DEBUG(REFCNT) { SrvPrint2( "Dereferencing byte lock 0x%lx; old refcnt %lx\n", Lock, Lock->BlockHeader.ReferenceCount ); } ASSERT( GET_BLOCK_TYPE( Lock ) == BlockTypeByteRangeLock ); ASSERT( Lock->BlockHeader.ReferenceCount > 0 ); result = InterlockedDecrement( &Lock->BlockHeader.ReferenceCount ); if ( result == 0 ) { ASSERT( GET_BLOCK_STATE(Lock) == BlockStateClosing ); // // Free the session block. // DEBUG SET_BLOCK_TYPE_STATE_SIZE( Lock, BlockTypeGarbage, BlockStateDead, -1 ); DEBUG Lock->BlockHeader.ReferenceCount = -1; FREE_HEAP( Lock ); IF_DEBUG(HEAP) { SrvPrint1( "SrvDereferenceLock: Freed session byte lock at 0x%lx\n", Lock ); } } return; } // SrvDereferenceLock #endif // def INCLUDE_SMB_PERSISTENT // blklock.c eof