diff --git a/reactos/include/ddk/iotypes.h b/reactos/include/ddk/iotypes.h index eff649ab22c..755c305f6d0 100644 --- a/reactos/include/ddk/iotypes.h +++ b/reactos/include/ddk/iotypes.h @@ -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; diff --git a/reactos/include/ddk/ketypes.h b/reactos/include/ddk/ketypes.h index 952932af281..1cf8ddd28a2 100644 --- a/reactos/include/ddk/ketypes.h +++ b/reactos/include/ddk/ketypes.h @@ -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, diff --git a/reactos/ntoskrnl/Makefile b/reactos/ntoskrnl/Makefile index 533a59365b4..7f48644bb6d 100644 --- a/reactos/ntoskrnl/Makefile +++ b/reactos/ntoskrnl/Makefile @@ -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 \ diff --git a/reactos/ntoskrnl/io/cntrller.c b/reactos/ntoskrnl/io/cntrller.c deleted file mode 100644 index 70a6dba75c8..00000000000 --- a/reactos/ntoskrnl/io/cntrller.c +++ /dev/null @@ -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 -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/io/controller.c b/reactos/ntoskrnl/io/controller.c new file mode 100644 index 00000000000..7e029792061 --- /dev/null +++ b/reactos/ntoskrnl/io/controller.c @@ -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 +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/io/errlog.c b/reactos/ntoskrnl/io/errlog.c deleted file mode 100644 index 43e13d76fa8..00000000000 --- a/reactos/ntoskrnl/io/errlog.c +++ /dev/null @@ -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 -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/io/error.c b/reactos/ntoskrnl/io/error.c index 5b85dd926ff..42c170b761c 100644 --- a/reactos/ntoskrnl/io/error.c +++ b/reactos/ntoskrnl/io/error.c @@ -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 +#define NDEBUG #include +/* 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 */