mirror of
https://github.com/reactos/reactos.git
synced 2024-12-26 17:14:41 +00:00
Implement IoRaiseHardError, combine error stuff, fix hideously wrong implementatin of Controller Objects.
svn path=/trunk/; revision=14816
This commit is contained in:
parent
c6c78c3133
commit
946594bdc0
7 changed files with 710 additions and 693 deletions
|
@ -684,6 +684,34 @@ typedef struct _FILE_OBJECT
|
||||||
PIO_COMPLETION_CONTEXT CompletionContext;
|
PIO_COMPLETION_CONTEXT CompletionContext;
|
||||||
} FILE_OBJECT, *PFILE_OBJECT;
|
} FILE_OBJECT, *PFILE_OBJECT;
|
||||||
|
|
||||||
|
typedef IO_ALLOCATION_ACTION STDCALL_FUNC
|
||||||
|
(*PDRIVER_CONTROL)(struct _DEVICE_OBJECT *DeviceObject,
|
||||||
|
struct _IRP *Irp,
|
||||||
|
PVOID MapRegisterBase,
|
||||||
|
PVOID Context);
|
||||||
|
#if (_WIN32_WINNT >= 0x0400)
|
||||||
|
typedef VOID STDCALL_FUNC
|
||||||
|
(*PFSDNOTIFICATIONPROC)(IN struct _DEVICE_OBJECT *PtrTargetFileSystemDeviceObject,
|
||||||
|
IN BOOLEAN DriverActive);
|
||||||
|
#endif // (_WIN32_WINNT >= 0x0400)
|
||||||
|
|
||||||
|
typedef struct _KDEVICE_QUEUE_ENTRY
|
||||||
|
{
|
||||||
|
LIST_ENTRY DeviceListEntry;
|
||||||
|
ULONG SortKey;
|
||||||
|
BOOLEAN Inserted;
|
||||||
|
} KDEVICE_QUEUE_ENTRY, *PKDEVICE_QUEUE_ENTRY;
|
||||||
|
|
||||||
|
typedef struct _WAIT_CONTEXT_BLOCK
|
||||||
|
{
|
||||||
|
KDEVICE_QUEUE_ENTRY WaitQueueEntry;
|
||||||
|
PDRIVER_CONTROL DeviceRoutine;
|
||||||
|
PVOID DeviceContext;
|
||||||
|
ULONG NumberOfMapRegisters;
|
||||||
|
PVOID DeviceObject;
|
||||||
|
PVOID CurrentIrp;
|
||||||
|
PKDPC BufferChainingDpc;
|
||||||
|
} WAIT_CONTEXT_BLOCK, *PWAIT_CONTEXT_BLOCK;
|
||||||
|
|
||||||
typedef struct _IRP
|
typedef struct _IRP
|
||||||
{
|
{
|
||||||
|
@ -757,7 +785,6 @@ typedef struct _VPB
|
||||||
WCHAR VolumeLabel[MAXIMUM_VOLUME_LABEL_LENGTH];
|
WCHAR VolumeLabel[MAXIMUM_VOLUME_LABEL_LENGTH];
|
||||||
} VPB, *PVPB;
|
} VPB, *PVPB;
|
||||||
|
|
||||||
|
|
||||||
typedef struct _DEVICE_OBJECT
|
typedef struct _DEVICE_OBJECT
|
||||||
{
|
{
|
||||||
CSHORT Type;
|
CSHORT Type;
|
||||||
|
@ -1133,18 +1160,6 @@ typedef struct _DRIVER_LAYOUT_INFORMATION
|
||||||
} DRIVER_LAYOUT_INFORMATION, *PDRIVER_LAYOUT_INFORMATION;
|
} DRIVER_LAYOUT_INFORMATION, *PDRIVER_LAYOUT_INFORMATION;
|
||||||
|
|
||||||
|
|
||||||
typedef IO_ALLOCATION_ACTION STDCALL_FUNC
|
|
||||||
(*PDRIVER_CONTROL)(PDEVICE_OBJECT DeviceObject,
|
|
||||||
PIRP Irp,
|
|
||||||
PVOID MapRegisterBase,
|
|
||||||
PVOID Context);
|
|
||||||
#if (_WIN32_WINNT >= 0x0400)
|
|
||||||
typedef VOID STDCALL_FUNC
|
|
||||||
(*PFSDNOTIFICATIONPROC)(IN PDEVICE_OBJECT PtrTargetFileSystemDeviceObject,
|
|
||||||
IN BOOLEAN DriverActive);
|
|
||||||
#endif // (_WIN32_WINNT >= 0x0400)
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct _NAMED_PIPE_CREATE_PARAMETERS
|
typedef struct _NAMED_PIPE_CREATE_PARAMETERS
|
||||||
{
|
{
|
||||||
ULONG NamedPipeType;
|
ULONG NamedPipeType;
|
||||||
|
|
|
@ -285,37 +285,6 @@ typedef struct _KDPC_DATA {
|
||||||
ULONG DpcCount;
|
ULONG DpcCount;
|
||||||
} KDPC_DATA, *PKDPC_DATA;
|
} KDPC_DATA, *PKDPC_DATA;
|
||||||
|
|
||||||
typedef struct _KDEVICE_QUEUE_ENTRY
|
|
||||||
{
|
|
||||||
LIST_ENTRY DeviceListEntry;
|
|
||||||
ULONG SortKey;
|
|
||||||
BOOLEAN Inserted;
|
|
||||||
} KDEVICE_QUEUE_ENTRY, *PKDEVICE_QUEUE_ENTRY;
|
|
||||||
|
|
||||||
typedef struct _WAIT_CONTEXT_BLOCK
|
|
||||||
{
|
|
||||||
KDEVICE_QUEUE_ENTRY WaitQueueEntry;
|
|
||||||
/*
|
|
||||||
* XXX THIS IS WRONG XXX
|
|
||||||
*
|
|
||||||
* Our headers have enough circular dependancies that
|
|
||||||
* I can't figure out, given 5 minutes of testing, what
|
|
||||||
* order to include them in to get PDRIVER_CONTROL to be
|
|
||||||
* defined here. The proper definition of the next item
|
|
||||||
* is:
|
|
||||||
*
|
|
||||||
* PDRIVER_CONTROL DeviceRoutine;
|
|
||||||
*
|
|
||||||
* but instead we use PVOID until headers are fixed.
|
|
||||||
*/
|
|
||||||
PVOID DeviceRoutine;
|
|
||||||
PVOID DeviceContext;
|
|
||||||
ULONG NumberOfMapRegisters;
|
|
||||||
PVOID DeviceObject;
|
|
||||||
PVOID CurrentIrp;
|
|
||||||
PKDPC BufferChainingDpc;
|
|
||||||
} WAIT_CONTEXT_BLOCK, *PWAIT_CONTEXT_BLOCK;
|
|
||||||
|
|
||||||
typedef enum _KBUGCHECK_CALLBACK_REASON {
|
typedef enum _KBUGCHECK_CALLBACK_REASON {
|
||||||
KbCallbackInvalid,
|
KbCallbackInvalid,
|
||||||
KbCallbackReserved1,
|
KbCallbackReserved1,
|
||||||
|
|
|
@ -149,14 +149,13 @@ OBJECTS_IO = \
|
||||||
io/buildirp.o \
|
io/buildirp.o \
|
||||||
io/cancel.o \
|
io/cancel.o \
|
||||||
io/cleanup.o \
|
io/cleanup.o \
|
||||||
io/cntrller.o \
|
io/controller.o \
|
||||||
io/create.o \
|
io/create.o \
|
||||||
io/device.o \
|
io/device.o \
|
||||||
io/deviface.o \
|
io/deviface.o \
|
||||||
io/dir.o \
|
io/dir.o \
|
||||||
io/driver.o \
|
io/driver.o \
|
||||||
io/efi.o \
|
io/efi.o \
|
||||||
io/errlog.o \
|
|
||||||
io/error.o \
|
io/error.o \
|
||||||
io/event.o \
|
io/event.o \
|
||||||
io/file.o \
|
io/file.o \
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
/* $Id$
|
|
||||||
*
|
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
|
||||||
* PROJECT: ReactOS kernel
|
|
||||||
* FILE: ntoskrnl/io/cntrller.c
|
|
||||||
* PURPOSE: Implements the controller object
|
|
||||||
*
|
|
||||||
* PROGRAMMERS: David Welch (welch@mcmail.com)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
|
||||||
#include <internal/debug.h>
|
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
|
||||||
|
|
||||||
#define TAG_CQE TAG('C', 'Q', 'E', ' ')
|
|
||||||
#define TAG_CONTROLLER TAG('C', 'N', 'T', 'R')
|
|
||||||
#define TAG_CONTROLLER_EXTENSION TAG('C', 'E', 'X', 'T')
|
|
||||||
|
|
||||||
/* TYPES ********************************************************************/
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
/*
|
|
||||||
* PURPOSE: A entry in the queue waiting for a controller object
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
KDEVICE_QUEUE_ENTRY Entry;
|
|
||||||
PDEVICE_OBJECT DeviceObject;
|
|
||||||
PDRIVER_CONTROL ExecutionRoutine;
|
|
||||||
PVOID Context;
|
|
||||||
} CONTROLLER_QUEUE_ENTRY, *PCONTROLLER_QUEUE_ENTRY;
|
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
VOID
|
|
||||||
STDCALL
|
|
||||||
IoAllocateController(PCONTROLLER_OBJECT ControllerObject,
|
|
||||||
PDEVICE_OBJECT DeviceObject,
|
|
||||||
PDRIVER_CONTROL ExecutionRoutine,
|
|
||||||
PVOID Context)
|
|
||||||
/*
|
|
||||||
* FUNCTION: Sets up a call to a driver-supplied ControllerControl routine
|
|
||||||
* as soon as the device controller, represented by the given controller
|
|
||||||
* object, is available to carry out an I/O operation for the target device,
|
|
||||||
* represented by the given device object.
|
|
||||||
* ARGUMENTS:
|
|
||||||
* ControllerObject = Driver created controller object
|
|
||||||
* DeviceObject = Target device for the current irp
|
|
||||||
* ExecutionRoutine = Routine to be called when the device is available
|
|
||||||
* Context = Driver supplied context to be passed on to the above routine
|
|
||||||
* NOTE: Is the below implementation correct.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
PCONTROLLER_QUEUE_ENTRY entry;
|
|
||||||
IO_ALLOCATION_ACTION Result;
|
|
||||||
|
|
||||||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
|
||||||
|
|
||||||
entry =
|
|
||||||
ExAllocatePoolWithTag(NonPagedPool, sizeof(CONTROLLER_QUEUE_ENTRY),
|
|
||||||
TAG_CQE);
|
|
||||||
ASSERT(entry!=NULL);
|
|
||||||
|
|
||||||
entry->DeviceObject = DeviceObject;
|
|
||||||
entry->ExecutionRoutine = ExecutionRoutine;
|
|
||||||
entry->Context = Context;
|
|
||||||
|
|
||||||
if (KeInsertDeviceQueue(&ControllerObject->DeviceWaitQueue,&entry->Entry))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Result = ExecutionRoutine(DeviceObject,DeviceObject->CurrentIrp,
|
|
||||||
NULL,Context);
|
|
||||||
if (Result == DeallocateObject)
|
|
||||||
{
|
|
||||||
IoFreeController(ControllerObject);
|
|
||||||
}
|
|
||||||
ExFreePool(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
PCONTROLLER_OBJECT
|
|
||||||
STDCALL
|
|
||||||
IoCreateController(ULONG Size)
|
|
||||||
/*
|
|
||||||
* FUNCTION: Allocates memory and initializes a controller object
|
|
||||||
* ARGUMENTS:
|
|
||||||
* Size = Size (in bytes) to be allocated for the controller extension
|
|
||||||
* RETURNS: A pointer to the created object
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
PCONTROLLER_OBJECT controller;
|
|
||||||
|
|
||||||
ASSERT_IRQL(PASSIVE_LEVEL);
|
|
||||||
|
|
||||||
controller =
|
|
||||||
ExAllocatePoolWithTag(NonPagedPool, sizeof(CONTROLLER_OBJECT),
|
|
||||||
TAG_CONTROLLER);
|
|
||||||
if (controller==NULL)
|
|
||||||
{
|
|
||||||
return(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller->ControllerExtension =
|
|
||||||
ExAllocatePoolWithTag(NonPagedPool, Size, TAG_CONTROLLER_EXTENSION);
|
|
||||||
if (controller->ControllerExtension==NULL)
|
|
||||||
{
|
|
||||||
ExFreePool(controller);
|
|
||||||
return(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeInitializeDeviceQueue(&controller->DeviceWaitQueue);
|
|
||||||
return(controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
VOID
|
|
||||||
STDCALL
|
|
||||||
IoDeleteController(PCONTROLLER_OBJECT ControllerObject)
|
|
||||||
/*
|
|
||||||
* FUNCTION: Removes a given controller object from the system
|
|
||||||
* ARGUMENTS:
|
|
||||||
* ControllerObject = Controller object to be released
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
ASSERT_IRQL(PASSIVE_LEVEL);
|
|
||||||
|
|
||||||
ExFreePool(ControllerObject->ControllerExtension);
|
|
||||||
ExFreePool(ControllerObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
VOID
|
|
||||||
STDCALL
|
|
||||||
IoFreeController(PCONTROLLER_OBJECT ControllerObject)
|
|
||||||
/*
|
|
||||||
* FUNCTION: Releases a previously allocated controller object when a
|
|
||||||
* device has finished an I/O request
|
|
||||||
* ARGUMENTS:
|
|
||||||
* ControllerObject = Controller object to be released
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
PKDEVICE_QUEUE_ENTRY QEntry;
|
|
||||||
CONTROLLER_QUEUE_ENTRY* Entry;
|
|
||||||
IO_ALLOCATION_ACTION Result;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
QEntry = KeRemoveDeviceQueue(&ControllerObject->DeviceWaitQueue);
|
|
||||||
Entry = CONTAINING_RECORD(QEntry,CONTROLLER_QUEUE_ENTRY,Entry);
|
|
||||||
if (QEntry==NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Result = Entry->ExecutionRoutine(Entry->DeviceObject,
|
|
||||||
Entry->DeviceObject->CurrentIrp,
|
|
||||||
NULL,
|
|
||||||
Entry->Context);
|
|
||||||
ExFreePool(Entry);
|
|
||||||
} while (Result == DeallocateObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* EOF */
|
|
178
reactos/ntoskrnl/io/controller.c
Normal file
178
reactos/ntoskrnl/io/controller.c
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS kernel
|
||||||
|
* FILE: ntoskrnl/io/contrller.c
|
||||||
|
* PURPOSE: Implements the controller object
|
||||||
|
*
|
||||||
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES *****************************************************************/
|
||||||
|
|
||||||
|
#include <ntoskrnl.h>
|
||||||
|
#include <internal/debug.h>
|
||||||
|
|
||||||
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
POBJECT_TYPE IoControllerObjectType;
|
||||||
|
|
||||||
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*
|
||||||
|
* FUNCTION: Sets up a call to a driver-supplied ControllerControl routine
|
||||||
|
* as soon as the device controller, represented by the given controller
|
||||||
|
* object, is available to carry out an I/O operation for the target device,
|
||||||
|
* represented by the given device object.
|
||||||
|
* ARGUMENTS:
|
||||||
|
* ControllerObject = Driver created controller object
|
||||||
|
* DeviceObject = Target device for the current irp
|
||||||
|
* ExecutionRoutine = Routine to be called when the device is available
|
||||||
|
* Context = Driver supplied context to be passed on to the above routine
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
IoAllocateController(PCONTROLLER_OBJECT ControllerObject,
|
||||||
|
PDEVICE_OBJECT DeviceObject,
|
||||||
|
PDRIVER_CONTROL ExecutionRoutine,
|
||||||
|
PVOID Context)
|
||||||
|
{
|
||||||
|
IO_ALLOCATION_ACTION Result;
|
||||||
|
|
||||||
|
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||||||
|
|
||||||
|
/* Initialize the Wait Context Block */
|
||||||
|
DeviceObject->Queue.Wcb.DeviceContext = Context;
|
||||||
|
DeviceObject->Queue.Wcb.DeviceRoutine = ExecutionRoutine;
|
||||||
|
|
||||||
|
/* Insert the Device Queue */
|
||||||
|
if (!KeInsertDeviceQueue(&ControllerObject->DeviceWaitQueue,
|
||||||
|
&DeviceObject->Queue.Wcb.WaitQueueEntry));
|
||||||
|
{
|
||||||
|
Result = ExecutionRoutine(DeviceObject,
|
||||||
|
DeviceObject->CurrentIrp,
|
||||||
|
NULL,
|
||||||
|
Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Result == DeallocateObject)
|
||||||
|
{
|
||||||
|
IoFreeController(ControllerObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*
|
||||||
|
* FUNCTION: Allocates memory and initializes a controller object
|
||||||
|
* ARGUMENTS:
|
||||||
|
* Size = Size (in bytes) to be allocated for the controller extension
|
||||||
|
* RETURNS: A pointer to the created object
|
||||||
|
*/
|
||||||
|
PCONTROLLER_OBJECT
|
||||||
|
STDCALL
|
||||||
|
IoCreateController(ULONG Size)
|
||||||
|
|
||||||
|
{
|
||||||
|
PCONTROLLER_OBJECT Controller;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
HANDLE Handle;
|
||||||
|
NTSTATUS Status;
|
||||||
|
ASSERT_IRQL(PASSIVE_LEVEL);
|
||||||
|
|
||||||
|
/* Initialize an empty OBA */
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
|
/* Create the Object */
|
||||||
|
Status = ObCreateObject(KernelMode,
|
||||||
|
IoControllerObjectType,
|
||||||
|
&ObjectAttributes,
|
||||||
|
KernelMode,
|
||||||
|
NULL,
|
||||||
|
sizeof(CONTROLLER_OBJECT) + Size,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(PVOID*)&Controller);
|
||||||
|
if (!NT_SUCCESS(Status)) return NULL;
|
||||||
|
|
||||||
|
/* Insert it */
|
||||||
|
Status = ObInsertObject(Controller,
|
||||||
|
NULL,
|
||||||
|
FILE_READ_DATA | FILE_WRITE_DATA,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
&Handle);
|
||||||
|
if (!NT_SUCCESS(Status)) return NULL;
|
||||||
|
|
||||||
|
/* Close the dummy handle */
|
||||||
|
NtClose(Handle);
|
||||||
|
|
||||||
|
/* Zero the Object and set its data */
|
||||||
|
RtlZeroMemory(Controller, sizeof(CONTROLLER_OBJECT) + Size);
|
||||||
|
Controller->Type = IO_TYPE_CONTROLLER;
|
||||||
|
Controller->Size = sizeof(CONTROLLER_OBJECT) + Size;
|
||||||
|
Controller->ControllerExtension = (Controller + 1);
|
||||||
|
|
||||||
|
/* Initialize its Queue */
|
||||||
|
KeInitializeDeviceQueue(&Controller->DeviceWaitQueue);
|
||||||
|
|
||||||
|
/* Return Controller */
|
||||||
|
return Controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*
|
||||||
|
* FUNCTION: Removes a given controller object from the system
|
||||||
|
* ARGUMENTS:
|
||||||
|
* ControllerObject = Controller object to be released
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
IoDeleteController(PCONTROLLER_OBJECT ControllerObject)
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Just Dereference it */
|
||||||
|
ObDereferenceObject(ControllerObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*
|
||||||
|
* FUNCTION: Releases a previously allocated controller object when a
|
||||||
|
* device has finished an I/O request
|
||||||
|
* ARGUMENTS:
|
||||||
|
* ControllerObject = Controller object to be released
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
IoFreeController(PCONTROLLER_OBJECT ControllerObject)
|
||||||
|
{
|
||||||
|
PKDEVICE_QUEUE_ENTRY QueueEntry;
|
||||||
|
PDEVICE_OBJECT DeviceObject;
|
||||||
|
IO_ALLOCATION_ACTION Result;
|
||||||
|
|
||||||
|
/* Remove the Queue */
|
||||||
|
if ((QueueEntry = KeRemoveDeviceQueue(&ControllerObject->DeviceWaitQueue)))
|
||||||
|
{
|
||||||
|
/* Get the Device Object */
|
||||||
|
DeviceObject = CONTAINING_RECORD(QueueEntry,
|
||||||
|
DEVICE_OBJECT,
|
||||||
|
Queue.Wcb.WaitQueueEntry);
|
||||||
|
/* Call the routine */
|
||||||
|
Result = DeviceObject->Queue.Wcb.DeviceRoutine(DeviceObject,
|
||||||
|
DeviceObject->CurrentIrp,
|
||||||
|
NULL,
|
||||||
|
DeviceObject->Queue.Wcb.DeviceContext);
|
||||||
|
/* Check the result */
|
||||||
|
if (Result == DeallocateObject)
|
||||||
|
{
|
||||||
|
/* Free it again */
|
||||||
|
IoFreeController(ControllerObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* EOF */
|
|
@ -1,450 +0,0 @@
|
||||||
/* $Id$
|
|
||||||
*
|
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
|
||||||
* PROJECT: ReactOS kernel
|
|
||||||
* FILE: ntoskrnl/io/errlog.c
|
|
||||||
* PURPOSE: Error logging
|
|
||||||
*
|
|
||||||
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
|
||||||
#define NDEBUG
|
|
||||||
#include <internal/debug.h>
|
|
||||||
|
|
||||||
/* TYPES *********************************************************************/
|
|
||||||
|
|
||||||
typedef struct _ERROR_LOG_ENTRY
|
|
||||||
{
|
|
||||||
LIST_ENTRY Entry;
|
|
||||||
LARGE_INTEGER TimeStamp;
|
|
||||||
PVOID IoObject;
|
|
||||||
ULONG PacketSize;
|
|
||||||
} ERROR_LOG_ENTRY, *PERROR_LOG_ENTRY;
|
|
||||||
|
|
||||||
typedef struct _LOG_WORKER_DPC
|
|
||||||
{
|
|
||||||
KDPC Dpc;
|
|
||||||
KTIMER Timer;
|
|
||||||
} LOG_WORKER_DPC, *PLOG_WORKER_DPC;
|
|
||||||
|
|
||||||
|
|
||||||
static VOID STDCALL
|
|
||||||
IopLogWorker (PVOID Parameter);
|
|
||||||
|
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
|
||||||
|
|
||||||
static KSPIN_LOCK IopAllocationLock;
|
|
||||||
static ULONG IopTotalLogSize;
|
|
||||||
|
|
||||||
static KSPIN_LOCK IopLogListLock;
|
|
||||||
static LIST_ENTRY IopLogListHead;
|
|
||||||
|
|
||||||
static BOOLEAN IopLogWorkerRunning = FALSE;
|
|
||||||
static BOOLEAN IopLogPortConnected = FALSE;
|
|
||||||
static HANDLE IopLogPort;
|
|
||||||
|
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
IopInitErrorLog (VOID)
|
|
||||||
{
|
|
||||||
IopTotalLogSize = 0;
|
|
||||||
KeInitializeSpinLock (&IopAllocationLock);
|
|
||||||
|
|
||||||
KeInitializeSpinLock (&IopLogListLock);
|
|
||||||
InitializeListHead (&IopLogListHead);
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static VOID STDCALL
|
|
||||||
IopLogDpcRoutine (PKDPC Dpc,
|
|
||||||
PVOID DeferredContext,
|
|
||||||
PVOID SystemArgument1,
|
|
||||||
PVOID SystemArgument2)
|
|
||||||
{
|
|
||||||
PWORK_QUEUE_ITEM LogWorkItem;
|
|
||||||
|
|
||||||
DPRINT ("\nIopLogDpcRoutine() called\n");
|
|
||||||
|
|
||||||
/* Release the WorkerDpc struct */
|
|
||||||
ExFreePool (DeferredContext);
|
|
||||||
|
|
||||||
/* Allocate, initialize and restart a work item */
|
|
||||||
LogWorkItem = ExAllocatePool (NonPagedPool,
|
|
||||||
sizeof(WORK_QUEUE_ITEM));
|
|
||||||
if (LogWorkItem == NULL)
|
|
||||||
{
|
|
||||||
IopLogWorkerRunning = FALSE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExInitializeWorkItem (LogWorkItem,
|
|
||||||
IopLogWorker,
|
|
||||||
LogWorkItem);
|
|
||||||
|
|
||||||
ExQueueWorkItem (LogWorkItem,
|
|
||||||
DelayedWorkQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static VOID
|
|
||||||
IopRestartLogWorker (VOID)
|
|
||||||
{
|
|
||||||
PLOG_WORKER_DPC WorkerDpc;
|
|
||||||
LARGE_INTEGER Timeout;
|
|
||||||
|
|
||||||
DPRINT ("IopRestartWorker() called\n");
|
|
||||||
|
|
||||||
WorkerDpc = ExAllocatePool (NonPagedPool,
|
|
||||||
sizeof(LOG_WORKER_DPC));
|
|
||||||
if (WorkerDpc == NULL)
|
|
||||||
{
|
|
||||||
IopLogWorkerRunning = FALSE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize DPC and Timer */
|
|
||||||
KeInitializeDpc (&WorkerDpc->Dpc,
|
|
||||||
IopLogDpcRoutine,
|
|
||||||
WorkerDpc);
|
|
||||||
KeInitializeTimer (&WorkerDpc->Timer);
|
|
||||||
|
|
||||||
/* Restart after 30 seconds */
|
|
||||||
Timeout.QuadPart = (LONGLONG)-300000000;
|
|
||||||
KeSetTimer (&WorkerDpc->Timer,
|
|
||||||
Timeout,
|
|
||||||
&WorkerDpc->Dpc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static BOOLEAN
|
|
||||||
IopConnectLogPort (VOID)
|
|
||||||
{
|
|
||||||
UNICODE_STRING PortName;
|
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
DPRINT ("IopConnectLogPort() called\n");
|
|
||||||
|
|
||||||
RtlInitUnicodeString (&PortName,
|
|
||||||
L"\\ErrorLogPort");
|
|
||||||
|
|
||||||
Status = ZwConnectPort (&IopLogPort,
|
|
||||||
&PortName,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT ("ZwConnectPort() failed (Status %lx)\n", Status);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT ("IopConnectLogPort() done\n");
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static VOID STDCALL
|
|
||||||
IopLogWorker (PVOID Parameter)
|
|
||||||
{
|
|
||||||
PERROR_LOG_ENTRY LogEntry;
|
|
||||||
PLPC_MAX_MESSAGE Request;
|
|
||||||
PIO_ERROR_LOG_MESSAGE Message;
|
|
||||||
PIO_ERROR_LOG_PACKET Packet;
|
|
||||||
KIRQL Irql;
|
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
UCHAR Buffer[256];
|
|
||||||
POBJECT_NAME_INFORMATION ObjectNameInfo;
|
|
||||||
ULONG ReturnedLength;
|
|
||||||
PWCHAR DriverName;
|
|
||||||
ULONG DriverNameLength;
|
|
||||||
|
|
||||||
DPRINT ("IopLogWorker() called\n");
|
|
||||||
|
|
||||||
/* Release the work item */
|
|
||||||
ExFreePool (Parameter);
|
|
||||||
|
|
||||||
/* Connect to the error log port */
|
|
||||||
if (IopLogPortConnected == FALSE)
|
|
||||||
{
|
|
||||||
if (IopConnectLogPort () == FALSE)
|
|
||||||
{
|
|
||||||
IopRestartLogWorker ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IopLogPortConnected = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
/* Remove last entry from the list */
|
|
||||||
KeAcquireSpinLock (&IopLogListLock,
|
|
||||||
&Irql);
|
|
||||||
|
|
||||||
if (!IsListEmpty (&IopLogListHead))
|
|
||||||
{
|
|
||||||
LogEntry = CONTAINING_RECORD (IopLogListHead.Blink,
|
|
||||||
ERROR_LOG_ENTRY,
|
|
||||||
Entry);
|
|
||||||
RemoveEntryList (&LogEntry->Entry);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogEntry = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeReleaseSpinLock (&IopLogListLock,
|
|
||||||
Irql);
|
|
||||||
|
|
||||||
if (LogEntry == NULL)
|
|
||||||
{
|
|
||||||
DPRINT ("No message in log list\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get pointer to the log packet */
|
|
||||||
Packet = (PIO_ERROR_LOG_PACKET)((ULONG_PTR)LogEntry + sizeof(ERROR_LOG_ENTRY));
|
|
||||||
|
|
||||||
|
|
||||||
/* Get driver or device name */
|
|
||||||
ObjectNameInfo = (POBJECT_NAME_INFORMATION)Buffer;
|
|
||||||
Status = ObQueryNameString (LogEntry->IoObject,
|
|
||||||
ObjectNameInfo,
|
|
||||||
256,
|
|
||||||
&ReturnedLength);
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT ("ReturnedLength: %lu\n", ReturnedLength);
|
|
||||||
DPRINT ("Length: %hu\n", ObjectNameInfo->Name.Length);
|
|
||||||
DPRINT ("MaximumLength: %hu\n", ObjectNameInfo->Name.MaximumLength);
|
|
||||||
DPRINT ("Object: %wZ\n", &ObjectNameInfo->Name);
|
|
||||||
|
|
||||||
DriverName = wcsrchr(ObjectNameInfo->Name.Buffer, L'\\');
|
|
||||||
if (DriverName != NULL)
|
|
||||||
DriverName++;
|
|
||||||
else
|
|
||||||
DriverName = ObjectNameInfo->Name.Buffer;
|
|
||||||
|
|
||||||
DriverNameLength = wcslen (DriverName) * sizeof(WCHAR);
|
|
||||||
DPRINT ("Driver name '%S'\n", DriverName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DriverName = NULL;
|
|
||||||
DriverNameLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate request buffer */
|
|
||||||
Request = ExAllocatePool (NonPagedPool,
|
|
||||||
sizeof(LPC_MAX_MESSAGE));
|
|
||||||
if (Request == NULL)
|
|
||||||
{
|
|
||||||
DPRINT ("Failed to allocate request buffer!\n");
|
|
||||||
|
|
||||||
/* Requeue log message and restart the worker */
|
|
||||||
ExInterlockedInsertTailList (&IopLogListHead,
|
|
||||||
&LogEntry->Entry,
|
|
||||||
&IopLogListLock);
|
|
||||||
IopRestartLogWorker ();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the log message */
|
|
||||||
Message = (PIO_ERROR_LOG_MESSAGE)Request->Data;
|
|
||||||
Message->Type = 0xC; //IO_TYPE_ERROR_MESSAGE;
|
|
||||||
Message->Size =
|
|
||||||
sizeof(IO_ERROR_LOG_MESSAGE) - sizeof(IO_ERROR_LOG_PACKET) +
|
|
||||||
LogEntry->PacketSize + DriverNameLength;
|
|
||||||
Message->DriverNameLength = (USHORT)DriverNameLength;
|
|
||||||
Message->TimeStamp.QuadPart = LogEntry->TimeStamp.QuadPart;
|
|
||||||
Message->DriverNameOffset = (DriverName != NULL) ? LogEntry->PacketSize : 0;
|
|
||||||
|
|
||||||
/* Copy error log packet */
|
|
||||||
RtlCopyMemory (&Message->EntryData,
|
|
||||||
Packet,
|
|
||||||
LogEntry->PacketSize);
|
|
||||||
|
|
||||||
/* Copy driver or device name */
|
|
||||||
RtlCopyMemory ((PVOID)((ULONG_PTR)Message + Message->DriverNameOffset),
|
|
||||||
DriverName,
|
|
||||||
DriverNameLength);
|
|
||||||
|
|
||||||
DPRINT ("SequenceNumber %lx\n", Packet->SequenceNumber);
|
|
||||||
|
|
||||||
Request->Header.DataSize = Message->Size;
|
|
||||||
Request->Header.MessageSize =
|
|
||||||
Request->Header.DataSize + sizeof(LPC_MESSAGE);
|
|
||||||
|
|
||||||
/* Send the error message to the log port */
|
|
||||||
Status = ZwRequestPort (IopLogPort,
|
|
||||||
&Request->Header);
|
|
||||||
|
|
||||||
/* Release request buffer */
|
|
||||||
ExFreePool (Request);
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT ("ZwRequestPort() failed (Status %lx)\n", Status);
|
|
||||||
|
|
||||||
/* Requeue log message and restart the worker */
|
|
||||||
ExInterlockedInsertTailList (&IopLogListHead,
|
|
||||||
&LogEntry->Entry,
|
|
||||||
&IopLogListLock);
|
|
||||||
IopRestartLogWorker ();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release error log entry */
|
|
||||||
KeAcquireSpinLock (&IopAllocationLock,
|
|
||||||
&Irql);
|
|
||||||
|
|
||||||
IopTotalLogSize -= (LogEntry->PacketSize - sizeof(ERROR_LOG_ENTRY));
|
|
||||||
ExFreePool (LogEntry);
|
|
||||||
|
|
||||||
KeReleaseSpinLock (&IopAllocationLock,
|
|
||||||
Irql);
|
|
||||||
}
|
|
||||||
|
|
||||||
IopLogWorkerRunning = FALSE;
|
|
||||||
|
|
||||||
DPRINT ("IopLogWorker() done\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
PVOID STDCALL
|
|
||||||
IoAllocateErrorLogEntry (IN PVOID IoObject,
|
|
||||||
IN UCHAR EntrySize)
|
|
||||||
{
|
|
||||||
PERROR_LOG_ENTRY LogEntry;
|
|
||||||
ULONG LogEntrySize;
|
|
||||||
KIRQL Irql;
|
|
||||||
|
|
||||||
DPRINT("IoAllocateErrorLogEntry() called\n");
|
|
||||||
|
|
||||||
if (IoObject == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
KeAcquireSpinLock (&IopAllocationLock,
|
|
||||||
&Irql);
|
|
||||||
|
|
||||||
if (IopTotalLogSize > PAGE_SIZE)
|
|
||||||
{
|
|
||||||
KeReleaseSpinLock (&IopAllocationLock,
|
|
||||||
Irql);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogEntrySize = sizeof(ERROR_LOG_ENTRY) + EntrySize;
|
|
||||||
LogEntry = ExAllocatePool (NonPagedPool,
|
|
||||||
LogEntrySize);
|
|
||||||
if (LogEntry == NULL)
|
|
||||||
{
|
|
||||||
KeReleaseSpinLock (&IopAllocationLock,
|
|
||||||
Irql);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
IopTotalLogSize += EntrySize;
|
|
||||||
|
|
||||||
LogEntry->IoObject = IoObject;
|
|
||||||
LogEntry->PacketSize = LogEntrySize;
|
|
||||||
|
|
||||||
KeReleaseSpinLock (&IopAllocationLock,
|
|
||||||
Irql);
|
|
||||||
|
|
||||||
return (PVOID)((ULONG_PTR)LogEntry + sizeof(ERROR_LOG_ENTRY));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
VOID STDCALL
|
|
||||||
IoFreeErrorLogEntry(IN PVOID ElEntry)
|
|
||||||
{
|
|
||||||
PERROR_LOG_ENTRY LogEntry;
|
|
||||||
KIRQL Irql;
|
|
||||||
|
|
||||||
DPRINT("IoFreeErrorLogEntry() called\n");
|
|
||||||
|
|
||||||
if (ElEntry == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
LogEntry = (PERROR_LOG_ENTRY)((ULONG_PTR)ElEntry - sizeof(ERROR_LOG_ENTRY));
|
|
||||||
|
|
||||||
KeAcquireSpinLock(&IopAllocationLock,
|
|
||||||
&Irql);
|
|
||||||
|
|
||||||
IopTotalLogSize -= (LogEntry->PacketSize - sizeof(ERROR_LOG_ENTRY));
|
|
||||||
ExFreePool(LogEntry);
|
|
||||||
|
|
||||||
KeReleaseSpinLock(&IopAllocationLock,
|
|
||||||
Irql);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
VOID STDCALL
|
|
||||||
IoWriteErrorLogEntry (IN PVOID ElEntry)
|
|
||||||
{
|
|
||||||
PWORK_QUEUE_ITEM LogWorkItem;
|
|
||||||
PERROR_LOG_ENTRY LogEntry;
|
|
||||||
KIRQL Irql;
|
|
||||||
|
|
||||||
DPRINT("IoWriteErrorLogEntry() called\n");
|
|
||||||
|
|
||||||
LogEntry = (PERROR_LOG_ENTRY)((ULONG_PTR)ElEntry - sizeof(ERROR_LOG_ENTRY));
|
|
||||||
|
|
||||||
/* Get time stamp */
|
|
||||||
KeQuerySystemTime (&LogEntry->TimeStamp);
|
|
||||||
|
|
||||||
KeAcquireSpinLock (&IopLogListLock,
|
|
||||||
&Irql);
|
|
||||||
|
|
||||||
InsertHeadList (&IopLogListHead,
|
|
||||||
&LogEntry->Entry);
|
|
||||||
|
|
||||||
if (IopLogWorkerRunning == FALSE)
|
|
||||||
{
|
|
||||||
LogWorkItem = ExAllocatePool (NonPagedPool,
|
|
||||||
sizeof(WORK_QUEUE_ITEM));
|
|
||||||
if (LogWorkItem != NULL)
|
|
||||||
{
|
|
||||||
ExInitializeWorkItem (LogWorkItem,
|
|
||||||
IopLogWorker,
|
|
||||||
LogWorkItem);
|
|
||||||
|
|
||||||
ExQueueWorkItem (LogWorkItem,
|
|
||||||
DelayedWorkQueue);
|
|
||||||
|
|
||||||
IopLogWorkerRunning = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KeReleaseSpinLock (&IopLogListLock,
|
|
||||||
Irql);
|
|
||||||
|
|
||||||
DPRINT("IoWriteErrorLogEntry() done\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* EOF */
|
|
|
@ -2,49 +2,530 @@
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
* FILE: ntoskrnl/io/error.c
|
* FILE: ntoskrnl/io/errlog.c
|
||||||
* PURPOSE: Handle media errors
|
* PURPOSE: Error logging
|
||||||
*
|
*
|
||||||
* PROGRAMMERS: David Welch (welch@mcmail.com)
|
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES *****************************************************************/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
|
/* TYPES *********************************************************************/
|
||||||
|
|
||||||
|
typedef struct _ERROR_LOG_ENTRY
|
||||||
|
{
|
||||||
|
LIST_ENTRY Entry;
|
||||||
|
LARGE_INTEGER TimeStamp;
|
||||||
|
PVOID IoObject;
|
||||||
|
ULONG PacketSize;
|
||||||
|
} ERROR_LOG_ENTRY, *PERROR_LOG_ENTRY;
|
||||||
|
|
||||||
|
typedef struct _LOG_WORKER_DPC
|
||||||
|
{
|
||||||
|
KDPC Dpc;
|
||||||
|
KTIMER Timer;
|
||||||
|
} LOG_WORKER_DPC, *PLOG_WORKER_DPC;
|
||||||
|
|
||||||
|
|
||||||
|
static VOID STDCALL
|
||||||
|
IopLogWorker (PVOID Parameter);
|
||||||
|
|
||||||
|
|
||||||
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
static KSPIN_LOCK IopAllocationLock;
|
||||||
|
static ULONG IopTotalLogSize;
|
||||||
|
|
||||||
|
static KSPIN_LOCK IopLogListLock;
|
||||||
|
static LIST_ENTRY IopLogListHead;
|
||||||
|
|
||||||
|
static BOOLEAN IopLogWorkerRunning = FALSE;
|
||||||
|
static BOOLEAN IopLogPortConnected = FALSE;
|
||||||
|
static HANDLE IopLogPort;
|
||||||
|
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
IopInitErrorLog (VOID)
|
||||||
|
{
|
||||||
|
IopTotalLogSize = 0;
|
||||||
|
KeInitializeSpinLock (&IopAllocationLock);
|
||||||
|
|
||||||
|
KeInitializeSpinLock (&IopLogListLock);
|
||||||
|
InitializeListHead (&IopLogListHead);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static VOID STDCALL
|
||||||
|
IopLogDpcRoutine (PKDPC Dpc,
|
||||||
|
PVOID DeferredContext,
|
||||||
|
PVOID SystemArgument1,
|
||||||
|
PVOID SystemArgument2)
|
||||||
|
{
|
||||||
|
PWORK_QUEUE_ITEM LogWorkItem;
|
||||||
|
|
||||||
|
DPRINT ("\nIopLogDpcRoutine() called\n");
|
||||||
|
|
||||||
|
/* Release the WorkerDpc struct */
|
||||||
|
ExFreePool (DeferredContext);
|
||||||
|
|
||||||
|
/* Allocate, initialize and restart a work item */
|
||||||
|
LogWorkItem = ExAllocatePool (NonPagedPool,
|
||||||
|
sizeof(WORK_QUEUE_ITEM));
|
||||||
|
if (LogWorkItem == NULL)
|
||||||
|
{
|
||||||
|
IopLogWorkerRunning = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExInitializeWorkItem (LogWorkItem,
|
||||||
|
IopLogWorker,
|
||||||
|
LogWorkItem);
|
||||||
|
|
||||||
|
ExQueueWorkItem (LogWorkItem,
|
||||||
|
DelayedWorkQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
IopRestartLogWorker (VOID)
|
||||||
|
{
|
||||||
|
PLOG_WORKER_DPC WorkerDpc;
|
||||||
|
LARGE_INTEGER Timeout;
|
||||||
|
|
||||||
|
DPRINT ("IopRestartWorker() called\n");
|
||||||
|
|
||||||
|
WorkerDpc = ExAllocatePool (NonPagedPool,
|
||||||
|
sizeof(LOG_WORKER_DPC));
|
||||||
|
if (WorkerDpc == NULL)
|
||||||
|
{
|
||||||
|
IopLogWorkerRunning = FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize DPC and Timer */
|
||||||
|
KeInitializeDpc (&WorkerDpc->Dpc,
|
||||||
|
IopLogDpcRoutine,
|
||||||
|
WorkerDpc);
|
||||||
|
KeInitializeTimer (&WorkerDpc->Timer);
|
||||||
|
|
||||||
|
/* Restart after 30 seconds */
|
||||||
|
Timeout.QuadPart = (LONGLONG)-300000000;
|
||||||
|
KeSetTimer (&WorkerDpc->Timer,
|
||||||
|
Timeout,
|
||||||
|
&WorkerDpc->Dpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BOOLEAN
|
||||||
|
IopConnectLogPort (VOID)
|
||||||
|
{
|
||||||
|
UNICODE_STRING PortName;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
DPRINT ("IopConnectLogPort() called\n");
|
||||||
|
|
||||||
|
RtlInitUnicodeString (&PortName,
|
||||||
|
L"\\ErrorLogPort");
|
||||||
|
|
||||||
|
Status = ZwConnectPort (&IopLogPort,
|
||||||
|
&PortName,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT ("ZwConnectPort() failed (Status %lx)\n", Status);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT ("IopConnectLogPort() done\n");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static VOID STDCALL
|
||||||
|
IopLogWorker (PVOID Parameter)
|
||||||
|
{
|
||||||
|
PERROR_LOG_ENTRY LogEntry;
|
||||||
|
PLPC_MAX_MESSAGE Request;
|
||||||
|
PIO_ERROR_LOG_MESSAGE Message;
|
||||||
|
PIO_ERROR_LOG_PACKET Packet;
|
||||||
|
KIRQL Irql;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
UCHAR Buffer[256];
|
||||||
|
POBJECT_NAME_INFORMATION ObjectNameInfo;
|
||||||
|
ULONG ReturnedLength;
|
||||||
|
PWCHAR DriverName;
|
||||||
|
ULONG DriverNameLength;
|
||||||
|
|
||||||
|
DPRINT ("IopLogWorker() called\n");
|
||||||
|
|
||||||
|
/* Release the work item */
|
||||||
|
ExFreePool (Parameter);
|
||||||
|
|
||||||
|
/* Connect to the error log port */
|
||||||
|
if (IopLogPortConnected == FALSE)
|
||||||
|
{
|
||||||
|
if (IopConnectLogPort () == FALSE)
|
||||||
|
{
|
||||||
|
IopRestartLogWorker ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IopLogPortConnected = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* Remove last entry from the list */
|
||||||
|
KeAcquireSpinLock (&IopLogListLock,
|
||||||
|
&Irql);
|
||||||
|
|
||||||
|
if (!IsListEmpty (&IopLogListHead))
|
||||||
|
{
|
||||||
|
LogEntry = CONTAINING_RECORD (IopLogListHead.Blink,
|
||||||
|
ERROR_LOG_ENTRY,
|
||||||
|
Entry);
|
||||||
|
RemoveEntryList (&LogEntry->Entry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogEntry = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeReleaseSpinLock (&IopLogListLock,
|
||||||
|
Irql);
|
||||||
|
|
||||||
|
if (LogEntry == NULL)
|
||||||
|
{
|
||||||
|
DPRINT ("No message in log list\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get pointer to the log packet */
|
||||||
|
Packet = (PIO_ERROR_LOG_PACKET)((ULONG_PTR)LogEntry + sizeof(ERROR_LOG_ENTRY));
|
||||||
|
|
||||||
|
|
||||||
|
/* Get driver or device name */
|
||||||
|
ObjectNameInfo = (POBJECT_NAME_INFORMATION)Buffer;
|
||||||
|
Status = ObQueryNameString (LogEntry->IoObject,
|
||||||
|
ObjectNameInfo,
|
||||||
|
256,
|
||||||
|
&ReturnedLength);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT ("ReturnedLength: %lu\n", ReturnedLength);
|
||||||
|
DPRINT ("Length: %hu\n", ObjectNameInfo->Name.Length);
|
||||||
|
DPRINT ("MaximumLength: %hu\n", ObjectNameInfo->Name.MaximumLength);
|
||||||
|
DPRINT ("Object: %wZ\n", &ObjectNameInfo->Name);
|
||||||
|
|
||||||
|
DriverName = wcsrchr(ObjectNameInfo->Name.Buffer, L'\\');
|
||||||
|
if (DriverName != NULL)
|
||||||
|
DriverName++;
|
||||||
|
else
|
||||||
|
DriverName = ObjectNameInfo->Name.Buffer;
|
||||||
|
|
||||||
|
DriverNameLength = wcslen (DriverName) * sizeof(WCHAR);
|
||||||
|
DPRINT ("Driver name '%S'\n", DriverName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DriverName = NULL;
|
||||||
|
DriverNameLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate request buffer */
|
||||||
|
Request = ExAllocatePool (NonPagedPool,
|
||||||
|
sizeof(LPC_MAX_MESSAGE));
|
||||||
|
if (Request == NULL)
|
||||||
|
{
|
||||||
|
DPRINT ("Failed to allocate request buffer!\n");
|
||||||
|
|
||||||
|
/* Requeue log message and restart the worker */
|
||||||
|
ExInterlockedInsertTailList (&IopLogListHead,
|
||||||
|
&LogEntry->Entry,
|
||||||
|
&IopLogListLock);
|
||||||
|
IopRestartLogWorker ();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the log message */
|
||||||
|
Message = (PIO_ERROR_LOG_MESSAGE)Request->Data;
|
||||||
|
Message->Type = 0xC; //IO_TYPE_ERROR_MESSAGE;
|
||||||
|
Message->Size =
|
||||||
|
sizeof(IO_ERROR_LOG_MESSAGE) - sizeof(IO_ERROR_LOG_PACKET) +
|
||||||
|
LogEntry->PacketSize + DriverNameLength;
|
||||||
|
Message->DriverNameLength = (USHORT)DriverNameLength;
|
||||||
|
Message->TimeStamp.QuadPart = LogEntry->TimeStamp.QuadPart;
|
||||||
|
Message->DriverNameOffset = (DriverName != NULL) ? LogEntry->PacketSize : 0;
|
||||||
|
|
||||||
|
/* Copy error log packet */
|
||||||
|
RtlCopyMemory (&Message->EntryData,
|
||||||
|
Packet,
|
||||||
|
LogEntry->PacketSize);
|
||||||
|
|
||||||
|
/* Copy driver or device name */
|
||||||
|
RtlCopyMemory ((PVOID)((ULONG_PTR)Message + Message->DriverNameOffset),
|
||||||
|
DriverName,
|
||||||
|
DriverNameLength);
|
||||||
|
|
||||||
|
DPRINT ("SequenceNumber %lx\n", Packet->SequenceNumber);
|
||||||
|
|
||||||
|
Request->Header.DataSize = Message->Size;
|
||||||
|
Request->Header.MessageSize =
|
||||||
|
Request->Header.DataSize + sizeof(LPC_MESSAGE);
|
||||||
|
|
||||||
|
/* Send the error message to the log port */
|
||||||
|
Status = ZwRequestPort (IopLogPort,
|
||||||
|
&Request->Header);
|
||||||
|
|
||||||
|
/* Release request buffer */
|
||||||
|
ExFreePool (Request);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT ("ZwRequestPort() failed (Status %lx)\n", Status);
|
||||||
|
|
||||||
|
/* Requeue log message and restart the worker */
|
||||||
|
ExInterlockedInsertTailList (&IopLogListHead,
|
||||||
|
&LogEntry->Entry,
|
||||||
|
&IopLogListLock);
|
||||||
|
IopRestartLogWorker ();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release error log entry */
|
||||||
|
KeAcquireSpinLock (&IopAllocationLock,
|
||||||
|
&Irql);
|
||||||
|
|
||||||
|
IopTotalLogSize -= (LogEntry->PacketSize - sizeof(ERROR_LOG_ENTRY));
|
||||||
|
ExFreePool (LogEntry);
|
||||||
|
|
||||||
|
KeReleaseSpinLock (&IopAllocationLock,
|
||||||
|
Irql);
|
||||||
|
}
|
||||||
|
|
||||||
|
IopLogWorkerRunning = FALSE;
|
||||||
|
|
||||||
|
DPRINT ("IopLogWorker() done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
VOID STDCALL
|
PVOID STDCALL
|
||||||
|
IoAllocateErrorLogEntry (IN PVOID IoObject,
|
||||||
|
IN UCHAR EntrySize)
|
||||||
|
{
|
||||||
|
PERROR_LOG_ENTRY LogEntry;
|
||||||
|
ULONG LogEntrySize;
|
||||||
|
KIRQL Irql;
|
||||||
|
|
||||||
|
DPRINT("IoAllocateErrorLogEntry() called\n");
|
||||||
|
|
||||||
|
if (IoObject == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
KeAcquireSpinLock (&IopAllocationLock,
|
||||||
|
&Irql);
|
||||||
|
|
||||||
|
if (IopTotalLogSize > PAGE_SIZE)
|
||||||
|
{
|
||||||
|
KeReleaseSpinLock (&IopAllocationLock,
|
||||||
|
Irql);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogEntrySize = sizeof(ERROR_LOG_ENTRY) + EntrySize;
|
||||||
|
LogEntry = ExAllocatePool (NonPagedPool,
|
||||||
|
LogEntrySize);
|
||||||
|
if (LogEntry == NULL)
|
||||||
|
{
|
||||||
|
KeReleaseSpinLock (&IopAllocationLock,
|
||||||
|
Irql);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
IopTotalLogSize += EntrySize;
|
||||||
|
|
||||||
|
LogEntry->IoObject = IoObject;
|
||||||
|
LogEntry->PacketSize = LogEntrySize;
|
||||||
|
|
||||||
|
KeReleaseSpinLock (&IopAllocationLock,
|
||||||
|
Irql);
|
||||||
|
|
||||||
|
return (PVOID)((ULONG_PTR)LogEntry + sizeof(ERROR_LOG_ENTRY));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
VOID STDCALL
|
||||||
|
IoFreeErrorLogEntry(IN PVOID ElEntry)
|
||||||
|
{
|
||||||
|
PERROR_LOG_ENTRY LogEntry;
|
||||||
|
KIRQL Irql;
|
||||||
|
|
||||||
|
DPRINT("IoFreeErrorLogEntry() called\n");
|
||||||
|
|
||||||
|
if (ElEntry == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LogEntry = (PERROR_LOG_ENTRY)((ULONG_PTR)ElEntry - sizeof(ERROR_LOG_ENTRY));
|
||||||
|
|
||||||
|
KeAcquireSpinLock(&IopAllocationLock,
|
||||||
|
&Irql);
|
||||||
|
|
||||||
|
IopTotalLogSize -= (LogEntry->PacketSize - sizeof(ERROR_LOG_ENTRY));
|
||||||
|
ExFreePool(LogEntry);
|
||||||
|
|
||||||
|
KeReleaseSpinLock(&IopAllocationLock,
|
||||||
|
Irql);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
VOID STDCALL
|
||||||
|
IoWriteErrorLogEntry (IN PVOID ElEntry)
|
||||||
|
{
|
||||||
|
PWORK_QUEUE_ITEM LogWorkItem;
|
||||||
|
PERROR_LOG_ENTRY LogEntry;
|
||||||
|
KIRQL Irql;
|
||||||
|
|
||||||
|
DPRINT("IoWriteErrorLogEntry() called\n");
|
||||||
|
|
||||||
|
LogEntry = (PERROR_LOG_ENTRY)((ULONG_PTR)ElEntry - sizeof(ERROR_LOG_ENTRY));
|
||||||
|
|
||||||
|
/* Get time stamp */
|
||||||
|
KeQuerySystemTime (&LogEntry->TimeStamp);
|
||||||
|
|
||||||
|
KeAcquireSpinLock (&IopLogListLock,
|
||||||
|
&Irql);
|
||||||
|
|
||||||
|
InsertHeadList (&IopLogListHead,
|
||||||
|
&LogEntry->Entry);
|
||||||
|
|
||||||
|
if (IopLogWorkerRunning == FALSE)
|
||||||
|
{
|
||||||
|
LogWorkItem = ExAllocatePool (NonPagedPool,
|
||||||
|
sizeof(WORK_QUEUE_ITEM));
|
||||||
|
if (LogWorkItem != NULL)
|
||||||
|
{
|
||||||
|
ExInitializeWorkItem (LogWorkItem,
|
||||||
|
IopLogWorker,
|
||||||
|
LogWorkItem);
|
||||||
|
|
||||||
|
ExQueueWorkItem (LogWorkItem,
|
||||||
|
DelayedWorkQueue);
|
||||||
|
|
||||||
|
IopLogWorkerRunning = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeReleaseSpinLock (&IopLogListLock,
|
||||||
|
Irql);
|
||||||
|
|
||||||
|
DPRINT("IoWriteErrorLogEntry() done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
IopFreeApc(PKAPC Apc,
|
||||||
|
PKNORMAL_ROUTINE *NormalRoutine,
|
||||||
|
PVOID *NormalContext,
|
||||||
|
PVOID *SystemArgument1,
|
||||||
|
PVOID *SystemArgument2)
|
||||||
|
{
|
||||||
|
/* Free the APC */
|
||||||
|
ExFreePool(Apc);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
IopRaiseHardError(PKAPC Apc,
|
||||||
|
PKNORMAL_ROUTINE *NormalRoutine,
|
||||||
|
PVOID *NormalContext,
|
||||||
|
PVOID *SystemArgument1,
|
||||||
|
PVOID *SystemArgument2)
|
||||||
|
{
|
||||||
|
PIRP Irp = (PIRP)NormalContext;
|
||||||
|
//PVPB Vpb = (PVPB)SystemArgument1;
|
||||||
|
//PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)SystemArgument2;
|
||||||
|
|
||||||
|
/* FIXME: UNIMPLEMENTED */
|
||||||
|
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
||||||
|
Irp->IoStatus.Information = 0;
|
||||||
|
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
IoRaiseHardError(PIRP Irp,
|
IoRaiseHardError(PIRP Irp,
|
||||||
PVPB Vpb,
|
PVPB Vpb,
|
||||||
PDEVICE_OBJECT RealDeviceObject)
|
PDEVICE_OBJECT RealDeviceObject)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
PETHREAD Thread = (PETHREAD)&Irp->Tail.Overlay.Thread;
|
||||||
}
|
PKAPC ErrorApc;
|
||||||
|
|
||||||
BOOLEAN
|
/* Don't do anything if hard errors are disabled on the thread */
|
||||||
IoIsTotalDeviceFailure(NTSTATUS Status)
|
if (Thread->HardErrorsAreDisabled)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
/* Complete the request */
|
||||||
return(FALSE);
|
Irp->IoStatus.Information = 0;
|
||||||
|
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup an APC */
|
||||||
|
ErrorApc = ExAllocatePoolWithTag(NonPagedPool,
|
||||||
|
sizeof(KAPC),
|
||||||
|
TAG('K', 'A', 'P', 'C'));
|
||||||
|
KeInitializeApc(ErrorApc,
|
||||||
|
&Thread->Tcb,
|
||||||
|
Irp->ApcEnvironment,
|
||||||
|
NULL,
|
||||||
|
(PKRUNDOWN_ROUTINE)IopFreeApc,
|
||||||
|
(PKNORMAL_ROUTINE)IopRaiseHardError,
|
||||||
|
KernelMode,
|
||||||
|
Irp);
|
||||||
|
|
||||||
|
/* Queue an APC to deal with the error (see osr documentation) */
|
||||||
|
KeInsertQueueApc(ErrorApc, Vpb, RealDeviceObject, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @unimplemented
|
||||||
*/
|
*/
|
||||||
BOOLEAN STDCALL
|
BOOLEAN
|
||||||
|
STDCALL
|
||||||
IoRaiseInformationalHardError(NTSTATUS ErrorStatus,
|
IoRaiseInformationalHardError(NTSTATUS ErrorStatus,
|
||||||
PUNICODE_STRING String,
|
PUNICODE_STRING String,
|
||||||
PKTHREAD Thread)
|
PKTHREAD Thread)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
UNIMPLEMENTED;
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
Loading…
Reference in a new issue