1 /* $Id: errlog.c,v 1.19 2004/08/21 20:51:26 tamlin 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 #if defined(__GNUC__)
122 Timeout
.QuadPart
= -300000000LL;
124 Timeout
.QuadPart
= -300000000;
126 KeSetTimer (&WorkerDpc
->Timer
,
133 IopConnectLogPort (VOID
)
135 UNICODE_STRING PortName
;
138 DPRINT ("IopConnectLogPort() called\n");
140 RtlInitUnicodeString (&PortName
,
143 Status
= NtConnectPort (&IopLogPort
,
151 if (!NT_SUCCESS(Status
))
153 DPRINT ("NtConnectPort() failed (Status %lx)\n", Status
);
157 DPRINT ("IopConnectLogPort() done\n");
164 IopLogWorker (PVOID Parameter
)
166 PERROR_LOG_ENTRY LogEntry
;
167 PLPC_MAX_MESSAGE Request
;
168 PIO_ERROR_LOG_MESSAGE Message
;
169 PIO_ERROR_LOG_PACKET Packet
;
174 POBJECT_NAME_INFORMATION ObjectNameInfo
;
175 ULONG ReturnedLength
;
177 ULONG DriverNameLength
;
179 DPRINT ("IopLogWorker() called\n");
181 /* Release the work item */
182 ExFreePool (Parameter
);
185 /* Connect to the error log port */
186 if (IopLogPortConnected
== FALSE
)
188 if (IopConnectLogPort () == FALSE
)
190 IopRestartLogWorker ();
194 IopLogPortConnected
= TRUE
;
199 /* Remove last entry from the list */
200 KeAcquireSpinLock (&IopLogListLock
,
203 if (!IsListEmpty (&IopLogListHead
))
205 LogEntry
= CONTAINING_RECORD (IopLogListHead
.Blink
,
208 RemoveEntryList (&LogEntry
->Entry
);
215 KeReleaseSpinLock (&IopLogListLock
,
218 if (LogEntry
== NULL
)
220 DPRINT ("No message in log list\n");
224 /* Get pointer to the log packet */
225 Packet
= (PIO_ERROR_LOG_PACKET
)((ULONG_PTR
)LogEntry
+ sizeof(ERROR_LOG_ENTRY
));
228 /* Get driver or device name */
229 ObjectNameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
230 Status
= ObQueryNameString (LogEntry
->IoObject
,
234 if (NT_SUCCESS(Status
))
236 DPRINT ("ReturnedLength: %lu\n", ReturnedLength
);
237 DPRINT ("Length: %hu\n", ObjectNameInfo
->Name
.Length
);
238 DPRINT ("MaximumLength: %hu\n", ObjectNameInfo
->Name
.MaximumLength
);
239 DPRINT ("Object: %wZ\n", &ObjectNameInfo
->Name
);
241 DriverName
= wcsrchr(ObjectNameInfo
->Name
.Buffer
, L
'\\');
242 if (DriverName
!= NULL
)
245 DriverName
= ObjectNameInfo
->Name
.Buffer
;
247 DriverNameLength
= wcslen (DriverName
) * sizeof(WCHAR
);
248 DPRINT ("Driver name '%S'\n", DriverName
);
253 DriverNameLength
= 0;
256 /* Allocate request buffer */
257 Request
= ExAllocatePool (NonPagedPool
,
258 sizeof(LPC_MAX_MESSAGE
));
261 DPRINT ("Failed to allocate request buffer!\n");
263 /* Requeue log message and restart the worker */
264 ExInterlockedInsertTailList (&IopLogListHead
,
267 IopRestartLogWorker ();
272 /* Initialize the log message */
273 Message
= (PIO_ERROR_LOG_MESSAGE
)Request
->Data
;
274 Message
->Type
= 0xC; //IO_TYPE_ERROR_MESSAGE;
276 sizeof(IO_ERROR_LOG_MESSAGE
) - sizeof(IO_ERROR_LOG_PACKET
) +
277 LogEntry
->PacketSize
+ DriverNameLength
;
278 Message
->DriverNameLength
= (USHORT
)DriverNameLength
;
279 Message
->TimeStamp
.QuadPart
= LogEntry
->TimeStamp
.QuadPart
;
280 Message
->DriverNameOffset
= (DriverName
!= NULL
) ? LogEntry
->PacketSize
: 0;
282 /* Copy error log packet */
283 RtlCopyMemory (&Message
->EntryData
,
285 LogEntry
->PacketSize
);
287 /* Copy driver or device name */
288 RtlCopyMemory ((PVOID
)((ULONG_PTR
)Message
+ Message
->DriverNameOffset
),
292 DPRINT ("SequenceNumber %lx\n", Packet
->SequenceNumber
);
294 Request
->Header
.DataSize
= Message
->Size
;
295 Request
->Header
.MessageSize
=
296 Request
->Header
.DataSize
+ sizeof(LPC_MESSAGE
);
298 /* Send the error message to the log port */
299 Status
= NtRequestPort (IopLogPort
,
302 /* Release request buffer */
303 ExFreePool (Request
);
305 if (!NT_SUCCESS(Status
))
307 DPRINT ("NtRequestPort() failed (Status %lx)\n", Status
);
309 /* Requeue log message and restart the worker */
310 ExInterlockedInsertTailList (&IopLogListHead
,
313 IopRestartLogWorker ();
318 /* Release error log entry */
319 KeAcquireSpinLock (&IopAllocationLock
,
322 IopTotalLogSize
-= LogEntry
->PacketSize
;
323 ExFreePool (LogEntry
);
325 KeReleaseSpinLock (&IopAllocationLock
,
329 IopLogWorkerRunning
= FALSE
;
331 DPRINT ("IopLogWorker() done\n");
339 IoAllocateErrorLogEntry (IN PVOID IoObject
,
342 PERROR_LOG_ENTRY LogEntry
;
346 DPRINT1 ("IoAllocateErrorLogEntry() called\n");
348 if (IoObject
== NULL
)
351 KeAcquireSpinLock (&IopAllocationLock
,
354 if (IopTotalLogSize
> PAGE_SIZE
)
356 KeReleaseSpinLock (&IopAllocationLock
,
361 LogEntrySize
= sizeof(ERROR_LOG_ENTRY
) + EntrySize
;
362 LogEntry
= ExAllocatePool (NonPagedPool
,
364 if (LogEntry
== NULL
)
366 KeReleaseSpinLock (&IopAllocationLock
,
371 IopTotalLogSize
+= EntrySize
;
373 LogEntry
->IoObject
= IoObject
;
374 LogEntry
->PacketSize
= LogEntrySize
;
376 KeReleaseSpinLock (&IopAllocationLock
,
379 return (PVOID
)((ULONG_PTR
)LogEntry
+ sizeof(ERROR_LOG_ENTRY
));
398 IoWriteErrorLogEntry (IN PVOID ElEntry
)
400 PWORK_QUEUE_ITEM LogWorkItem
;
401 PERROR_LOG_ENTRY LogEntry
;
404 DPRINT ("IoWriteErrorLogEntry() called\n");
406 LogEntry
= (PERROR_LOG_ENTRY
)((ULONG_PTR
)ElEntry
- sizeof(ERROR_LOG_ENTRY
));
409 KeQuerySystemTime (&LogEntry
->TimeStamp
);
411 KeAcquireSpinLock (&IopLogListLock
,
414 InsertHeadList (&IopLogListHead
,
417 if (IopLogWorkerRunning
== FALSE
)
419 LogWorkItem
= ExAllocatePool (NonPagedPool
,
420 sizeof(WORK_QUEUE_ITEM
));
421 if (LogWorkItem
!= NULL
)
423 ExInitializeWorkItem (LogWorkItem
,
427 ExQueueWorkItem (LogWorkItem
,
430 IopLogWorkerRunning
= TRUE
;
434 KeReleaseSpinLock (&IopLogListLock
,
437 DPRINT ("IoWriteErrorLogEntry() done\n");