1 /* $Id: errlog.c,v 1.20 2004/09/28 12:51:14 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 *****************************************************************/
16 #include <internal/debug.h>
18 /* TYPES *********************************************************************/
20 typedef struct _ERROR_LOG_ENTRY
23 LARGE_INTEGER TimeStamp
;
26 } ERROR_LOG_ENTRY
, *PERROR_LOG_ENTRY
;
28 typedef struct _LOG_WORKER_DPC
32 } LOG_WORKER_DPC
, *PLOG_WORKER_DPC
;
36 IopLogWorker (PVOID Parameter
);
39 /* GLOBALS *******************************************************************/
41 static KSPIN_LOCK IopAllocationLock
;
42 static ULONG IopTotalLogSize
;
44 static KSPIN_LOCK IopLogListLock
;
45 static LIST_ENTRY IopLogListHead
;
47 static BOOLEAN IopLogWorkerRunning
= FALSE
;
48 static BOOLEAN IopLogPortConnected
= FALSE
;
49 static HANDLE IopLogPort
;
52 /* FUNCTIONS *****************************************************************/
55 IopInitErrorLog (VOID
)
58 KeInitializeSpinLock (&IopAllocationLock
);
60 KeInitializeSpinLock (&IopLogListLock
);
61 InitializeListHead (&IopLogListHead
);
63 return STATUS_SUCCESS
;
68 IopLogDpcRoutine (PKDPC Dpc
,
69 PVOID DeferredContext
,
70 PVOID SystemArgument1
,
71 PVOID SystemArgument2
)
73 PWORK_QUEUE_ITEM LogWorkItem
;
75 DPRINT ("\nIopLogDpcRoutine() called\n");
77 /* Release the WorkerDpc struct */
78 ExFreePool (DeferredContext
);
80 /* Allocate, initialize and restart a work item */
81 LogWorkItem
= ExAllocatePool (NonPagedPool
,
82 sizeof(WORK_QUEUE_ITEM
));
83 if (LogWorkItem
== NULL
)
85 IopLogWorkerRunning
= FALSE
;
89 ExInitializeWorkItem (LogWorkItem
,
93 ExQueueWorkItem (LogWorkItem
,
99 IopRestartLogWorker (VOID
)
101 PLOG_WORKER_DPC WorkerDpc
;
102 LARGE_INTEGER Timeout
;
104 DPRINT ("IopRestartWorker() called\n");
106 WorkerDpc
= ExAllocatePool (NonPagedPool
,
107 sizeof(LOG_WORKER_DPC
));
108 if (WorkerDpc
== NULL
)
110 IopLogWorkerRunning
= FALSE
;
114 /* Initialize DPC and Timer */
115 KeInitializeDpc (&WorkerDpc
->Dpc
,
118 KeInitializeTimer (&WorkerDpc
->Timer
);
120 /* Restart after 30 seconds */
121 Timeout
.QuadPart
= (LONGLONG
)-300000000;
122 KeSetTimer (&WorkerDpc
->Timer
,
129 IopConnectLogPort (VOID
)
131 UNICODE_STRING PortName
;
134 DPRINT ("IopConnectLogPort() called\n");
136 RtlInitUnicodeString (&PortName
,
139 Status
= NtConnectPort (&IopLogPort
,
147 if (!NT_SUCCESS(Status
))
149 DPRINT ("NtConnectPort() failed (Status %lx)\n", Status
);
153 DPRINT ("IopConnectLogPort() done\n");
160 IopLogWorker (PVOID Parameter
)
162 PERROR_LOG_ENTRY LogEntry
;
163 PLPC_MAX_MESSAGE Request
;
164 PIO_ERROR_LOG_MESSAGE Message
;
165 PIO_ERROR_LOG_PACKET Packet
;
170 POBJECT_NAME_INFORMATION ObjectNameInfo
;
171 ULONG ReturnedLength
;
173 ULONG DriverNameLength
;
175 DPRINT ("IopLogWorker() called\n");
177 /* Release the work item */
178 ExFreePool (Parameter
);
180 /* Connect to the error log port */
181 if (IopLogPortConnected
== FALSE
)
183 if (IopConnectLogPort () == FALSE
)
185 IopRestartLogWorker ();
189 IopLogPortConnected
= TRUE
;
194 /* Remove last entry from the list */
195 KeAcquireSpinLock (&IopLogListLock
,
198 if (!IsListEmpty (&IopLogListHead
))
200 LogEntry
= CONTAINING_RECORD (IopLogListHead
.Blink
,
203 RemoveEntryList (&LogEntry
->Entry
);
210 KeReleaseSpinLock (&IopLogListLock
,
213 if (LogEntry
== NULL
)
215 DPRINT ("No message in log list\n");
219 /* Get pointer to the log packet */
220 Packet
= (PIO_ERROR_LOG_PACKET
)((ULONG_PTR
)LogEntry
+ sizeof(ERROR_LOG_ENTRY
));
223 /* Get driver or device name */
224 ObjectNameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
225 Status
= ObQueryNameString (LogEntry
->IoObject
,
229 if (NT_SUCCESS(Status
))
231 DPRINT ("ReturnedLength: %lu\n", ReturnedLength
);
232 DPRINT ("Length: %hu\n", ObjectNameInfo
->Name
.Length
);
233 DPRINT ("MaximumLength: %hu\n", ObjectNameInfo
->Name
.MaximumLength
);
234 DPRINT ("Object: %wZ\n", &ObjectNameInfo
->Name
);
236 DriverName
= wcsrchr(ObjectNameInfo
->Name
.Buffer
, L
'\\');
237 if (DriverName
!= NULL
)
240 DriverName
= ObjectNameInfo
->Name
.Buffer
;
242 DriverNameLength
= wcslen (DriverName
) * sizeof(WCHAR
);
243 DPRINT ("Driver name '%S'\n", DriverName
);
248 DriverNameLength
= 0;
251 /* Allocate request buffer */
252 Request
= ExAllocatePool (NonPagedPool
,
253 sizeof(LPC_MAX_MESSAGE
));
256 DPRINT ("Failed to allocate request buffer!\n");
258 /* Requeue log message and restart the worker */
259 ExInterlockedInsertTailList (&IopLogListHead
,
262 IopRestartLogWorker ();
267 /* Initialize the log message */
268 Message
= (PIO_ERROR_LOG_MESSAGE
)Request
->Data
;
269 Message
->Type
= 0xC; //IO_TYPE_ERROR_MESSAGE;
271 sizeof(IO_ERROR_LOG_MESSAGE
) - sizeof(IO_ERROR_LOG_PACKET
) +
272 LogEntry
->PacketSize
+ DriverNameLength
;
273 Message
->DriverNameLength
= (USHORT
)DriverNameLength
;
274 Message
->TimeStamp
.QuadPart
= LogEntry
->TimeStamp
.QuadPart
;
275 Message
->DriverNameOffset
= (DriverName
!= NULL
) ? LogEntry
->PacketSize
: 0;
277 /* Copy error log packet */
278 RtlCopyMemory (&Message
->EntryData
,
280 LogEntry
->PacketSize
);
282 /* Copy driver or device name */
283 RtlCopyMemory ((PVOID
)((ULONG_PTR
)Message
+ Message
->DriverNameOffset
),
287 DPRINT ("SequenceNumber %lx\n", Packet
->SequenceNumber
);
289 Request
->Header
.DataSize
= Message
->Size
;
290 Request
->Header
.MessageSize
=
291 Request
->Header
.DataSize
+ sizeof(LPC_MESSAGE
);
293 /* Send the error message to the log port */
294 Status
= NtRequestPort (IopLogPort
,
297 /* Release request buffer */
298 ExFreePool (Request
);
300 if (!NT_SUCCESS(Status
))
302 DPRINT ("NtRequestPort() failed (Status %lx)\n", Status
);
304 /* Requeue log message and restart the worker */
305 ExInterlockedInsertTailList (&IopLogListHead
,
308 IopRestartLogWorker ();
313 /* Release error log entry */
314 KeAcquireSpinLock (&IopAllocationLock
,
317 IopTotalLogSize
-= (LogEntry
->PacketSize
- sizeof(ERROR_LOG_ENTRY
));
318 ExFreePool (LogEntry
);
320 KeReleaseSpinLock (&IopAllocationLock
,
324 IopLogWorkerRunning
= FALSE
;
326 DPRINT ("IopLogWorker() done\n");
334 IoAllocateErrorLogEntry (IN PVOID IoObject
,
337 PERROR_LOG_ENTRY LogEntry
;
341 DPRINT("IoAllocateErrorLogEntry() called\n");
343 if (IoObject
== NULL
)
346 KeAcquireSpinLock (&IopAllocationLock
,
349 if (IopTotalLogSize
> PAGE_SIZE
)
351 KeReleaseSpinLock (&IopAllocationLock
,
356 LogEntrySize
= sizeof(ERROR_LOG_ENTRY
) + EntrySize
;
357 LogEntry
= ExAllocatePool (NonPagedPool
,
359 if (LogEntry
== NULL
)
361 KeReleaseSpinLock (&IopAllocationLock
,
366 IopTotalLogSize
+= EntrySize
;
368 LogEntry
->IoObject
= IoObject
;
369 LogEntry
->PacketSize
= LogEntrySize
;
371 KeReleaseSpinLock (&IopAllocationLock
,
374 return (PVOID
)((ULONG_PTR
)LogEntry
+ sizeof(ERROR_LOG_ENTRY
));
382 IoFreeErrorLogEntry(IN PVOID ElEntry
)
384 PERROR_LOG_ENTRY LogEntry
;
387 DPRINT("IoFreeErrorLogEntry() called\n");
392 LogEntry
= (PERROR_LOG_ENTRY
)((ULONG_PTR
)ElEntry
- sizeof(ERROR_LOG_ENTRY
));
394 KeAcquireSpinLock(&IopAllocationLock
,
397 IopTotalLogSize
-= (LogEntry
->PacketSize
- sizeof(ERROR_LOG_ENTRY
));
398 ExFreePool(LogEntry
);
400 KeReleaseSpinLock(&IopAllocationLock
,
409 IoWriteErrorLogEntry (IN PVOID ElEntry
)
411 PWORK_QUEUE_ITEM LogWorkItem
;
412 PERROR_LOG_ENTRY LogEntry
;
415 DPRINT("IoWriteErrorLogEntry() called\n");
417 LogEntry
= (PERROR_LOG_ENTRY
)((ULONG_PTR
)ElEntry
- sizeof(ERROR_LOG_ENTRY
));
420 KeQuerySystemTime (&LogEntry
->TimeStamp
);
422 KeAcquireSpinLock (&IopLogListLock
,
425 InsertHeadList (&IopLogListHead
,
428 if (IopLogWorkerRunning
== FALSE
)
430 LogWorkItem
= ExAllocatePool (NonPagedPool
,
431 sizeof(WORK_QUEUE_ITEM
));
432 if (LogWorkItem
!= NULL
)
434 ExInitializeWorkItem (LogWorkItem
,
438 ExQueueWorkItem (LogWorkItem
,
441 IopLogWorkerRunning
= TRUE
;
445 KeReleaseSpinLock (&IopLogListLock
,
448 DPRINT("IoWriteErrorLogEntry() done\n");