Index: ntoskrnl/cc/copy.c =================================================================== --- ntoskrnl/cc/copy.c (revision 58285) +++ ntoskrnl/cc/copy.c (working copy) @@ -336,12 +336,12 @@ PLIST_ENTRY current_entry; PCACHE_SEGMENT current; - DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, " + Bcb = FileObject->SectionObjectPointer->SharedCacheMap; + DPRINT("CcCopyRead(FileObject 0x%p, Bcb 0x%p FileOffset %I64x, " "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n", - FileObject, FileOffset->QuadPart, Length, Wait, + FileObject, Bcb, FileOffset->QuadPart, Length, Wait, Buffer, IoStatus); - Bcb = FileObject->SectionObjectPointer->SharedCacheMap; ReadOffset = (ULONG)FileOffset->QuadPart; DPRINT("AllocationSize %d, FileSize %d\n", Index: ntoskrnl/cc/fs.c =================================================================== --- ntoskrnl/cc/fs.c (revision 58285) +++ ntoskrnl/cc/fs.c (working copy) @@ -86,9 +86,11 @@ ASSERT(FileSizes); /* Call old ROS cache init function */ + KeAcquireGuardedMutex(&ViewLock); CcRosInitializeFileCache(FileObject, /*PAGE_SIZE*/ VACB_MAPPING_GRANULARITY, CallBacks, LazyWriterContext); + KeReleaseGuardedMutex(&ViewLock); } /* @@ -234,12 +236,11 @@ IN PLARGE_INTEGER TruncateSize OPTIONAL, IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL) { -#if 0 - UNIMPLEMENTED; - return FALSE; -#else - return NT_SUCCESS(CcRosReleaseFileCache(FileObject)); -#endif + BOOLEAN Result; + KeAcquireGuardedMutex(&ViewLock); + Result = NT_SUCCESS(CcRosReleaseFileCache(FileObject)); + KeReleaseGuardedMutex(&ViewLock); + return Result; } BOOLEAN Index: ntoskrnl/cc/view.c =================================================================== --- ntoskrnl/cc/view.c (revision 58285) +++ ntoskrnl/cc/view.c (working copy) @@ -70,6 +70,8 @@ static NPAGED_LOOKASIDE_LIST BcbLookasideList; static NPAGED_LOOKASIDE_LIST CacheSegLookasideList; +LIST_ENTRY CcpAllSharedCacheMaps; + #if DBG static void CcRosCacheSegmentIncRefCount_ ( PCACHE_SEGMENT cs, const char* file, int line ) { @@ -1126,60 +1128,51 @@ ASSERT(Bcb); - Bcb->RefCount++; + RemoveEntryList(&Bcb->AllSharedCacheMaps); KeReleaseGuardedMutex(&ViewLock); CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL); KeAcquireGuardedMutex(&ViewLock); - Bcb->RefCount--; - if (Bcb->RefCount == 0) + FileObject->SectionObjectPointer->SharedCacheMap = NULL; + + /* + * Release all cache segments. + */ + InitializeListHead(&FreeList); + KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); + current_entry = Bcb->BcbSegmentListHead.Flink; + while (!IsListEmpty(&Bcb->BcbSegmentListHead)) { - if (Bcb->BcbRemoveListEntry.Flink != NULL) + current_entry = RemoveTailList(&Bcb->BcbSegmentListHead); + current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry); + RemoveEntryList(¤t->CacheSegmentListEntry); + RemoveEntryList(¤t->CacheSegmentLRUListEntry); + if (current->Dirty) { - RemoveEntryList(&Bcb->BcbRemoveListEntry); - Bcb->BcbRemoveListEntry.Flink = NULL; + RemoveEntryList(¤t->DirtySegmentListEntry); + DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE; + ASSERT(FALSE); + DPRINT1("Freeing dirty segment\n"); } - - FileObject->SectionObjectPointer->SharedCacheMap = NULL; - - /* - * Release all cache segments. - */ - InitializeListHead(&FreeList); - 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) - { - RemoveEntryList(¤t->DirtySegmentListEntry); - DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE; - DPRINT1("Freeing dirty segment\n"); - } - InsertHeadList(&FreeList, ¤t->BcbSegmentListEntry); - } + InsertHeadList(&FreeList, ¤t->BcbSegmentListEntry); + } #if DBG - Bcb->Trace = FALSE; + Bcb->Trace = FALSE; #endif - KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); - - KeReleaseGuardedMutex(&ViewLock); - ObDereferenceObject (Bcb->FileObject); - - while (!IsListEmpty(&FreeList)) - { - current_entry = RemoveTailList(&FreeList); - current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry); - CcRosInternalFreeCacheSegment(current); - } - ExFreeToNPagedLookasideList(&BcbLookasideList, Bcb); - KeAcquireGuardedMutex(&ViewLock); + KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); + + KeReleaseGuardedMutex(&ViewLock); + ObDereferenceObject (Bcb->FileObject); + + while (!IsListEmpty(&FreeList)) + { + current_entry = RemoveTailList(&FreeList); + current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry); + CcRosInternalFreeCacheSegment(current); } + ExFreeToNPagedLookasideList(&BcbLookasideList, Bcb); + KeAcquireGuardedMutex(&ViewLock); return(STATUS_SUCCESS); } @@ -1192,17 +1185,6 @@ KeAcquireGuardedMutex(&ViewLock); Bcb = (PBCB)FileObject->SectionObjectPointer->SharedCacheMap; ASSERT(Bcb); - if (Bcb->RefCount == 0) - { - ASSERT(Bcb->BcbRemoveListEntry.Flink != NULL); - RemoveEntryList(&Bcb->BcbRemoveListEntry); - Bcb->BcbRemoveListEntry.Flink = NULL; - - } - else - { - ASSERT(Bcb->BcbRemoveListEntry.Flink == NULL); - } Bcb->RefCount++; KeReleaseGuardedMutex(&ViewLock); } @@ -1221,7 +1203,7 @@ Bcb->RemoveOnClose = TRUE; if (Bcb->RefCount == 0) { - CcRosDeleteFileCache(Bcb->FileObject, Bcb); + CcRosReleaseFileCache(Bcb->FileObject); } } KeReleaseGuardedMutex(&ViewLock); @@ -1237,14 +1219,10 @@ KeAcquireGuardedMutex(&ViewLock); Bcb = (PBCB)FileObject->SectionObjectPointer->SharedCacheMap; ASSERT(Bcb); - if (Bcb->RefCount > 0) + ASSERT(Bcb->RefCount > 0); + if (Bcb->RefCount-- == 0) { - Bcb->RefCount--; - if (Bcb->RefCount == 0) - { - MmFreeSectionSegments(Bcb->FileObject); - CcRosDeleteFileCache(FileObject, Bcb); - } + CcRosReleaseFileCache(FileObject); } KeReleaseGuardedMutex(&ViewLock); } @@ -1258,28 +1236,29 @@ * has been closed. */ { - PBCB Bcb; + PBCB Map = (PBCB)FileObject->SectionObjectPointer->SharedCacheMap; + PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap; - KeAcquireGuardedMutex(&ViewLock); + DPRINT("CcRosReleaseFileCache(Map %p, Private %p)", Map, PrivateCacheMap); - if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) + /* We have a private cache map, so we've been initialized and haven't been + * uninitialized. */ + if (PrivateCacheMap) { - Bcb = FileObject->SectionObjectPointer->SharedCacheMap; - if (FileObject->PrivateCacheMap != NULL) - { - FileObject->PrivateCacheMap = NULL; - if (Bcb->RefCount > 0) - { - Bcb->RefCount--; - if (Bcb->RefCount == 0) - { - MmFreeSectionSegments(Bcb->FileObject); - CcRosDeleteFileCache(FileObject, Bcb); - } - } - } + ASSERT(!Map || Map == PrivateCacheMap->Map); + Map = PrivateCacheMap->Map; + ASSERT(PrivateCacheMap->FileObject == FileObject); + RemoveEntryList(&PrivateCacheMap->ListEntry); + ObDereferenceObject(PrivateCacheMap->FileObject); + RemoveEntryList(&PrivateCacheMap->Map->AllSharedCacheMaps); + FileObject->PrivateCacheMap = NULL; + ExFreePool(PrivateCacheMap); } - KeReleaseGuardedMutex(&ViewLock); + + if (Map && Map->RefCount == 0 && IsListEmpty(&Map->PrivateCacheMaps)) + { + CcRosDeleteFileCache(FileObject, Map); + } return(STATUS_SUCCESS); } @@ -1301,23 +1280,43 @@ } else { - if (FileObject->PrivateCacheMap == NULL) - { - FileObject->PrivateCacheMap = Bcb; - Bcb->RefCount++; - } - if (Bcb->BcbRemoveListEntry.Flink != NULL) - { - RemoveEntryList(&Bcb->BcbRemoveListEntry); - Bcb->BcbRemoveListEntry.Flink = NULL; - } - Status = STATUS_SUCCESS; + Status = CcRosInitializeFileCache + (FileObject, VACB_MAPPING_GRANULARITY, NULL, NULL); } KeReleaseGuardedMutex(&ViewLock); return Status; } +PFILE_OBJECT CcpFindOtherStreamFileObject(PFILE_OBJECT FileObject) +{ + PLIST_ENTRY Entry, Private; + for (Entry = CcpAllSharedCacheMaps.Flink; + Entry != &CcpAllSharedCacheMaps; + Entry = Entry->Flink) + { + /* 'Identical' test for other stream file object */ + PBCB Map = CONTAINING_RECORD(Entry, BCB, AllSharedCacheMaps); + for (Private = Map->PrivateCacheMaps.Flink; + Private != &Map->PrivateCacheMaps; + Private = Private->Flink) + { + PNOCC_PRIVATE_CACHE_MAP PrivateMap = CONTAINING_RECORD + (Private, NOCC_PRIVATE_CACHE_MAP, ListEntry); + ASSERT(PrivateMap->Map == Map); + if (PrivateMap->FileObject->Flags & FO_STREAM_FILE && + PrivateMap->FileObject->DeviceObject == FileObject->DeviceObject && + PrivateMap->FileObject->Vpb == FileObject->Vpb && + PrivateMap->FileObject->FsContext == FileObject->FsContext && + PrivateMap->FileObject->FsContext2 == FileObject->FsContext2 && + 1) + { + return PrivateMap->FileObject; + } + } + } + return 0; +} NTSTATUS NTAPI @@ -1330,54 +1329,79 @@ * FUNCTION: Initializes a BCB for a file object */ { - PBCB Bcb; + PBCB Map = FileObject->SectionObjectPointer->SharedCacheMap; + PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap; - Bcb = FileObject->SectionObjectPointer->SharedCacheMap; DPRINT("CcRosInitializeFileCache(FileObject 0x%p, Bcb 0x%p, CacheSegmentSize %d)\n", - FileObject, Bcb, CacheSegmentSize); + FileObject, Map, CacheSegmentSize); - KeAcquireGuardedMutex(&ViewLock); - if (Bcb == NULL) + if (!Map && FileObject->Flags & FO_STREAM_FILE) { - Bcb = ExAllocateFromNPagedLookasideList(&BcbLookasideList); - if (Bcb == NULL) + PFILE_OBJECT IdenticalStreamFileObject; + DPRINT("Finding sibling map for Stream File Object %p\n", FileObject); + IdenticalStreamFileObject = CcpFindOtherStreamFileObject(FileObject); + if (IdenticalStreamFileObject) + Map = IdenticalStreamFileObject->SectionObjectPointer->SharedCacheMap; + if (Map) { - KeReleaseGuardedMutex(&ViewLock); + DPRINT("Linking SFO %x to previous SFO %x through cache map %x #\n", + FileObject, + IdenticalStreamFileObject, + Map); + } + } + + if (PrivateCacheMap) + { + FileObject->SectionObjectPointer->SharedCacheMap = PrivateCacheMap->Map; + return STATUS_SUCCESS; + } + + if (Map == NULL) + { + Map = ExAllocateFromNPagedLookasideList(&BcbLookasideList); + if (Map == NULL) + { return(STATUS_UNSUCCESSFUL); } - memset(Bcb, 0, sizeof(BCB)); + memset(Map, 0, sizeof(BCB)); ObReferenceObjectByPointer(FileObject, FILE_ALL_ACCESS, NULL, KernelMode); - Bcb->FileObject = FileObject; - Bcb->CacheSegmentSize = CacheSegmentSize; - Bcb->Callbacks = CallBacks; - Bcb->LazyWriteContext = LazyWriterContext; + Map->FileObject = FileObject; + Map->CacheSegmentSize = CacheSegmentSize; + Map->Callbacks = CallBacks; + Map->LazyWriteContext = LazyWriterContext; if (FileObject->FsContext) { - Bcb->AllocationSize = + Map->AllocationSize = ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->AllocationSize; - Bcb->FileSize = + Map->FileSize = ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize; } - KeInitializeSpinLock(&Bcb->BcbLock); - InitializeListHead(&Bcb->BcbSegmentListHead); - FileObject->SectionObjectPointer->SharedCacheMap = Bcb; + KeInitializeSpinLock(&Map->BcbLock); + InitializeListHead(&Map->PrivateCacheMaps); + InitializeListHead(&Map->BcbSegmentListHead); + InsertTailList(&CcpAllSharedCacheMaps, &Map->AllSharedCacheMaps); + FileObject->SectionObjectPointer->SharedCacheMap = Map; } - if (FileObject->PrivateCacheMap == NULL) + /* We don't have a private cache map. Link it with the shared cache map + to serve as a held reference. When the list in the shared cache map + is empty, we know we can delete it. */ + if (!PrivateCacheMap) { - FileObject->PrivateCacheMap = Bcb; - Bcb->RefCount++; + PrivateCacheMap = ExAllocatePool(NonPagedPool, + sizeof(*PrivateCacheMap)); + FileObject->PrivateCacheMap = PrivateCacheMap; + PrivateCacheMap->FileObject = FileObject; + ObReferenceObject(PrivateCacheMap->FileObject); } - if (Bcb->BcbRemoveListEntry.Flink != NULL) - { - RemoveEntryList(&Bcb->BcbRemoveListEntry); - Bcb->BcbRemoveListEntry.Flink = NULL; - } - KeReleaseGuardedMutex(&ViewLock); - return(STATUS_SUCCESS); + PrivateCacheMap->Map = Map; + InsertTailList(&Map->PrivateCacheMaps, &PrivateCacheMap->ListEntry); + + return STATUS_SUCCESS; } /* @@ -1472,6 +1496,7 @@ 20); MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache); + InitializeListHead(&CcpAllSharedCacheMaps); CcInitCacheZeroPage(); Index: ntoskrnl/include/internal/cc.h =================================================================== --- ntoskrnl/include/internal/cc.h (revision 58285) +++ ntoskrnl/include/internal/cc.h (working copy) @@ -104,7 +104,6 @@ typedef struct _BCB { LIST_ENTRY BcbSegmentListHead; - LIST_ENTRY BcbRemoveListEntry; BOOLEAN RemoveOnClose; ULONG TimeStamp; PFILE_OBJECT FileObject; @@ -118,8 +117,19 @@ #if DBG BOOLEAN Trace; /* enable extra trace output for this BCB and it's cache segments */ #endif + LIST_ENTRY AllSharedCacheMaps; + LIST_ENTRY PrivateCacheMaps; } BCB, *PBCB; +typedef struct _NOCC_PRIVATE_CACHE_MAP +{ + LIST_ENTRY ListEntry; + PFILE_OBJECT FileObject; + PBCB Map; +} NOCC_PRIVATE_CACHE_MAP, *PNOCC_PRIVATE_CACHE_MAP; + +extern LIST_ENTRY CcpAllSharedCacheMaps; + typedef struct _CACHE_SEGMENT { /* Base address of the region where the cache segment data is mapped. */