397 lines
7.6 KiB
C
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
|
||
|
|
||
|
|