/* * PROJECT: Alcyone System Kernel * LICENSE: BSD Clause 3 * PURPOSE: Cache Controller:: Pin Support * NT KERNEL: 5.11.9360 * COPYRIGHT: 2023-2029 Dibymartanda Samanta <> */ #include #define NTDEBUG #include #include "ccinternal.hpp" extern "C" /* Move Typedef later to cctypes in sdk */ /* NOTE: This structure have reconstructed analyzing CcAllocateObcb, might be icomplete to one in Windows NT Kernel*/ /* We just need API Compatibility, so it doesn't matter */ typedef struct _OBCB { short NodeTypeCode; short NodeByteSize; ULONG ByteLength; LARGE_INTEGER FileOffset; struct PCC_BCB Bcbs[1]; long __PADDING__[1]; } OBCB, *POBCB; /*Internal Function*/ POBCB NTAPI CcAllocateObcb( _In_ PLARGE_INTEGER FileOffset, _In_ ULONG Length, _In_ PCC_BCB Bcb) { /*Calculate the size needed for the OBCB*/ SIZE_T AllocationSize = sizeof(OBCB) + ((Length + PAGE_SIZE - 1 + FileOffset->LowPart - *reinterpret_cast(reinterpret_cast(FirstBcb) & ~1UL) - *reinterpret_cast((reinterpret_cast(FirstBcb) & ~1UL) + sizeof(ULONG))) >> PAGE_SHIFT) * sizeof(PVOID); /*Allocate memory for the OBCB*/ POBCB NewObcb = reinterpret_cast(ExAllocatePoolWithTag(NonPagedPool,AllocationSize,'cObC')); if (NewObcb == nullptr) { return nullptr; } /* Initialize the OBCB */ RtlZeroMemory(NewObcb, AllocationSize); NewObcb->NodeByteSize = static_cast(AllocationSize); NewObcb->NodeTypeCode = 762; NewObcb->ByteLength = Length; NewObcb->FileOffset = *FileOffset; NewObcb->Bcbs[0] = Bcb; return NewObcb; } VOID VECTORCALL CcMapDataForOverwrite( PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, PVOID *Bcb, PVOID *Buffer) { NTSTATUS status = STATUS_SUCCESS; PETHREAD currentThread = nullptr; PSHARED_CACHE_MAP sharedCacheMap = nullptr; ULONG pageCount = {0}; PVOID outBcb = nullptr; PVOID localBuffer = nullptr; ULONG savedState = {0}; ULONG readClusterSize = {0}; pageCount = (Length >> PAGE_SHIFT) + (((FileOffset->LowPart & PAGE_OFFSET) + 4095 + (Length & PAGE_OFFSET)) >> PAGE_SHIFT); currentThread = (PETHREAD)KeGetCurrentThread(); sharedCacheMap = (PSHARED_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap; if ((sharedCacheMap->Flags & 0x20000) == 0) { SpinLockGuard lockGuard(LockQueueMasterLock); sharedCacheMap->Flags |= 0x20000; } savedState = currentThread->CacheManagerActive + 2 * currentThread->ReadClusterSize; readClusterSize = currentThread->ReadClusterSize; CcMapDataCommon(FileObject, FileOffset, Length, TRUE, &outBcb, &localBuffer); auto SystemCacheAddress = *localBuffer; ULONG remainingPages = pageCount; while (remainingPages) { currentThread->CacheManagerActive = 1; if (--remainingPages > readClusterSize) { currentThread->ReadClusterSize = (remainingPages > 0xF) ? 15 : remainingPages; } if (!MmCheckCachedPageState(SystemCacheAddress,true)) { MmCheckCachedPageState(SystemCacheAddress,false); } SystemCacheAddress += 4096; } currentThread->CacheManagerActive = savedState & 1; currentThread->ReadClusterSize = savedState >> 1; *Bcb = outBcb; *Buffer = localBuffer; } VOID NTAPI CcSetDirtyPinnedData( IN PBCB BcbVoid, IN PLARGE_INTEGER Lsn OPTIONAL) { PSHARED_CACHE_MAP SharedCacheMap; PBCB Bcb; PBCB* BcbArray; PFAST_MUTEX Mutex; KIRQL OldIrql; ULONG PagesToWrite; PETHREAD CurrentThread; if (BcbVoid->NodeTypeCode == 762) { BcbArray = (ULONG_PTR)BcbVoid-Bcbs; } SharedCacheMap = (*BcbArray)->SharedCacheMap; /* Handle logging if necessary */ auto VolumeLogHandleContext = &SharedCacheMap->VolumeCacheMap->LogHandleContext; if ( (SharedCacheMap->Flags & 0x1000000) != 0 && LogHandleContext.LastLWTimeStamp.QuadPart = -1 ) { KeQuerySystemTime(&LogHandleContext.LastLWTimeStamp) } if (!(SharedCacheMap->Flags & 0x200)) { CcSetDirtyInMask(SharedCacheMap, &BcbVoid->FileOffset, BcbVoid->PagesToWrite, NULL); return; } Bcb = *BcbArray; while (Bcb) { if ((ULONG_PTR)Bcb & 1) { KeBugCheckEx(CACHE_MANAGER, 0xE94, 0xC0000420, 0, 0); } SharedCacheMap = Bcb->SharedCacheMap; Mutex = &SharedCacheMap->BcbLock; /* Acquire the BCB lock */ OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); // KeAcquireInStackQueuedSpinLock((PKSPIN_LOCK)(v6 + 184), &LockHandle) KeAcquireQueuedSpinLockAtDpcLevel((ULONG_PTR)&KeGetPcr()->Prcb->LockQueue[5]); if (!Bcb->Dirty) { PagesToWrite = Bcb->PagesToWrite >> PAGE_SHIFT; Bcb->Dirty = TRUE; if (Lsn) { Bcb->OldestLsn = *Lsn; Bcb->NewestLsn = *Lsn; } /* Update dirty page statistics */ if (!SharedCacheMap->DirtyPages && !(SharedCacheMap->Flags & PRIVATE_CACHE_MAP_FLAGS_WRITE_THROUGH)) { CcScheduleLazyWriteScan(FALSE, FALSE); CcInsertIntoDirtySharedCacheMapList(SharedCacheMap); } CcChargeDirtyPages(SharedCacheMap, 0, 0, PagesToWrite); /* Handle process disk counters if necessary */ if (SharedCacheMap->Flags & PRIVATE_CACHE_MAP_FLAGS_TRACK_DIRTY_PAGES) { PsUpdateDiskCounters(PsGetCurrentThread()->ThreadsProcess, 0, PagesToWrite << PAGE_SHIFT, 0, 1, 0); } } KeReleaseQueuedSpinLockFromDpcLevel((ULONG_PTR)&Prcb->LockQueue[5]); /* Update LSN information */ if (Lsn) { if (!Bcb->MostRecentlyDirtiedPage || Lsn->QuadPart < Bcb->MostRecentlyDirtiedPage) { Bcb->OldestLsn = *Lsn; } if (!Bcb->NewestLsn.QuadPart || Lsn->QuadPart > Bcb->NewestLsn.QuadPart) { Bcb->NewestLsn = *Lsn; } if (Lsn->QuadPart > SharedCacheMap->LargestLSN.QuadPart) { SharedCacheMap->LargestLSN = *Lsn; } } /* Update ValidDataGoal if necessary */ if (Bcb->ResumeWritePage > SharedCacheMap->ValidDataGoal.QuadPart) { SharedCacheMap->ValidDataGoal.QuadPart = Bcb->ResumeWritePage; } /* Release the BCB lock */ KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); // KeAcquireInStackQueuedSpinLock /* Move to the next BCB */ BcbArray++; Bcb = *BcbArray; } } BOOLEAN NTAPI CcPinFileData( _In_ PFILE_OBJECT FileObject, _In_ PLARGE_INTEGER FileOffset, _In_ ULONG Length, _In_ BOOLEAN IsNoWrite, _In_ BOOLEAN Flags, _In_ ULONG PinFlags, _Out_ PCC_BCB* Bcb, _Out_ PVOID* Buffer, _Out_ LARGE_INTEGER* BeyondLastByte) { KLOCK_QUEUE_HANDLE LockHandle ={0}; PSHARED_CACHE_MAP SharedMap = nullptr; PVACB Vacb = nullptr; PCC_BCB Bcb = nullptr; LARGE_INTEGER EndFileOffset ={0}; LARGE_INTEGER offset = {0}; LARGE_INTEGER length = {0}; ULONG ActivePage = {0}; ULONG ReceivedLength ={0}; ULONG MapFlags = {0}; BOOLEAN IsLocked = false; BOOLEAN IsVacbLocked = false; BOOLEAN Result = false; SharedMap = FileObject->SectionObjectPointer->SharedCacheMap; CcGetActiveVacb(SharedMap, &Vacb, &ActivePage, &IsVacbLocked); if (Vacb || SharedMap->NeedToZero) { CcFreeActiveVacb(SharedMap, Vacb, ActivePage, IsVacbLocked); Vacb = nullptr; } *Bcb = nullptr; *Buffer = nullptr; if (PinFlags & PIN_NO_READ) { ReceivedLength = PAGE_SIZE - (FileOffset->LowPart & (PAGE_SIZE - 1)); CcReferenceFileOffset(SharedMap, *FileOffset); } else { *Buffer = CcGetVirtualAddress(SharedMap, *FileOffset, &Vacb, &ReceivedLength); } KeAcquireInStackQueuedSpinLock(&SharedMap->BcbSpinLock, &LockHandle); IsLocked = true; _try{ EndFileOffset.QuadPart = (FileOffset->QuadPart + Length); if (CcFindBcb(SharedMap, FileOffset, &EndFileOffset, &Bcb)) { if (!(SharedMap->Flags & SHARE_FL_MODIFIED_NO_WRITE)) IsNoWrite = true; if (Bcb->BaseAddress) { if (PinFlags & PIN_WAIT) { Bcb->PinCount++; KeReleaseInStackQueuedSpinLock(&LockHandle); IsLocked = false; if (!IsNoWrite) { if (PinFlags & PIN_EXCLUSIVE) ExAcquireResourceExclusiveLite(&Bcb->BcbResource, true); else ExAcquireSharedStarveExclusive(&Bcb->BcbResource, true); } } if (!(PinFlags & PIN_WAIT)) { if (!IsNoWrite && !ExAcquireSharedStarveExclusive(&Bcb->BcbResource, false)) { Bcb = nullptr; Result = false; goto finish; } InterlockedIncrement(&Bcb->PinCount); KeReleaseInStackQueuedSpinLock(&LockHandle); IsLocked = false; Result = CcMapAndRead(SharedMap, &offset, length.LowPart, 0, false, *Buffer); if (!Result) goto finish; } *Buffer = reinterpret_cast(reinterpret_cast(Bcb->BaseAddress) + (FileOffset->LowPart - Bcb->FileOffset.LowPart)); Result = true; goto finish; } else { *Buffer = reinterpret_cast(reinterpret_cast(*Buffer) + (Bcb->FileOffset.LowPart - FileOffset->LowPart)); offset.QuadPart = Bcb->FileOffset.QuadPart; length.QuadPart = Bcb->Length; if (PinFlags & PIN_WAIT) { Bcb->PinCount++; KeReleaseInStackQueuedSpinLock(&LockHandle); IsLocked = false; if (!IsNoWrite) { if (PinFlags & PIN_EXCLUSIVE) ExAcquireResourceExclusiveLite(&Bcb->BcbResource, true); else ExAcquireSharedStarveExclusive(&Bcb->BcbResource, true); } if (PinFlags & PIN_NO_READ) { Result = true; goto finish; } CcMapAndRead(SharedMap, &offset, length.LowPart, 0, true, *Buffer); KeAcquireInStackQueuedSpinLock(&SharedMap->BcbSpinLock, &LockHandle); if (!Bcb->BaseAddress) { Bcb->BaseAddress = *Buffer; Bcb->Vacb = Vacb; Vacb = nullptr; } KeReleaseInStackQueuedSpinLock(&LockHandle); *Buffer = reinterpret_cast(reinterpret_cast(Bcb->BaseAddress) + (FileOffset->LowPart - Bcb->FileOffset.LowPart)); Result = true; goto finish; } *Buffer = reinterpret_cast(reinterpret_cast(Bcb->BaseAddress) + (FileOffset->LowPart - Bcb->FileOffset.LowPart)); Result = true; goto finish; } } else { if (PinFlags & PIN_IF_BCB) { Bcb = nullptr; Result = false; goto finish; } offset.QuadPart = FileOffset->QuadPart; length.QuadPart = (EndFileOffset.QuadPart - offset.QuadPart); length.LowPart += (offset.LowPart & (PAGE_SIZE - 1)); ReceivedLength += (offset.LowPart & (PAGE_SIZE - 1)); if ((!IsNoWrite && !(SharedMap->Flags & SHARE_FL_PIN_ACCESS)) || Flags) { if (!(offset.LowPart & (PAGE_SIZE - 1)) && Length >= PAGE_SIZE) MapFlags = 3; else MapFlags = 2; if (!(length.LowPart & (PAGE_SIZE - 1))) MapFlags |= 4; } if (!(SharedMap->Flags & SHARE_FL_MODIFIED_NO_WRITE)) IsNoWrite = true; *Buffer = reinterpret_cast(reinterpret_cast(*Buffer) - (FileOffset->LowPart & (PAGE_SIZE - 1))); offset.LowPart &= ~(PAGE_SIZE - 1); length.LowPart = ROUND_TO_PAGES(length.LowPart); if (length.LowPart > ReceivedLength) length.LowPart = ReceivedLength; Bcb = CcAllocateInitializeBcb(SharedMap, Bcb, &offset, &length); if (PinFlags & PIN_WAIT) { if (!Bcb) { KeReleaseInStackQueuedSpinLock(&LockHandle); IsLocked = false; RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); } if (!IsNoWrite) { /* For writing need acquire Bcb */ if (PinFlags & PIN_EXCLUSIVE) ExAcquireResourceExclusiveLite(&Bcb->BcbResource, true); else ExAcquireSharedStarveExclusive(&Bcb->BcbResource, true); } KeReleaseInStackQueuedSpinLock(&LockHandle); IsLocked = false; if (PinFlags & PIN_NO_READ) { Result = true; goto finish; } CcMapAndRead(SharedMap, &offset, length.LowPart, MapFlags, true, *Buffer); KeAcquireInStackQueuedSpinLock(&SharedMap->BcbSpinLock, &LockHandle); if (!Bcb->BaseAddress) { Bcb->BaseAddress = *Buffer; Bcb->Vacb = Vacb; Vacb = nullptr; } KeReleaseInStackQueuedSpinLock(&LockHandle); *Buffer = reinterpret_cast( reinterpret_cast(Bcb->BaseAddress) + (FileOffset->LowPart - Bcb->FileOffset.LowPart)); Result = true; goto finish; } else { if (!IsNoWrite && !ExAcquireSharedStarveExclusive(&Bcb->BcbResource, false)) { Bcb = nullptr; Result = false; goto Finish; } _InterlockedIncrement(&Bcb->PinCount); KeReleaseInStackQueuedSpinLock(&LockHandle); IsLocked = false; Result = CcMapAndRead(SharedMap, &offset, length.LowPart, MapFlags, false, *Buffer); if (!Result) goto finish; } } } finish: if ((PinFlags & PIN_NO_READ) && (PinFlags & PIN_EXCLUSIVE) && Bcb && Bcb->BaseAddress) { CcFreeVirtualAddress(Bcb->Vacb); Bcb->BaseAddress = nullptr; Bcb->Vacb = nullptr; } __finally{ if (IsLocked) KeReleaseInStackQueuedSpinLock(&LockHandle); if (Vacb) CcFreeVirtualAddress(Vacb); if (PinFlags & PIN_NO_READ) { CcDereferenceFileOffset(SharedMap, *FileOffset); } if (Result) { *Bcb = Bcb; BeyondLastByte->QuadPart = Bcb->BeyondLastByte.QuadPart; } else { *Buffer = nullptr; if (Bcb) CcUnpinFileDataEx(Bcb, IsNoWrite, 0); } return Result; } } BOOLEAN NTAPI CcMapDataCommon( _In_ PFILE_OBJECT FileObject, _In_ PLARGE_INTEGER FileOffset, _In_ ULONG Length, _In_ ULONG Flags, _Out_ PVOID *Bcb, _Out_ PVOID *Buffer ) { if (Flags & FILE_PIN_SEQUENTIAL_READ) InterlockedIncrement(&CcSequentialReadCount); else InterlockedIncrement(&CcRandomReadCount); KeGetCurrentThread()->WaitIrql = PASSIVE_LEVEL; if (Flags & FILE_PIN_SEQUENTIAL_READ) { *Buffer = CcGetVirtualAddress(SharedMap, *FileOffset, (PVACB *)&Bcb, &ReceivedLength); return TRUE; } else { LARGE_INTEGER BeyondLastByte; if (CcPinFileData(FileObject, FileOffset, Length, TRUE, 0, Flags, Bcb, Buffer, &BeyondLastByte)) { return TRUE; } else { InterlockedIncrement(&CCFailedPinReadCount); return FALSE; } } } } VOID NTAPI CcUnpinFileDataEx( _In_ PCC_BCB Bcb, _In_ BOOLEAN& WriteStatus, _In_ ULONG& UnPinType) { PSHARED_CACHE_MAP SharedCacheMap = nullptr; KIRQL OldIrql = {0}; ULONG NumberOfPages = {0}; BOOLEAN ReadOnly = false; /* If it is not BCB Ptr,it must be VACB Pointer, free it*/ if (Bcb->NodeTypeCode != BCB_NODE_TYPE_CODE) { PVACB Vacb = reinterpret_cast(Bcb); CcFreeVirtualAddress(Vacb); return; } SharedCacheMap = Bcb->SharedCacheMap; /* Is it only Unpinning if so is their no write performed by Cache Controller */ if (!(SharedCacheMap->Flags & SHARED_CACHE_MAP_MODIFIED_NO_WRITE) || UnPinType == UnPin) ReadOnly = TRUE; OldIrql = KeAcquireSpinLockRaiseToDpc(&SharedCacheMap->BcbSpinLock); /* Just reduce pin count if BCB is not set to be cleaned else perform cleaning of BCB*/ if (UnPinType < CLEAN_BCB_PIN) { ASSERT(Bcb->PinCount > 0); Bcb->PinCount--; } else { if (UnPinType != CLEAN_BCB_PIN) KeBugCheckEx(UNEXPECTED_VALUE, UnPinType, (ULONG_PTR)Bcb, 0, 0); if (Bcb->IsBCBDirty) { NumberOfPages = (Bcb->Length / PAGE_SIZE); Bcb->IsBCBDirty = FALSE; Bcb->NewestDirtiedPage = 0; Bcb->NewestLsn.QuadPart = 0; CcDeductIsBCBDirtyPages(SharedCacheMap, NumberOfPages); /*Adjust page count */ if (CcPagesYetToWrite <= NumberOfPages) CcPagesYetToWrite = 0; else CcPagesYetToWrite -= NumberOfPages; if (!SharedCacheMap->IsBCBDirtyPages && SharedCacheMap->OpenCount) CcInsertIntoCleanSharedCacheMapList(SharedCacheMap); } } if (Bcb->PinCount) { /* If not read only BCB, release resources,their no point being pinned at that case */ if (!ReadOnly) ExReleaseResourceLite(&Bcb->BcbResource); KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); } /*if BCB is dirty, free the virtual adress*/ else if (Bcb->IsBCBDirty) { if (Bcb->BaseAddress) { CcFreeVirtualAddress(Bcb->Vacb); Bcb->BaseAddress = NULL; Bcb->Vacb = NULL; } if (!ReadOnly) ExReleaseResourceLite(&Bcb->BcbResource); KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); } else { KeAcquireSpinLockAtDpcLevel(&SharedCacheMap->VacbSpinLock); RemoveEntryList(&Bcb->Link); if (SharedCacheMap->SectionSize.QuadPart > CACHE_OVERALL_SIZE && (SharedCacheMap->Flags & SHARED_CACHE_MAP_MODIFIED_NO_WRITE)) { CcAdjustVacbLevelLockCount(SharedCacheMap, &Bcb->FileOffset.QuadPart, -1); } KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->VacbSpinLock); if (Bcb->BaseAddress) CcFreeVirtualAddress(Bcb->Vacb); if (!ReadOnly) ExReleaseResourceLite(&Bcb->BcbResource); KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); CcDeallocateBcb(Bcb); } } BOOLEAN NTAPI CcMapData( _In_ In PFILE_OBJECT FileObject, _In_ PLARGE_INTEGER FileOffset, _In_ ULONG Length, _In_ ULONG Flags, _Out_ PVOID *Bcb, _Out_ PVOID *Buffer) { PVOID LocalBuffer = nullptr; /* Call CcMapDataCommon to perform the actual mapping */ if (!CcMapDataCommon(FileObject,FileOffset,Length,Flags,Bcb,&LocalBuffer)) { return false; } /* Check if we need to read the data */ if (!(Flags & MAP_NO_READ)) { /* Read the data */ if (!CcMapAndRead(Length, 0, true, LocalBuffer)) { return false; } } /* Set Bcb to point after the LocalBuffer */ *Bcb = reinterpret_cast(reinterpret_cast(LocalBuffer) + sizeof(PVOID)); /* Set the output Buffer */ *Buffer = LocalBuffer; return true; } BOOLEAN NTAPI CcPinMappedData( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG Flags, IN OUT PCC_BCB Bcb) { //Unimplemented } BOOLEAN NTAPI CcPinRead( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG Flags, OUT PVOID *Bcb, OUT PVOID *Buffer) { //Unimplemented } BOOLEAN NTAPI CcPreparePinWrite( _In_ PFILE_OBJECT FileObject, _In_ PLARGE_INTEGER FileOffset, _In_ ULONG Length, _In_ BOOLEAN Zero, _In_ ULONG Flags, _Out_ PVOID *Bcb, _Out_ PVOID *Buffer) { LARGE_INTEGER LocalFileOffset = *FileOffset; LARGE_INTEGER BeyondLastByte ={0}; ULONG RemainingLength = Length; POBCB localbcb = nullptr; PCC_BCB *localbcbPtr = nullptr; PVOID LocalBuffer = nullptr; BOOLEAN Result = false; if (Flags & PIN_WAIT) { return CcMapDataForOverwrite(FileObject, FileOffset, Length, Bcb, Buffer); } /*Pinning Loop*/ while(true) { if (localbcb) { if (localbcbPtr == reinterpret_cast(&localbcb)) { localbcb = CcAllocateObcb(&LocalFileOffset, RemainingLength, localbcb); localbcbPtr = localbcb->Bcbs; *Buffer = LocalBuffer; } RemainingLength += LocalFileOffset.QuadPart - BeyondLastByte.QuadPart; LocalFileOffset.QuadPart = BeyondLastByte.QuadPart; localbcbPtr++; } if (!CcPinFileData(FileObject, &LocalFileOffset,RemainingLength,false,false,Flags,localbcbPtr,&LocalBuffer, &BeyondLastByte)) { /* Pinning failed */ if (localbcb) { CcUnpinData(localbcb); } return false; } if(BeyondLastByte.QuadPart < LocalFileOffset.QuadPart + RemainingLength) break; } if (localbcbPtr == reinterpret_cast(&localbcb)) { *Buffer = LocalBuffer; } if (Zero) { RtlZeroMemory(*Buffer, Length); } CcSetDirtyPinnedData(localbcb, nullptr); *Bcb = localbcb; return true; } VOID NTAPI CcSetBcbOwnerPointer( IN PMBCB Bcb, IN PVOID OwnerPointer) { if (Bcb->NodeTypeCode == 762) { /* Iterate through all bitmap ranges */ for (auto it = ListEntryIterator::begin(&Bcb->BitmapRanges); it != ListEntryIterator::end(&Bcb->BitmapRanges); ++it) { auto* Bcb = CONTAINING_RECORD(it->Blink,MBCB,BitmapRanges); ExSetResourceOwnerPointer(&Bcb->DirtyPages,OwnerPointer); } } else { /* Single bitmap range */ ExSetResourceOwnerPointer(&Bcb->BitmapRange1.FirstDirtyPage,OwnerPointer); } } VOID NTAPI CcUnpinData( _In_ PVOID BcbPtr) { PCC_BCB Bcb = reinterpret_cast(BcbPtr); BOOLEAN WRITE_FLAG = NULL; if (reinterpret_cast((Bcb) & 1)) { WRITE_FLAG = TRUE; Bcb = reinterpret_cast(reinterpret_cast(Bcb) & ~(1)); CcUnpinFileDataEx(Bcb, WRITE_FLAG, UNPIN_BCB); return; } if (Bcb->NodeTypeCode != 762) { WRITE_FLAG = FALSE; CcUnpinFileDataEx(Bcb, WRITE_FLAG, UNPIN_BCB); return; } for (auto it = ListEntryIterator::begin(&Bcb->BcbLinks); it != ListEntryIterator::end(&Bcb->BcbLinks); ++it) { auto* BCB_CURRENT = CONTAINING_RECORD(it->Blink, CC_BCB, BcbLinks); CcUnpinData(BCB_CURRENT); } ExFreePoolWithTag(Bcb,NULL); } VOID NTAPI CcUnpinDataForThread(IN PVOID BcbPtr, IN ERESOURCE_THREAD ResourceThreadId) { PCC_BCB Bcb = BcbPtr; BOOLEAN WRITE_FLAG = NULL; if (reinterpret_cast((Bcb) & 1)) { WRITE_FLAG = TRUE; Bcb = reinterpret_cast(reinterpret_cast(Bcb) & ~(1)); CcUnpinFileDataEx(Bcb, WRITE_FLAG, ); return; } if (Bcb->NodeTypeCode != 762) { WRITE_FLAG = FALSE; ExReleaseResourceForThreadLite(&Bcb->Resource, ResourceThreadId); CcUnpinFileDataEx(Bcb, WRITE_FLAG, UNPIN_BCB); return; } for (auto it = ListEntryIterator::begin(&Bcb->BcbLinks); it != ListEntryIterator::end(&Bcb->BcbLinks); ++it) { auto* BCB_CURRENT = CONTAINING_RECORD(it->Blink, CC_BCB, BcbLinks); CcUnpinData(BCB_CURRENT); } ExFreePoolWithTag(Bcb,NULL); }