From 8aca0dc3709cf8a8eda7aee2d094f7f68a1ccae0 Mon Sep 17 00:00:00 2001 From: Hartmut Birr Date: Wed, 2 Oct 2002 19:20:51 +0000 Subject: [PATCH] Modified some functions, changed the sequence for acquiring some of the protection elements (VieLock, BcbLock, SegmentLock..) and protected the access to some elements with the associated locking element. Implemented CcFlushCache and CcGetFileObjectFromSectionPtrs. svn path=/trunk/; revision=3596 --- reactos/ntoskrnl/cc/view.c | 598 +++++++++++++++++++++++-------------- 1 file changed, 375 insertions(+), 223 deletions(-) diff --git a/reactos/ntoskrnl/cc/view.c b/reactos/ntoskrnl/cc/view.c index 00b3fb293a1..27b53f18f77 100644 --- a/reactos/ntoskrnl/cc/view.c +++ b/reactos/ntoskrnl/cc/view.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: view.c,v 1.52 2002/10/01 19:27:20 chorns Exp $ +/* $Id: view.c,v 1.53 2002/10/02 19:20:51 hbirr Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/cc/view.c @@ -78,7 +78,7 @@ static FAST_MUTEX ViewLock; void * alloca(size_t size); NTSTATUS STDCALL -CcRosInternalFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg); +CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg); /* FUNCTIONS *****************************************************************/ @@ -86,11 +86,17 @@ NTSTATUS STATIC CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment) { NTSTATUS Status; + KIRQL oldIrql; Status = WriteCacheSegment(CacheSegment); if (NT_SUCCESS(Status)) { + ExAcquireFastMutex(&ViewLock); + KeAcquireSpinLock(&CacheSegment->Bcb->BcbLock, &oldIrql); CacheSegment->Dirty = FALSE; RemoveEntryList(&CacheSegment->DirtySegmentListEntry); + CacheSegment->ReferenceCount--; + KeReleaseSpinLock(&CacheSegment->Bcb->BcbLock, oldIrql); + ExReleaseFastMutex(&ViewLock); } return(Status); } @@ -121,24 +127,24 @@ CcRosFlushDirtyPages(ULONG Target, PULONG Count) continue; } assert(current->Dirty); - if (current->ReferenceCount > 0) + if (current->ReferenceCount > 1) { ExReleaseFastMutex(¤t->Lock); continue; } - current->ReferenceCount++; ExReleaseFastMutex(&ViewLock); PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE; Status = CcRosFlushCacheSegment(current); - current->ReferenceCount--; ExReleaseFastMutex(¤t->Lock); if (!NT_SUCCESS(Status)) - { - DPRINT1("CC: Failed to flush cache segment.\n"); - } - (*Count) += PagesPerSegment; - Target -= PagesPerSegment; - + { + DPRINT1("CC: Failed to flush cache segment.\n"); + } + else + { + (*Count) += PagesPerSegment; + Target -= PagesPerSegment; + } ExAcquireFastMutex(&ViewLock); current_entry = DirtySegmentListHead.Flink; } @@ -162,12 +168,15 @@ CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed) PCACHE_SEGMENT current; ULONG PagesPerSegment; ULONG PagesFreed; - BOOLEAN Locked; + KIRQL oldIrql; + LIST_ENTRY FreeList; DPRINT("CcRosTrimCache(Target %d)\n", Target); *NrFreed = 0; - + + InitializeListHead(&FreeList); + ExAcquireFastMutex(&ViewLock); current_entry = CacheSegmentLRUListHead.Flink; while (current_entry != &CacheSegmentLRUListHead && Target > 0) @@ -175,28 +184,35 @@ CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed) current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, CacheSegmentLRUListEntry); current_entry = current_entry->Flink; - Locked = ExTryToAcquireFastMutex(¤t->Lock); - if (!Locked) - { - continue; - } - if (current->MappedCount > 0 || current->Dirty || - current->ReferenceCount > 0) - { - ExReleaseFastMutex(¤t->Lock); - continue; - } - ExReleaseFastMutex(¤t->Lock); - DPRINT("current->Bcb->CacheSegmentSize %d\n", - current->Bcb->CacheSegmentSize); - PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE; - CcRosInternalFreeCacheSegment(current->Bcb, current); - DPRINT("CcRosTrimCache(): Freed %d\n", PagesPerSegment); - PagesFreed = min(PagesPerSegment, Target); - Target = Target - PagesFreed; - (*NrFreed) = (*NrFreed) + PagesFreed; - } + + KeAcquireSpinLock(¤t->Bcb->BcbLock, &oldIrql); + if (current->ReferenceCount == 0) + { + RemoveEntryList(¤t->BcbSegmentListEntry); + KeReleaseSpinLock(¤t->Bcb->BcbLock, oldIrql); + RemoveEntryList(¤t->CacheSegmentListEntry); + RemoveEntryList(¤t->CacheSegmentLRUListEntry); + InsertHeadList(&FreeList, ¤t->BcbSegmentListEntry); + } + else + { + KeReleaseSpinLock(¤t->Bcb->BcbLock, oldIrql); + } + } ExReleaseFastMutex(&ViewLock); + + while (!IsListEmpty(&FreeList)) + { + current_entry = RemoveHeadList(&FreeList); + current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, + BcbSegmentListEntry); + PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE; + PagesFreed = min(PagesPerSegment, Target); + Target -= PagesFreed; + (*NrFreed) += PagesFreed; + CcRosInternalFreeCacheSegment(current); + } + DPRINT("CcRosTrimCache() finished\n"); return(STATUS_SUCCESS); } @@ -209,29 +225,39 @@ CcRosReleaseCacheSegment(PBCB Bcb, BOOLEAN Mapped) { BOOLEAN WasDirty = CacheSeg->Dirty; + KIRQL oldIrql; - DPRINT("CcReleaseCachePage(Bcb %x, CacheSeg %x, Valid %d)\n", + DPRINT("CcReleaseCacheSegment(Bcb %x, CacheSeg %x, Valid %d)\n", Bcb, CacheSeg, Valid); - + CacheSeg->Valid = Valid; CacheSeg->Dirty = CacheSeg->Dirty || Dirty; - if (Mapped) - { - CacheSeg->MappedCount++; - } - ExReleaseFastMutex(&CacheSeg->Lock); + ExAcquireFastMutex(&ViewLock); if (!WasDirty && CacheSeg->Dirty) { InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry); } RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry); - InsertTailList(&CacheSegmentLRUListHead, - &CacheSeg->CacheSegmentLRUListEntry); + InsertTailList(&CacheSegmentLRUListHead, &CacheSeg->CacheSegmentLRUListEntry); + + if (Mapped) + { + CacheSeg->MappedCount++; + } + KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); + CacheSeg->ReferenceCount--; + if (Mapped && CacheSeg->MappedCount == 1) + { + CacheSeg->ReferenceCount++; + } + if (!WasDirty && CacheSeg->Dirty) + { + CacheSeg->ReferenceCount++; + } + KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); ExReleaseFastMutex(&ViewLock); - InterlockedDecrement(&CacheSeg->ReferenceCount); - - DPRINT("CcReleaseCachePage() finished\n"); + ExReleaseFastMutex(&CacheSeg->Lock); return(STATUS_SUCCESS); } @@ -242,6 +268,8 @@ PCACHE_SEGMENT CcRosLookupCacheSegment(PBCB Bcb, ULONG FileOffset) PCACHE_SEGMENT current; KIRQL oldIrql; + DPRINT("CcRosLookupCacheSegment(Bcb %x, FileOffset %d)\n", Bcb, FileOffset); + KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); current_entry = Bcb->BcbSegmentListHead.Flink; while (current_entry != &Bcb->BcbSegmentListHead) @@ -251,6 +279,7 @@ PCACHE_SEGMENT CcRosLookupCacheSegment(PBCB Bcb, ULONG FileOffset) if (current->FileOffset <= FileOffset && (current->FileOffset + Bcb->CacheSegmentSize) > FileOffset) { + current->ReferenceCount++; KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); return(current); } @@ -264,8 +293,10 @@ NTSTATUS CcRosMarkDirtyCacheSegment(PBCB Bcb, ULONG FileOffset) { PCACHE_SEGMENT CacheSeg; + KIRQL oldIrql; + + DPRINT("CcRosMarkDirtyCacheSegment(Bcb %x, FileOffset %d)\n", Bcb, FileOffset); - ExAcquireFastMutex(&ViewLock); CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset); if (CacheSeg == NULL) { @@ -274,40 +305,21 @@ CcRosMarkDirtyCacheSegment(PBCB Bcb, ULONG FileOffset) ExAcquireFastMutex(&CacheSeg->Lock); if (!CacheSeg->Dirty) { + ExAcquireFastMutex(&ViewLock); InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry); + ExReleaseFastMutex(&ViewLock); } + else + { + KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); + CacheSeg->ReferenceCount--; + KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); + } + + CacheSeg->Dirty = TRUE; ExReleaseFastMutex(&CacheSeg->Lock); - ExReleaseFastMutex(&ViewLock); - return(STATUS_SUCCESS); -} -NTSTATUS -CcRosSuggestFreeCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty) -{ - PCACHE_SEGMENT CacheSeg; - - ExAcquireFastMutex(&ViewLock); - CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset); - if (CacheSeg == NULL) - { - KeBugCheck(0); - } - ExAcquireFastMutex(&CacheSeg->Lock); - if (CacheSeg->MappedCount > 0) - { - KeBugCheck(0); - } - CacheSeg->Dirty = CacheSeg->Dirty || NowDirty; - if (CacheSeg->Dirty || CacheSeg->ReferenceCount > 0) - { - ExReleaseFastMutex(&CacheSeg->Lock); - ExReleaseFastMutex(&ViewLock); - return(STATUS_UNSUCCESSFUL); - } - ExReleaseFastMutex(&CacheSeg->Lock); - CcRosInternalFreeCacheSegment(CacheSeg->Bcb, CacheSeg); - ExReleaseFastMutex(&ViewLock); return(STATUS_SUCCESS); } @@ -315,20 +327,43 @@ NTSTATUS CcRosUnmapCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty) { PCACHE_SEGMENT CacheSeg; + BOOLEAN WasDirty; + KIRQL oldIrql; + + DPRINT("CcRosUnmapCacheSegment(Bcb %x, FileOffset %d, NowDirty %d)\n", + Bcb, FileOffset, NowDirty); - ExAcquireFastMutex(&ViewLock); CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset); if (CacheSeg == NULL) { - ExReleaseFastMutex(&ViewLock); return(STATUS_UNSUCCESSFUL); } - CacheSeg->ReferenceCount++; - ExReleaseFastMutex(&ViewLock); ExAcquireFastMutex(&CacheSeg->Lock); - CacheSeg->MappedCount--; + + WasDirty = CacheSeg->Dirty; CacheSeg->Dirty = CacheSeg->Dirty || NowDirty; + + CacheSeg->MappedCount--; + + if (!WasDirty && NowDirty) + { + ExAcquireFastMutex(&ViewLock); + InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry); + ExReleaseFastMutex(&ViewLock); + } + + KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); CacheSeg->ReferenceCount--; + if (!WasDirty && NowDirty) + { + CacheSeg->ReferenceCount++; + } + if (CacheSeg->MappedCount == 0) + { + CacheSeg->ReferenceCount--; + } + KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); + ExReleaseFastMutex(&CacheSeg->Lock); return(STATUS_SUCCESS); } @@ -341,15 +376,66 @@ CcRosCreateCacheSegment(PBCB Bcb, { ULONG i; PCACHE_SEGMENT current; + PLIST_ENTRY current_entry; NTSTATUS Status; KIRQL oldIrql; + DPRINT("CcRosCreateCacheSegment()\n"); + current = ExAllocatePoolWithTag(NonPagedPool, sizeof(CACHE_SEGMENT), - TAG_CSEG); + TAG_CSEG); + current->Valid = FALSE; + current->Dirty = FALSE; + current->FileOffset = ROUND_DOWN(FileOffset, Bcb->CacheSegmentSize); + current->Bcb = Bcb; + current->MappedCount = 0; + current->DirtySegmentListEntry.Flink = NULL; + current->DirtySegmentListEntry.Blink = NULL; + current->ReferenceCount = 1; + ExInitializeFastMutex(¤t->Lock); + ExAcquireFastMutex(¤t->Lock); + ExAcquireFastMutex(&ViewLock); + + *CacheSeg = current; + /* There is window between the call to CcRosLookupCacheSegment + * and CcRosCreateCacheSegment. We must check if a segment on + * the fileoffset exist. If there exist a segment, we release + * our new created segment and return the existing one. + */ + KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); + current_entry = Bcb->BcbSegmentListHead.Flink; + while (current_entry != &Bcb->BcbSegmentListHead) + { + current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, + BcbSegmentListEntry); + if (current->FileOffset <= FileOffset && + (current->FileOffset + Bcb->CacheSegmentSize) > FileOffset) + { + current->ReferenceCount++; + KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); + ExReleaseFastMutex(&(*CacheSeg)->Lock); + ExReleaseFastMutex(&ViewLock); + ExFreePool(*CacheSeg); + *CacheSeg = current; + if (Lock) + { + ExAcquireFastMutex(¤t->Lock); + } + return STATUS_SUCCESS; + } + current_entry = current_entry->Flink; + } + /* There was no existing segment. */ + current = *CacheSeg; + InsertTailList(&Bcb->BcbSegmentListHead, ¤t->BcbSegmentListEntry); + KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); + InsertTailList(&CacheSegmentListHead, ¤t->CacheSegmentListEntry); + InsertTailList(&CacheSegmentLRUListHead, ¤t->CacheSegmentLRUListEntry); + ExReleaseFastMutex(&ViewLock); MmLockAddressSpace(MmGetKernelAddressSpace()); current->BaseAddress = NULL; - Status = MmCreateMemoryArea(KernelMode, + Status = MmCreateMemoryArea(NULL, MmGetKernelAddressSpace(), MEMORY_AREA_CACHE_SEGMENT, ¤t->BaseAddress, @@ -357,53 +443,36 @@ CcRosCreateCacheSegment(PBCB Bcb, PAGE_READWRITE, (PMEMORY_AREA*)¤t->MemoryArea, FALSE); - if (!NT_SUCCESS(Status)) - { - MmUnlockAddressSpace(MmGetKernelAddressSpace()); - KeBugCheck(0); - } MmUnlockAddressSpace(MmGetKernelAddressSpace()); - current->Valid = FALSE; - current->Dirty = FALSE; - current->FileOffset = ROUND_DOWN(FileOffset, Bcb->CacheSegmentSize); - current->Bcb = Bcb; - current->MappedCount = 0; - ExInitializeFastMutex(¤t->Lock); - current->ReferenceCount = 1; - KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); - InsertTailList(&Bcb->BcbSegmentListHead, ¤t->BcbSegmentListEntry); - KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); - InsertTailList(&CacheSegmentListHead, ¤t->CacheSegmentListEntry); - InsertTailList(&CacheSegmentLRUListHead, - ¤t->CacheSegmentLRUListEntry); - current->DirtySegmentListEntry.Flink = - current->DirtySegmentListEntry.Blink = NULL; - if (Lock) - { - ExAcquireFastMutex(¤t->Lock); - } - ExReleaseFastMutex(&ViewLock); + if (!NT_SUCCESS(Status)) + { + KeBugCheck(0); + } for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++) - { - PHYSICAL_ADDRESS Page; + { + PHYSICAL_ADDRESS Page; - Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page); - if (!NT_SUCCESS(Status)) - { - KeBugCheck(0); - } + Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page); + if (!NT_SUCCESS(Status)) + { + KeBugCheck(0); + } - Status = MmCreateVirtualMapping(NULL, - current->BaseAddress + (i * PAGE_SIZE), - PAGE_READWRITE, - Page, - TRUE); - if (!NT_SUCCESS(Status)) - { - KeBugCheck(0); - } - } - *CacheSeg = current; + Status = MmCreateVirtualMapping(NULL, + current->BaseAddress + (i * PAGE_SIZE), + PAGE_READWRITE, + Page, + TRUE); + if (!NT_SUCCESS(Status)) + { + KeBugCheck(0); + } + } + if (!Lock) + { + ExReleaseFastMutex(¤t->Lock); + } + return(STATUS_SUCCESS); } @@ -418,16 +487,13 @@ CcRosGetCacheSegmentChain(PBCB Bcb, PCACHE_SEGMENT* CacheSegList; PCACHE_SEGMENT Previous = NULL; + DPRINT("CcRosGetCacheSegmentChain()\n"); + Length = ROUND_UP(Length, Bcb->CacheSegmentSize); CacheSegList = alloca(sizeof(PCACHE_SEGMENT) * (Length / Bcb->CacheSegmentSize)); - /* - * Acquire the global lock. - */ - ExAcquireFastMutex(&ViewLock); - /* * Look for a cache segment already mapping the same data. */ @@ -437,20 +503,14 @@ CcRosGetCacheSegmentChain(PBCB Bcb, current = CcRosLookupCacheSegment(Bcb, CurrentOffset); if (current != NULL) { - /* - * Make sure the cache segment can't go away outside of our control. - */ - current->ReferenceCount++; CacheSegList[i] = current; } else { CcRosCreateCacheSegment(Bcb, CurrentOffset, ¤t, FALSE); CacheSegList[i] = current; - ExAcquireFastMutex(&ViewLock); } } - ExReleaseFastMutex(&ViewLock); for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++) { @@ -482,47 +542,31 @@ CcRosGetCacheSegment(PBCB Bcb, PCACHE_SEGMENT current; NTSTATUS Status; - /* - * Acquire the global lock. - */ - ExAcquireFastMutex(&ViewLock); + DPRINT("CcRosGetCacheSegment()\n"); /* * Look for a cache segment already mapping the same data. */ current = CcRosLookupCacheSegment(Bcb, FileOffset); if (current != NULL) - { - /* - * Make sure the cache segment can't go away outside of our control. - */ - current->ReferenceCount++; - /* - * Release the global lock and lock the cache segment. - */ - ExReleaseFastMutex(&ViewLock); - ExAcquireFastMutex(¤t->Lock); - /* - * Return information about the segment to the caller. - */ - *UptoDate = current->Valid; - *BaseAddress = current->BaseAddress; - DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress); - *CacheSeg = current; - *BaseOffset = current->FileOffset; - return(STATUS_SUCCESS); - } - + { + ExAcquireFastMutex(¤t->Lock); + } + else + { + /* + * Otherwise create a new segment. + */ + Status = CcRosCreateCacheSegment(Bcb, FileOffset, ¤t, TRUE); + } /* - * Otherwise create a new segment. + * Return information about the segment to the caller. */ - Status = CcRosCreateCacheSegment(Bcb, FileOffset, ¤t, TRUE); *UptoDate = current->Valid; *BaseAddress = current->BaseAddress; DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress); *CacheSeg = current; *BaseOffset = current->FileOffset; - return(STATUS_SUCCESS); } @@ -537,7 +581,7 @@ CcRosRequestCacheSegment(PBCB Bcb, */ { ULONG BaseOffset; - + if ((FileOffset % Bcb->CacheSegmentSize) != 0) { CPRINT("Bad fileoffset %x should be multiple of %x", @@ -565,19 +609,18 @@ CcFreeCachePage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, } NTSTATUS STDCALL -CcRosInternalFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg) +CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg) /* * FUNCTION: Releases a cache segment associated with a BCB */ { + DPRINT("Freeing cache segment %x\n", CacheSeg); - RemoveEntryList(&CacheSeg->CacheSegmentListEntry); - RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry); - RemoveEntryList(&CacheSeg->BcbSegmentListEntry); + MmLockAddressSpace(MmGetKernelAddressSpace()); MmFreeMemoryArea(MmGetKernelAddressSpace(), CacheSeg->BaseAddress, - Bcb->CacheSegmentSize, + CacheSeg->Bcb->CacheSegmentSize, CcFreeCachePage, NULL); MmUnlockAddressSpace(MmGetKernelAddressSpace()); @@ -589,12 +632,101 @@ NTSTATUS STDCALL CcRosFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg) { NTSTATUS Status; + KIRQL oldIrql; + + DPRINT("CcRosFreeCacheSegment(Bcb %x, CacheSeg %x)\n", + Bcb, CacheSeg); + ExAcquireFastMutex(&ViewLock); - Status = CcRosInternalFreeCacheSegment(Bcb, CacheSeg); + KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); + RemoveEntryList(&CacheSeg->BcbSegmentListEntry); + RemoveEntryList(&CacheSeg->CacheSegmentListEntry); + RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry); + if (CacheSeg->Dirty) + { + RemoveEntryList(&CacheSeg->DirtySegmentListEntry); + } + KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); ExReleaseFastMutex(&ViewLock); + + Status = CcRosInternalFreeCacheSegment(CacheSeg); return(Status); } +VOID STDCALL +CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointers, + IN PLARGE_INTEGER FileOffset OPTIONAL, + IN ULONG Length, + OUT PIO_STATUS_BLOCK IoStatus) +{ + PBCB Bcb; + LARGE_INTEGER Offset; + PCACHE_SEGMENT current; + NTSTATUS Status; + KIRQL oldIrql; + + DPRINT("CcFlushCache(SectionObjectPointers %x, FileOffset %x, Length %d, IoStatus %x)\n", + SectionObjectPointers, FileOffset, Length, IoStatus); + + if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap) + { + Bcb = (PBCB)SectionObjectPointers->SharedCacheMap; + if (FileOffset) + { + Offset = *FileOffset; + } + else + { + Offset.QuadPart = 0LL; + Length = Bcb->FileSize.u.LowPart; + } + + if (IoStatus) + { + IoStatus->Status = STATUS_SUCCESS; + IoStatus->Information = 0; + } + + while (Length > 0) + { + current = CcRosLookupCacheSegment (Bcb, Offset.u.LowPart); + if (current != NULL) + { + ExAcquireFastMutex(¤t->Lock); + if (current->Dirty) + { + Status = CcRosFlushCacheSegment(current); + if (!NT_SUCCESS(Status) && IoStatus != NULL) + { + IoStatus->Status = Status; + } + } + ExReleaseFastMutex(¤t->Lock); + KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); + current->ReferenceCount--; + KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); + } + + Offset.QuadPart += Bcb->CacheSegmentSize; + if (Length > Bcb->CacheSegmentSize) + { + Length -= Bcb->CacheSegmentSize; + } + else + { + Length = 0; + } + } + } + else + { + if (IoStatus) + { + IoStatus->Status = STATUS_INVALID_PARAMETER; + } + } +} + NTSTATUS STDCALL CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb) /* @@ -604,72 +736,77 @@ CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb) PLIST_ENTRY current_entry; PCACHE_SEGMENT current; NTSTATUS Status; + LIST_ENTRY FreeList; + KIRQL oldIrql; - DPRINT("CcRosDeleteFileCache(FileObject %x, Bcb %x)\n", Bcb->FileObject, - Bcb); + DPRINT("CcRosDeleteFileCache(FileObject %x, Bcb %x)\n", + Bcb->FileObject, Bcb); - MmFreeSectionSegments(Bcb->FileObject); + ExReleaseFastMutex(&ViewLock); - /* - * Write back dirty cache segments. - */ - current_entry = Bcb->BcbSegmentListHead.Flink; - while (current_entry != &Bcb->BcbSegmentListHead) - { - current = - CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry); - if (current->Dirty) + CcFlushCache(FileObject->SectionObjectPointers, NULL, 0, NULL); + + ExAcquireFastMutex(&ViewLock); + + if (Bcb->RefCount == 0) + { + MmFreeSectionSegments(Bcb->FileObject); + + /* + * Release all cache segments. + */ + InitializeListHead(&FreeList); + + FileObject->SectionObjectPointers->SharedCacheMap = NULL; + KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); + current_entry = Bcb->BcbSegmentListHead.Flink; + while (!IsListEmpty(&Bcb->BcbSegmentListHead)) + { + current_entry = RemoveTailList(&Bcb->BcbSegmentListHead); + current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry); + RemoveEntryList(¤t->CacheSegmentListEntry); + RemoveEntryList(¤t->CacheSegmentLRUListEntry); + if (current->Dirty) { - Status = WriteCacheSegment(current); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to write cache segment (Status %X)\n", Status); - } - ExAcquireFastMutex(&ViewLock); - RemoveEntryList(¤t->DirtySegmentListEntry); - ExReleaseFastMutex(&ViewLock); + RemoveEntryList(¤t->DirtySegmentListEntry); } - current_entry = current_entry->Flink; - } - - /* - * Release all cache segments. - */ - current_entry = Bcb->BcbSegmentListHead.Flink; - while (current_entry != &Bcb->BcbSegmentListHead) - { - current = - CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry); - current_entry = current_entry->Flink; - CcRosFreeCacheSegment(Bcb, current); - } - FileObject->SectionObjectPointers->SharedCacheMap = NULL; - ObDereferenceObject (Bcb->FileObject); - ExFreePool(Bcb); + InsertHeadList(&FreeList, ¤t->BcbSegmentListEntry); + } + KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); + while (!IsListEmpty(&FreeList)) + { + current_entry = RemoveTailList(&FreeList); + current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry); + Status = CcRosInternalFreeCacheSegment(current); + } + + ObDereferenceObject (Bcb->FileObject); + ExFreePool(Bcb); + } return(STATUS_SUCCESS); } VOID CcRosReferenceCache(PFILE_OBJECT FileObject) { - KIRQL oldIrql; - PBCB Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap; - KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); + PBCB Bcb; + ExAcquireFastMutex(&ViewLock); + Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap; Bcb->RefCount++; - KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); + ExReleaseFastMutex(&ViewLock); } VOID CcRosDereferenceCache(PFILE_OBJECT FileObject) { - KIRQL oldIrql; - PBCB Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap; - KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); + PBCB Bcb; + ExAcquireFastMutex(&ViewLock); + Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap; Bcb->RefCount--; - KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); if (Bcb->RefCount == 0) { CcRosDeleteFileCache(FileObject, Bcb); } + ExReleaseFastMutex(&ViewLock); } NTSTATUS STDCALL @@ -679,21 +816,21 @@ CcRosReleaseFileCache(PFILE_OBJECT FileObject, PBCB Bcb) * has been closed. */ { - KIRQL oldIrql; + ExAcquireFastMutex(&ViewLock); + if (FileObject->SectionObjectPointers->SharedCacheMap != NULL) { - KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); if (FileObject->PrivateCacheMap != NULL) { FileObject->PrivateCacheMap = NULL; Bcb->RefCount--; } - KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); if (Bcb->RefCount == 0) { CcRosDeleteFileCache(FileObject, Bcb); } } + ExReleaseFastMutex(&ViewLock); return(STATUS_SUCCESS); } @@ -705,7 +842,11 @@ CcRosInitializeFileCache(PFILE_OBJECT FileObject, * FUNCTION: Initializes a BCB for a file object */ { - KIRQL oldIrql; + DPRINT("CcRosInitializeFileCache(FileObject %x, *Bcb %x, CacheSegmentSize %d)\n", + FileObject, Bcb, CacheSegmentSize); + + ExAcquireFastMutex(&ViewLock); + if (*Bcb == NULL) { (*Bcb) = ExAllocatePoolWithTag(NonPagedPool, sizeof(BCB), TAG_BCB); @@ -731,17 +872,28 @@ CcRosInitializeFileCache(PFILE_OBJECT FileObject, InitializeListHead(&(*Bcb)->BcbSegmentListHead); FileObject->SectionObjectPointers->SharedCacheMap = *Bcb; } - KeAcquireSpinLock(&(*Bcb)->BcbLock, &oldIrql); if (FileObject->PrivateCacheMap == NULL) { FileObject->PrivateCacheMap = *Bcb; (*Bcb)->RefCount++; } - KeReleaseSpinLock(&(*Bcb)->BcbLock, oldIrql); + ExReleaseFastMutex(&ViewLock); return(STATUS_SUCCESS); } +PFILE_OBJECT STDCALL +CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointers) +{ + PBCB Bcb; + if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap) + { + Bcb = (PBCB)SectionObjectPointers->SharedCacheMap; + return Bcb->FileObject; + } + return NULL; +} + VOID CcInitView(VOID) {