1 /* $Id: errlog.c,v 1.15 2003/11/21 22:28:50 ekohl Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/errlog.c
6 * PURPOSE: Error logging
7 * PROGRAMMER: David Welch (welch@cwcom.net)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
16 #include <internal/port.h>
19 #include <internal/debug.h>
21 /* TYPES *********************************************************************/
23 typedef struct _ERROR_LOG_ENTRY
26 LARGE_INTEGER TimeStamp
;
29 } ERROR_LOG_ENTRY
, *PERROR_LOG_ENTRY
;
31 typedef struct _LOG_WORKER_DPC
35 } LOG_WORKER_DPC
, *PLOG_WORKER_DPC
;
39 IopLogWorker (PVOID Parameter
);
42 /* GLOBALS *******************************************************************/
44 static KSPIN_LOCK IopAllocationLock
;
45 static ULONG IopTotalLogSize
;
47 static KSPIN_LOCK IopLogListLock
;
48 static LIST_ENTRY IopLogListHead
;
50 static BOOLEAN IopLogWorkerRunning
= FALSE
;
51 static BOOLEAN IopLogPortConnected
= FALSE
;
52 static HANDLE IopLogPort
;
55 /* FUNCTIONS *****************************************************************/
58 IopInitErrorLog (VOID
)
61 KeInitializeSpinLock (&IopAllocationLock
);
63 KeInitializeSpinLock (&IopLogListLock
);
64 InitializeListHead (&IopLogListHead
);
66 return STATUS_SUCCESS
;
71 IopLogDpcRoutine (PKDPC Dpc
,
72 PVOID DeferredContext
,
73 PVOID SystemArgument1
,
74 PVOID SystemArgument2
)
76 PWORK_QUEUE_ITEM LogWorkItem
;
78 DPRINT ("\nIopLogDpcRoutine() called\n");
80 /* Release the WorkerDpc struct */
81 ExFreePool (DeferredContext
);
83 /* Allocate, initialize and restart a work item */
84 LogWorkItem
= ExAllocatePool (NonPagedPool
,
85 sizeof(WORK_QUEUE_ITEM
));
86 if (LogWorkItem
== NULL
)
88 IopLogWorkerRunning
= FALSE
;
92 ExInitializeWorkItem (LogWorkItem
,
96 ExQueueWorkItem (LogWorkItem
,
102 IopRestartLogWorker (VOID
)
104 PLOG_WORKER_DPC WorkerDpc
;
105 LARGE_INTEGER Timeout
;
107 DPRINT ("IopRestartWorker() called\n");
109 WorkerDpc
= ExAllocatePool (NonPagedPool
,
110 sizeof(LOG_WORKER_DPC
));
111 if (WorkerDpc
== NULL
)
113 IopLogWorkerRunning
= FALSE
;
117 /* Initialize DPC and Timer */
118 KeInitializeDpc (&WorkerDpc
->Dpc
,
121 KeInitializeTimer (&WorkerDpc
->Timer
);
123 /* Restart after 30 seconds */
124 Timeout
.QuadPart
= -300000000LL;
125 KeSetTimer (&WorkerDpc
->Timer
,
132 IopConnectLogPort (VOID
)
134 UNICODE_STRING PortName
;
137 DPRINT ("IopConnectLogPort() called\n");
139 RtlInitUnicodeString (&PortName
,
142 Status
= NtConnectPort (&IopLogPort
,
150 if (!NT_SUCCESS(Status
))
152 DPRINT ("NtConnectPort() failed (Status %lx)\n", Status
);
156 DPRINT ("IopConnectLogPort() done\n");
163 IopLogWorker (PVOID Parameter
)
165 PERROR_LOG_ENTRY LogEntry
;
166 PLPC_MAX_MESSAGE Request
;
167 PIO_ERROR_LOG_MESSAGE Message
;
168 PIO_ERROR_LOG_PACKET Packet
;
173 POBJECT_NAME_INFORMATION ObjectNameInfo
;
174 ULONG ReturnedLength
;
176 ULONG DriverNameLength
;
178 DPRINT ("IopLogWorker() called\n");
180 /* Release the work item */
181 ExFreePool (Parameter
);
184 /* Connect to the error log port */
185 if (IopLogPortConnected
== FALSE
)
187 if (IopConnectLogPort () == FALSE
)
189 IopRestartLogWorker ();
193 IopLogPortConnected
= TRUE
;
198 /* Remove last entry from the list */
199 KeAcquireSpinLock (&IopLogListLock
,
202 if (!IsListEmpty (&IopLogListHead
))
204 LogEntry
= CONTAINING_RECORD (IopLogListHead
.Blink
,
207 RemoveEntryList (&LogEntry
->Entry
);
214 KeReleaseSpinLock (&IopLogListLock
,
217 if (LogEntry
== NULL
)
219 DPRINT ("No message in log list\n");
223 /* Get pointer to the log packet */
224 Packet
= (PIO_ERROR_LOG_PACKET
)((ULONG_PTR
)LogEntry
+ sizeof(ERROR_LOG_ENTRY
));
227 /* Get driver or device name */
228 ObjectNameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
229 Status
= ObQueryNameString (LogEntry
->IoObject
,
233 if (NT_SUCCESS(Status
))
235 DPRINT ("ReturnedLength: %lu\n", ReturnedLength
);
236 DPRINT ("Length: %hu\n", ObjectNameInfo
->Name
.Length
);
237 DPRINT ("MaximumLength: %hu\n", ObjectNameInfo
->Name
.MaximumLength
);
238 DPRINT ("Object: %wZ\n", &ObjectNameInfo
->Name
);
240 DriverName
= wcsrchr(ObjectNameInfo
->Name
.Buffer
, L
'\\');
241 if (DriverName
!= NULL
)
244 DriverName
= ObjectNameInfo
->Name
.Buffer
;
246 DriverNameLength
= wcslen (DriverName
) * sizeof(WCHAR
);
247 DPRINT ("Driver name '%S'\n", DriverName
);
252 DriverNameLength
= 0;
255 /* Allocate request buffer */
256 Request
= ExAllocatePool (NonPagedPool
,
257 sizeof(LPC_MAX_MESSAGE
));
260 DPRINT ("Failed to allocate request buffer!\n");
262 /* Requeue log message and restart the worker */
263 ExInterlockedInsertTailList (&IopLogListHead
,
266 IopRestartLogWorker ();
271 /* Initialize the log message */
272 Message
= (PIO_ERROR_LOG_MESSAGE
)Request
->Data
;
273 Message
->Type
= 0xC; //IO_TYPE_ERROR_MESSAGE;
275 sizeof(IO_ERROR_LOG_MESSAGE
) - sizeof(IO_ERROR_LOG_PACKET
) +
276 LogEntry
->PacketSize
+ DriverNameLength
;
277 Message
->DriverNameLength
= DriverNameLength
;
278 Message
->TimeStamp
.QuadPart
= LogEntry
->TimeStamp
.QuadPart
;
279 Message
->DriverNameOffset
= (DriverName
!= NULL
) ? LogEntry
->PacketSize
: 0;
281 /* Copy error log packet */
282 RtlCopyMemory (&Message
->EntryData
,
284 LogEntry
->PacketSize
);
286 /* Copy driver or device name */
287 RtlCopyMemory ((PVOID
)((ULONG_PTR
)Message
+ Message
->DriverNameOffset
),
291 DPRINT ("SequenceNumber %lx\n", Packet
->SequenceNumber
);
293 Request
->Header
.DataSize
= Message
->Size
;
294 Request
->Header
.MessageSize
=
295 Request
->Header
.DataSize
+ sizeof(LPC_MESSAGE
);
297 /* Send the error message to the log port */
298 Status
= NtRequestPort (IopLogPort
,
301 /* Release request buffer */
302 ExFreePool (Request
);
304 if (!NT_SUCCESS(Status
))
306 DPRINT ("NtRequestPort() failed (Status %lx)\n", Status
);
308 /* Requeue log message and restart the worker */
309 ExInterlockedInsertTailList (&IopLogListHead
,
312 IopRestartLogWorker ();
317 /* Release error log entry */
318 KeAcquireSpinLock (&IopAllocationLock
,
321 IopTotalLogSize
-= LogEntry
->PacketSize
;
322 ExFreePool (LogEntry
);
324 KeReleaseSpinLock (&IopAllocationLock
,
328 IopLogWorkerRunning
= FALSE
;
330 DPRINT ("IopLogWorker() done\n");
338 IoAllocateErrorLogEntry (IN PVOID IoObject
,
341 PERROR_LOG_ENTRY LogEntry
;
345 DPRINT1 ("IoAllocateErrorLogEntry() called\n");
347 if (IoObject
== NULL
)
350 KeAcquireSpinLock (&IopAllocationLock
,
353 if (IopTotalLogSize
> PAGE_SIZE
)
355 KeReleaseSpinLock (&IopAllocationLock
,
360 LogEntrySize
= sizeof(ERROR_LOG_ENTRY
) + EntrySize
;
361 LogEntry
= ExAllocatePool (NonPagedPool
,
363 if (LogEntry
== NULL
)
365 KeReleaseSpinLock (&IopAllocationLock
,
370 IopTotalLogSize
+= EntrySize
;
372 LogEntry
->IoObject
= IoObject
;
373 LogEntry
->PacketSize
= LogEntrySize
;
375 KeReleaseSpinLock (&IopAllocationLock
,
378 return (PVOID
)((ULONG_PTR
)LogEntry
+ sizeof(ERROR_LOG_ENTRY
));
386 IoWriteErrorLogEntry (IN PVOID ElEntry
)
388 PWORK_QUEUE_ITEM LogWorkItem
;
389 PERROR_LOG_ENTRY LogEntry
;
392 DPRINT ("IoWriteErrorLogEntry() called\n");
394 LogEntry
= (PERROR_LOG_ENTRY
)((ULONG_PTR
)ElEntry
- sizeof(ERROR_LOG_ENTRY
));
397 KeQuerySystemTime (&LogEntry
->TimeStamp
);
399 KeAcquireSpinLock (&IopLogListLock
,
402 InsertHeadList (&IopLogListHead
,
405 if (IopLogWorkerRunning
== FALSE
)
407 LogWorkItem
= ExAllocatePool (NonPagedPool
,
408 sizeof(WORK_QUEUE_ITEM
));
409 if (LogWorkItem
!= NULL
)
411 ExInitializeWorkItem (LogWorkItem
,
415 ExQueueWorkItem (LogWorkItem
,
418 IopLogWorkerRunning
= TRUE
;
422 KeReleaseSpinLock (&IopLogListLock
,
425 DPRINT ("IoWriteErrorLogEntry() done\n");