3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/errlog.c
6 * PURPOSE: Error logging
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* TYPES *********************************************************************/
19 typedef struct _ERROR_LOG_ENTRY
22 LARGE_INTEGER TimeStamp
;
25 } ERROR_LOG_ENTRY
, *PERROR_LOG_ENTRY
;
27 typedef struct _LOG_WORKER_DPC
31 } LOG_WORKER_DPC
, *PLOG_WORKER_DPC
;
35 IopLogWorker (PVOID Parameter
);
38 /* GLOBALS *******************************************************************/
40 static KSPIN_LOCK IopAllocationLock
;
41 static ULONG IopTotalLogSize
;
43 static KSPIN_LOCK IopLogListLock
;
44 static LIST_ENTRY IopLogListHead
;
46 static BOOLEAN IopLogWorkerRunning
= FALSE
;
47 static BOOLEAN IopLogPortConnected
= FALSE
;
48 static HANDLE IopLogPort
;
51 /* FUNCTIONS *****************************************************************/
54 IopInitErrorLog (VOID
)
57 KeInitializeSpinLock (&IopAllocationLock
);
59 KeInitializeSpinLock (&IopLogListLock
);
60 InitializeListHead (&IopLogListHead
);
62 return STATUS_SUCCESS
;
67 IopLogDpcRoutine (PKDPC Dpc
,
68 PVOID DeferredContext
,
69 PVOID SystemArgument1
,
70 PVOID SystemArgument2
)
72 PWORK_QUEUE_ITEM LogWorkItem
;
74 DPRINT ("\nIopLogDpcRoutine() called\n");
76 /* Release the WorkerDpc struct */
77 ExFreePool (DeferredContext
);
79 /* Allocate, initialize and restart a work item */
80 LogWorkItem
= ExAllocatePool (NonPagedPool
,
81 sizeof(WORK_QUEUE_ITEM
));
82 if (LogWorkItem
== NULL
)
84 IopLogWorkerRunning
= FALSE
;
88 ExInitializeWorkItem (LogWorkItem
,
92 ExQueueWorkItem (LogWorkItem
,
98 IopRestartLogWorker (VOID
)
100 PLOG_WORKER_DPC WorkerDpc
;
101 LARGE_INTEGER Timeout
;
103 DPRINT ("IopRestartWorker() called\n");
105 WorkerDpc
= ExAllocatePool (NonPagedPool
,
106 sizeof(LOG_WORKER_DPC
));
107 if (WorkerDpc
== NULL
)
109 IopLogWorkerRunning
= FALSE
;
113 /* Initialize DPC and Timer */
114 KeInitializeDpc (&WorkerDpc
->Dpc
,
117 KeInitializeTimer (&WorkerDpc
->Timer
);
119 /* Restart after 30 seconds */
120 Timeout
.QuadPart
= (LONGLONG
)-300000000;
121 KeSetTimer (&WorkerDpc
->Timer
,
128 IopConnectLogPort (VOID
)
130 UNICODE_STRING PortName
;
133 DPRINT ("IopConnectLogPort() called\n");
135 RtlInitUnicodeString (&PortName
,
138 Status
= ZwConnectPort (&IopLogPort
,
146 if (!NT_SUCCESS(Status
))
148 DPRINT ("ZwConnectPort() failed (Status %lx)\n", Status
);
152 DPRINT ("IopConnectLogPort() done\n");
159 IopLogWorker (PVOID Parameter
)
161 PERROR_LOG_ENTRY LogEntry
;
162 PPORT_MESSAGE Request
;
163 PIO_ERROR_LOG_MESSAGE Message
;
164 PIO_ERROR_LOG_PACKET Packet
;
169 POBJECT_NAME_INFORMATION ObjectNameInfo
;
170 ULONG ReturnedLength
;
172 ULONG DriverNameLength
;
174 DPRINT ("IopLogWorker() called\n");
176 /* Release the work item */
177 ExFreePool (Parameter
);
179 /* Connect to the error log port */
180 if (IopLogPortConnected
== FALSE
)
182 if (IopConnectLogPort () == FALSE
)
184 IopRestartLogWorker ();
188 IopLogPortConnected
= TRUE
;
193 /* Remove last entry from the list */
194 KeAcquireSpinLock (&IopLogListLock
,
197 if (!IsListEmpty (&IopLogListHead
))
199 LogEntry
= CONTAINING_RECORD (IopLogListHead
.Blink
,
202 RemoveEntryList (&LogEntry
->Entry
);
209 KeReleaseSpinLock (&IopLogListLock
,
212 if (LogEntry
== NULL
)
214 DPRINT ("No message in log list\n");
218 /* Get pointer to the log packet */
219 Packet
= (PIO_ERROR_LOG_PACKET
)((ULONG_PTR
)LogEntry
+ sizeof(ERROR_LOG_ENTRY
));
222 /* Get driver or device name */
223 ObjectNameInfo
= (POBJECT_NAME_INFORMATION
)Buffer
;
224 Status
= ObQueryNameString (LogEntry
->IoObject
,
228 if (NT_SUCCESS(Status
))
230 DPRINT ("ReturnedLength: %lu\n", ReturnedLength
);
231 DPRINT ("Length: %hu\n", ObjectNameInfo
->Name
.Length
);
232 DPRINT ("MaximumLength: %hu\n", ObjectNameInfo
->Name
.MaximumLength
);
233 DPRINT ("Object: %wZ\n", &ObjectNameInfo
->Name
);
235 DriverName
= wcsrchr(ObjectNameInfo
->Name
.Buffer
, L
'\\');
236 if (DriverName
!= NULL
)
239 DriverName
= ObjectNameInfo
->Name
.Buffer
;
241 DriverNameLength
= wcslen (DriverName
) * sizeof(WCHAR
);
242 DPRINT ("Driver name '%S'\n", DriverName
);
247 DriverNameLength
= 0;
250 /* Allocate request buffer */
251 Request
= ExAllocatePool (NonPagedPool
,
252 sizeof(PORT_MESSAGE
) + PORT_MAXIMUM_MESSAGE_LENGTH
);
255 DPRINT ("Failed to allocate request buffer!\n");
257 /* Requeue log message and restart the worker */
258 ExInterlockedInsertTailList (&IopLogListHead
,
261 IopRestartLogWorker ();
266 /* Initialize the log message */
267 Message
= (PIO_ERROR_LOG_MESSAGE
)(Request
+ 1);
268 Message
->Type
= IO_TYPE_ERROR_MESSAGE
;
270 sizeof(IO_ERROR_LOG_MESSAGE
) - sizeof(IO_ERROR_LOG_PACKET
) +
271 LogEntry
->PacketSize
+ DriverNameLength
;
272 Message
->DriverNameLength
= (USHORT
)DriverNameLength
;
273 Message
->TimeStamp
.QuadPart
= LogEntry
->TimeStamp
.QuadPart
;
274 Message
->DriverNameOffset
= (DriverName
!= NULL
) ? LogEntry
->PacketSize
: 0;
276 /* Copy error log packet */
277 RtlCopyMemory (&Message
->EntryData
,
279 LogEntry
->PacketSize
);
281 /* Copy driver or device name */
282 RtlCopyMemory ((PVOID
)((ULONG_PTR
)Message
+ Message
->DriverNameOffset
),
286 DPRINT ("SequenceNumber %lx\n", Packet
->SequenceNumber
);
288 Request
->u1
.s1
.DataLength
= Message
->Size
;
289 Request
->u1
.s1
.TotalLength
=
290 Request
->u1
.s1
.DataLength
+ sizeof(PPORT_MESSAGE
);
292 /* Send the error message to the log port */
293 Status
= ZwRequestPort (IopLogPort
,
296 /* Release request buffer */
297 ExFreePool (Request
);
299 if (!NT_SUCCESS(Status
))
301 DPRINT ("ZwRequestPort() failed (Status %lx)\n", Status
);
303 /* Requeue log message and restart the worker */
304 ExInterlockedInsertTailList (&IopLogListHead
,
307 IopRestartLogWorker ();
312 /* Release error log entry */
313 KeAcquireSpinLock (&IopAllocationLock
,
316 IopTotalLogSize
-= (LogEntry
->PacketSize
- sizeof(ERROR_LOG_ENTRY
));
317 ExFreePool (LogEntry
);
319 KeReleaseSpinLock (&IopAllocationLock
,
323 IopLogWorkerRunning
= FALSE
;
325 DPRINT ("IopLogWorker() done\n");
333 IoAllocateErrorLogEntry (IN PVOID IoObject
,
336 PERROR_LOG_ENTRY LogEntry
;
340 DPRINT("IoAllocateErrorLogEntry() called\n");
342 if (IoObject
== NULL
)
345 KeAcquireSpinLock (&IopAllocationLock
,
348 if (IopTotalLogSize
> PAGE_SIZE
)
350 KeReleaseSpinLock (&IopAllocationLock
,
355 LogEntrySize
= sizeof(ERROR_LOG_ENTRY
) + EntrySize
;
356 LogEntry
= ExAllocatePool (NonPagedPool
,
358 if (LogEntry
== NULL
)
360 KeReleaseSpinLock (&IopAllocationLock
,
365 IopTotalLogSize
+= EntrySize
;
367 LogEntry
->IoObject
= IoObject
;
368 LogEntry
->PacketSize
= LogEntrySize
;
370 KeReleaseSpinLock (&IopAllocationLock
,
373 return (PVOID
)((ULONG_PTR
)LogEntry
+ sizeof(ERROR_LOG_ENTRY
));
381 IoFreeErrorLogEntry(IN PVOID ElEntry
)
383 PERROR_LOG_ENTRY LogEntry
;
386 DPRINT("IoFreeErrorLogEntry() called\n");
391 LogEntry
= (PERROR_LOG_ENTRY
)((ULONG_PTR
)ElEntry
- sizeof(ERROR_LOG_ENTRY
));
393 KeAcquireSpinLock(&IopAllocationLock
,
396 IopTotalLogSize
-= (LogEntry
->PacketSize
- sizeof(ERROR_LOG_ENTRY
));
397 ExFreePool(LogEntry
);
399 KeReleaseSpinLock(&IopAllocationLock
,
408 IoWriteErrorLogEntry (IN PVOID ElEntry
)
410 PWORK_QUEUE_ITEM LogWorkItem
;
411 PERROR_LOG_ENTRY LogEntry
;
414 DPRINT("IoWriteErrorLogEntry() called\n");
416 LogEntry
= (PERROR_LOG_ENTRY
)((ULONG_PTR
)ElEntry
- sizeof(ERROR_LOG_ENTRY
));
419 KeQuerySystemTime (&LogEntry
->TimeStamp
);
421 KeAcquireSpinLock (&IopLogListLock
,
424 InsertHeadList (&IopLogListHead
,
427 if (IopLogWorkerRunning
== FALSE
)
429 LogWorkItem
= ExAllocatePool (NonPagedPool
,
430 sizeof(WORK_QUEUE_ITEM
));
431 if (LogWorkItem
!= NULL
)
433 ExInitializeWorkItem (LogWorkItem
,
437 ExQueueWorkItem (LogWorkItem
,
440 IopLogWorkerRunning
= TRUE
;
444 KeReleaseSpinLock (&IopLogListLock
,
447 DPRINT("IoWriteErrorLogEntry() done\n");
452 IopFreeApc(PKAPC Apc
,
453 PKNORMAL_ROUTINE
*NormalRoutine
,
454 PVOID
*NormalContext
,
455 PVOID
*SystemArgument1
,
456 PVOID
*SystemArgument2
)
464 IopRaiseHardError(PKAPC Apc
,
465 PKNORMAL_ROUTINE
*NormalRoutine
,
466 PVOID
*NormalContext
,
467 PVOID
*SystemArgument1
,
468 PVOID
*SystemArgument2
)
470 PIRP Irp
= (PIRP
)NormalContext
;
471 //PVPB Vpb = (PVPB)SystemArgument1;
472 //PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)SystemArgument2;
474 /* FIXME: UNIMPLEMENTED */
475 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
476 Irp
->IoStatus
.Information
= 0;
477 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
485 IoRaiseHardError(PIRP Irp
,
487 PDEVICE_OBJECT RealDeviceObject
)
489 PETHREAD Thread
= (PETHREAD
)&Irp
->Tail
.Overlay
.Thread
;
492 /* Don't do anything if hard errors are disabled on the thread */
493 if (Thread
->HardErrorsAreDisabled
)
495 /* Complete the request */
496 Irp
->IoStatus
.Information
= 0;
497 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
502 ErrorApc
= ExAllocatePoolWithTag(NonPagedPool
,
504 TAG('K', 'A', 'P', 'C'));
505 KeInitializeApc(ErrorApc
,
509 (PKRUNDOWN_ROUTINE
)IopFreeApc
,
510 (PKNORMAL_ROUTINE
)IopRaiseHardError
,
514 /* Queue an APC to deal with the error (see osr documentation) */
515 KeInsertQueueApc(ErrorApc
, Vpb
, RealDeviceObject
, 0);
523 IoRaiseInformationalHardError(NTSTATUS ErrorStatus
,
524 PUNICODE_STRING String
,
531 /**********************************************************************
533 * IoSetThreadHardErrorMode@4
537 * TRUE : enable hard errors processing;
538 * FALSE: do NOT process hard errors.
541 * Previous value for the current thread's hard errors
548 IoSetThreadHardErrorMode(IN BOOLEAN HardErrorEnabled
)
550 BOOLEAN PreviousHEM
= (BOOLEAN
)(NtCurrentTeb()->HardErrorDisabled
);
552 NtCurrentTeb()->HardErrorDisabled
= ((TRUE
== HardErrorEnabled
) ? FALSE
: TRUE
);
554 return((TRUE
== PreviousHEM
) ? FALSE
: TRUE
);