windows-nt/Source/XPSP1/NT/admin/pchealth/sr/kernel/control.c
2020-09-26 16:20:57 +08:00

397 lines
7.6 KiB
C

/*++
Copyright (c) 1998-2000 Microsoft Corporation
Module Name:
control.c
Abstract:
this has code for the sr control object. this is the object that is
created that matches the HANDLE usermode uses to perform operations
with the sr driver
Author:
Paul McDaniel (paulmcd) 23-Jan-2000
Revision History:
--*/
#include "precomp.h"
//
// Private constants.
//
//
// Private types.
//
//
// Private prototypes.
//
//
// linker commands
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, SrCreateControlObject )
#pragma alloc_text( PAGE, SrDeleteControlObject )
#pragma alloc_text( PAGE, SrCancelControlIo )
#pragma alloc_text( PAGE, SrReferenceControlObject)
#pragma alloc_text( PAGE, SrDereferenceControlObject )
#endif // ALLOC_PRAGMA
//
// Private globals.
//
//
// Public globals.
//
//
// Public functions.
//
//
// you must have the lock EXCLUSIVE prior to calling this !
//
NTSTATUS
SrCreateControlObject(
OUT PSR_CONTROL_OBJECT * ppControlObject,
IN ULONG Options
)
{
NTSTATUS Status = STATUS_SUCCESS;
PSR_CONTROL_OBJECT pControlObject = NULL;
PAGED_CODE();
SrTrace(FUNC_ENTRY, ("SR!SrCreateControlObject()\n"));
//
// allocate the control object
//
pControlObject = SR_ALLOCATE_STRUCT(
NonPagedPool,
SR_CONTROL_OBJECT,
SR_CONTROL_OBJECT_TAG
);
if (pControlObject == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
//
// wipe it clean
//
RtlZeroMemory(pControlObject, sizeof(SR_CONTROL_OBJECT));
pControlObject->Signature = SR_CONTROL_OBJECT_TAG;
//
// Start the refcount at 1 (the caller's ref)
//
pControlObject->RefCount = 1;
//
// Copy over the info from create
//
pControlObject->Options = Options;
//
// Init our lists
//
InitializeListHead(&pControlObject->IrpListHead);
InitializeListHead(&pControlObject->NotifyRecordListHead);
//
// Fill in the EPROCESS
//
pControlObject->pProcess = IoGetCurrentProcess();
//
// return the object
//
*ppControlObject = pControlObject;
//
// all done
//
SrTrace(NOTIFY, ("SR!SrCreateControlObject(%p)\n", pControlObject));
end:
if (NT_SUCCESS(Status) == FALSE)
{
if (pControlObject != NULL)
{
SR_FREE_POOL_WITH_SIG(pControlObject, SR_CONTROL_OBJECT_TAG);
}
}
RETURN(Status);
} // SrCreateControlObject
NTSTATUS
SrDeleteControlObject(
IN PSR_CONTROL_OBJECT pControlObject
)
{
NTSTATUS Status;
PLIST_ENTRY pEntry;
ASSERT(IS_GLOBAL_LOCK_ACQUIRED());
PAGED_CODE();
SrTrace(NOTIFY, ("SR!SrDeleteControlObject(%p)\n", pControlObject));
if (IS_VALID_CONTROL_OBJECT(pControlObject) == FALSE)
{
RETURN(STATUS_INVALID_DEVICE_REQUEST);
}
//
// cancel all pending io (just in case)
//
Status = SrCancelControlIo(pControlObject);
CHECK_STATUS(Status);
//
// dump all of our pending notif records...
//
while (IsListEmpty(&pControlObject->NotifyRecordListHead) == FALSE)
{
PSR_NOTIFICATION_RECORD pRecord;
//
// Pop it off the list.
//
pEntry = RemoveHeadList(&pControlObject->NotifyRecordListHead);
pEntry->Blink = pEntry->Flink = NULL;
pRecord = CONTAINING_RECORD( pEntry,
SR_NOTIFICATION_RECORD,
ListEntry );
ASSERT(IS_VALID_NOTIFICATION_RECORD(pRecord));
//
// free the record
//
SR_FREE_POOL_WITH_SIG(pRecord, SR_NOTIFICATION_RECORD_TAG);
//
// move on to the next one
//
} // while (IsListEmpty(&pControlObject->NotifyRecordListHead) == FALSE)
//
// we no longer have a process lying around
//
pControlObject->pProcess = NULL;
//
// and release the final reference ... this should delete it
// (pending async cancels)
//
SrDereferenceControlObject(pControlObject);
pControlObject = NULL;
//
// all done
//
RETURN(STATUS_SUCCESS);
} // SrDeleteControlObject
NTSTATUS
SrCancelControlIo(
IN PSR_CONTROL_OBJECT pControlObject
)
{
PLIST_ENTRY pEntry;
ASSERT(IS_GLOBAL_LOCK_ACQUIRED());
PAGED_CODE();
SrTrace(NOTIFY, ("SR!SrCancelControlIo(%p)\n", pControlObject));
if (IS_VALID_CONTROL_OBJECT(pControlObject) == FALSE)
{
RETURN(STATUS_INVALID_DEVICE_REQUEST);
}
//
// loop over the list and cancel any pending io.
//
while (!IsListEmpty(&pControlObject->IrpListHead))
{
PIRP pIrp;
//
// Pop it off the list.
//
pEntry = RemoveHeadList(&pControlObject->IrpListHead);
pEntry->Blink = pEntry->Flink = NULL;
pIrp = CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
ASSERT(IS_VALID_IRP(pIrp));
//
// pop the cancel routine
//
if (IoSetCancelRoutine(pIrp, NULL) == NULL)
{
//
// IoCancelIrp pop'd it first
//
// ok to just ignore this irp, it's been pop'd off the queue
// and will be completed in the cancel routine.
//
// keep looping
//
pIrp = NULL;
}
else
{
PSR_CONTROL_OBJECT pIrpControlObject;
//
// cancel it. even if pIrp->Cancel == TRUE we are supposed to
// complete it, our cancel routine will never run.
//
pIrpControlObject = (PSR_CONTROL_OBJECT)(
IoGetCurrentIrpStackLocation(pIrp)->
Parameters.DeviceIoControl.Type3InputBuffer
);
ASSERT(pIrpControlObject == pControlObject);
ASSERT(IS_VALID_CONTROL_OBJECT(pIrpControlObject));
SrDereferenceControlObject(pIrpControlObject);
IoGetCurrentIrpStackLocation(pIrp)->
Parameters.DeviceIoControl.Type3InputBuffer = NULL;
pIrp->IoStatus.Status = STATUS_CANCELLED;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
pIrp = NULL;
}
//
// move on to the next one
//
}
//
// our irp list should now empty.
//
ASSERT(IsListEmpty(&pControlObject->IrpListHead));
RETURN(STATUS_SUCCESS);
} // SrCancelControlIo
VOID
SrReferenceControlObject(
IN PSR_CONTROL_OBJECT pControlObject
)
{
LONG RefCount;
//
// Sanity check.
//
PAGED_CODE();
ASSERT(IS_VALID_CONTROL_OBJECT(pControlObject));
RefCount = InterlockedIncrement( &pControlObject->RefCount );
} // SrReferenceControlObject
VOID
SrDereferenceControlObject(
IN PSR_CONTROL_OBJECT pControlObject
)
{
LONG RefCount;
//
// Sanity check.
//
PAGED_CODE();
ASSERT(IS_VALID_CONTROL_OBJECT(pControlObject));
RefCount = InterlockedDecrement( &pControlObject->RefCount );
if (RefCount == 0)
{
//
// there better not be any items on any lists
//
ASSERT(IsListEmpty(&pControlObject->NotifyRecordListHead));
ASSERT(IsListEmpty(&pControlObject->IrpListHead));
//
// and the memory
//
SR_FREE_POOL_WITH_SIG(pControlObject, SR_CONTROL_OBJECT_TAG);
}
} // SrDereferenceControlObject