-/*
+/* $Id: errlog.c,v 1.20 2004/09/28 12:51:14 ekohl Exp $
+ *
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/io/errlog.c
/* INCLUDES *****************************************************************/
-#include <ddk/ntddk.h>
-
-#include <internal/port.h>
-
+#include <ntoskrnl.h>
+#define NDEBUG
#include <internal/debug.h>
/* TYPES *********************************************************************/
-typedef struct _IO_ERROR_LOG_PACKET
+typedef struct _ERROR_LOG_ENTRY
{
- UCHAR MajorFunctionCode;
- UCHAR RetryCount;
- USHORT DumpDataSize;
- USHORT NumberOfStrings;
- USHORT StringOffset;
- USHORT EventCategory;
- NTSTATUS ErrorCode;
- ULONG UniqueErrorValue;
- NTSTATUS FinalStatus;
- ULONG SequenceNumber;
- ULONG IoControlCode;
- LARGE_INTEGER DeviceOffset;
- ULONG DumpData[1];
-} IO_ERROR_LOG_PACKET, *PIO_ERROR_LOG_PACKET;
-
-typedef struct _ERROR_LOG_MESSAGE
+ LIST_ENTRY Entry;
+ LARGE_INTEGER TimeStamp;
+ PVOID IoObject;
+ ULONG PacketSize;
+} ERROR_LOG_ENTRY, *PERROR_LOG_ENTRY;
+
+typedef struct _LOG_WORKER_DPC
{
- PIO_ERROR_LOG_PACKET Packet;
- LIST_ENTRY ListEntry;
-} IO_ERROR_LOG_MESSAGE, *PIO_ERROR_LOG_MESSAGE;
+ KDPC Dpc;
+ KTIMER Timer;
+} LOG_WORKER_DPC, *PLOG_WORKER_DPC;
+
+
+static VOID STDCALL
+IopLogWorker (PVOID Parameter);
+
/* GLOBALS *******************************************************************/
-static HANDLE ErrorLogPortHandle;
-static HANDLE ErrorLogThreadHandle;
-static PEPORT ErrorLogPort;
+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;
-static LIST_ENTRY ErrorLogListHead;
-static KSPIN_LOCK ErrorLogListLock;
-static KSEMAPHORE ErrorLogSemaphore;
/* FUNCTIONS *****************************************************************/
-static VOID IoSendErrorLogEntry(PIO_ERROR_LOG_PACKET Packet)
+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)
{
- LPCMESSAGE Message;
- ULONG Size;
- ULONG i;
-
- Size = sizeof(IO_ERROR_LOG_PACKET) +
- (Packet->DumpDataSize * sizeof(UCHAR));
-
- for (i=0; i<((Size % MAX_MESSAGE_DATA) - 1); i++)
- {
- Message.ActualMessageLength = MAX_MESSAGE_DATA;
- Message.TotalMessageLength = sizeof(LPCMESSAGE);
- Message.MessageType = i;
- memcpy(Message.MessageData, (PVOID)Packet, MAX_MESSAGE_DATA);
- LpcRequestPort(ErrorLogPort, &Message);
- }
- Message.ActualMessageLength = MAX_MESSAGE_DATA;
- Message.TotalMessageLength = sizeof(LPCMESSAGE);
- Message.MessageType = i;
- memcpy(Message.MessageData, (PVOID)Packet, Size % MAX_MESSAGE_DATA);
- LpcRequestPort(ErrorLogPort, &Message);
+ UNICODE_STRING PortName;
+ NTSTATUS Status;
+
+ DPRINT ("IopConnectLogPort() called\n");
+
+ RtlInitUnicodeString (&PortName,
+ L"\\ErrorLogPort");
+
+ Status = NtConnectPort (&IopLogPort,
+ &PortName,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT ("NtConnectPort() failed (Status %lx)\n", Status);
+ return FALSE;
+ }
+
+ DPRINT ("IopConnectLogPort() done\n");
+
+ return TRUE;
}
-NTSTATUS IoErrorLogThreadMain(PVOID Context)
+
+static VOID STDCALL
+IopLogWorker (PVOID Parameter)
{
- NTSTATUS Status;
- LPCMESSAGE ConnectMsg;
- HANDLE PortHandle;
- PIO_ERROR_LOG_MESSAGE Message;
- KIRQL oldIrql;
- PLIST_ENTRY ListEntry;
-
- for (;;)
- {
- Status = NtListenPort(ErrorLogPortHandle, &ConnectMsg);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- Status = NtAcceptConnectPort(&PortHandle,
- ErrorLogPortHandle,
- NULL,
- 1,
- 0,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- Status = NtCompleteConnectPort(PortHandle);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- Status = ObReferenceObjectByHandle(PortHandle,
- PORT_ALL_ACCESS,
- ExPortType,
- UserMode,
- (PVOID*)&ErrorLogPort,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- ZwClose(PortHandle);
- return(Status);
- }
-
- ZwClose(PortHandle);
-
- for (;;)
- {
-
- KeWaitForSingleObject(&ErrorLogSemaphore,
- UserRequest,
- KernelMode,
- FALSE,
- NULL);
-
- KeAcquireSpinLock(&ErrorLogListLock, &oldIrql);
-
- ListEntry = RemoveHeadList(&ErrorLogListHead);
-
- KeReleaseSpinLock(&ErrorLogListLock, oldIrql);
-
- Message = CONTAINING_RECORD(ListEntry,
- IO_ERROR_LOG_MESSAGE,
- ListEntry);
-
- IoSendErrorLogEntry(Message->Packet);
-
- ExFreePool(Message->Packet);
- ExFreePool(Message);
- }
- }
+ 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 = NtRequestPort (IopLogPort,
+ &Request->Header);
+
+ /* Release request buffer */
+ ExFreePool (Request);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT ("NtRequestPort() 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");
}
-NTSTATUS IoInitErrorLog(VOID)
+
+/*
+ * @implemented
+ */
+PVOID STDCALL
+IoAllocateErrorLogEntry (IN PVOID IoObject,
+ IN UCHAR EntrySize)
{
- NTSTATUS Status;
- OBJECT_ATTRIBUTES ObjectAttributes;
- UNICODE_STRING PortName;
- CLIENT_ID Cid;
-
- InitializeListHead(&ErrorLogListHead);
- KeInitializeSpinLock(&ErrorLogListLock);
-
- KeInitializeSemaphore(&ErrorLogSemaphore,
- 0,
- 500);
-
- RtlInitUnicodeString(&PortName, L"\\ErrorLogPort");
- InitializeObjectAttributes(&ObjectAttributes,
- &PortName,
- 0,
- NULL,
- NULL);
- Status = NtCreatePort(&ErrorLogPortHandle,
- &ObjectAttributes,
- 0,
- 0,
- 0);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- Status = PsCreateSystemThread(ErrorLogThreadHandle,
- 0,
- NULL,
- NULL,
- &Cid,
- IoErrorLogThreadMain,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- return(STATUS_SUCCESS);
+ 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));
}
-PVOID IoAllocateErrorLogEntry(PVOID IoObject, UCHAR EntrySize)
+/*
+ * @implemented
+ */
+VOID STDCALL
+IoFreeErrorLogEntry(IN PVOID ElEntry)
{
- UNIMPLEMENTED;
+ 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);
}
-VOID IoWriteErrorLogEntry(PVOID ElEntry)
+
+/*
+ * @implemented
+ */
+VOID STDCALL
+IoWriteErrorLogEntry (IN PVOID ElEntry)
{
- KIRQL oldIrql;
- PIO_ERROR_LOG_MESSAGE Message;
-
- Message = ExAllocatePool(NonPagedPool, sizeof(IO_ERROR_LOG_MESSAGE));
- Message->Packet = (PIO_ERROR_LOG_PACKET)ElEntry;
-
- KeAcquireSpinLock(&ErrorLogListLock, &oldIrql);
-
- InsertTailList(&ErrorLogListHead, &Message->ListEntry);
-
- KeReleaseSemaphore(&ErrorLogSemaphore,
- IO_NO_INCREMENT,
- 1,
- FALSE);
-
- KeReleaseSpinLock(&ErrorLogListLock, oldIrql);
-}
+ 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 */