549b57f65dbe560c3a2f8a212e5316deef46cb22
[openafs.git] / src / WINNT / afsrdr / kernel / fs / AFSLogSupport.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include "AFSCommon.h"
36
37 NTSTATUS
38 AFSDbgLogMsg( IN ULONG Subsystem,
39               IN ULONG Level,
40               IN PCCH Format,
41               ...)
42 {
43
44     NTSTATUS ntStatus = STATUS_SUCCESS;
45     va_list va_args;
46     ULONG ulBytesWritten = 0;
47     BOOLEAN bReleaseLock = FALSE;
48     char    *pCurrentTrace = NULL;
49
50     __Enter
51     {
52
53         if( AFSDbgBuffer == NULL)
54         {
55
56             try_return( ntStatus = STATUS_DEVICE_NOT_READY);
57         }
58
59         if( Subsystem > 0 &&
60             (Subsystem & AFSTraceComponent) == 0)
61         {
62
63             //
64             // Not tracing this subsystem
65             //
66
67             try_return( ntStatus);
68         }
69
70         if( Level > 0 &&
71             Level > AFSTraceLevel)
72         {
73
74             //
75             // Not tracing this level
76             //
77
78             try_return( ntStatus);
79         }
80
81         AFSAcquireExcl( &AFSDbgLogLock,
82                         TRUE);
83
84         bReleaseLock = TRUE;
85
86         //
87         // Check again under lock
88         //
89
90         if( AFSDbgBuffer == NULL)
91         {
92
93             try_return( ntStatus = STATUS_DEVICE_NOT_READY);
94         }
95
96         if( AFSDbgLogRemainingLength < 255)
97         {
98
99             AFSDbgLogRemainingLength = AFSDbgBufferLength;
100
101             AFSDbgCurrentBuffer = AFSDbgBuffer;
102
103             SetFlag( AFSDbgLogFlags, AFS_DBG_LOG_WRAPPED);
104         }
105
106         pCurrentTrace = AFSDbgCurrentBuffer;
107
108         RtlStringCchPrintfA( AFSDbgCurrentBuffer,
109                              10,
110                              "%08lX:",
111                              AFSDbgLogCounter++);
112
113         AFSDbgCurrentBuffer += 9;
114
115         AFSDbgLogRemainingLength -= 9;
116
117         va_start( va_args, Format);
118
119         ntStatus = RtlStringCbVPrintfA( AFSDbgCurrentBuffer,
120                                         AFSDbgLogRemainingLength,
121                                         Format,
122                                         va_args);
123
124         if( ntStatus == STATUS_BUFFER_OVERFLOW)
125         {
126
127             RtlZeroMemory( AFSDbgCurrentBuffer,
128                            AFSDbgLogRemainingLength);
129
130             AFSDbgLogRemainingLength = AFSDbgBufferLength;
131
132             AFSDbgCurrentBuffer = AFSDbgBuffer;
133
134             SetFlag( AFSDbgLogFlags, AFS_DBG_LOG_WRAPPED);
135
136             pCurrentTrace = AFSDbgCurrentBuffer;
137
138             RtlStringCchPrintfA( AFSDbgCurrentBuffer,
139                                  10,
140                                  "%08lX:",
141                                  AFSDbgLogCounter++);
142
143             AFSDbgCurrentBuffer += 9;
144
145             AFSDbgLogRemainingLength -= 9;
146
147             ntStatus = RtlStringCbVPrintfA( AFSDbgCurrentBuffer,
148                                             AFSDbgLogRemainingLength,
149                                             Format,
150                                             va_args);
151         }
152
153         if( NT_SUCCESS( ntStatus))
154         {
155
156             RtlStringCbLengthA( AFSDbgCurrentBuffer,
157                                 AFSDbgLogRemainingLength,
158                                 (size_t *)&ulBytesWritten);
159
160             AFSDbgCurrentBuffer += ulBytesWritten;
161
162             AFSDbgLogRemainingLength -= ulBytesWritten;
163         }
164
165         va_end( va_args);
166
167         if( BooleanFlagOn( AFSDebugFlags, AFS_DBG_TRACE_TO_DEBUGGER) &&
168             pCurrentTrace != NULL)
169         {
170
171             DbgPrint( pCurrentTrace);
172         }
173
174 try_exit:
175
176         if( bReleaseLock)
177         {
178
179             AFSReleaseResource( &AFSDbgLogLock);
180         }
181     }
182
183     return ntStatus;
184 }
185
186 NTSTATUS
187 AFSInitializeDbgLog()
188 {
189
190     NTSTATUS ntStatus = STATUS_INSUFFICIENT_RESOURCES;
191
192     AFSAcquireExcl( &AFSDbgLogLock,
193                     TRUE);
194
195     if( AFSDbgBufferLength > 0)
196     {
197
198         AFSDbgBuffer = (char *)AFSExAllocatePoolWithTag( NonPagedPool,
199                                                          AFSDbgBufferLength,
200                                                          AFS_GENERIC_MEMORY_19_TAG);
201
202         if( AFSDbgBuffer != NULL)
203         {
204
205             AFSDbgCurrentBuffer = AFSDbgBuffer;
206
207             AFSDbgLogRemainingLength = AFSDbgBufferLength;
208
209             ntStatus = STATUS_SUCCESS;
210         }
211     }
212
213     AFSReleaseResource( &AFSDbgLogLock);
214
215     if( NT_SUCCESS( ntStatus))
216     {
217         AFSTagInitialLogEntry();
218     }
219
220     return ntStatus;
221 }
222
223 NTSTATUS
224 AFSTearDownDbgLog()
225 {
226
227     NTSTATUS ntStatus = STATUS_SUCCESS;
228
229     AFSAcquireExcl( &AFSDbgLogLock,
230                     TRUE);
231
232     if( AFSDbgBuffer != NULL)
233     {
234
235         ExFreePool( AFSDbgBuffer);
236     }
237
238     AFSDbgBuffer = NULL;
239
240     AFSDbgCurrentBuffer = NULL;
241
242     AFSDbgLogRemainingLength = 0;
243
244     AFSReleaseResource( &AFSDbgLogLock);
245
246     return ntStatus;
247 }
248
249 NTSTATUS
250 AFSConfigureTrace( IN AFSTraceConfigCB *TraceInfo)
251 {
252
253     NTSTATUS ntStatus = STATUS_SUCCESS;
254     UNICODE_STRING uniString;
255
256     __Enter
257     {
258
259         AFSAcquireExcl( &AFSDbgLogLock,
260                         TRUE);
261
262         if( TraceInfo->TraceLevel == AFSTraceLevel &&
263             TraceInfo->TraceBufferLength == AFSDbgBufferLength &&
264             TraceInfo->Subsystem == AFSTraceComponent)
265         {
266
267             //
268             // Nothing to do
269             //
270
271             try_return( ntStatus);
272         }
273
274         //
275         // Go update the registry with the new entries
276         //
277
278         if( TraceInfo->TraceLevel != (ULONG)-1 &&
279             TraceInfo->TraceLevel != AFSTraceLevel)
280         {
281
282             AFSTraceLevel = TraceInfo->TraceLevel;
283
284             RtlInitUnicodeString( &uniString,
285                                   AFS_REG_TRACE_LEVEL);
286
287             ntStatus = AFSUpdateRegistryParameter( &uniString,
288                                                    REG_DWORD,
289                                                    &TraceInfo->TraceLevel,
290                                                    sizeof( ULONG));
291
292             if( !NT_SUCCESS( ntStatus))
293             {
294
295                 DbgPrint("AFSConfigureTrace Failed to set debug level in registry Status %08lX\n", ntStatus);
296             }
297         }
298
299         if( TraceInfo->Subsystem != (ULONG)-1 &&
300             TraceInfo->Subsystem != AFSTraceComponent)
301         {
302
303             AFSTraceComponent = TraceInfo->Subsystem;
304
305             RtlInitUnicodeString( &uniString,
306                                   AFS_REG_TRACE_SUBSYSTEM);
307
308             ntStatus = AFSUpdateRegistryParameter( &uniString,
309                                                    REG_DWORD,
310                                                    &TraceInfo->Subsystem,
311                                                    sizeof( ULONG));
312
313             if( !NT_SUCCESS( ntStatus))
314             {
315
316                 DbgPrint("AFSConfigureTrace Failed to set debug subsystem in registry Status %08lX\n", ntStatus);
317             }
318         }
319
320         if( TraceInfo->DebugFlags != (ULONG)-1 &&
321             TraceInfo->DebugFlags != AFSDebugFlags)
322         {
323
324             AFSDebugFlags = TraceInfo->DebugFlags;
325
326             RtlInitUnicodeString( &uniString,
327                                   AFS_REG_DEBUG_FLAGS);
328
329             ntStatus = AFSUpdateRegistryParameter( &uniString,
330                                                    REG_DWORD,
331                                                    &TraceInfo->DebugFlags,
332                                                    sizeof( ULONG));
333
334             if( !NT_SUCCESS( ntStatus))
335             {
336
337                 DbgPrint("AFSConfigureTrace Failed to set debug flags in registry Status %08lX\n", ntStatus);
338             }
339         }
340
341         if( TraceInfo->TraceBufferLength != (ULONG)-1 &&
342             TraceInfo->TraceBufferLength != AFSDbgBufferLength)
343         {
344
345             RtlInitUnicodeString( &uniString,
346                                   AFS_REG_TRACE_BUFFER_LENGTH);
347
348             ntStatus = AFSUpdateRegistryParameter( &uniString,
349                                                    REG_DWORD,
350                                                    &TraceInfo->TraceBufferLength,
351                                                    sizeof( ULONG));
352
353             if( !NT_SUCCESS( ntStatus))
354             {
355
356                 DbgPrint("AFSConfigureTrace Failed to set debug buffer length in registry Status %08lX\n", ntStatus);
357             }
358
359             AFSDbgBufferLength = TraceInfo->TraceBufferLength * 1024;
360
361             ClearFlag( AFSDbgLogFlags, AFS_DBG_LOG_WRAPPED);
362
363             if( AFSDbgBuffer != NULL)
364             {
365
366                 ExFreePool( AFSDbgBuffer);
367
368                 AFSDbgBuffer = NULL;
369
370                 AFSDbgCurrentBuffer = NULL;
371
372                 AFSDbgLogRemainingLength = 0;
373             }
374
375             if( AFSDbgBufferLength > 0)
376             {
377
378                 AFSDbgBuffer = (char *)AFSExAllocatePoolWithTag( NonPagedPool,
379                                                                  AFSDbgBufferLength,
380                                                                  AFS_GENERIC_MEMORY_20_TAG);
381
382                 if( AFSDbgBuffer == NULL)
383                 {
384
385                     AFSDbgBufferLength = 0;
386
387                     try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
388                 }
389
390                 AFSDbgCurrentBuffer = AFSDbgBuffer;
391
392                 AFSDbgLogRemainingLength = AFSDbgBufferLength;
393
394                 AFSTagInitialLogEntry();
395             }
396         }
397
398 try_exit:
399
400         AFSReleaseResource( &AFSDbgLogLock);
401     }
402
403     return ntStatus;
404 }
405
406 NTSTATUS
407 AFSGetTraceBuffer( IN ULONG TraceBufferLength,
408                    OUT void *TraceBuffer,
409                    OUT ULONG_PTR *CopiedLength)
410 {
411
412     NTSTATUS ntStatus = STATUS_SUCCESS;
413     ULONG ulCopyLength = 0;
414     char *pCurrentLocation = NULL;
415
416     __Enter
417     {
418
419         AFSAcquireShared( &AFSDbgLogLock,
420                           TRUE);
421
422         if( TraceBufferLength < AFSDbgBufferLength)
423         {
424
425             try_return( ntStatus = STATUS_INVALID_PARAMETER);
426         }
427
428         //
429         // If we have wrapped then copy in the remaining portion
430         //
431
432         pCurrentLocation = (char *)TraceBuffer;
433
434         *CopiedLength = 0;
435
436         if( BooleanFlagOn( AFSDbgLogFlags, AFS_DBG_LOG_WRAPPED))
437         {
438
439             ulCopyLength = AFSDbgLogRemainingLength;
440
441             RtlCopyMemory( pCurrentLocation,
442                            AFSDbgCurrentBuffer,
443                            ulCopyLength);
444
445             pCurrentLocation[ 0] = '0'; // The buffer is NULL terminated ...
446
447             pCurrentLocation += ulCopyLength;
448
449             *CopiedLength = ulCopyLength;
450         }
451
452         ulCopyLength = AFSDbgBufferLength - AFSDbgLogRemainingLength;
453
454         if( ulCopyLength > 0)
455         {
456
457             RtlCopyMemory( pCurrentLocation,
458                            AFSDbgBuffer,
459                            ulCopyLength);
460
461             *CopiedLength += ulCopyLength;
462         }
463
464 try_exit:
465
466         AFSReleaseResource( &AFSDbgLogLock);
467     }
468
469     return ntStatus;
470 }
471
472 void
473 AFSTagInitialLogEntry()
474 {
475
476     LARGE_INTEGER liTime, liLocalTime;
477     TIME_FIELDS timeFields;
478
479     KeQuerySystemTime( &liTime);
480
481     ExSystemTimeToLocalTime( &liTime,
482                              &liLocalTime);
483
484     RtlTimeToTimeFields( &liLocalTime,
485                          &timeFields);
486
487     AFSDbgLogMsg( 0,
488                   0,
489                   "AFS Log Initialized %d-%d-%d %d:%d Level %d Subsystems %08lX\n",
490                   timeFields.Month,
491                   timeFields.Day,
492                   timeFields.Year,
493                   timeFields.Hour,
494                   timeFields.Minute,
495                   AFSTraceLevel,
496                   AFSTraceComponent);
497
498     return;
499 }
500
501 void
502 AFSDumpTraceFiles()
503 {
504
505     NTSTATUS ntStatus = STATUS_SUCCESS;
506     HANDLE hDirectory = NULL;
507     OBJECT_ATTRIBUTES   stObjectAttribs;
508     IO_STATUS_BLOCK stIoStatus;
509     LARGE_INTEGER liTime, liLocalTime;
510     TIME_FIELDS timeFields;
511     ULONG ulBytesWritten = 0;
512     HANDLE hDumpFile = NULL;
513     ULONG ulBytesProcessed, ulCopyLength;
514     LARGE_INTEGER liOffset;
515     ULONG ulDumpLength = 0;
516     BOOLEAN bSetEvent = FALSE;
517
518     __Enter
519     {
520
521         AFSAcquireShared( &AFSDbgLogLock,
522                           TRUE);
523
524         ulDumpLength = AFSDbgBufferLength - AFSDbgLogRemainingLength;
525
526         AFSReleaseResource( &AFSDbgLogLock);
527
528         if( AFSDumpFileLocation.Length == 0 ||
529             AFSDumpFileLocation.Buffer == NULL ||
530             AFSDbgBufferLength == 0 ||
531             ulDumpLength == 0 ||
532             AFSDumpFileName.MaximumLength == 0 ||
533             AFSDumpFileName.Buffer == NULL ||
534             AFSDumpBuffer == NULL)
535         {
536             try_return( ntStatus);
537         }
538
539         //
540         // Go open the cache file
541         //
542
543         InitializeObjectAttributes( &stObjectAttribs,
544                                     &AFSDumpFileLocation,
545                                     OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
546                                     NULL,
547                                     NULL);
548
549         ntStatus = ZwCreateFile( &hDirectory,
550                                  GENERIC_READ | GENERIC_WRITE,
551                                  &stObjectAttribs,
552                                  &stIoStatus,
553                                  NULL,
554                                  0,
555                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
556                                  FILE_OPEN,
557                                  FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
558                                  NULL,
559                                  0);
560
561         if( !NT_SUCCESS( ntStatus))
562         {
563
564             try_return( ntStatus);
565         }
566
567         ntStatus = KeWaitForSingleObject( &AFSDumpFileEvent,
568                                           Executive,
569                                           KernelMode,
570                                           FALSE,
571                                           NULL);
572
573         if( !NT_SUCCESS( ntStatus))
574         {
575
576             try_return( ntStatus);
577         }
578
579         bSetEvent = TRUE;
580
581         AFSDumpFileName.Length = 0;
582
583         RtlZeroMemory( AFSDumpFileName.Buffer,
584                        AFSDumpFileName.MaximumLength);
585
586         KeQuerySystemTime( &liTime);
587
588         ExSystemTimeToLocalTime( &liTime,
589                                  &liLocalTime);
590
591         RtlTimeToTimeFields( &liLocalTime,
592                              &timeFields);
593
594         ntStatus = RtlStringCchPrintfW( AFSDumpFileName.Buffer,
595                                         AFSDumpFileName.MaximumLength/sizeof( WCHAR),
596                                         L"AFSDumpFile %d.%d.%d %d.%d.%d.log",
597                                                   timeFields.Month,
598                                                   timeFields.Day,
599                                                   timeFields.Year,
600                                                   timeFields.Hour,
601                                                   timeFields.Minute,
602                                                   timeFields.Second);
603
604         if( !NT_SUCCESS( ntStatus))
605         {
606             try_return( ntStatus);
607         }
608
609         RtlStringCbLengthW( AFSDumpFileName.Buffer,
610                             AFSDumpFileName.MaximumLength,
611                             (size_t *)&ulBytesWritten);
612
613         AFSDumpFileName.Length = (USHORT)ulBytesWritten;
614
615         InitializeObjectAttributes( &stObjectAttribs,
616                                     &AFSDumpFileName,
617                                     OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
618                                     hDirectory,
619                                     NULL);
620
621         ntStatus = ZwCreateFile( &hDumpFile,
622                                  GENERIC_READ | GENERIC_WRITE,
623                                  &stObjectAttribs,
624                                  &stIoStatus,
625                                  NULL,
626                                  0,
627                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
628                                  FILE_CREATE,
629                                  FILE_SYNCHRONOUS_IO_NONALERT,
630                                  NULL,
631                                  0);
632
633         if( !NT_SUCCESS( ntStatus))
634         {
635             try_return( ntStatus);
636         }
637
638         //
639         // Write out the trace buffer
640         //
641
642         liOffset.QuadPart = 0;
643
644         ulBytesProcessed = 0;
645
646         while( ulBytesProcessed < ulDumpLength)
647         {
648
649             ulCopyLength = AFSDumpBufferLength;
650
651             if( ulCopyLength > ulDumpLength - ulBytesProcessed)
652             {
653                 ulCopyLength = ulDumpLength - ulBytesProcessed;
654             }
655
656             RtlCopyMemory( AFSDumpBuffer,
657                            (void *)((char *)AFSDbgBuffer + ulBytesProcessed),
658                            ulCopyLength);
659
660             ntStatus = ZwWriteFile( hDumpFile,
661                                     NULL,
662                                     NULL,
663                                     NULL,
664                                     &stIoStatus,
665                                     AFSDumpBuffer,
666                                     ulCopyLength,
667                                     &liOffset,
668                                     NULL);
669
670             if( !NT_SUCCESS( ntStatus))
671             {
672                 break;
673             }
674
675             liOffset.QuadPart += ulCopyLength;
676
677             ulBytesProcessed += ulCopyLength;
678         }
679
680 try_exit:
681
682         if( hDumpFile != NULL)
683         {
684             ZwClose( hDumpFile);
685         }
686
687         if( hDirectory != NULL)
688         {
689             ZwClose( hDirectory);
690         }
691
692         if( bSetEvent)
693         {
694             KeSetEvent( &AFSDumpFileEvent,
695                         0,
696                         FALSE);
697         }
698     }
699
700     return;
701 }
702
703 NTSTATUS
704 AFSInitializeDumpFile()
705 {
706
707     NTSTATUS ntStatus = STATUS_SUCCESS;
708
709     __Enter
710     {
711
712         KeInitializeEvent( &AFSDumpFileEvent,
713                            SynchronizationEvent,
714                            TRUE);
715
716         AFSDumpFileName.Length = 0;
717         AFSDumpFileName.Buffer = NULL;
718         AFSDumpFileName.MaximumLength = PAGE_SIZE;
719
720         AFSDumpFileName.Buffer = (WCHAR *)ExAllocatePoolWithTag( PagedPool,
721                                                                  AFSDumpFileName.MaximumLength,
722                                                                  AFS_GENERIC_MEMORY_28_TAG);
723
724         if( AFSDumpFileName.Buffer == NULL)
725         {
726             AFSDumpFileName.MaximumLength = 0;
727
728             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
729         }
730
731         AFSDumpBufferLength = 64 * 1024;
732
733         AFSDumpBuffer = ExAllocatePoolWithTag( PagedPool,
734                                                AFSDumpBufferLength,
735                                                AFS_GENERIC_MEMORY_28_TAG);
736
737         if( AFSDumpBuffer == NULL)
738         {
739
740             ExFreePool( AFSDumpFileName.Buffer);
741
742             AFSDumpFileName.Buffer = NULL;
743             AFSDumpFileName.MaximumLength = 0;
744
745             AFSDumpBufferLength = 0;
746
747             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
748         }
749
750 try_exit:
751
752         NOTHING;
753     }
754
755     return ntStatus;
756 }