?? fspyctx.c
字號:
SpyFreeContext( pContext );
INC_STATS(TotalContextNonDeferredFrees);
INC_LOCAL_STATS(deleteNowCount);
} else {
//
// Someone still has a pointer to it, it will get deleted
// later when they release
//
INC_LOCAL_STATS(deleteDeferredCount);
SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
("FileSpy!SpyDeleteAllContexts: DEFERRED (%p) Fl=%02x Use=%d \"%wZ\"\n",
pContext,
pContext->Flags,
pContext->UseCount,
&pContext->Name) );
}
}
SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
("FileSpy!SpyDeleteAllContexts: %3d deleted now, %3d deferred, %3d close contention \"%wZ\"\n",
deleteNowCount,
deleteDeferredCount,
deleteInCallbackCount,
&devExt->NLExtHeader.DeviceName) );
}
VOID
SpyDeleteContext (
IN PDEVICE_OBJECT DeviceObject,
IN PSPY_STREAM_CONTEXT pContext
)
/*++
Routine Description:
Unlink and release the given context.
Arguments:
DeviceObject - Device to operate on
pContext - The context to delete
Return Value:
None.
--*/
{
PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
PAGED_CODE();
ASSERT(IS_FILESPY_DEVICE_OBJECT(DeviceObject));
SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
("FileSpy!SpyDeleteContext: (%p) Fl=%02x Use=%d \"%wZ\"\n",
pContext,
pContext->Flags,
pContext->UseCount,
&pContext->Name));
//
// Acquire list lock
//
SpyAcquireContextLockExclusive( devExt );
//
// Remove from extension list (if still in it)
//
if (FlagOn(pContext->Flags,CTXFL_InExtensionList)) {
RemoveEntryList( &pContext->ExtensionLink );
RtlInterlockedClearBitsDiscardReturn(&pContext->Flags,CTXFL_InExtensionList);
}
//
// See if still in stream list.
//
if (!FlagOn(pContext->Flags,CTXFL_InStreamList)) {
//
// Not in stream list, release lock and return
//
SpyReleaseContextLock( devExt );
} else {
//
// Remove from Stream list
//
ctxCtrl = FsRtlRemovePerStreamContext( pContext->Stream,
devExt,
NULL );
//
// Always clear the flag wether we found it in the list or not. We
// can have the flag set and not be in the list if after we acquired
// the context list lock we context swapped and the file system
// is right now in SpyDeleteContextCallback waiting on the list lock.
//
RtlInterlockedClearBitsDiscardReturn(&pContext->Flags,CTXFL_InStreamList);
//
// Release list lock
//
SpyReleaseContextLock( devExt );
//
// The context is now deleted from all of the lists and the lock is
// removed. We need to see if we found this entry on the systems context
// list. If not that means the callback was in the middle of trying
// to free this (while we were) and has already deleted it.
// If we found a structure then delete it now ourselves.
//
if (NULL != ctxCtrl) {
ASSERT(pContext == CONTAINING_RECORD(ctxCtrl,SPY_STREAM_CONTEXT,ContextCtrl));
//
// Decrement USE count, free context if zero
//
ASSERT(pContext->UseCount > 0);
if (InterlockedDecrement( &pContext->UseCount ) <= 0) {
INC_STATS(TotalContextNonDeferredFrees);
SpyFreeContext( pContext );
} else {
SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
("FileSpy!SpyDeleteContext: DEFERRED (%p) Fl=%02x Use=%d \"%wZ\"\n",
pContext,
pContext->Flags,
pContext->UseCount,
&pContext->Name));
}
} else {
INC_STATS(TotalContextsNotFoundInStreamList);
}
}
}
VOID
SpyDeleteContextCallback (
IN PVOID Context
)
/*++
Routine Description:
This is called by base file systems when a context needs to be deleted.
Arguments:
Context - The context structure being deleted
Return Value:
None.
--*/
{
PSPY_STREAM_CONTEXT pContext = Context;
PFILESPY_DEVICE_EXTENSION devExt;
PAGED_CODE();
devExt = (PFILESPY_DEVICE_EXTENSION)pContext->ContextCtrl.OwnerId;
SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
("FileSpy!SpyDeleteContextCallback: (%p) Fl=%02x Use=%d \"%wZ\"\n",
pContext,
pContext->Flags,
pContext->UseCount,
&pContext->Name) );
//
// When we get here we have already been removed from the stream list (by
// the calling file system), flag that this has happened.
//
RtlInterlockedClearBitsDiscardReturn(&pContext->Flags,CTXFL_InStreamList);
//
// Lock the context list lock in the extension
//
SpyAcquireContextLockExclusive( devExt );
//
// See if we are still linked into the extension list. If not then skip
// the unlinking. This can happen if someone is trying to delete this
// context at the same time as we are.
//
if (FlagOn(pContext->Flags,CTXFL_InExtensionList)) {
RemoveEntryList( &pContext->ExtensionLink );
RtlInterlockedClearBitsDiscardReturn(&pContext->Flags,CTXFL_InExtensionList);
}
SpyReleaseContextLock( devExt );
//
// Decrement USE count, free context if zero
//
ASSERT(pContext->UseCount > 0);
if (InterlockedDecrement( &pContext->UseCount ) <= 0) {
INC_STATS(TotalContextCtxCallbackFrees);
SpyFreeContext( pContext );
} else {
SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
("FileSpy!SpyDeleteContextCB: DEFFERED (%p) Fl=%02x Use=%d \"%wZ\"\n",
pContext,
pContext->Flags,
pContext->UseCount,
&pContext->Name) );
}
}
VOID
SpyLinkContext (
IN PDEVICE_OBJECT DeviceObject,
IN PFILE_OBJECT FileObject,
IN OUT PSPY_STREAM_CONTEXT *ppContext
)
/*++
Routine Description:
This will link the given context into the context list for the given
device as well as into the given stream.
NOTE: It is possible for this entry to already exist in the table since
between the time we initially looked and the time we inserted
(which is now) someone else may have inserted one. If we find an
entry that already exists we will free the entry passed in and
return the entry found.
Arguments:
DeviceObject - Device we are operating on
FileObject - Represents the stream to link the context into
ppContext - Enters with the context to link, returns with the context
to use. They may be different if the given context already
exists.
Return Value:
None.
--*/
{
PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
NTSTATUS status;
PSPY_STREAM_CONTEXT pContext = *ppContext;
PSPY_STREAM_CONTEXT ctx;
PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
PAGED_CODE();
ASSERT(IS_FILESPY_DEVICE_OBJECT(DeviceObject));
ASSERT(FileObject->FsContext != NULL);
ASSERT(pContext != NULL);
//
// If this is marked as a temporary context, return now. Because we
// don't bump the reference count, when it is release it to be freed.
//
if (FlagOn(pContext->Flags,CTXFL_Temporary)) {
ASSERT(!FlagOn(pContext->Flags,CTXFL_InExtensionList));
return;
}
//
// We need to figure out if a duplicate entry already exists on
// the context list for this file object. Acquire our list lock
// and then see if it exists. If not, insert into the stream and
// volume lists. If so, then simply free this new entry and return
// the original.
//
// This can happen when:
// - Someone created an entry at the exact same time as we were
// creating an entry.
// - When someone does a create with overwrite or supersede we
// do not have the information yet to see if a context already
// exists. Because of this we have to create a new context
// every time. During post-create we then see if one already
// exists.
//
//
// Initialize the context control structure. We do this now so we
// don't have to do it while the lock is held (even if we might
// have to free it because of a duplicate found)
//
FsRtlInitPerStreamContext( &pContext->ContextCtrl,
devExt,
NULL,
SpyDeleteContextCallback );
//
// Save the stream we are associated with.
//
pContext->Stream = FsRtlGetPerStreamContextPointer(FileObject);
//
// Acquire list lock exclusively
//
SpyAcquireContextLockExclusive( devExt );
ASSERT(pContext->UseCount == 1);
ASSERT(!FlagOn(pContext->Flags,CTXFL_InExtensionList));
ASSERT(!FlagOn(pContext->Flags,CTXFL_Temporary));
//
// See if we have an entry already on the list
//
ctxCtrl = FsRtlLookupPerStreamContext( FsRtlGetPerStreamContextPointer(FileObject),
devExt,
NULL );
if (NULL != ctxCtrl) {
//
// The context already exists so free the new one we just
// created. First increment the use count on the one we found in
// the list.
//
ctx = CONTAINING_RECORD(ctxCtrl,SPY_STREAM_CONTEXT,ContextCtrl);
ASSERT(ctx->Stream == FsRtlGetPerStreamContextPointer(FileObject));
ASSERT(FlagOn(ctx->Flags,CTXFL_InExtensionList));
ASSERT(ctx->UseCount > 0);
//
// Bump ref count and release lock
//
InterlockedIncrement( &ctx->UseCount );
SpyReleaseContextLock( devExt );
//
// Since this cache is across opens on the same stream there are
// cases where the names will be different even though they are the
// same file. These cases are:
// - One open could be by short name where another open
// is by long name.
// - This does not presently strip extended stream names like
// :$DATA
// When enabled this will display to the debugger screen when the
// names don't exactly match. You can also break on this difference.
//
if (!RtlEqualUnicodeString( &pContext->Name,&ctx->Name,TRUE )) {
SPY_LOG_PRINT( SPYDEBUG_TRACE_MISMATCHED_NAMES,
("FileSpy!SpyLinkContext: Old Name: (%p) Fl=%02x Use=%d \"%wZ\"\n"
" New Name: (%p) Fl=%02x Use=%d \"%wZ\"\n",
ctx,
ctx->Flags,
ctx->UseCount,
&ctx->Name,
pContext,
pContext->Flags,
pContext->UseCount,
&pContext->Name) );
if (FlagOn(gFileSpyDebugLevel,SPYDEBUG_ASSERT_MISMATCHED_NAMES)) {
DbgBreakPoint();
}
}
SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
("FileSpy!SpyLinkContext: Rel Dup: (%p) Fl=%02x Use=%d \"%wZ\"\n",
pContext,
pContext->Flags,
pContext->UseCount,
&pContext->Name) );
//
// Free the new structure because it was already resident. Note
// that this entry has never been linked into any lists so we know
// no one else has a reference to it. Decrement use count to keep
// the ASSERTS happy then free the memory.
//
INC_STATS(TotalContextDuplicateFrees);
pContext->UseCount--;
SpyFreeContext( pContext );
//
// Return the one we found in the list
//
*ppContext = ctx;
} else {
//
// The new context did not exist, insert this new one.
//
//
// Link into Stream context. This can fail for the following
// reasons:
// This is a paging file
// This is a volume open
// If this happens then don't bump the reference count and it will be
// freed when the caller is done with it.
//
status = FsRtlInsertPerStreamContext( FsRtlGetPerStreamContextPointer(FileObject),
&pContext->ContextCtrl );
if (NT_SUCCESS(status)) {
//
// Increment the USE count (because it is added to the stream)
//
InterlockedIncrement( &pContext->UseCount );
//
// Link into Device extension
//
InsertHeadList( &devExt->CtxList, &pContext->ExtensionLink );
//
// Mark that we have been inserted into both lists. We don't have
// to do this interlocked because no one can access this entry
// until we release the context lock.
//
SetFlag( pContext->Flags, CTXFL_InExtensionList|CTXFL_InStreamList );
}
//
// Release lock
//
SpyReleaseContextLock( devExt );
}
}
/***************************************************************************++
Routine Description:
This will allocate and initialize a context structure but it does NOT
link it into the context hash list.
Arguments:
Return Value:
--***************************************************************************/
NTSTATUS
SpyCreateContext (
IN PDEVICE_OBJECT DeviceObject,
IN PFILE_OBJECT FileObject,
IN NAME_LOOKUP_FLAGS LookupFlags,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -