414 lines
8 KiB
C
414 lines
8 KiB
C
/*++
|
||
|
||
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
|
||
|