📄 close.c
字号:
//
if (++LoopsWithVcbHeld >= 20) {
if (ExGetSharedWaiterCount( &CurrentVcb->Resource ) +
ExGetExclusiveWaiterCount( &CurrentVcb->Resource )) {
ExReleaseResourceLite( &CurrentVcb->Resource);
(VOID)ExAcquireResourceExclusiveLite( &CurrentVcb->Resource, TRUE );
}
LoopsWithVcbHeld = 0;
}
}
//
// Now check the Open count. We may be about to delete this volume!
//
// The test below must be <= 1 because there could still be outstanding
// stream references on this VCB that are not counted in the OpenFileCount.
// For example if there are no open files OpenFileCount could be zero and we would
// not release the resource here. The call to FatCommonClose() below may cause
// the VCB to be torn down and we will try to release memory we don't
// own later.
//
if (CurrentVcb->OpenFileCount <= 1) {
ExReleaseResourceLite( &CurrentVcb->Resource);
CurrentVcb = NULL;
}
//
// If shutdown has started while processing our list, drop the
// current Vcb resource.
//
} else if (CurrentVcb != NULL) {
ExReleaseResourceLite( &CurrentVcb->Resource);
CurrentVcb = NULL;
}
}
LastVcb = CurrentVcb;
//
// Call the common Close routine. Protected in a try {} except {}
//
try {
//
// The close context either is in the CCB, automatically freed,
// or was from pool for a metadata fileobject, CCB is NULL, and
// we'll need to free it.
//
FreeContext = CloseContext->Free;
(VOID)FatCommonClose( CloseContext->Vcb,
CloseContext->Fcb,
(FreeContext ? NULL :
CONTAINING_RECORD( CloseContext, CCB, CloseContext)),
CloseContext->TypeOfOpen,
TRUE,
NULL );
} except(FatExceptionFilter( NULL, GetExceptionInformation() )) {
//
// Ignore anything we expect.
//
NOTHING;
}
//
// Drop the context if it came from pool.
//
if (FreeContext) {
ExFreePool( CloseContext );
}
}
//
// Release a previously held Vcb, if any.
//
if (CurrentVcb != NULL) {
ExReleaseResourceLite( &CurrentVcb->Resource);
}
//
// Clean up the top level IRP hint if we owned it.
//
if (!ARGUMENT_PRESENT( Vcb )) {
IoSetTopLevelIrp( NULL );
}
//
// And return to our caller
//
DebugTrace(-1, Dbg, "FatFspClose -> NULL\n", 0);
}
VOID
FatQueueClose (
IN PCLOSE_CONTEXT CloseContext,
IN BOOLEAN DelayClose
)
/*++
Routine Description:
Enqueue a deferred close to one of the two delayed close queues.
Arguments:
CloseContext - a close context to enqueue for the delayed close thread.
DelayClose - whether this should go on the delayed close queue (unreferenced
objects).
Return Value:
None.
--*/
{
BOOLEAN StartWorker = FALSE;
FatAcquireCloseMutex();
if (DelayClose) {
InsertTailList( &FatData.DelayedCloseList,
&CloseContext->GlobalLinks );
InsertTailList( &CloseContext->Vcb->DelayedCloseList,
&CloseContext->VcbLinks );
FatData.DelayedCloseCount += 1;
if ((FatData.DelayedCloseCount > FatMaxDelayedCloseCount) &&
!FatData.AsyncCloseActive) {
FatData.AsyncCloseActive = TRUE;
StartWorker = TRUE;
}
} else {
InsertTailList( &FatData.AsyncCloseList,
&CloseContext->GlobalLinks );
InsertTailList( &CloseContext->Vcb->AsyncCloseList,
&CloseContext->VcbLinks );
FatData.AsyncCloseCount += 1;
if (!FatData.AsyncCloseActive) {
FatData.AsyncCloseActive = TRUE;
StartWorker = TRUE;
}
}
FatReleaseCloseMutex();
if (StartWorker) {
IoQueueWorkItem( FatData.FatCloseItem, FatCloseWorker, CriticalWorkQueue, NULL );
}
}
PCLOSE_CONTEXT
FatRemoveClose (
PVCB Vcb OPTIONAL,
PVCB LastVcbHint OPTIONAL
)
/*++
Routine Description:
Dequeue a deferred close from one of the two delayed close queues.
Arguments:
Vcb - if specified, only returns close for this volume.
LastVcbHint - if specified and other starvation avoidance is required by
the system condition, will attempt to return closes for this volume.
Return Value:
A close to perform.
--*/
{
PLIST_ENTRY Entry;
PCLOSE_CONTEXT CloseContext;
BOOLEAN WorkerThread;
FatAcquireCloseMutex();
//
// Remember if this is the worker thread, so we can pull down the active
// flag should we run everything out.
//
WorkerThread = (Vcb == NULL);
//
// If the queues are above the limits by a significant amount, we have
// to try hard to pull them down. To do this, we will aggresively try
// to find closes for the last volume the caller looked at. This will
// make sure we fully utilize the acquisition of the volume, which can
// be a hugely expensive resource to get (create/close/cleanup use it
// exclusively).
//
// Only do this in the delayed close thread. We will know this is the
// case by seeing a NULL mandatory Vcb.
//
if (Vcb == NULL && LastVcbHint != NULL) {
//
// Flip over to aggressive at twice the legal limit, and flip it
// off at the legal limit.
//
if (!FatData.HighAsync && FatData.AsyncCloseCount > FatMaxDelayedCloseCount*2) {
FatData.HighAsync = TRUE;
} else if (FatData.HighAsync && FatData.AsyncCloseCount < FatMaxDelayedCloseCount) {
FatData.HighAsync = FALSE;
}
if (!FatData.HighDelayed && FatData.DelayedCloseCount > FatMaxDelayedCloseCount*2) {
FatData.HighDelayed = TRUE;
} else if (FatData.HighDelayed && FatData.DelayedCloseCount < FatMaxDelayedCloseCount) {
FatData.HighDelayed = FALSE;
}
if (FatData.HighAsync || FatData.HighDelayed) {
Vcb = LastVcbHint;
}
}
//
// Do the case when we don't care about which Vcb the close is on.
// This is the case when we are in an ExWorkerThread and aren't
// under pressure.
//
if (Vcb == NULL) {
AnyClose:
//
// First check the list of async closes.
//
if (!IsListEmpty( &FatData.AsyncCloseList )) {
Entry = RemoveHeadList( &FatData.AsyncCloseList );
FatData.AsyncCloseCount -= 1;
CloseContext = CONTAINING_RECORD( Entry,
CLOSE_CONTEXT,
GlobalLinks );
RemoveEntryList( &CloseContext->VcbLinks );
//
// Do any delayed closes over half the limit, unless shutdown has
// started (then kill them all).
//
} else if (!IsListEmpty( &FatData.DelayedCloseList ) &&
(FatData.DelayedCloseCount > FatMaxDelayedCloseCount/2 ||
FatData.ShutdownStarted)) {
Entry = RemoveHeadList( &FatData.DelayedCloseList );
FatData.DelayedCloseCount -= 1;
CloseContext = CONTAINING_RECORD( Entry,
CLOSE_CONTEXT,
GlobalLinks );
RemoveEntryList( &CloseContext->VcbLinks );
//
// There are no more closes to perform; show that we are done.
//
} else {
CloseContext = NULL;
if (WorkerThread) {
FatData.AsyncCloseActive = FALSE;
}
}
//
// We're running down a specific volume.
//
} else {
//
// First check the list of async closes.
//
if (!IsListEmpty( &Vcb->AsyncCloseList )) {
Entry = RemoveHeadList( &Vcb->AsyncCloseList );
FatData.AsyncCloseCount -= 1;
CloseContext = CONTAINING_RECORD( Entry,
CLOSE_CONTEXT,
VcbLinks );
RemoveEntryList( &CloseContext->GlobalLinks );
//
// Do any delayed closes.
//
} else if (!IsListEmpty( &Vcb->DelayedCloseList )) {
Entry = RemoveHeadList( &Vcb->DelayedCloseList );
FatData.DelayedCloseCount -= 1;
CloseContext = CONTAINING_RECORD( Entry,
CLOSE_CONTEXT,
VcbLinks );
RemoveEntryList( &CloseContext->GlobalLinks );
//
// If we were trying to run down the queues but didn't find anything for this
// volume, flip over to accept anything and try again.
//
} else if (LastVcbHint) {
goto AnyClose;
//
// There are no more closes to perform; show that we are done.
//
} else {
CloseContext = NULL;
}
}
FatReleaseCloseMutex();
return CloseContext;
}
NTSTATUS
FatCommonClose (
IN PVCB Vcb,
IN PFCB Fcb,
IN PCCB Ccb,
IN TYPE_OF_OPEN TypeOfOpen,
IN BOOLEAN Wait,
OUT PBOOLEAN VcbDeleted OPTIONAL
)
/*++
Routine Description:
This is the common routine for closing a file/directory called by both
the fsd and fsp threads.
Close is invoked whenever the last reference to a file object is deleted.
Cleanup is invoked when the last handle to a file object is closed, and
is called before close.
The function of close is to completely tear down and remove the fcb/dcb/ccb
structures associated with the file object.
Arguments:
Fcb - Supplies the file to process.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -