2025-04-27 07:49:33 -04:00

359 lines
9.2 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
oplock.cxx
Abstract:
This module implements the oplock object.
Author:
Keith Moore (keithmo) 29-Aug-1997
Split off from the overly huge creatfil.cxx.
Revision History:
--*/
#include "TsunamiP.Hxx"
#pragma hdrstop
POPLOCK_OBJECT
CreateOplockObject(
VOID
)
/*++
Routine Description:
Creates a new oplock object.
Arguments:
None.
Return Value:
POPLOCK_OBJECT - Pointer to the newly created object if successful,
NULL otherwise.
--*/
{
POPLOCK_OBJECT oplock;
LPSTR eventName;
oplock = (POPLOCK_OBJECT)ALLOC( sizeof(*oplock) );
if( oplock != NULL ) {
oplock->Signature = OPLOCK_OBJ_SIGNATURE;
oplock->lpPFInfo = NULL;
//
// On checked builds, we'll create a name for our event. The
// name contains the address of the containing oplock structure
// and the process ID. This ensures the name should be unique
// across all processes. (Using a named event makes it easy
// to search for orphaned oplocks using the handles.exe utility.)
//
// On free builds, we'll create an unnamed event.
//
#if DBG
CHAR dbgEventName[sizeof("Oplock @ 12345678 PID 1234567890")];
wsprintf(
dbgEventName,
"Oplock @ %08lx PID %lu",
oplock,
GetCurrentProcessId()
);
eventName = dbgEventName;
#else
eventName = NULL;
#endif
oplock->hOplockInitComplete = CreateEvent(
NULL,
TRUE,
FALSE,
eventName
);
if( oplock->hOplockInitComplete == NULL ) {
FREE( oplock );
oplock = NULL;
} else {
TSUNAMI_TRACE( TRACE_OPLOCK_CREATE, oplock );
}
}
return oplock;
} // CreateOplockObject
VOID
DestroyOplockObject(
IN POPLOCK_OBJECT Oplock
)
/*++
Routine Description:
Destroys an oplock object.
Arguments:
Oplock - The oplock object to destroy.
Return Value:
None.
--*/
{
BOOL bSuccess;
ASSERT( Oplock != NULL );
ASSERT( Oplock->Signature == OPLOCK_OBJ_SIGNATURE );
TSUNAMI_TRACE( TRACE_OPLOCK_DESTROY, Oplock );
bSuccess = CloseHandle( Oplock->hOplockInitComplete );
ASSERT( bSuccess );
Oplock->Signature = OPLOCK_OBJ_SIGNATURE_X;
FREE( Oplock );
} // DestroyOplockObject
VOID
OplockCreateFile(
PVOID Context,
DWORD Status
)
/*++
Routine Description:
This routine is called by ATQ after an oplock break notification
is received. This routine is responsible for flushing the item
from the open file cache to ensure the file will be closed in
a timely manner.
Arguments:
Context - An uninterpreted context value. In reality, this is
a pointer to an OPLOCK_OBJECT.
Status - The oplock break status. This will be one of the following
values:
OPLOCK_BREAK_NO_OPLOCK - This notification is sent
immediately if the oplock could not be acquired.
This typically occurs if the target file is already
open.
OPLOCK_BREAK_OPEN -
OPLOCK_BREAK_CLOSE -
Return Value:
None.
--*/
{
POPLOCK_OBJECT lpOplock = (POPLOCK_OBJECT)Context;
PBLOB_HEADER pbhBlob;
PCACHE_OBJECT cache;
PCACHE_OBJECT pCacheTmp;
PCACHE_OBJECT TmpCache;
BOOL result = FALSE;
LIST_ENTRY ListHead;
PLIST_ENTRY pEntry;
IF_DEBUG(OPLOCKS) {
DBGPRINTF((
DBG_CONTEXT,
"OplockCreateFile(%08lx, %08lx) - Entered\n",
Context,
Status
));
}
ASSERT( lpOplock != NULL );
ASSERT( lpOplock->Signature == OPLOCK_OBJ_SIGNATURE );
if( Status != OPLOCK_BREAK_NO_OPLOCK ) {
DWORD waitResult;
while( TRUE ) {
waitResult = WaitForSingleObject(
lpOplock->hOplockInitComplete,
1000
);
if( waitResult == WAIT_OBJECT_0 ) {
break;
}
ASSERT( waitResult == WAIT_TIMEOUT );
DBGPRINTF((
DBG_CONTEXT,
"Rewaiting on oplock @ %08lx\n",
lpOplock
));
}
}
EnterCriticalSection( &CacheTable.CriticalSection );
EnterCriticalSection( &csVirtualRoots );
if( lpOplock->lpPFInfo == NULL ) {
TSUNAMI_TRACE( TRACE_OPLOCK_FAILURE, lpOplock );
} else {
ASSERT( lpOplock->lpPFInfo->Signature == PHYS_OBJ_SIGNATURE );
ASSERT( lpOplock->lpPFInfo->pOplock == lpOplock );
lpOplock->lpPFInfo->pOplock = NULL;
TSUNAMI_TRACE( TRACE_OPLOCK_BREAK, lpOplock );
pbhBlob = (( PBLOB_HEADER )lpOplock->lpPFInfo ) - 1;
if( pbhBlob->IsCached ) {
cache = pbhBlob->pCache;
TSUNAMI_TRACE( TRACE_CACHE_BREAK, cache );
InitializeListHead( &ListHead );
for( pEntry = CacheTable.MruList.Flink;
pEntry != &CacheTable.MruList;
pEntry = pEntry->Flink ) {
pCacheTmp = CONTAINING_RECORD( pEntry, CACHE_OBJECT, MruList );
ASSERT( pCacheTmp->Signature == CACHE_OBJ_SIGNATURE );
if( pCacheTmp != cache ) {
continue;
}
result = TRUE;
while( !IsListEmpty( &lpOplock->lpPFInfo->OpenReferenceList ) ) {
pEntry = RemoveHeadList( &lpOplock->lpPFInfo->OpenReferenceList );
InitializeListHead( pEntry );
pbhBlob = CONTAINING_RECORD( pEntry, BLOB_HEADER, PFList );
TmpCache = pbhBlob->pCache;
if( !RemoveCacheObjFromLists( TmpCache, FALSE ) ) {
IF_DEBUG(OPLOCKS) {
DBGPRINTF((
DBG_CONTEXT,
"OplockCreateFile(%08lx, %08lx, %08lx) - Error Processing Open Reference %08lx\n",
Context,
Status,
pEntry,
TmpCache
));
}
continue;
}
IF_DEBUG(OPLOCKS) {
DBGPRINTF((
DBG_CONTEXT,
"OplockCreateFile(%08lx, %08lx, %08lx) - Processing Open Reference %08lx\n",
Context,
Status,
pEntry,
TmpCache
));
}
InsertTailList( &ListHead, pEntry );
}
break;
}
if( result ) {
while( !IsListEmpty( &ListHead ) ) {
pEntry = RemoveHeadList( &ListHead );
InitializeListHead( pEntry );
pbhBlob = CONTAINING_RECORD( pEntry, BLOB_HEADER, PFList );
TmpCache = pbhBlob->pCache;
IF_DEBUG(OPLOCKS) {
DBGPRINTF((
DBG_CONTEXT,
"OplockCreateFile(%08lx, %08lx) - Processing Open Reference %08lx %08lx\n",
Context,
Status,
pEntry,
TmpCache
));
}
TsDereferenceCacheObj( TmpCache, FALSE );
}
if( RemoveCacheObjFromLists( cache, FALSE ) ) {
if( cache->fZombie ) {
//DON'T DO IT! TsDereferenceCacheObj( cache, FALSE );
}
} else {
IF_DEBUG(OPLOCKS) {
DBGPRINTF((
DBG_CONTEXT,
"OplockCreateFile(%08lx, %08lx) - Error Processing Open Reference %08lx\n",
Context,
Status,
cache
));
}
}
} else {
DBGPRINTF((
DBG_CONTEXT,
"Unknown oplock %08lx, cache == %08lx\n",
lpOplock,
cache
));
}
}
}
LeaveCriticalSection( &csVirtualRoots );
LeaveCriticalSection( &CacheTable.CriticalSection );
DestroyOplockObject( lpOplock );
} // OplockCreateFile