Implement IoRaiseHardError, combine error stuff, fix hideously wrong implementatin of Controller Objects.

svn path=/trunk/; revision=14816
This commit is contained in:
Alex Ionescu 2005-04-26 14:51:18 +00:00
parent c6c78c3133
commit 946594bdc0
7 changed files with 710 additions and 693 deletions

View file

@ -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;

View file

@ -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,

View file

@ -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 \

View file

@ -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 */

View 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 */

View file

@ -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 */

View file

@ -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 */