mirror of
https://github.com/reactos/reactos.git
synced 2024-12-26 00:54:40 +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;
|
||||
} 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
|
||||
{
|
||||
|
@ -757,7 +785,6 @@ typedef struct _VPB
|
|||
WCHAR VolumeLabel[MAXIMUM_VOLUME_LABEL_LENGTH];
|
||||
} VPB, *PVPB;
|
||||
|
||||
|
||||
typedef struct _DEVICE_OBJECT
|
||||
{
|
||||
CSHORT Type;
|
||||
|
@ -1133,18 +1160,6 @@ typedef struct _DRIVER_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
|
||||
{
|
||||
ULONG NamedPipeType;
|
||||
|
|
|
@ -285,37 +285,6 @@ typedef struct _KDPC_DATA {
|
|||
ULONG DpcCount;
|
||||
} 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 {
|
||||
KbCallbackInvalid,
|
||||
KbCallbackReserved1,
|
||||
|
|
|
@ -149,14 +149,13 @@ OBJECTS_IO = \
|
|||
io/buildirp.o \
|
||||
io/cancel.o \
|
||||
io/cleanup.o \
|
||||
io/cntrller.o \
|
||||
io/controller.o \
|
||||
io/create.o \
|
||||
io/device.o \
|
||||
io/deviface.o \
|
||||
io/dir.o \
|
||||
io/driver.o \
|
||||
io/efi.o \
|
||||
io/errlog.o \
|
||||
io/error.o \
|
||||
io/event.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
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/io/error.c
|
||||
* PURPOSE: Handle media errors
|
||||
*
|
||||
* PROGRAMMERS: David Welch (welch@mcmail.com)
|
||||
* 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");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @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,
|
||||
PVPB Vpb,
|
||||
PDEVICE_OBJECT RealDeviceObject)
|
||||
PVPB Vpb,
|
||||
PDEVICE_OBJECT RealDeviceObject)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
IoIsTotalDeviceFailure(NTSTATUS Status)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return(FALSE);
|
||||
PETHREAD Thread = (PETHREAD)&Irp->Tail.Overlay.Thread;
|
||||
PKAPC ErrorApc;
|
||||
|
||||
/* Don't do anything if hard errors are disabled on the thread */
|
||||
if (Thread->HardErrorsAreDisabled)
|
||||
{
|
||||
/* Complete the request */
|
||||
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
|
||||
*/
|
||||
BOOLEAN STDCALL
|
||||
BOOLEAN
|
||||
STDCALL
|
||||
IoRaiseInformationalHardError(NTSTATUS ErrorStatus,
|
||||
PUNICODE_STRING String,
|
||||
PKTHREAD Thread)
|
||||
PUNICODE_STRING String,
|
||||
PKTHREAD Thread)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return(FALSE);
|
||||
UNIMPLEMENTED;
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
|
||||
/* EOF */
|
||||
|
|
Loading…
Reference in a new issue