/*++ Copyright (c) 1989 Microsoft Corporation Module Name: rxdebug.c Abstract: This module implements functions supporting read/write tracking for help in tracking down data corruption problems. Currently it is only implemented for files that are created of drive letter X:. For each file that is created there are three additional bitmaps are created. The first one marks the ranges of fileoffset, length for which write were submitted to rdbss. The second bitmap marks the ranges of the file for which write requests were passed onto the mini redirector (initiation of Lowio). The third bitmap marks the ranges for which the I/O was successfully completed. Each bit map kas 8k bits long enough to accomodate files upto ( 8K * PAGE_SIZE) bytes. The FCB contains a pointer to this data structure. The data structure is independent of FCB's and a new one is created everytime a new FCB instance is created. Author: Balan Sethu Raman -- --*/ #include "precomp.h" #pragma hdrstop #include #include #ifdef RDBSSLOG #include #endif VOID RxInitializeDebugSupport() { #ifdef RX_WJ_DBG_SUPPORT RxdInitializeWriteJournalSupport(); #endif } VOID RxTearDownDebugSupport() { #ifdef RX_WJ_DBG_SUPPORT RxdTearDownWriteJournalSupport(); #endif } #ifdef RX_WJ_DBG_SUPPORT #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, RxdInitializeWriteJournalSupport) #pragma alloc_text(PAGE, RxdTearDownWriteJournalSupport) #pragma alloc_text(PAGE, RxdInitializeFcbWriteJournalDebugSupport) #pragma alloc_text(PAGE, RxdTearDownFcbWriteJournalDebugSupport) #pragma alloc_text(PAGE, RxdUpdateJournalOnWriteInitiation) #pragma alloc_text(PAGE, RxdUpdateJournalOnLowIoWriteInitiation) #pragma alloc_text(PAGE, RxdUpdateJournalOnLowIoWriteCompletion) #pragma alloc_text(PAGE, RxdFindWriteJournal) #pragma alloc_text(PAGE, UpdateBitmap) #endif LIST_ENTRY OldWriteJournals; LIST_ENTRY ActiveWriteJournals; ERESOURCE WriteJournalsResource; extern VOID UpdateBitmap( PBYTE pBitmap, LARGE_INTEGER Offset, ULONG Length); extern PFCB_WRITE_JOURNAL RxdFindWriteJournal( PFCB pFcb); VOID RxdInitializeWriteJournalSupport() { PAGED_CODE(); InitializeListHead(&ActiveWriteJournals); InitializeListHead(&OldWriteJournals); ExInitializeResource(&WriteJournalsResource); } VOID RxdTearDownWriteJournalSupport() { PLIST_ENTRY pJournalEntry; PFCB_WRITE_JOURNAL pJournal; PAGED_CODE(); ExAcquireResourceExclusive(&WriteJournalsResource,TRUE); while (ActiveWriteJournals.Flink != &ActiveWriteJournals) { pJournalEntry = RemoveHeadList(&ActiveWriteJournals); pJournal = (PFCB_WRITE_JOURNAL) CONTAINING_RECORD( pJournalEntry, FCB_WRITE_JOURNAL, JournalsList); RxFreePool(pJournal); } while (OldWriteJournals.Flink != &OldWriteJournals) { pJournalEntry = RemoveHeadList(&OldWriteJournals); pJournal = (PFCB_WRITE_JOURNAL) CONTAINING_RECORD( pJournalEntry, FCB_WRITE_JOURNAL, JournalsList); RxFreePool(pJournal); } ExReleaseResource(&WriteJournalsResource); ExDeleteResource(&WriteJournalsResource); } VOID RxdInitializeFcbWriteJournalDebugSupport( PFCB pFcb) { PFCB_WRITE_JOURNAL pJournal; PAGED_CODE(); if (pFcb->pNetRoot->DeviceType == RxDeviceType(DISK)) { pJournal = RxAllocatePoolWithTag( PagedPool | POOL_COLD_ALLOCATION, sizeof(FCB_WRITE_JOURNAL), RX_MISC_POOLTAG); if (pJournal != NULL) { ULONG PathLength; RtlZeroMemory( pJournal, sizeof(FCB_WRITE_JOURNAL)); pJournal->pName = &pJournal->Path[0]; if (pFcb->AlreadyPrefixedName.Length > (MAX_PATH * sizeof(WCHAR))) { PathLength = MAX_PATH * sizeof(WCHAR); } else { PathLength = pFcb->AlreadyPrefixedName.Length; } RtlCopyMemory( pJournal->pName, pFcb->AlreadyPrefixedName.Buffer, PathLength); pJournal->pFcb = pFcb; pJournal->pWriteInitiationBitmap = pJournal->WriteInitiationBitmap; pJournal->pLowIoWriteInitiationBitmap = pJournal->LowIoWriteInitiationBitmap; pJournal->pLowIoWriteCompletionBitmap = pJournal->LowIoWriteCompletionBitmap; ExAcquireResourceExclusive(&WriteJournalsResource,TRUE); InsertHeadList( &ActiveWriteJournals, &pJournal->JournalsList); ExReleaseResource(&WriteJournalsResource); } } } VOID RxdTearDownFcbWriteJournalDebugSupport( PFCB pFcb) { PAGED_CODE(); if (pFcb->pNetRoot->DeviceType == RxDeviceType(DISK)) { PFCB_WRITE_JOURNAL pJournal; PLIST_ENTRY pJournalEntry; ExAcquireResourceExclusive(&WriteJournalsResource,TRUE); pJournal = RxdFindWriteJournal(pFcb); if (pJournal != NULL) { RemoveEntryList(&pJournal->JournalsList); // InsertHeadList( // &OldWriteJournals, // &pJournal->JournalsList); RxFreePool(pJournal); } ExReleaseResource(&WriteJournalsResource); } } VOID RxdUpdateJournalOnWriteInitiation( IN OUT PFCB pFcb, IN LARGE_INTEGER Offset, IN ULONG Length) { PAGED_CODE(); if (pFcb->pNetRoot->DeviceType == RxDeviceType(DISK)) { PFCB_WRITE_JOURNAL pJournal; PLIST_ENTRY pJournalEntry; ExAcquireResourceExclusive(&WriteJournalsResource, TRUE); pJournal = RxdFindWriteJournal(pFcb); if (pJournal != NULL) { UpdateBitmap( pJournal->WriteInitiationBitmap, Offset, Length); pJournal->WritesInitiated++; } ExReleaseResource(&WriteJournalsResource); } } VOID RxdUpdateJournalOnLowIoWriteInitiation( IN OUT PFCB pFcb, IN LARGE_INTEGER Offset, IN ULONG Length) { PAGED_CODE(); if (pFcb->pNetRoot->DeviceType == RxDeviceType(DISK)) { PFCB_WRITE_JOURNAL pJournal; PLIST_ENTRY pJournalEntry; ExAcquireResourceExclusive(&WriteJournalsResource, TRUE); pJournal = RxdFindWriteJournal(pFcb); if (pJournal != NULL) { UpdateBitmap( pJournal->LowIoWriteInitiationBitmap, Offset, Length); pJournal->LowIoWritesInitiated++; } ExReleaseResource(&WriteJournalsResource); } } VOID RxdUpdateJournalOnLowIoWriteCompletion( IN OUT PFCB pFcb, IN LARGE_INTEGER Offset, IN ULONG Length) { PAGED_CODE(); if (pFcb->pNetRoot->DeviceType == RxDeviceType(DISK)) { PFCB_WRITE_JOURNAL pJournal; PLIST_ENTRY pJournalEntry; ExAcquireResourceExclusive(&WriteJournalsResource, TRUE); pJournal = RxdFindWriteJournal(pFcb); if (pJournal != NULL) { UpdateBitmap( pJournal->LowIoWriteCompletionBitmap, Offset, Length); pJournal->LowIoWritesCompleted++; } ExReleaseResource(&WriteJournalsResource); } } PFCB_WRITE_JOURNAL RxdFindWriteJournal( PFCB pFcb) { PFCB_WRITE_JOURNAL pJournal; PLIST_ENTRY pJournalEntry; PAGED_CODE(); pJournalEntry = ActiveWriteJournals.Flink; while (pJournalEntry != &ActiveWriteJournals) { pJournal = (PFCB_WRITE_JOURNAL) CONTAINING_RECORD( pJournalEntry, FCB_WRITE_JOURNAL, JournalsList); if (pJournal->pFcb == pFcb) { break; } else { pJournalEntry = pJournalEntry->Flink; } } if (pJournalEntry == &ActiveWriteJournals) { pJournal = NULL; } return pJournal; } CHAR PageMask[8] = { 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff}; VOID UpdateBitmap( PBYTE pBitmap, LARGE_INTEGER Offset, ULONG Length) { LONG OffsetIn4kChunks; LONG OffsetIn32kChunks; LONG NumberOf4kChunks,Starting4kChunk; PAGED_CODE(); // Each byte in the bit map represents a 32k region since each bit represents // a 4k region in the file. // we ignore the offset's high part for now because the bitmap's max size is // far less than what can be accomodated in the low part. OffsetIn4kChunks = Offset.LowPart / (0x1000); OffsetIn32kChunks = Offset.LowPart / (0x8000); Starting4kChunk = ((Offset.LowPart & ~0xfff) - (Offset.LowPart & ~0x7fff)) / 0x1000; NumberOf4kChunks = Length / 0x1000; if (NumberOf4kChunks > (8 - Starting4kChunk)) { pBitmap[OffsetIn32kChunks++] |= (PageMask[7] & ~PageMask[Starting4kChunk]); Length -= (8 - Starting4kChunk) * 0x1000; } if (Length > 0x8000) { while (Length > (0x8000)) { pBitmap[OffsetIn32kChunks++] = PageMask[7]; Length -= (0x8000); } Starting4kChunk = 0; } // The final chunk is less then 32k. The byte in the bitmao needs to be // updated accordingly. if (Length > 0) { NumberOf4kChunks = Length / (0x1000); pBitmap[OffsetIn32kChunks] |= PageMask[NumberOf4kChunks + Starting4kChunk]; } } #endif