/* PROJECT: Alcyone Kernel * LICENSE: BSD Clause 3 * PURPOSE: Cache Controller:: LOG Handler * NT KERNEL: 5.11.9360 * COPYRIGHT: 2023-2029 Dibymartanda Samanta <> */ #include #define NTDEBUG #include #include "ccinternal.hpp" #include "ccloghandler.hpp" extern "C" LARGE_INTEGER NTAPI CcGetDirtyPages(IN PVOID LogHandle, IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine, IN PVOID Context1, IN PVOID Context2) { __try { KIRQL OldIrql = {0}; PSHARED_CACHE_MAP SharedCacheMap = nullptr; PFILE_OBJECT *FileObject = nullptr; PCC_BCB Bcb = nullptr, PCC_BCB BcbToUnpin = nullptr; PLIST_ENTRY Entry = &CcDirtyLoggedStreamLinks; LARGE_INTEGER OldestLsn = {0}; LARGE_INTEGER Result = {0}; BOOLEAN FirstIteration = TRUE; // Acquire Master Lock OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); // Iterate through all Dirty Shared Cache Maps for (auto it = ListEntryIterator::begin(Entry); it != ListEntryIterator::end(Entry); ++it) { SharedCacheMap = CONTAINING_RECORD(*it, SHARED_CACHE_MAP, LoggedStreamLinks); // Check flags and validate LogHandle if ((SharedCacheMap->Flags & 0x800) != 0) { DBGPRINT("CcGetDirtyPages::Invalid Flag \n") return; } if ((SharedCacheMap->Flags & 0x2000000) != 0 && SharedCacheMap->LogHandle == LogHandle) { SharedCacheMap->OpenCount++; SharedCacheMap->DirtyPages++; KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); /* Reference the shared cache map file object*/ FileObject = CcReferenceSharedCacheMapFileObject(SharedCacheMap); /* Acquire the BCB Lock */ oldIrql = ExAcquireSpinLockShared (&SharedCacheMap->BcbSpinLock); /* Iterate over BCB List */ for (auto it = ListEntryIterator::begin(&SharedCacheMap->BcbList); it != ListEntryIterator::end(&SharedCacheMap->BcbList); ++it) { Bcb = CONTAINING_RECORD(*it, CC_BCB, BcbLinks); /* Ensure the BCB is marked as dirty */ if (Bcb->NodeTypeCode == NODE_TYPE_DIRTY_BCB && Bcb->NodeByteCode) { LocalFileOffset = Bcb->BaseData; LocalOldestLsn = Bcb->OldestLsn; LocalNewestLsn = Bcb->NewestLsn; /*Increment the PinCount to keep the BCB pinned*/ Bcb->PinCount++; /*Release the BCB lock temporarily for the callback*/ ExReleaseSpinLockShared (&SharedCacheMap->BcbSpinLock,oldIrql); /*Unpin any previously pinned BCB*/ if (BcbToUnpin) { CcUnpinFileDataEx(BcbToUnpin, 1, 0); BcbToUnpin = NULL; } /* Invoke the provided dirty page routine*/ DirtyPageRoutine(FileObject, &LocalFileOffset, SharedCacheMap, &LocalOldestLsn, &LocalNewestLsn, Context1, Context2); if (LocalOldestLsn.QuadPart && OldestLsn.QuadPart || LocalOldestLsn.QuadPart < OldestLsn.QuadPart) { OldestLsn = LocalOldestLsn; } } // Reacquire the BCB lock oldIrql = ExAcquireSpinLockShared (&SharedCacheMap->BcbSpinLock); // Decrement the PinCount or mark for unpinning if (Bcb->PinCount > 1) { Bcb->PinCount--; BcbToUnpin = NULL; } else { BcbToUnpin = Bcb; } } } /*Release the BCB lock*/ ExReleaseSpinLockShared (&SharedCacheMap->BcbSpinLock,oldIrql); /* Dereference the shared cache map file object*/ CcDereferenceSharedCacheMapFileObject(SharedCacheMap, FileObject); /*Unpin any remaining BCB*/ if (BcbToUnpin) { CcUnpinFileDataEx(BcbToUnpin, 1,0); BcbToUnpin = NULL; } OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); /*Decrement the OpenCount and DirtyPages*/ SharedCacheMap->OpenCount--; SharedCacheMap->DirtyPages--; KeReleaseQueuedSpinLock(LockQueueMasterLock,OldIrql); } } } LARGE_INTEGER NTAPI CcGetLsnForFileObject(IN PFILE_OBJECT FileObject, OUT OPTIONAL PLARGE_INTEGER OldestLsn) { /* IMPLEMENTATION INCOMPLETE*/ } Void NTAPI CcSetAdditionalCacheAttributes( In PFILE_OBJECT FileObject, In BOOLEAN DisableReadAhead, In BOOLEAN DisableWriteBehind ) { PSHARED_CACHE_MAP SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; KIRQL oldlock = KeAcquireQueuedSpinLock(LockQueueMasterLock); if ( DisableReadAhead ) SharedCacheMap->Flags |= READAHEAD_FLAG; else SharedCacheMap->Flags &= ~READAHEAD_FLAG; if ( DisableWriteBehind ) SharedCacheMap->Flags |= DISABLE_WRITE_FLAG; else SharedCacheMap->Flags &= ~ENABLE_WRITE_FLAG; KeReleaseQueuedSpinLock(LockQueueMasterLock, oldlock); } VOID NTAPI CcSetAdditionalCacheAttributesEx(PFILE_OBJECT FileObject, ULONG Flags) { PSHARED_CACHE_MAP sharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; KIRQL irqlDisableWriteBehind = {0}; KLOCK_QUEUE_HANDLE lockQueueHandle = {0}; BOOL disableReadAhead = (Flags & 2) != 0; if (sharedCacheMap == nullptr||!sharedCacheMap->OpenCount) DBGPRINT("Invalid Shared Cache Map or Open Count") return; if ((sharedCacheMap->Flags & 0x2000) == 0) CcSetAdditionalCacheAttributes(FileObject, disableReadAhead, (Flags & 4) != 0); KeAcquireInStackQueuedSpinLockAtDpcLevel(&sharedCacheMap->BcbLock, &lockQueueHandle); if ((Flags & 1) != 0) sharedCacheMap->Flags |= FLAG_DISABLE_WRITE_BEHIND; else sharedCacheMap->Flags &= ~FLAG_DISABLE_WRITE_BEHIND; if ((Flags & 8) != 0) { sharedCacheMap->Flags |= FLAG_DISABLE_LAZY_WRITER; } else { if ((sharedCacheMap->Flags & FLAG_DISABLE_LAZY_WRITER) != 0) sharedCacheMap->Flags |= FLAG_LAZY_WRITER_ACTIVE; sharedCacheMap->Flags &= ~FLAG_DISABLE_LAZY_WRITER; } if ((Flags & 0x10) != 0) sharedCacheMap->Flags |= FLAG_DISABLE_LAZY_WRITER_SCAN; else sharedCacheMap->Flags &= ~FLAG_DISABLE_LAZY_WRITER_SCAN; if ((Flags & 0x20) != 0) sharedCacheMap->Flags |= FLAG_DISABLE_METADATA_FLUSH; else sharedCacheMap->Flags &= ~FLAG_DISABLE_METADATA_FLUSH; KeReleaseInStackQueuedSpinLockFromDpcLevel(&lockQueueHandle); } VOID NTAPI CcSetLogHandleForFile(IN PFILE_OBJECT FileObject, IN PVOID LogHandle, IN PFLUSH_TO_LSN FlushToLsnRoutine) { PSHARED_CACHE_MAP SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap SharedCacheMap->LogHandle = LogHandle; SharedCacheMap->FlushToLsnRoutine = FlushToLsnRoutine; } VOID NTAPI CcSetLogHandleForFileEx( IN PFILE_OBJECT FileObject, IN PVOID LogHandle, IN PFLUSH_TO_LSN FlushToLsnRoutine IN PQUERY_LOG_USAGE QueryLogUsageRoutine _In_opt_ PFILE_OBJECT RelatedLogHandleFileObject ) { PSHARED_CACHE_MAP SharedCacheMap; KIRQL OldIrql; LOG_HANDLE_CONTEXT LogHandleContext; PLOG_HANDLE_CONTEXT VolumeLogHandleContext; LIST_ENTRY *ListHead; LIST_ENTRY *PrevEntry; // Retrieve the Shared Cache Map SharedCacheMap = (PSHARED_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap; // Validate Shared Cache Map if (!SharedCacheMap || SharedCacheMap->OpenCount == 0) { return; } if (SharedCacheMap->Flags & FLAG_LOGHANDLE_SET) { return; } OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); /* Remove the existing log handle if present*/ if (SharedCacheMap->LogHandle) { RemoveEntryList(&SharedCacheMap->LoggedStreamLinks); } /*Handle the case when a new log handle is not provided*/ if (!LogHandle) { SharedCacheMap->Flags &= ~FLAG_LOGHANDLE_NOT_SET; SharedCacheMap->LogHandle = NULL; KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); return; } /* Determine the appropriate list based on whether there are dirty pages*/ if (SharedCacheMap->DirtyPages) { ListHead = &CcDirtyLoggedStreamLinks; } else { ListHead = &CcCleanLoggedStreamLinks; } PrevEntry = ListHead->Blink; InsertTailList(ListHead, &SharedCacheMap->LoggedStreamLinks); /*Initialize the volume log handle context if not already present*/ VolumeLogHandleContext = &SharedCacheMap->VolumeCacheMap->LogHandleContext; if (VolumeLogHandleContext->LogHandle == NULL) { RtlZeroMemory(&LogHandleContext, sizeof(LOG_HANDLE_CONTEXT)); LogHandleContext.LastLWTimeStamp.QuadPart = -1; LogHandleContext.LogHandle = LogHandle; LogHandleContext.FlushToLsnRoutine = FlushToLsnRoutine; LogHandleContext.QueryLogUsageRoutine = QueryLogUsageRoutine; if (RelatedLogHandleFileObject) { ObfReferenceObjectWithTag(RelatedLogHandleFileObject, 'tlFD'); LogHandleContext.RelatedFileObject = RelatedLogHandleFileObject; } RtlCopyMemory(VolumeLogHandleContext, &LogHandleContext, sizeof(LOG_HANDLE_CONTEXT)); } SharedCacheMap->LogHandle = VolumeLogHandleContext; /*Update the flags and dirty page statistics*/ if (!(SharedCacheMap->Flags & FLAG_LOGHANDLE_NOT_SET)) { if (SharedCacheMap->DirtyPages) { VolumeLogHandleContext->DirtyPageStatistics.DirtyPages += SharedCacheMap->DirtyPages; } } SharedCacheMap->Flags |= FLAG_LOGHANDLE_NOT_SET; KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); }