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
|
|||
|
|