X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=ntoskrnl%2Fcc%2Fview.c;h=e896c570932987c011b8de5b1cb03bcf17df3b8f;hp=0584917098c0b876f85f005afa4ad5ff8a6ede6b;hb=1e579843bcf2f54da8e717ec9713b86e9ad1c02c;hpb=73d72624b097cb6c2f8481e75e99ed28ccbe907c diff --git a/ntoskrnl/cc/view.c b/ntoskrnl/cc/view.c index 0584917098c..e896c570932 100644 --- a/ntoskrnl/cc/view.c +++ b/ntoskrnl/cc/view.c @@ -5,6 +5,7 @@ * PURPOSE: Cache manager * * PROGRAMMERS: David Welch (welch@mcmail.com) + * Pierre Schweitzer (pierre@reactos.org) */ /* NOTES ********************************************************************** @@ -41,10 +42,8 @@ /* GLOBALS *******************************************************************/ -static LIST_ENTRY DirtyVacbListHead; -static LIST_ENTRY VacbListHead; +LIST_ENTRY DirtyVacbListHead; static LIST_ENTRY VacbLruListHead; -ULONG DirtyPageCount = 0; KGUARDED_MUTEX ViewLock; @@ -52,8 +51,21 @@ NPAGED_LOOKASIDE_LIST iBcbLookasideList; static NPAGED_LOOKASIDE_LIST SharedCacheMapLookasideList; static NPAGED_LOOKASIDE_LIST VacbLookasideList; +/* Internal vars (MS): + * - Threshold above which lazy writer will start action + * - Amount of dirty pages + * - List for deferred writes + * - Spinlock when dealing with the deferred list + * - List for "clean" shared cache maps + */ +ULONG CcDirtyPageThreshold = 0; +ULONG CcTotalDirtyPages = 0; +LIST_ENTRY CcDeferredWrites; +KSPIN_LOCK CcDeferredWriteSpinLock; +LIST_ENTRY CcCleanSharedCacheMapList; + #if DBG -static void CcRosVacbIncRefCount_(PROS_VACB vacb, const char* file, int line) +VOID CcRosVacbIncRefCount_(PROS_VACB vacb, PCSTR file, INT line) { ++vacb->ReferenceCount; if (vacb->SharedCacheMap->Trace) @@ -62,20 +74,17 @@ static void CcRosVacbIncRefCount_(PROS_VACB vacb, const char* file, int line) file, line, vacb, vacb->ReferenceCount, vacb->Dirty, vacb->PageOut); } } -static void CcRosVacbDecRefCount_(PROS_VACB vacb, const char* file, int line) +VOID CcRosVacbDecRefCount_(PROS_VACB vacb, PCSTR file, INT line) { + ASSERT(vacb->ReferenceCount != 0); --vacb->ReferenceCount; + ASSERT(!(vacb->ReferenceCount == 0 && vacb->Dirty)); if (vacb->SharedCacheMap->Trace) { DbgPrint("(%s:%i) VACB %p --RefCount=%lu, Dirty %u, PageOut %lu\n", file, line, vacb, vacb->ReferenceCount, vacb->Dirty, vacb->PageOut); } } -#define CcRosVacbIncRefCount(vacb) CcRosVacbIncRefCount_(vacb,__FILE__,__LINE__) -#define CcRosVacbDecRefCount(vacb) CcRosVacbDecRefCount_(vacb,__FILE__,__LINE__) -#else -#define CcRosVacbIncRefCount(vacb) (++((vacb)->ReferenceCount)) -#define CcRosVacbDecRefCount(vacb) (--((vacb)->ReferenceCount)) #endif NTSTATUS @@ -136,21 +145,11 @@ CcRosFlushVacb ( PROS_VACB Vacb) { NTSTATUS Status; - KIRQL oldIrql; Status = CcWriteVirtualAddress(Vacb); if (NT_SUCCESS(Status)) { - KeAcquireGuardedMutex(&ViewLock); - KeAcquireSpinLock(&Vacb->SharedCacheMap->CacheMapLock, &oldIrql); - - Vacb->Dirty = FALSE; - RemoveEntryList(&Vacb->DirtyVacbListEntry); - DirtyPageCount -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; - CcRosVacbDecRefCount(Vacb); - - KeReleaseSpinLock(&Vacb->SharedCacheMap->CacheMapLock, oldIrql); - KeReleaseGuardedMutex(&ViewLock); + CcRosUnmarkDirtyVacb(Vacb, TRUE); } return Status; @@ -161,7 +160,8 @@ NTAPI CcRosFlushDirtyPages ( ULONG Target, PULONG Count, - BOOLEAN Wait) + BOOLEAN Wait, + BOOLEAN CalledFromLazy) { PLIST_ENTRY current_entry; PROS_VACB current; @@ -192,6 +192,14 @@ CcRosFlushDirtyPages ( CcRosVacbIncRefCount(current); + /* When performing lazy write, don't handle temporary files */ + if (CalledFromLazy && + BooleanFlagOn(current->SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE)) + { + CcRosVacbDecRefCount(current); + continue; + } + Locked = current->SharedCacheMap->Callbacks->AcquireForLazyWrite( current->SharedCacheMap->LazyWriteContext, Wait); if (!Locked) @@ -200,11 +208,8 @@ CcRosFlushDirtyPages ( continue; } - Status = KeWaitForSingleObject(¤t->Mutex, - Executive, - KernelMode, - FALSE, - Wait ? NULL : &ZeroTimeout); + Status = CcRosAcquireVacbLock(current, + Wait ? NULL : &ZeroTimeout); if (Status != STATUS_SUCCESS) { current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite( @@ -218,7 +223,7 @@ CcRosFlushDirtyPages ( /* One reference is added above */ if (current->ReferenceCount > 2) { - KeReleaseMutex(¤t->Mutex, FALSE); + CcRosReleaseVacbLock(current); current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite( current->SharedCacheMap->LazyWriteContext); CcRosVacbDecRefCount(current); @@ -229,21 +234,36 @@ CcRosFlushDirtyPages ( Status = CcRosFlushVacb(current); - KeReleaseMutex(¤t->Mutex, FALSE); + CcRosReleaseVacbLock(current); current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite( current->SharedCacheMap->LazyWriteContext); KeAcquireGuardedMutex(&ViewLock); CcRosVacbDecRefCount(current); - if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE)) + if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE) && + (Status != STATUS_MEDIA_WRITE_PROTECTED)) { DPRINT1("CC: Failed to flush VACB.\n"); } else { - (*Count) += VACB_MAPPING_GRANULARITY / PAGE_SIZE; - Target -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + ULONG PagesFreed; + + /* How many pages did we free? */ + PagesFreed = VACB_MAPPING_GRANULARITY / PAGE_SIZE; + (*Count) += PagesFreed; + + /* Make sure we don't overflow target! */ + if (Target < PagesFreed) + { + /* If we would have, jump to zero directly */ + Target = 0; + } + else + { + Target -= PagesFreed; + } } current_entry = DirtyVacbListHead.Flink; @@ -325,13 +345,13 @@ retry: CcRosVacbDecRefCount(current); /* Check if we can free this entry now */ - if (current->ReferenceCount == 0) + if (current->ReferenceCount < 2) { ASSERT(!current->Dirty); ASSERT(!current->MappedCount); + ASSERT(current->ReferenceCount == 1); RemoveEntryList(¤t->CacheMapVacbListEntry); - RemoveEntryList(¤t->VacbListEntry); RemoveEntryList(¤t->VacbLruListEntry); InsertHeadList(&FreeList, ¤t->CacheMapVacbListEntry); @@ -350,7 +370,7 @@ retry: if ((Target > 0) && !FlushedPages) { /* Flush dirty pages to disk */ - CcRosFlushDirtyPages(Target, &PagesFreed, FALSE); + CcRosFlushDirtyPages(Target, &PagesFreed, FALSE, FALSE); FlushedPages = TRUE; /* We can only swap as many pages as we flushed */ @@ -371,6 +391,7 @@ retry: current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry); + CcRosVacbDecRefCount(current); CcRosInternalFreeVacb(current); } @@ -388,26 +409,16 @@ CcRosReleaseVacb ( BOOLEAN Dirty, BOOLEAN Mapped) { - BOOLEAN WasDirty; - KIRQL oldIrql; - ASSERT(SharedCacheMap); DPRINT("CcRosReleaseVacb(SharedCacheMap 0x%p, Vacb 0x%p, Valid %u)\n", SharedCacheMap, Vacb, Valid); - KeAcquireGuardedMutex(&ViewLock); - KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); - Vacb->Valid = Valid; - WasDirty = Vacb->Dirty; - Vacb->Dirty = Vacb->Dirty || Dirty; - - if (!WasDirty && Vacb->Dirty) + if (Dirty && !Vacb->Dirty) { - InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); - DirtyPageCount += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcRosMarkDirtyVacb(Vacb); } if (Mapped) @@ -419,14 +430,10 @@ CcRosReleaseVacb ( { CcRosVacbIncRefCount(Vacb); } - if (!WasDirty && Vacb->Dirty) - { - CcRosVacbIncRefCount(Vacb); - } - KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); - KeReleaseGuardedMutex(&ViewLock); - KeReleaseMutex(&Vacb->Mutex, FALSE); + ASSERT(Vacb->ReferenceCount != 0); + + CcRosReleaseVacbLock(Vacb); return STATUS_SUCCESS; } @@ -436,7 +443,7 @@ PROS_VACB NTAPI CcRosLookupVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, - ULONG FileOffset) + LONGLONG FileOffset) { PLIST_ENTRY current_entry; PROS_VACB current; @@ -444,7 +451,7 @@ CcRosLookupVacb ( ASSERT(SharedCacheMap); - DPRINT("CcRosLookupVacb(SharedCacheMap 0x%p, FileOffset %lu)\n", + DPRINT("CcRosLookupVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n", SharedCacheMap, FileOffset); KeAcquireGuardedMutex(&ViewLock); @@ -463,11 +470,7 @@ CcRosLookupVacb ( CcRosVacbIncRefCount(current); KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); KeReleaseGuardedMutex(&ViewLock); - KeWaitForSingleObject(¤t->Mutex, - Executive, - KernelMode, - FALSE, - NULL); + CcRosAcquireVacbLock(current, NULL); return current; } if (current->FileOffset.QuadPart > FileOffset) @@ -481,38 +484,25 @@ CcRosLookupVacb ( return NULL; } -NTSTATUS +VOID NTAPI CcRosMarkDirtyVacb ( - PROS_SHARED_CACHE_MAP SharedCacheMap, - ULONG FileOffset) + PROS_VACB Vacb) { - PROS_VACB Vacb; KIRQL oldIrql; + PROS_SHARED_CACHE_MAP SharedCacheMap; - ASSERT(SharedCacheMap); - - DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %lu)\n", - SharedCacheMap, FileOffset); - - Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset); - if (Vacb == NULL) - { - KeBugCheck(CACHE_MANAGER); - } + SharedCacheMap = Vacb->SharedCacheMap; KeAcquireGuardedMutex(&ViewLock); KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); - if (!Vacb->Dirty) - { - InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); - DirtyPageCount += VACB_MAPPING_GRANULARITY / PAGE_SIZE; - } - else - { - CcRosVacbDecRefCount(Vacb); - } + ASSERT(!Vacb->Dirty); + + InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); + CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + Vacb->SharedCacheMap->DirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcRosVacbIncRefCount(Vacb); /* Move to the tail of the LRU list */ RemoveEntryList(&Vacb->VacbLruListEntry); @@ -522,25 +512,89 @@ CcRosMarkDirtyVacb ( KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); KeReleaseGuardedMutex(&ViewLock); - KeReleaseMutex(&Vacb->Mutex, FALSE); + + /* Schedule a lazy writer run to now that we have dirty VACB */ + oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + if (!LazyWriter.ScanActive) + { + CcScheduleLazyWriteScan(FALSE); + } + KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql); +} + +VOID +NTAPI +CcRosUnmarkDirtyVacb ( + PROS_VACB Vacb, + BOOLEAN LockViews) +{ + KIRQL oldIrql; + PROS_SHARED_CACHE_MAP SharedCacheMap; + + SharedCacheMap = Vacb->SharedCacheMap; + + if (LockViews) + { + KeAcquireGuardedMutex(&ViewLock); + KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); + } + + ASSERT(Vacb->Dirty); + + Vacb->Dirty = FALSE; + + RemoveEntryList(&Vacb->DirtyVacbListEntry); + CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + Vacb->SharedCacheMap->DirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcRosVacbDecRefCount(Vacb); + + if (LockViews) + { + KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); + KeReleaseGuardedMutex(&ViewLock); + } +} + +NTSTATUS +NTAPI +CcRosMarkDirtyFile ( + PROS_SHARED_CACHE_MAP SharedCacheMap, + LONGLONG FileOffset) +{ + PROS_VACB Vacb; + + ASSERT(SharedCacheMap); + + DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n", + SharedCacheMap, FileOffset); + + Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset); + if (Vacb == NULL) + { + KeBugCheck(CACHE_MANAGER); + } + + CcRosReleaseVacb(SharedCacheMap, Vacb, Vacb->Valid, TRUE, FALSE); return STATUS_SUCCESS; } +/* + * Note: this is not the contrary function of + * CcRosMapVacbInKernelSpace() + */ NTSTATUS NTAPI CcRosUnmapVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, - ULONG FileOffset, + LONGLONG FileOffset, BOOLEAN NowDirty) { PROS_VACB Vacb; - BOOLEAN WasDirty; - KIRQL oldIrql; ASSERT(SharedCacheMap); - DPRINT("CcRosUnmapVacb(SharedCacheMap 0x%p, FileOffset %lu, NowDirty %u)\n", + DPRINT("CcRosUnmapVacb(SharedCacheMap 0x%p, FileOffset %I64u, NowDirty %u)\n", SharedCacheMap, FileOffset, NowDirty); Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset); @@ -549,33 +603,73 @@ CcRosUnmapVacb ( return STATUS_UNSUCCESSFUL; } - KeAcquireGuardedMutex(&ViewLock); - KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); - - WasDirty = Vacb->Dirty; - Vacb->Dirty = Vacb->Dirty || NowDirty; - + ASSERT(Vacb->MappedCount != 0); Vacb->MappedCount--; - if (!WasDirty && NowDirty) + if (Vacb->MappedCount == 0) { - InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); - DirtyPageCount += VACB_MAPPING_GRANULARITY / PAGE_SIZE; + CcRosVacbDecRefCount(Vacb); } - CcRosVacbDecRefCount(Vacb); - if (!WasDirty && NowDirty) + CcRosReleaseVacb(SharedCacheMap, Vacb, Vacb->Valid, NowDirty, FALSE); + + return STATUS_SUCCESS; +} + +static +NTSTATUS +CcRosMapVacbInKernelSpace( + PROS_VACB Vacb) +{ + ULONG i; + NTSTATUS Status; + ULONG_PTR NumberOfPages; + + /* Create a memory area. */ + MmLockAddressSpace(MmGetKernelAddressSpace()); + Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), + 0, // nothing checks for VACB mareas, so set to 0 + &Vacb->BaseAddress, + VACB_MAPPING_GRANULARITY, + PAGE_READWRITE, + (PMEMORY_AREA*)&Vacb->MemoryArea, + 0, + PAGE_SIZE); + MmUnlockAddressSpace(MmGetKernelAddressSpace()); + if (!NT_SUCCESS(Status)) { - CcRosVacbIncRefCount(Vacb); + DPRINT1("MmCreateMemoryArea failed with %lx for VACB %p\n", Status, Vacb); + return Status; } - if (Vacb->MappedCount == 0) + + ASSERT(((ULONG_PTR)Vacb->BaseAddress % PAGE_SIZE) == 0); + ASSERT((ULONG_PTR)Vacb->BaseAddress > (ULONG_PTR)MmSystemRangeStart); + + /* Create a virtual mapping for this memory area */ + NumberOfPages = BYTES_TO_PAGES(VACB_MAPPING_GRANULARITY); + for (i = 0; i < NumberOfPages; i++) { - CcRosVacbDecRefCount(Vacb); - } + PFN_NUMBER PageFrameNumber; - KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); - KeReleaseGuardedMutex(&ViewLock); - KeReleaseMutex(&Vacb->Mutex, FALSE); + MI_SET_USAGE(MI_USAGE_CACHE); + Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &PageFrameNumber); + if (PageFrameNumber == 0) + { + DPRINT1("Unable to allocate page\n"); + KeBugCheck(MEMORY_MANAGEMENT); + } + + Status = MmCreateVirtualMapping(NULL, + (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i * PAGE_SIZE)), + PAGE_READWRITE, + &PageFrameNumber, + 1); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Unable to create virtual mapping\n"); + KeBugCheck(MEMORY_MANAGEMENT); + } + } return STATUS_SUCCESS; } @@ -584,7 +678,7 @@ static NTSTATUS CcRosCreateVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, - ULONG FileOffset, + LONGLONG FileOffset, PROS_VACB *Vacb) { PROS_VACB current; @@ -597,13 +691,14 @@ CcRosCreateVacb ( DPRINT("CcRosCreateVacb()\n"); - if (FileOffset >= SharedCacheMap->FileSize.u.LowPart) + if (FileOffset >= SharedCacheMap->SectionSize.QuadPart) { *Vacb = NULL; return STATUS_INVALID_PARAMETER; } current = ExAllocateFromNPagedLookasideList(&VacbLookasideList); + current->BaseAddress = NULL; current->Valid = FALSE; current->Dirty = FALSE; current->PageOut = FALSE; @@ -618,13 +713,10 @@ CcRosCreateVacb ( current->MappedCount = 0; current->DirtyVacbListEntry.Flink = NULL; current->DirtyVacbListEntry.Blink = NULL; - current->ReferenceCount = 1; + current->ReferenceCount = 0; + current->PinCount = 0; KeInitializeMutex(¤t->Mutex, 0); - KeWaitForSingleObject(¤t->Mutex, - Executive, - KernelMode, - FALSE, - NULL); + CcRosAcquireVacbLock(current, NULL); KeAcquireGuardedMutex(&ViewLock); *Vacb = current; @@ -656,15 +748,11 @@ CcRosCreateVacb ( current); } #endif - KeReleaseMutex(&(*Vacb)->Mutex, FALSE); + CcRosReleaseVacbLock(*Vacb); KeReleaseGuardedMutex(&ViewLock); ExFreeToNPagedLookasideList(&VacbLookasideList, *Vacb); *Vacb = current; - KeWaitForSingleObject(¤t->Mutex, - Executive, - KernelMode, - FALSE, - NULL); + CcRosAcquireVacbLock(current, NULL); return STATUS_SUCCESS; } if (current->FileOffset.QuadPart < FileOffset) @@ -688,119 +776,50 @@ CcRosCreateVacb ( InsertHeadList(&SharedCacheMap->CacheMapVacbListHead, ¤t->CacheMapVacbListEntry); } KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); - InsertTailList(&VacbListHead, ¤t->VacbListEntry); InsertTailList(&VacbLruListHead, ¤t->VacbLruListEntry); + CcRosVacbIncRefCount(current); KeReleaseGuardedMutex(&ViewLock); - MmLockAddressSpace(MmGetKernelAddressSpace()); - current->BaseAddress = NULL; - Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), - 0, // nothing checks for VACB mareas, so set to 0 - ¤t->BaseAddress, - VACB_MAPPING_GRANULARITY, - PAGE_READWRITE, - (PMEMORY_AREA*)¤t->MemoryArea, - FALSE, - 0, - PAGE_SIZE); - MmUnlockAddressSpace(MmGetKernelAddressSpace()); - if (!NT_SUCCESS(Status)) - { - KeBugCheck(CACHE_MANAGER); - } - - /* Create a virtual mapping for this memory area */ MI_SET_USAGE(MI_USAGE_CACHE); #if MI_TRACE_PFNS - PWCHAR pos = NULL; - ULONG len = 0; if ((SharedCacheMap->FileObject) && (SharedCacheMap->FileObject->FileName.Buffer)) { + PWCHAR pos; + ULONG len = 0; pos = wcsrchr(SharedCacheMap->FileObject->FileName.Buffer, '\\'); - len = wcslen(pos) * sizeof(WCHAR); - if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos); - } -#endif - - MmMapMemoryArea(current->BaseAddress, VACB_MAPPING_GRANULARITY, - MC_CACHE, PAGE_READWRITE); - - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -CcRosGetVacbChain ( - PROS_SHARED_CACHE_MAP SharedCacheMap, - ULONG FileOffset, - ULONG Length, - PROS_VACB *Vacb) -{ - PROS_VACB current; - ULONG i; - PROS_VACB *VacbList; - PROS_VACB Previous = NULL; - - ASSERT(SharedCacheMap); - - DPRINT("CcRosGetVacbChain()\n"); - - Length = ROUND_UP(Length, VACB_MAPPING_GRANULARITY); - - VacbList = _alloca(sizeof(PROS_VACB) * - (Length / VACB_MAPPING_GRANULARITY)); - - /* - * Look for a VACB already mapping the same data. - */ - for (i = 0; i < (Length / VACB_MAPPING_GRANULARITY); i++) - { - ULONG CurrentOffset = FileOffset + (i * VACB_MAPPING_GRANULARITY); - current = CcRosLookupVacb(SharedCacheMap, CurrentOffset); - if (current != NULL) + if (pos) { - KeAcquireGuardedMutex(&ViewLock); - - /* Move to tail of LRU list */ - RemoveEntryList(¤t->VacbLruListEntry); - InsertTailList(&VacbLruListHead, ¤t->VacbLruListEntry); - - KeReleaseGuardedMutex(&ViewLock); - - VacbList[i] = current; + len = wcslen(pos) * sizeof(WCHAR); + snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos); } else { - CcRosCreateVacb(SharedCacheMap, CurrentOffset, ¤t); - VacbList[i] = current; + snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%wZ", &SharedCacheMap->FileObject->FileName); } } +#endif - for (i = 0; i < Length / VACB_MAPPING_GRANULARITY; i++) + Status = CcRosMapVacbInKernelSpace(current); + if (!NT_SUCCESS(Status)) { - if (i == 0) - { - *Vacb = VacbList[i]; - Previous = VacbList[i]; - } - else - { - Previous->NextInChain = VacbList[i]; - Previous = VacbList[i]; - } + RemoveEntryList(¤t->CacheMapVacbListEntry); + RemoveEntryList(¤t->VacbLruListEntry); + CcRosReleaseVacbLock(current); + ExFreeToNPagedLookasideList(&VacbLookasideList, current); } - ASSERT(Previous); - Previous->NextInChain = NULL; - return STATUS_SUCCESS; + /* Reference it to allow release */ + CcRosVacbIncRefCount(current); + + return Status; } NTSTATUS NTAPI CcRosGetVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, - ULONG FileOffset, - PULONGLONG BaseOffset, + LONGLONG FileOffset, + PLONGLONG BaseOffset, PVOID* BaseAddress, PBOOLEAN UptoDate, PROS_VACB *Vacb) @@ -851,7 +870,7 @@ NTSTATUS NTAPI CcRosRequestVacb ( PROS_SHARED_CACHE_MAP SharedCacheMap, - ULONG FileOffset, + LONGLONG FileOffset, PVOID* BaseAddress, PBOOLEAN UptoDate, PROS_VACB *Vacb) @@ -859,13 +878,13 @@ CcRosRequestVacb ( * FUNCTION: Request a page mapping for a shared cache map */ { - ULONGLONG BaseOffset; + LONGLONG BaseOffset; ASSERT(SharedCacheMap); if (FileOffset % VACB_MAPPING_GRANULARITY != 0) { - DPRINT1("Bad fileoffset %x should be multiple of %x", + DPRINT1("Bad fileoffset %I64x should be multiple of %x", FileOffset, VACB_MAPPING_GRANULARITY); KeBugCheck(CACHE_MANAGER); } @@ -918,6 +937,17 @@ CcRosInternalFreeVacb ( NULL); MmUnlockAddressSpace(MmGetKernelAddressSpace()); + if (Vacb->PinCount != 0 || Vacb->ReferenceCount != 0) + { + DPRINT1("Invalid free: %ld, %ld\n", Vacb->ReferenceCount, Vacb->PinCount); + if (Vacb->SharedCacheMap->FileObject && Vacb->SharedCacheMap->FileObject->FileName.Length) + { + DPRINT1("For file: %wZ\n", &Vacb->SharedCacheMap->FileObject->FileName); + } + } + + ASSERT(Vacb->PinCount == 0); + ASSERT(Vacb->ReferenceCount == 0); ExFreeToNPagedLookasideList(&VacbLookasideList, Vacb); return STATUS_SUCCESS; } @@ -935,9 +965,12 @@ CcFlushCache ( { PROS_SHARED_CACHE_MAP SharedCacheMap; LARGE_INTEGER Offset; + LONGLONG RemainingLength; PROS_VACB current; NTSTATUS Status; - KIRQL oldIrql; + + CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p FileOffset=%p Length=%lu\n", + SectionObjectPointers, FileOffset, Length); DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %lu, IoStatus 0x%p)\n", SectionObjectPointers, FileOffset, Length, IoStatus); @@ -949,11 +982,12 @@ CcFlushCache ( if (FileOffset) { Offset = *FileOffset; + RemainingLength = Length; } else { - Offset.QuadPart = (LONGLONG)0; - Length = SharedCacheMap->FileSize.u.LowPart; + Offset.QuadPart = 0; + RemainingLength = SharedCacheMap->FileSize.QuadPart; } if (IoStatus) @@ -962,9 +996,9 @@ CcFlushCache ( IoStatus->Information = 0; } - while (Length > 0) + while (RemainingLength > 0) { - current = CcRosLookupVacb(SharedCacheMap, Offset.u.LowPart); + current = CcRosLookupVacb(SharedCacheMap, Offset.QuadPart); if (current != NULL) { if (current->Dirty) @@ -975,24 +1009,12 @@ CcFlushCache ( IoStatus->Status = Status; } } - KeReleaseMutex(¤t->Mutex, FALSE); - KeAcquireGuardedMutex(&ViewLock); - KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); - CcRosVacbDecRefCount(current); - KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); - KeReleaseGuardedMutex(&ViewLock); + CcRosReleaseVacb(SharedCacheMap, current, current->Valid, current->Dirty, FALSE); } Offset.QuadPart += VACB_MAPPING_GRANULARITY; - if (Length > VACB_MAPPING_GRANULARITY) - { - Length -= VACB_MAPPING_GRANULARITY; - } - else - { - Length = 0; - } + RemainingLength -= min(RemainingLength, VACB_MAPPING_GRANULARITY); } } else @@ -1020,15 +1042,17 @@ CcRosDeleteFileCache ( ASSERT(SharedCacheMap); - SharedCacheMap->RefCount++; + SharedCacheMap->OpenCount++; KeReleaseGuardedMutex(&ViewLock); CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL); KeAcquireGuardedMutex(&ViewLock); - SharedCacheMap->RefCount--; - if (SharedCacheMap->RefCount == 0) + SharedCacheMap->OpenCount--; + if (SharedCacheMap->OpenCount == 0) { + KIRQL OldIrql; + FileObject->SectionObjectPointer->SharedCacheMap = NULL; /* @@ -1039,16 +1063,22 @@ CcRosDeleteFileCache ( while (!IsListEmpty(&SharedCacheMap->CacheMapVacbListHead)) { current_entry = RemoveTailList(&SharedCacheMap->CacheMapVacbListHead); + KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); + current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry); - RemoveEntryList(¤t->VacbListEntry); + CcRosAcquireVacbLock(current, NULL); RemoveEntryList(¤t->VacbLruListEntry); if (current->Dirty) { - RemoveEntryList(¤t->DirtyVacbListEntry); - DirtyPageCount -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; + KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); + CcRosUnmarkDirtyVacb(current, FALSE); + KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); DPRINT1("Freeing dirty VACB\n"); } InsertHeadList(&FreeList, ¤t->CacheMapVacbListEntry); + CcRosReleaseVacbLock(current); + + KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); } #if DBG SharedCacheMap->Trace = FALSE; @@ -1062,8 +1092,14 @@ CcRosDeleteFileCache ( { current_entry = RemoveTailList(&FreeList); current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry); + CcRosVacbDecRefCount(current); CcRosInternalFreeVacb(current); } + + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + RemoveEntryList(&SharedCacheMap->SharedCacheMapLinks); + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap); KeAcquireGuardedMutex(&ViewLock); } @@ -1079,8 +1115,8 @@ CcRosReferenceCache ( KeAcquireGuardedMutex(&ViewLock); SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; ASSERT(SharedCacheMap); - ASSERT(SharedCacheMap->RefCount != 0); - SharedCacheMap->RefCount++; + ASSERT(SharedCacheMap->OpenCount != 0); + SharedCacheMap->OpenCount++; KeReleaseGuardedMutex(&ViewLock); } @@ -1093,7 +1129,7 @@ CcRosRemoveIfClosed ( DPRINT("CcRosRemoveIfClosed()\n"); KeAcquireGuardedMutex(&ViewLock); SharedCacheMap = SectionObjectPointer->SharedCacheMap; - if (SharedCacheMap && SharedCacheMap->RefCount == 0) + if (SharedCacheMap && SharedCacheMap->OpenCount == 0) { CcRosDeleteFileCache(SharedCacheMap->FileObject, SharedCacheMap); } @@ -1110,10 +1146,10 @@ CcRosDereferenceCache ( KeAcquireGuardedMutex(&ViewLock); SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; ASSERT(SharedCacheMap); - if (SharedCacheMap->RefCount > 0) + if (SharedCacheMap->OpenCount > 0) { - SharedCacheMap->RefCount--; - if (SharedCacheMap->RefCount == 0) + SharedCacheMap->OpenCount--; + if (SharedCacheMap->OpenCount == 0) { MmFreeSectionSegments(SharedCacheMap->FileObject); CcRosDeleteFileCache(FileObject, SharedCacheMap); @@ -1131,6 +1167,8 @@ CcRosReleaseFileCache ( * has been closed. */ { + KIRQL OldIrql; + PPRIVATE_CACHE_MAP PrivateMap; PROS_SHARED_CACHE_MAP SharedCacheMap; KeAcquireGuardedMutex(&ViewLock); @@ -1138,13 +1176,38 @@ CcRosReleaseFileCache ( if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) { SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - if (FileObject->PrivateCacheMap != NULL) + + /* Closing the handle, so kill the private cache map + * Before you event try to remove it from FO, always + * lock the master lock, to be sure not to race + * with a potential read ahead ongoing! + */ + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + PrivateMap = FileObject->PrivateCacheMap; + FileObject->PrivateCacheMap = NULL; + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + + if (PrivateMap != NULL) { - FileObject->PrivateCacheMap = NULL; - if (SharedCacheMap->RefCount > 0) + /* Remove it from the file */ + KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); + RemoveEntryList(&PrivateMap->PrivateLinks); + KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); + + /* And free it. */ + if (PrivateMap != &SharedCacheMap->PrivateCacheMap) + { + ExFreePoolWithTag(PrivateMap, TAG_PRIVATE_CACHE_MAP); + } + else { - SharedCacheMap->RefCount--; - if (SharedCacheMap->RefCount == 0) + PrivateMap->NodeTypeCode = 0; + } + + if (SharedCacheMap->OpenCount > 0) + { + SharedCacheMap->OpenCount--; + if (SharedCacheMap->OpenCount == 0) { MmFreeSectionSegments(SharedCacheMap->FileObject); CcRosDeleteFileCache(FileObject, SharedCacheMap); @@ -1156,85 +1219,107 @@ CcRosReleaseFileCache ( return STATUS_SUCCESS; } -NTSTATUS -NTAPI -CcTryToInitializeFileCache ( - PFILE_OBJECT FileObject) -{ - PROS_SHARED_CACHE_MAP SharedCacheMap; - NTSTATUS Status; - - KeAcquireGuardedMutex(&ViewLock); - - ASSERT(FileObject->SectionObjectPointer); - SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; - if (SharedCacheMap == NULL) - { - Status = STATUS_UNSUCCESSFUL; - } - else - { - if (FileObject->PrivateCacheMap == NULL) - { - FileObject->PrivateCacheMap = SharedCacheMap; - SharedCacheMap->RefCount++; - } - Status = STATUS_SUCCESS; - } - KeReleaseGuardedMutex(&ViewLock); - - return Status; -} - - NTSTATUS NTAPI CcRosInitializeFileCache ( PFILE_OBJECT FileObject, + PCC_FILE_SIZES FileSizes, + BOOLEAN PinAccess, PCACHE_MANAGER_CALLBACKS CallBacks, PVOID LazyWriterContext) /* * FUNCTION: Initializes a shared cache map for a file object */ { + KIRQL OldIrql; + BOOLEAN Allocated; PROS_SHARED_CACHE_MAP SharedCacheMap; SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; DPRINT("CcRosInitializeFileCache(FileObject 0x%p, SharedCacheMap 0x%p)\n", FileObject, SharedCacheMap); + Allocated = FALSE; KeAcquireGuardedMutex(&ViewLock); if (SharedCacheMap == NULL) { + Allocated = TRUE; SharedCacheMap = ExAllocateFromNPagedLookasideList(&SharedCacheMapLookasideList); if (SharedCacheMap == NULL) { KeReleaseGuardedMutex(&ViewLock); - return STATUS_UNSUCCESSFUL; + return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(SharedCacheMap, sizeof(*SharedCacheMap)); ObReferenceObjectByPointer(FileObject, FILE_ALL_ACCESS, NULL, KernelMode); + SharedCacheMap->NodeTypeCode = NODE_TYPE_SHARED_MAP; + SharedCacheMap->NodeByteSize = sizeof(*SharedCacheMap); SharedCacheMap->FileObject = FileObject; SharedCacheMap->Callbacks = CallBacks; SharedCacheMap->LazyWriteContext = LazyWriterContext; - if (FileObject->FsContext) - { - SharedCacheMap->SectionSize = - ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->AllocationSize; - SharedCacheMap->FileSize = - ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize; - } + SharedCacheMap->SectionSize = FileSizes->AllocationSize; + SharedCacheMap->FileSize = FileSizes->FileSize; + SharedCacheMap->PinAccess = PinAccess; + SharedCacheMap->DirtyPageThreshold = 0; + SharedCacheMap->DirtyPages = 0; + InitializeListHead(&SharedCacheMap->PrivateList); KeInitializeSpinLock(&SharedCacheMap->CacheMapLock); InitializeListHead(&SharedCacheMap->CacheMapVacbListHead); FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap; + + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + InsertTailList(&CcCleanSharedCacheMapList, &SharedCacheMap->SharedCacheMapLinks); + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); } if (FileObject->PrivateCacheMap == NULL) { - FileObject->PrivateCacheMap = SharedCacheMap; - SharedCacheMap->RefCount++; + PPRIVATE_CACHE_MAP PrivateMap; + + /* Allocate the private cache map for this handle */ + if (SharedCacheMap->PrivateCacheMap.NodeTypeCode != 0) + { + PrivateMap = ExAllocatePoolWithTag(NonPagedPool, sizeof(PRIVATE_CACHE_MAP), TAG_PRIVATE_CACHE_MAP); + } + else + { + PrivateMap = &SharedCacheMap->PrivateCacheMap; + } + + if (PrivateMap == NULL) + { + /* If we also allocated the shared cache map for this file, kill it */ + if (Allocated) + { + OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); + RemoveEntryList(&SharedCacheMap->SharedCacheMapLinks); + KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); + + FileObject->SectionObjectPointer->SharedCacheMap = NULL; + ObDereferenceObject(FileObject); + ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap); + } + + KeReleaseGuardedMutex(&ViewLock); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Initialize it */ + RtlZeroMemory(PrivateMap, sizeof(PRIVATE_CACHE_MAP)); + PrivateMap->NodeTypeCode = NODE_TYPE_PRIVATE_MAP; + PrivateMap->ReadAheadMask = PAGE_SIZE - 1; + PrivateMap->FileObject = FileObject; + KeInitializeSpinLock(&PrivateMap->ReadAheadSpinLock); + + /* Link it to the file */ + KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); + InsertTailList(&SharedCacheMap->PrivateList, &PrivateMap->PrivateLinks); + KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); + + FileObject->PrivateCacheMap = PrivateMap; + SharedCacheMap->OpenCount++; } KeReleaseGuardedMutex(&ViewLock); @@ -1250,6 +1335,9 @@ CcGetFileObjectFromSectionPtrs ( IN PSECTION_OBJECT_POINTERS SectionObjectPointers) { PROS_SHARED_CACHE_MAP SharedCacheMap; + + CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p\n", SectionObjectPointers); + if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap) { SharedCacheMap = SectionObjectPointers->SharedCacheMap; @@ -1267,9 +1355,11 @@ CcInitView ( { DPRINT("CcInitView()\n"); - InitializeListHead(&VacbListHead); InitializeListHead(&DirtyVacbListHead); InitializeListHead(&VacbLruListHead); + InitializeListHead(&CcDeferredWrites); + InitializeListHead(&CcCleanSharedCacheMapList); + KeInitializeSpinLock(&CcDeferredWriteSpinLock); KeInitializeGuardedMutex(&ViewLock); ExInitializeNPagedLookasideList(&iBcbLookasideList, NULL, @@ -1298,4 +1388,93 @@ CcInitView ( CcInitCacheZeroPage(); } +#if DBG && defined(KDBG) +BOOLEAN +ExpKdbgExtFileCache(ULONG Argc, PCHAR Argv[]) +{ + PLIST_ENTRY ListEntry; + UNICODE_STRING NoName = RTL_CONSTANT_STRING(L"No name for File"); + + KdbpPrint(" Usage Summary (in kb)\n"); + KdbpPrint("Shared\t\tValid\tDirty\tName\n"); + /* No need to lock the spin lock here, we're in DBG */ + for (ListEntry = CcCleanSharedCacheMapList.Flink; + ListEntry != &CcCleanSharedCacheMapList; + ListEntry = ListEntry->Flink) + { + PLIST_ENTRY Vacbs; + ULONG Valid = 0, Dirty = 0; + PROS_SHARED_CACHE_MAP SharedCacheMap; + PUNICODE_STRING FileName; + + SharedCacheMap = CONTAINING_RECORD(ListEntry, ROS_SHARED_CACHE_MAP, SharedCacheMapLinks); + + /* Dirty size */ + Dirty = (SharedCacheMap->DirtyPages * PAGE_SIZE) / 1024; + + /* First, count for all the associated VACB */ + for (Vacbs = SharedCacheMap->CacheMapVacbListHead.Flink; + Vacbs != &SharedCacheMap->CacheMapVacbListHead; + Vacbs = Vacbs->Flink) + { + PROS_VACB Vacb; + + Vacb = CONTAINING_RECORD(Vacbs, ROS_VACB, CacheMapVacbListEntry); + if (Vacb->Valid) + { + Valid += VACB_MAPPING_GRANULARITY / 1024; + } + } + + /* Setup name */ + if (SharedCacheMap->FileObject != NULL && + SharedCacheMap->FileObject->FileName.Length != 0) + { + FileName = &SharedCacheMap->FileObject->FileName; + } + else + { + FileName = &NoName; + } + + /* And print */ + KdbpPrint("%p\t%d\t%d\t%wZ\n", SharedCacheMap, Valid, Dirty, FileName); + } + + return TRUE; +} + +BOOLEAN +ExpKdbgExtDefWrites(ULONG Argc, PCHAR Argv[]) +{ + KdbpPrint("CcTotalDirtyPages:\t%lu (%lu Kb)\n", CcTotalDirtyPages, + (CcTotalDirtyPages * PAGE_SIZE) / 1024); + KdbpPrint("CcDirtyPageThreshold:\t%lu (%lu Kb)\n", CcDirtyPageThreshold, + (CcDirtyPageThreshold * PAGE_SIZE) / 1024); + KdbpPrint("MmAvailablePages:\t%lu (%lu Kb)\n", MmAvailablePages, + (MmAvailablePages * PAGE_SIZE) / 1024); + KdbpPrint("MmThrottleTop:\t\t%lu (%lu Kb)\n", MmThrottleTop, + (MmThrottleTop * PAGE_SIZE) / 1024); + KdbpPrint("MmThrottleBottom:\t%lu (%lu Kb)\n", MmThrottleBottom, + (MmThrottleBottom * PAGE_SIZE) / 1024); + KdbpPrint("MmModifiedPageListHead.Total:\t%lu (%lu Kb)\n", MmModifiedPageListHead.Total, + (MmModifiedPageListHead.Total * PAGE_SIZE) / 1024); + + if (CcTotalDirtyPages >= CcDirtyPageThreshold) + { + KdbpPrint("CcTotalDirtyPages above the threshold, writes should be throttled\n"); + } + else if (CcTotalDirtyPages + 64 >= CcDirtyPageThreshold) + { + KdbpPrint("CcTotalDirtyPages within 64 (max charge) pages of the threshold, writes may be throttled\n"); + } + else + { + KdbpPrint("CcTotalDirtyPages below the threshold, writes should not be throttled\n"); + } + + return TRUE; +} +#endif + /* EOF */