398 lines
10 KiB
C
398 lines
10 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
cancel.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the support for cancelling operations in the RDBSS driver
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Balan Sethu Raman [SethuR] 7-June-95
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
//
|
|||
|
// The debug trace level
|
|||
|
//
|
|||
|
|
|||
|
#define Dbg (DEBUG_TRACE_CANCEL)
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxSetMinirdrCancelRoutine(
|
|||
|
IN OUT PRX_CONTEXT RxContext,
|
|||
|
IN PMRX_CALLDOWN MRxCancelRoutine)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The routine sets up a mini rdr cancel routine for an RxContext.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RxContext - the context
|
|||
|
|
|||
|
MRxCancelRoutine - the cancel routine
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
KIRQL SavedIrql;
|
|||
|
|
|||
|
KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
|
|||
|
|
|||
|
if (!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_CANCELLED)) {
|
|||
|
RxContext->MRxCancelRoutine = MRxCancelRoutine;
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
Status = STATUS_CANCELLED;
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
RxpCancelRoutine(
|
|||
|
PRX_CONTEXT pRxContext)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is invoked to the underlying mini rdr cancel routine at a non
|
|||
|
DPC level
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RxContext - the context
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PMRX_CALLDOWN MRxCancelRoutine;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
MRxCancelRoutine = pRxContext->MRxCancelRoutine;
|
|||
|
|
|||
|
if (MRxCancelRoutine != NULL) {
|
|||
|
(MRxCancelRoutine)(pRxContext);
|
|||
|
} else {
|
|||
|
if (!RxCancelOperationInOverflowQueue(pRxContext)) {
|
|||
|
|
|||
|
//RxCancelBlockingOperation(pRxContext);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
RxLog((
|
|||
|
"Dec RxC %lx L %ld %lx\n",
|
|||
|
pRxContext,__LINE__,pRxContext->ReferenceCount));
|
|||
|
RxWmiLog(LOG,
|
|||
|
RxpCancelRoutine,
|
|||
|
LOGPTR(pRxContext)
|
|||
|
LOGULONG(pRxContext->ReferenceCount));
|
|||
|
|
|||
|
RxDereferenceAndDeleteRxContext(pRxContext);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
RxCancelRoutine(
|
|||
|
PDEVICE_OBJECT pDeviceObject,
|
|||
|
PIRP pIrp)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The cancel routine for RDBSS
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pDeviceObject - the device object
|
|||
|
|
|||
|
pIrp - the IRP to be cancelled
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
Any request can be in one of three states in RDBSS ---
|
|||
|
|
|||
|
1) the request is being processed.
|
|||
|
|
|||
|
2) the request is waiting for the results of a calldown to a minirdr.
|
|||
|
|
|||
|
3) the request is waiting on a resource.
|
|||
|
|
|||
|
Any request that has been accepted by RDBSS ( the corresponding RxContext has been
|
|||
|
created and the cancel routine has been set ) is a valid target for cancel. The RDBSS
|
|||
|
driver does not make any effort to cancel requests that are in state (1) as described
|
|||
|
above.
|
|||
|
|
|||
|
The cancelling action is invoked on those requests which are either in state (2),
|
|||
|
state(3) or when it is about to transition to/from either of these states.
|
|||
|
|
|||
|
In order to expedite cancelling a similar strategy needs to be in place for the mini
|
|||
|
redirectors. This is provided by enabling the mini redirectors to register a cancel routine
|
|||
|
and rreserving fields in the RxContext for the mini redirectors to store the state information.
|
|||
|
|
|||
|
As part of the RDBSS cancel routine the following steps will be taken .....
|
|||
|
|
|||
|
1) Locate the RxContext corresponding to the given IRP.
|
|||
|
|
|||
|
2) If the RxContext is waiting for a minirdr invoke the appropriate cancel routine.
|
|||
|
|
|||
|
Note that the request is not immediately completed in all cases. This implies that there
|
|||
|
will be latencies in cancelling a request. The goal is to minimise the latency rather
|
|||
|
than completely eliminate them.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL SavedIrql;
|
|||
|
PRX_CONTEXT pRxContext;
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
|
|||
|
// Locate the context corresponding to the given Irp.
|
|||
|
KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
|
|||
|
|
|||
|
pListEntry = RxActiveContexts.Flink;
|
|||
|
|
|||
|
while (pListEntry != &RxActiveContexts) {
|
|||
|
pRxContext = CONTAINING_RECORD(pListEntry,RX_CONTEXT,ContextListEntry);
|
|||
|
|
|||
|
if (pRxContext->CurrentIrp == pIrp) {
|
|||
|
break;
|
|||
|
} else {
|
|||
|
pListEntry = pListEntry->Flink;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((pListEntry != &RxActiveContexts) &&
|
|||
|
!FlagOn(pRxContext->Flags,RX_CONTEXT_FLAG_CANCELLED)) {
|
|||
|
SetFlag( pRxContext->Flags, RX_CONTEXT_FLAG_CANCELLED );
|
|||
|
InterlockedIncrement(&pRxContext->ReferenceCount);
|
|||
|
} else {
|
|||
|
pRxContext = NULL;
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
|
|||
|
|
|||
|
IoReleaseCancelSpinLock(pIrp->CancelIrql);
|
|||
|
|
|||
|
if (pRxContext != NULL) {
|
|||
|
if (!RxShouldPostCompletion()) {
|
|||
|
RxpCancelRoutine(pRxContext);
|
|||
|
} else {
|
|||
|
RxDispatchToWorkerThread(
|
|||
|
RxFileSystemDeviceObject,
|
|||
|
CriticalWorkQueue,
|
|||
|
RxpCancelRoutine,
|
|||
|
pRxContext);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
|
|||
|
PV_NET_ROOT pVNetRoot,
|
|||
|
BOOLEAN ForceFilesClosed
|
|||
|
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine cancels all the outstanding requests for a given instance of V_NET_ROOT. The
|
|||
|
V_NET_ROOT's are created/deleted are independent of the files that are opened/manipulated
|
|||
|
in them. Therefore it is imperative that when a delete operation is attempted
|
|||
|
all the outstanding requests are cancelled.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pVNetRoot - the V_NET_ROOT instance about to be deleted
|
|||
|
|
|||
|
ForceFilesClosed - if true force close, otherwise fai if opens exist
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL SavedIrql;
|
|||
|
PRX_CONTEXT pRxContext;
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
LIST_ENTRY CancelledContexts;
|
|||
|
PMRX_CALLDOWN MRxCancelRoutine;
|
|||
|
NTSTATUS Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
InitializeListHead(&CancelledContexts);
|
|||
|
|
|||
|
// Locate the context corresponding to the given Irp.
|
|||
|
KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
|
|||
|
|
|||
|
pListEntry = RxActiveContexts.Flink;
|
|||
|
|
|||
|
while (pListEntry != &RxActiveContexts) {
|
|||
|
pRxContext = CONTAINING_RECORD(pListEntry,RX_CONTEXT,ContextListEntry);
|
|||
|
pListEntry = pListEntry->Flink;
|
|||
|
|
|||
|
if ((pRxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL) &&
|
|||
|
(pRxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) &&
|
|||
|
(pRxContext->pFcb != NULL) &&
|
|||
|
(pRxContext->NotifyChangeDirectory.pVNetRoot == (PMRX_V_NET_ROOT)pVNetRoot) &&
|
|||
|
(pRxContext->MRxCancelRoutine != NULL)) {
|
|||
|
|
|||
|
if (!ForceFilesClosed)
|
|||
|
{
|
|||
|
Status = STATUS_FILES_OPEN;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
SetFlag( pRxContext->Flags, RX_CONTEXT_FLAG_CANCELLED );
|
|||
|
RemoveEntryList(&pRxContext->ContextListEntry);
|
|||
|
InsertTailList(&CancelledContexts,&pRxContext->ContextListEntry);
|
|||
|
InterlockedIncrement(&pRxContext->ReferenceCount);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
|
|||
|
|
|||
|
if (Status == STATUS_SUCCESS)
|
|||
|
{
|
|||
|
while (!IsListEmpty(&CancelledContexts)) {
|
|||
|
pListEntry = RemoveHeadList(&CancelledContexts);
|
|||
|
|
|||
|
InitializeListHead(pListEntry);
|
|||
|
pRxContext = CONTAINING_RECORD(pListEntry,RX_CONTEXT,ContextListEntry);
|
|||
|
|
|||
|
//check to see if this guy is already completed..........if so, don't call down.
|
|||
|
if (pRxContext->CurrentIrp != NULL) {
|
|||
|
MRxCancelRoutine = pRxContext->MRxCancelRoutine;
|
|||
|
pRxContext->MRxCancelRoutine = NULL;
|
|||
|
|
|||
|
ASSERT(MRxCancelRoutine != NULL);
|
|||
|
|
|||
|
RxLog(("CCtx %lx CRtn %lx\n",pRxContext,MRxCancelRoutine));
|
|||
|
RxWmiLog(LOG,
|
|||
|
RxCancelNotifyChangeDirectoryRequestsForVNetRoot,
|
|||
|
LOGPTR(pRxContext)
|
|||
|
LOGPTR(MRxCancelRoutine));
|
|||
|
|
|||
|
(MRxCancelRoutine)(pRxContext);
|
|||
|
}
|
|||
|
|
|||
|
RxDereferenceAndDeleteRxContext(pRxContext);
|
|||
|
}
|
|||
|
}
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
RxCancelNotifyChangeDirectoryRequestsForFobx(
|
|||
|
PFOBX pFobx)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine cancels all the outstanding requests for a given FileObject This
|
|||
|
handles the case when a directory handle is closed while it has outstanding
|
|||
|
change notify requests pending.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pFobx - the FOBX instance about to be closed
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL SavedIrql;
|
|||
|
PRX_CONTEXT pRxContext;
|
|||
|
PLIST_ENTRY pListEntry;
|
|||
|
LIST_ENTRY CancelledContexts;
|
|||
|
PMRX_CALLDOWN MRxCancelRoutine;
|
|||
|
|
|||
|
InitializeListHead(&CancelledContexts);
|
|||
|
|
|||
|
// Locate the context corresponding to the given Irp.
|
|||
|
KeAcquireSpinLock( &RxStrucSupSpinLock, &SavedIrql );
|
|||
|
|
|||
|
pListEntry = RxActiveContexts.Flink;
|
|||
|
|
|||
|
while (pListEntry != &RxActiveContexts) {
|
|||
|
pRxContext = CONTAINING_RECORD(pListEntry,RX_CONTEXT,ContextListEntry);
|
|||
|
pListEntry = pListEntry->Flink;
|
|||
|
|
|||
|
if ((pRxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL) &&
|
|||
|
(pRxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) &&
|
|||
|
(pRxContext->pFobx == (PMRX_FOBX)pFobx) &&
|
|||
|
(pRxContext->MRxCancelRoutine != NULL)) {
|
|||
|
|
|||
|
SetFlag( pRxContext->Flags, RX_CONTEXT_FLAG_CANCELLED );
|
|||
|
RemoveEntryList(&pRxContext->ContextListEntry);
|
|||
|
InsertTailList(&CancelledContexts,&pRxContext->ContextListEntry);
|
|||
|
InterlockedIncrement(&pRxContext->ReferenceCount);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
KeReleaseSpinLock( &RxStrucSupSpinLock, SavedIrql );
|
|||
|
|
|||
|
while (!IsListEmpty(&CancelledContexts)) {
|
|||
|
pListEntry = RemoveHeadList(&CancelledContexts);
|
|||
|
|
|||
|
InitializeListHead(pListEntry);
|
|||
|
pRxContext = CONTAINING_RECORD(pListEntry,RX_CONTEXT,ContextListEntry);
|
|||
|
|
|||
|
// check to see if this IRP is already completed..........if so,
|
|||
|
// don't call down.
|
|||
|
|
|||
|
if (pRxContext->CurrentIrp != NULL) {
|
|||
|
MRxCancelRoutine = pRxContext->MRxCancelRoutine;
|
|||
|
pRxContext->MRxCancelRoutine = NULL;
|
|||
|
|
|||
|
ASSERT(MRxCancelRoutine != NULL);
|
|||
|
|
|||
|
RxLog(("CCtx %lx CRtn %lx\n",pRxContext,MRxCancelRoutine));
|
|||
|
RxWmiLog(LOG,
|
|||
|
RxCancelNotifyChangeDirectoryRequestsForFobx,
|
|||
|
LOGPTR(pRxContext)
|
|||
|
LOGPTR(MRxCancelRoutine));
|
|||
|
|
|||
|
(MRxCancelRoutine)(pRxContext);
|
|||
|
}
|
|||
|
|
|||
|
RxDereferenceAndDeleteRxContext(pRxContext);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|