Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenview.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS kernel 00004 * FILE: ntoskrnl/cc/view.c 00005 * PURPOSE: Cache manager 00006 * 00007 * PROGRAMMERS: David Welch (welch@mcmail.com) 00008 */ 00009 00010 /* NOTES ********************************************************************** 00011 * 00012 * This is not the NT implementation of a file cache nor anything much like 00013 * it. 00014 * 00015 * The general procedure for a filesystem to implement a read or write 00016 * dispatch routine is as follows 00017 * 00018 * (1) If caching for the FCB hasn't been initiated then so do by calling 00019 * CcInitializeFileCache. 00020 * 00021 * (2) For each 4k region which is being read or written obtain a cache page 00022 * by calling CcRequestCachePage. 00023 * 00024 * (3) If either the page is being read or not completely written, and it is 00025 * not up to date then read its data from the underlying medium. If the read 00026 * fails then call CcReleaseCachePage with VALID as FALSE and return a error. 00027 * 00028 * (4) Copy the data into or out of the page as necessary. 00029 * 00030 * (5) Release the cache page 00031 */ 00032 /* INCLUDES ******************************************************************/ 00033 00034 #include <ntoskrnl.h> 00035 #define NDEBUG 00036 #include <debug.h> 00037 00038 #if defined (ALLOC_PRAGMA) 00039 #pragma alloc_text(INIT, CcInitView) 00040 #endif 00041 00042 /* GLOBALS *******************************************************************/ 00043 00044 /* 00045 * If CACHE_BITMAP is defined, the cache manager uses one large memory region 00046 * within the kernel address space and allocate/deallocate space from this block 00047 * over a bitmap. If CACHE_BITMAP is used, the size of the mdl mapping region 00048 * must be reduced (ntoskrnl\mm\mdl.c, MI_MDLMAPPING_REGION_SIZE). 00049 */ 00050 //#define CACHE_BITMAP 00051 00052 static LIST_ENTRY DirtySegmentListHead; 00053 static LIST_ENTRY CacheSegmentListHead; 00054 static LIST_ENTRY CacheSegmentLRUListHead; 00055 static LIST_ENTRY ClosedListHead; 00056 ULONG DirtyPageCount=0; 00057 00058 KGUARDED_MUTEX ViewLock; 00059 00060 #ifdef CACHE_BITMAP 00061 #define CI_CACHESEG_MAPPING_REGION_SIZE (128*1024*1024) 00062 00063 static PVOID CiCacheSegMappingRegionBase = NULL; 00064 static RTL_BITMAP CiCacheSegMappingRegionAllocMap; 00065 static ULONG CiCacheSegMappingRegionHint; 00066 static KSPIN_LOCK CiCacheSegMappingRegionLock; 00067 #endif 00068 00069 NPAGED_LOOKASIDE_LIST iBcbLookasideList; 00070 static NPAGED_LOOKASIDE_LIST BcbLookasideList; 00071 static NPAGED_LOOKASIDE_LIST CacheSegLookasideList; 00072 00073 #if DBG 00074 static void CcRosCacheSegmentIncRefCount_ ( PCACHE_SEGMENT cs, const char* file, int line ) 00075 { 00076 ++cs->ReferenceCount; 00077 if ( cs->Bcb->Trace ) 00078 { 00079 DbgPrint("(%s:%i) CacheSegment %p ++RefCount=%d, Dirty %d, PageOut %d\n", 00080 file, line, cs, cs->ReferenceCount, cs->Dirty, cs->PageOut ); 00081 } 00082 } 00083 static void CcRosCacheSegmentDecRefCount_ ( PCACHE_SEGMENT cs, const char* file, int line ) 00084 { 00085 --cs->ReferenceCount; 00086 if ( cs->Bcb->Trace ) 00087 { 00088 DbgPrint("(%s:%i) CacheSegment %p --RefCount=%d, Dirty %d, PageOut %d\n", 00089 file, line, cs, cs->ReferenceCount, cs->Dirty, cs->PageOut ); 00090 } 00091 } 00092 #define CcRosCacheSegmentIncRefCount(cs) CcRosCacheSegmentIncRefCount_(cs,__FILE__,__LINE__) 00093 #define CcRosCacheSegmentDecRefCount(cs) CcRosCacheSegmentDecRefCount_(cs,__FILE__,__LINE__) 00094 #else 00095 #define CcRosCacheSegmentIncRefCount(cs) (++((cs)->ReferenceCount)) 00096 #define CcRosCacheSegmentDecRefCount(cs) (--((cs)->ReferenceCount)) 00097 #endif 00098 00099 NTSTATUS 00100 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg); 00101 00102 00103 /* FUNCTIONS *****************************************************************/ 00104 00105 VOID 00106 NTAPI 00107 CcRosTraceCacheMap ( 00108 PBCB Bcb, 00109 BOOLEAN Trace ) 00110 { 00111 #if DBG 00112 KIRQL oldirql; 00113 PLIST_ENTRY current_entry; 00114 PCACHE_SEGMENT current; 00115 00116 if ( !Bcb ) 00117 return; 00118 00119 Bcb->Trace = Trace; 00120 00121 if ( Trace ) 00122 { 00123 DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", Bcb ); 00124 00125 KeAcquireGuardedMutex(&ViewLock); 00126 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql); 00127 00128 current_entry = Bcb->BcbSegmentListHead.Flink; 00129 while (current_entry != &Bcb->BcbSegmentListHead) 00130 { 00131 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry); 00132 current_entry = current_entry->Flink; 00133 00134 DPRINT1(" CacheSegment 0x%p enabled, RefCount %d, Dirty %d, PageOut %d\n", 00135 current, current->ReferenceCount, current->Dirty, current->PageOut ); 00136 } 00137 KeReleaseSpinLock(&Bcb->BcbLock, oldirql); 00138 KeReleaseGuardedMutex(&ViewLock); 00139 } 00140 else 00141 { 00142 DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", Bcb ); 00143 } 00144 00145 #else 00146 Bcb = Bcb; 00147 Trace = Trace; 00148 #endif 00149 } 00150 00151 NTSTATUS 00152 NTAPI 00153 CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment) 00154 { 00155 NTSTATUS Status; 00156 KIRQL oldIrql; 00157 00158 Status = WriteCacheSegment(CacheSegment); 00159 if (NT_SUCCESS(Status)) 00160 { 00161 KeAcquireGuardedMutex(&ViewLock); 00162 KeAcquireSpinLock(&CacheSegment->Bcb->BcbLock, &oldIrql); 00163 00164 CacheSegment->Dirty = FALSE; 00165 RemoveEntryList(&CacheSegment->DirtySegmentListEntry); 00166 DirtyPageCount -= CacheSegment->Bcb->CacheSegmentSize / PAGE_SIZE; 00167 CcRosCacheSegmentDecRefCount ( CacheSegment ); 00168 00169 KeReleaseSpinLock(&CacheSegment->Bcb->BcbLock, oldIrql); 00170 KeReleaseGuardedMutex(&ViewLock); 00171 } 00172 00173 return(Status); 00174 } 00175 00176 NTSTATUS 00177 NTAPI 00178 CcRosFlushDirtyPages(ULONG Target, PULONG Count, BOOLEAN Wait) 00179 { 00180 PLIST_ENTRY current_entry; 00181 PCACHE_SEGMENT current; 00182 ULONG PagesPerSegment; 00183 BOOLEAN Locked; 00184 NTSTATUS Status; 00185 LARGE_INTEGER ZeroTimeout; 00186 00187 DPRINT("CcRosFlushDirtyPages(Target %d)\n", Target); 00188 00189 (*Count) = 0; 00190 ZeroTimeout.QuadPart = 0; 00191 00192 KeEnterCriticalRegion(); 00193 KeAcquireGuardedMutex(&ViewLock); 00194 00195 current_entry = DirtySegmentListHead.Flink; 00196 if (current_entry == &DirtySegmentListHead) 00197 { 00198 DPRINT("No Dirty pages\n"); 00199 } 00200 00201 while (current_entry != &DirtySegmentListHead && Target > 0) 00202 { 00203 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 00204 DirtySegmentListEntry); 00205 current_entry = current_entry->Flink; 00206 00207 CcRosCacheSegmentIncRefCount(current); 00208 00209 Locked = current->Bcb->Callbacks->AcquireForLazyWrite( 00210 current->Bcb->LazyWriteContext, Wait); 00211 if (!Locked) 00212 { 00213 CcRosCacheSegmentDecRefCount(current); 00214 continue; 00215 } 00216 00217 Status = KeWaitForSingleObject(¤t->Mutex, 00218 Executive, 00219 KernelMode, 00220 FALSE, 00221 Wait ? NULL : &ZeroTimeout); 00222 if (Status != STATUS_SUCCESS) 00223 { 00224 current->Bcb->Callbacks->ReleaseFromLazyWrite( 00225 current->Bcb->LazyWriteContext); 00226 CcRosCacheSegmentDecRefCount(current); 00227 continue; 00228 } 00229 00230 ASSERT(current->Dirty); 00231 00232 /* One reference is added above */ 00233 if (current->ReferenceCount > 2) 00234 { 00235 KeReleaseMutex(¤t->Mutex, 0); 00236 current->Bcb->Callbacks->ReleaseFromLazyWrite( 00237 current->Bcb->LazyWriteContext); 00238 CcRosCacheSegmentDecRefCount(current); 00239 continue; 00240 } 00241 00242 PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE; 00243 00244 KeReleaseGuardedMutex(&ViewLock); 00245 00246 Status = CcRosFlushCacheSegment(current); 00247 00248 KeReleaseMutex(¤t->Mutex, 0); 00249 current->Bcb->Callbacks->ReleaseFromLazyWrite( 00250 current->Bcb->LazyWriteContext); 00251 00252 KeAcquireGuardedMutex(&ViewLock); 00253 CcRosCacheSegmentDecRefCount(current); 00254 00255 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE)) 00256 { 00257 DPRINT1("CC: Failed to flush cache segment.\n"); 00258 } 00259 else 00260 { 00261 (*Count) += PagesPerSegment; 00262 Target -= PagesPerSegment; 00263 } 00264 00265 current_entry = DirtySegmentListHead.Flink; 00266 } 00267 00268 KeReleaseGuardedMutex(&ViewLock); 00269 KeLeaveCriticalRegion(); 00270 00271 DPRINT("CcRosFlushDirtyPages() finished\n"); 00272 return(STATUS_SUCCESS); 00273 } 00274 00275 NTSTATUS 00276 CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed) 00277 /* 00278 * FUNCTION: Try to free some memory from the file cache. 00279 * ARGUMENTS: 00280 * Target - The number of pages to be freed. 00281 * Priority - The priority of free (currently unused). 00282 * NrFreed - Points to a variable where the number of pages 00283 * actually freed is returned. 00284 */ 00285 { 00286 PLIST_ENTRY current_entry; 00287 PCACHE_SEGMENT current; 00288 ULONG PagesPerSegment; 00289 ULONG PagesFreed; 00290 KIRQL oldIrql; 00291 LIST_ENTRY FreeList; 00292 PFN_NUMBER Page; 00293 ULONG i; 00294 BOOLEAN FlushedPages = FALSE; 00295 00296 DPRINT("CcRosTrimCache(Target %d)\n", Target); 00297 00298 InitializeListHead(&FreeList); 00299 00300 *NrFreed = 0; 00301 00302 retry: 00303 KeAcquireGuardedMutex(&ViewLock); 00304 00305 current_entry = CacheSegmentLRUListHead.Flink; 00306 while (current_entry != &CacheSegmentLRUListHead) 00307 { 00308 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 00309 CacheSegmentLRUListEntry); 00310 current_entry = current_entry->Flink; 00311 00312 KeAcquireSpinLock(¤t->Bcb->BcbLock, &oldIrql); 00313 00314 /* Reference the cache segment */ 00315 CcRosCacheSegmentIncRefCount(current); 00316 00317 /* Check if it's mapped and not dirty */ 00318 if (current->MappedCount > 0 && !current->Dirty) 00319 { 00320 /* We have to break these locks because Cc sucks */ 00321 KeReleaseSpinLock(¤t->Bcb->BcbLock, oldIrql); 00322 KeReleaseGuardedMutex(&ViewLock); 00323 00324 /* Page out the segment */ 00325 for (i = 0; i < current->Bcb->CacheSegmentSize / PAGE_SIZE; i++) 00326 { 00327 Page = (PFN_NUMBER)(MmGetPhysicalAddress((PUCHAR)current->BaseAddress + (i * PAGE_SIZE)).QuadPart >> PAGE_SHIFT); 00328 00329 MmPageOutPhysicalAddress(Page); 00330 } 00331 00332 /* Reacquire the locks */ 00333 KeAcquireGuardedMutex(&ViewLock); 00334 KeAcquireSpinLock(¤t->Bcb->BcbLock, &oldIrql); 00335 } 00336 00337 /* Dereference the cache segment */ 00338 CcRosCacheSegmentDecRefCount(current); 00339 00340 /* Check if we can free this entry now */ 00341 if (current->ReferenceCount == 0) 00342 { 00343 ASSERT(!current->Dirty); 00344 ASSERT(!current->MappedCount); 00345 00346 RemoveEntryList(¤t->BcbSegmentListEntry); 00347 RemoveEntryList(¤t->CacheSegmentListEntry); 00348 RemoveEntryList(¤t->CacheSegmentLRUListEntry); 00349 InsertHeadList(&FreeList, ¤t->BcbSegmentListEntry); 00350 00351 /* Calculate how many pages we freed for Mm */ 00352 PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE; 00353 PagesFreed = min(PagesPerSegment, Target); 00354 Target -= PagesFreed; 00355 (*NrFreed) += PagesFreed; 00356 } 00357 00358 KeReleaseSpinLock(¤t->Bcb->BcbLock, oldIrql); 00359 } 00360 00361 KeReleaseGuardedMutex(&ViewLock); 00362 00363 /* Try flushing pages if we haven't met our target */ 00364 if (Target > 0 && !FlushedPages) 00365 { 00366 /* Flush dirty pages to disk */ 00367 CcRosFlushDirtyPages(Target, &PagesFreed, FALSE); 00368 FlushedPages = TRUE; 00369 00370 /* We can only swap as many pages as we flushed */ 00371 if (PagesFreed < Target) Target = PagesFreed; 00372 00373 /* Check if we flushed anything */ 00374 if (PagesFreed != 0) 00375 { 00376 /* Try again after flushing dirty pages */ 00377 DPRINT("Flushed %d dirty cache pages to disk\n", PagesFreed); 00378 goto retry; 00379 } 00380 } 00381 00382 while (!IsListEmpty(&FreeList)) 00383 { 00384 current_entry = RemoveHeadList(&FreeList); 00385 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 00386 BcbSegmentListEntry); 00387 CcRosInternalFreeCacheSegment(current); 00388 } 00389 00390 DPRINT("Evicted %d cache pages\n", (*NrFreed)); 00391 00392 return(STATUS_SUCCESS); 00393 } 00394 00395 NTSTATUS 00396 NTAPI 00397 CcRosReleaseCacheSegment(PBCB Bcb, 00398 PCACHE_SEGMENT CacheSeg, 00399 BOOLEAN Valid, 00400 BOOLEAN Dirty, 00401 BOOLEAN Mapped) 00402 { 00403 BOOLEAN WasDirty; 00404 KIRQL oldIrql; 00405 00406 ASSERT(Bcb); 00407 00408 DPRINT("CcReleaseCacheSegment(Bcb 0x%p, CacheSeg 0x%p, Valid %d)\n", 00409 Bcb, CacheSeg, Valid); 00410 00411 KeAcquireGuardedMutex(&ViewLock); 00412 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); 00413 00414 CacheSeg->Valid = Valid; 00415 00416 WasDirty = CacheSeg->Dirty; 00417 CacheSeg->Dirty = CacheSeg->Dirty || Dirty; 00418 00419 if (!WasDirty && CacheSeg->Dirty) 00420 { 00421 InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry); 00422 DirtyPageCount += Bcb->CacheSegmentSize / PAGE_SIZE; 00423 } 00424 00425 if (Mapped) 00426 { 00427 CacheSeg->MappedCount++; 00428 } 00429 CcRosCacheSegmentDecRefCount(CacheSeg); 00430 if (Mapped && CacheSeg->MappedCount == 1) 00431 { 00432 CcRosCacheSegmentIncRefCount(CacheSeg); 00433 } 00434 if (!WasDirty && CacheSeg->Dirty) 00435 { 00436 CcRosCacheSegmentIncRefCount(CacheSeg); 00437 } 00438 00439 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); 00440 KeReleaseGuardedMutex(&ViewLock); 00441 KeReleaseMutex(&CacheSeg->Mutex, 0); 00442 00443 return(STATUS_SUCCESS); 00444 } 00445 00446 /* Returns with Cache Segment Lock Held! */ 00447 PCACHE_SEGMENT 00448 NTAPI 00449 CcRosLookupCacheSegment(PBCB Bcb, ULONG FileOffset) 00450 { 00451 PLIST_ENTRY current_entry; 00452 PCACHE_SEGMENT current; 00453 KIRQL oldIrql; 00454 00455 ASSERT(Bcb); 00456 00457 DPRINT("CcRosLookupCacheSegment(Bcb -x%p, FileOffset %d)\n", Bcb, FileOffset); 00458 00459 KeAcquireGuardedMutex(&ViewLock); 00460 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); 00461 00462 current_entry = Bcb->BcbSegmentListHead.Flink; 00463 while (current_entry != &Bcb->BcbSegmentListHead) 00464 { 00465 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 00466 BcbSegmentListEntry); 00467 if (current->FileOffset <= FileOffset && 00468 (current->FileOffset + Bcb->CacheSegmentSize) > FileOffset) 00469 { 00470 CcRosCacheSegmentIncRefCount(current); 00471 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); 00472 KeReleaseGuardedMutex(&ViewLock); 00473 KeWaitForSingleObject(¤t->Mutex, 00474 Executive, 00475 KernelMode, 00476 FALSE, 00477 NULL); 00478 return(current); 00479 } 00480 current_entry = current_entry->Flink; 00481 } 00482 00483 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); 00484 KeReleaseGuardedMutex(&ViewLock); 00485 00486 return(NULL); 00487 } 00488 00489 NTSTATUS 00490 NTAPI 00491 CcRosMarkDirtyCacheSegment(PBCB Bcb, ULONG FileOffset) 00492 { 00493 PCACHE_SEGMENT CacheSeg; 00494 KIRQL oldIrql; 00495 00496 ASSERT(Bcb); 00497 00498 DPRINT("CcRosMarkDirtyCacheSegment(Bcb 0x%p, FileOffset %d)\n", Bcb, FileOffset); 00499 00500 CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset); 00501 if (CacheSeg == NULL) 00502 { 00503 KeBugCheck(CACHE_MANAGER); 00504 } 00505 00506 KeAcquireGuardedMutex(&ViewLock); 00507 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); 00508 00509 if (!CacheSeg->Dirty) 00510 { 00511 InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry); 00512 DirtyPageCount += Bcb->CacheSegmentSize / PAGE_SIZE; 00513 } 00514 else 00515 { 00516 CcRosCacheSegmentDecRefCount(CacheSeg); 00517 } 00518 00519 /* Move to the tail of the LRU list */ 00520 RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry); 00521 InsertTailList(&CacheSegmentLRUListHead, &CacheSeg->CacheSegmentLRUListEntry); 00522 00523 CacheSeg->Dirty = TRUE; 00524 00525 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); 00526 KeReleaseGuardedMutex(&ViewLock); 00527 KeReleaseMutex(&CacheSeg->Mutex, 0); 00528 00529 return(STATUS_SUCCESS); 00530 } 00531 00532 NTSTATUS 00533 NTAPI 00534 CcRosUnmapCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty) 00535 { 00536 PCACHE_SEGMENT CacheSeg; 00537 BOOLEAN WasDirty; 00538 KIRQL oldIrql; 00539 00540 ASSERT(Bcb); 00541 00542 DPRINT("CcRosUnmapCacheSegment(Bcb 0x%p, FileOffset %d, NowDirty %d)\n", 00543 Bcb, FileOffset, NowDirty); 00544 00545 CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset); 00546 if (CacheSeg == NULL) 00547 { 00548 return(STATUS_UNSUCCESSFUL); 00549 } 00550 00551 KeAcquireGuardedMutex(&ViewLock); 00552 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); 00553 00554 WasDirty = CacheSeg->Dirty; 00555 CacheSeg->Dirty = CacheSeg->Dirty || NowDirty; 00556 00557 CacheSeg->MappedCount--; 00558 00559 if (!WasDirty && NowDirty) 00560 { 00561 InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry); 00562 DirtyPageCount += Bcb->CacheSegmentSize / PAGE_SIZE; 00563 } 00564 00565 CcRosCacheSegmentDecRefCount(CacheSeg); 00566 if (!WasDirty && NowDirty) 00567 { 00568 CcRosCacheSegmentIncRefCount(CacheSeg); 00569 } 00570 if (CacheSeg->MappedCount == 0) 00571 { 00572 CcRosCacheSegmentDecRefCount(CacheSeg); 00573 } 00574 00575 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); 00576 KeReleaseGuardedMutex(&ViewLock); 00577 KeReleaseMutex(&CacheSeg->Mutex, 0); 00578 00579 return(STATUS_SUCCESS); 00580 } 00581 00582 static 00583 NTSTATUS 00584 CcRosCreateCacheSegment(PBCB Bcb, 00585 ULONG FileOffset, 00586 PCACHE_SEGMENT* CacheSeg) 00587 { 00588 PCACHE_SEGMENT current; 00589 PCACHE_SEGMENT previous; 00590 PLIST_ENTRY current_entry; 00591 NTSTATUS Status; 00592 KIRQL oldIrql; 00593 #ifdef CACHE_BITMAP 00594 ULONG StartingOffset; 00595 #endif 00596 PHYSICAL_ADDRESS BoundaryAddressMultiple; 00597 00598 ASSERT(Bcb); 00599 00600 DPRINT("CcRosCreateCacheSegment()\n"); 00601 00602 BoundaryAddressMultiple.QuadPart = 0; 00603 if (FileOffset >= Bcb->FileSize.u.LowPart) 00604 { 00605 CacheSeg = NULL; 00606 return STATUS_INVALID_PARAMETER; 00607 } 00608 00609 current = ExAllocateFromNPagedLookasideList(&CacheSegLookasideList); 00610 current->Valid = FALSE; 00611 current->Dirty = FALSE; 00612 current->PageOut = FALSE; 00613 current->FileOffset = ROUND_DOWN(FileOffset, Bcb->CacheSegmentSize); 00614 current->Bcb = Bcb; 00615 #if DBG 00616 if ( Bcb->Trace ) 00617 { 00618 DPRINT1("CacheMap 0x%p: new Cache Segment: 0x%p\n", Bcb, current ); 00619 } 00620 #endif 00621 current->MappedCount = 0; 00622 current->DirtySegmentListEntry.Flink = NULL; 00623 current->DirtySegmentListEntry.Blink = NULL; 00624 current->ReferenceCount = 1; 00625 KeInitializeMutex(¤t->Mutex, 0); 00626 KeWaitForSingleObject(¤t->Mutex, 00627 Executive, 00628 KernelMode, 00629 FALSE, 00630 NULL); 00631 KeAcquireGuardedMutex(&ViewLock); 00632 00633 *CacheSeg = current; 00634 /* There is window between the call to CcRosLookupCacheSegment 00635 * and CcRosCreateCacheSegment. We must check if a segment on 00636 * the fileoffset exist. If there exist a segment, we release 00637 * our new created segment and return the existing one. 00638 */ 00639 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); 00640 current_entry = Bcb->BcbSegmentListHead.Flink; 00641 previous = NULL; 00642 while (current_entry != &Bcb->BcbSegmentListHead) 00643 { 00644 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 00645 BcbSegmentListEntry); 00646 if (current->FileOffset <= FileOffset && 00647 (current->FileOffset + Bcb->CacheSegmentSize) > FileOffset) 00648 { 00649 CcRosCacheSegmentIncRefCount(current); 00650 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); 00651 #if DBG 00652 if ( Bcb->Trace ) 00653 { 00654 DPRINT1("CacheMap 0x%p: deleting newly created Cache Segment 0x%p ( found existing one 0x%p )\n", 00655 Bcb, 00656 (*CacheSeg), 00657 current ); 00658 } 00659 #endif 00660 KeReleaseMutex(&(*CacheSeg)->Mutex, 0); 00661 KeReleaseGuardedMutex(&ViewLock); 00662 ExFreeToNPagedLookasideList(&CacheSegLookasideList, *CacheSeg); 00663 *CacheSeg = current; 00664 KeWaitForSingleObject(¤t->Mutex, 00665 Executive, 00666 KernelMode, 00667 FALSE, 00668 NULL); 00669 return STATUS_SUCCESS; 00670 } 00671 if (current->FileOffset < FileOffset) 00672 { 00673 if (previous == NULL) 00674 { 00675 previous = current; 00676 } 00677 else 00678 { 00679 if (previous->FileOffset < current->FileOffset) 00680 { 00681 previous = current; 00682 } 00683 } 00684 } 00685 current_entry = current_entry->Flink; 00686 } 00687 /* There was no existing segment. */ 00688 current = *CacheSeg; 00689 if (previous) 00690 { 00691 InsertHeadList(&previous->BcbSegmentListEntry, ¤t->BcbSegmentListEntry); 00692 } 00693 else 00694 { 00695 InsertHeadList(&Bcb->BcbSegmentListHead, ¤t->BcbSegmentListEntry); 00696 } 00697 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); 00698 InsertTailList(&CacheSegmentListHead, ¤t->CacheSegmentListEntry); 00699 InsertTailList(&CacheSegmentLRUListHead, ¤t->CacheSegmentLRUListEntry); 00700 KeReleaseGuardedMutex(&ViewLock); 00701 #ifdef CACHE_BITMAP 00702 KeAcquireSpinLock(&CiCacheSegMappingRegionLock, &oldIrql); 00703 00704 StartingOffset = RtlFindClearBitsAndSet(&CiCacheSegMappingRegionAllocMap, Bcb->CacheSegmentSize / PAGE_SIZE, CiCacheSegMappingRegionHint); 00705 00706 if (StartingOffset == 0xffffffff) 00707 { 00708 DPRINT1("Out of CacheSeg mapping space\n"); 00709 KeBugCheck(CACHE_MANAGER); 00710 } 00711 00712 current->BaseAddress = CiCacheSegMappingRegionBase + StartingOffset * PAGE_SIZE; 00713 00714 if (CiCacheSegMappingRegionHint == StartingOffset) 00715 { 00716 CiCacheSegMappingRegionHint += Bcb->CacheSegmentSize / PAGE_SIZE; 00717 } 00718 00719 KeReleaseSpinLock(&CiCacheSegMappingRegionLock, oldIrql); 00720 #else 00721 MmLockAddressSpace(MmGetKernelAddressSpace()); 00722 current->BaseAddress = NULL; 00723 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), 00724 0, // nothing checks for cache_segment mareas, so set to 0 00725 ¤t->BaseAddress, 00726 Bcb->CacheSegmentSize, 00727 PAGE_READWRITE, 00728 (PMEMORY_AREA*)¤t->MemoryArea, 00729 FALSE, 00730 0, 00731 BoundaryAddressMultiple); 00732 MmUnlockAddressSpace(MmGetKernelAddressSpace()); 00733 if (!NT_SUCCESS(Status)) 00734 { 00735 KeBugCheck(CACHE_MANAGER); 00736 } 00737 #endif 00738 00739 /* Create a virtual mapping for this memory area */ 00740 MI_SET_USAGE(MI_USAGE_CACHE); 00741 #if MI_TRACE_PFNS 00742 PWCHAR pos = NULL; 00743 ULONG len = 0; 00744 if ((Bcb->FileObject) && (Bcb->FileObject->FileName.Buffer)) 00745 { 00746 pos = wcsrchr(Bcb->FileObject->FileName.Buffer, '\\'); 00747 len = wcslen(pos) * sizeof(WCHAR); 00748 if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos); 00749 } 00750 #endif 00751 00752 MmMapMemoryArea(current->BaseAddress, Bcb->CacheSegmentSize, 00753 MC_CACHE, PAGE_READWRITE); 00754 00755 return(STATUS_SUCCESS); 00756 } 00757 00758 NTSTATUS 00759 NTAPI 00760 CcRosGetCacheSegmentChain(PBCB Bcb, 00761 ULONG FileOffset, 00762 ULONG Length, 00763 PCACHE_SEGMENT* CacheSeg) 00764 { 00765 PCACHE_SEGMENT current; 00766 ULONG i; 00767 PCACHE_SEGMENT* CacheSegList; 00768 PCACHE_SEGMENT Previous = NULL; 00769 00770 ASSERT(Bcb); 00771 00772 DPRINT("CcRosGetCacheSegmentChain()\n"); 00773 00774 Length = ROUND_UP(Length, Bcb->CacheSegmentSize); 00775 00776 CacheSegList = _alloca(sizeof(PCACHE_SEGMENT) * 00777 (Length / Bcb->CacheSegmentSize)); 00778 00779 /* 00780 * Look for a cache segment already mapping the same data. 00781 */ 00782 for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++) 00783 { 00784 ULONG CurrentOffset = FileOffset + (i * Bcb->CacheSegmentSize); 00785 current = CcRosLookupCacheSegment(Bcb, CurrentOffset); 00786 if (current != NULL) 00787 { 00788 KeAcquireGuardedMutex(&ViewLock); 00789 00790 /* Move to tail of LRU list */ 00791 RemoveEntryList(¤t->CacheSegmentLRUListEntry); 00792 InsertTailList(&CacheSegmentLRUListHead, ¤t->CacheSegmentLRUListEntry); 00793 00794 KeReleaseGuardedMutex(&ViewLock); 00795 00796 CacheSegList[i] = current; 00797 } 00798 else 00799 { 00800 CcRosCreateCacheSegment(Bcb, CurrentOffset, ¤t); 00801 CacheSegList[i] = current; 00802 } 00803 } 00804 00805 for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++) 00806 { 00807 if (i == 0) 00808 { 00809 *CacheSeg = CacheSegList[i]; 00810 Previous = CacheSegList[i]; 00811 } 00812 else 00813 { 00814 Previous->NextInChain = CacheSegList[i]; 00815 Previous = CacheSegList[i]; 00816 } 00817 } 00818 ASSERT(Previous); 00819 Previous->NextInChain = NULL; 00820 00821 return(STATUS_SUCCESS); 00822 } 00823 00824 NTSTATUS 00825 NTAPI 00826 CcRosGetCacheSegment(PBCB Bcb, 00827 ULONG FileOffset, 00828 PULONG BaseOffset, 00829 PVOID* BaseAddress, 00830 PBOOLEAN UptoDate, 00831 PCACHE_SEGMENT* CacheSeg) 00832 { 00833 PCACHE_SEGMENT current; 00834 NTSTATUS Status; 00835 00836 ASSERT(Bcb); 00837 00838 DPRINT("CcRosGetCacheSegment()\n"); 00839 00840 /* 00841 * Look for a cache segment already mapping the same data. 00842 */ 00843 current = CcRosLookupCacheSegment(Bcb, FileOffset); 00844 if (current == NULL) 00845 { 00846 /* 00847 * Otherwise create a new segment. 00848 */ 00849 Status = CcRosCreateCacheSegment(Bcb, FileOffset, ¤t); 00850 if (!NT_SUCCESS(Status)) 00851 { 00852 return Status; 00853 } 00854 } 00855 00856 KeAcquireGuardedMutex(&ViewLock); 00857 00858 /* Move to the tail of the LRU list */ 00859 RemoveEntryList(¤t->CacheSegmentLRUListEntry); 00860 InsertTailList(&CacheSegmentLRUListHead, ¤t->CacheSegmentLRUListEntry); 00861 00862 KeReleaseGuardedMutex(&ViewLock); 00863 00864 /* 00865 * Return information about the segment to the caller. 00866 */ 00867 *UptoDate = current->Valid; 00868 *BaseAddress = current->BaseAddress; 00869 DPRINT("*BaseAddress %p\n", *BaseAddress); 00870 *CacheSeg = current; 00871 *BaseOffset = current->FileOffset; 00872 return(STATUS_SUCCESS); 00873 } 00874 00875 NTSTATUS NTAPI 00876 CcRosRequestCacheSegment(PBCB Bcb, 00877 ULONG FileOffset, 00878 PVOID* BaseAddress, 00879 PBOOLEAN UptoDate, 00880 PCACHE_SEGMENT* CacheSeg) 00881 /* 00882 * FUNCTION: Request a page mapping for a BCB 00883 */ 00884 { 00885 ULONG BaseOffset; 00886 00887 ASSERT(Bcb); 00888 00889 if ((FileOffset % Bcb->CacheSegmentSize) != 0) 00890 { 00891 DPRINT1("Bad fileoffset %x should be multiple of %x", 00892 FileOffset, Bcb->CacheSegmentSize); 00893 KeBugCheck(CACHE_MANAGER); 00894 } 00895 00896 return(CcRosGetCacheSegment(Bcb, 00897 FileOffset, 00898 &BaseOffset, 00899 BaseAddress, 00900 UptoDate, 00901 CacheSeg)); 00902 } 00903 #ifdef CACHE_BITMAP 00904 #else 00905 static VOID 00906 CcFreeCachePage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address, 00907 PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty) 00908 { 00909 ASSERT(SwapEntry == 0); 00910 if (Page != 0) 00911 { 00912 ASSERT(MmGetReferenceCountPage(Page) == 1); 00913 MmReleasePageMemoryConsumer(MC_CACHE, Page); 00914 } 00915 } 00916 #endif 00917 NTSTATUS 00918 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg) 00919 /* 00920 * FUNCTION: Releases a cache segment associated with a BCB 00921 */ 00922 { 00923 #ifdef CACHE_BITMAP 00924 ULONG i; 00925 ULONG RegionSize; 00926 ULONG Base; 00927 PFN_NUMBER Page; 00928 KIRQL oldIrql; 00929 #endif 00930 DPRINT("Freeing cache segment 0x%p\n", CacheSeg); 00931 #if DBG 00932 if ( CacheSeg->Bcb->Trace ) 00933 { 00934 DPRINT1("CacheMap 0x%p: deleting Cache Segment: 0x%p\n", CacheSeg->Bcb, CacheSeg ); 00935 } 00936 #endif 00937 #ifdef CACHE_BITMAP 00938 RegionSize = CacheSeg->Bcb->CacheSegmentSize / PAGE_SIZE; 00939 00940 /* Unmap all the pages. */ 00941 for (i = 0; i < RegionSize; i++) 00942 { 00943 MmDeleteVirtualMapping(NULL, 00944 CacheSeg->BaseAddress + (i * PAGE_SIZE), 00945 FALSE, 00946 NULL, 00947 &Page); 00948 MmReleasePageMemoryConsumer(MC_CACHE, Page); 00949 } 00950 00951 KeAcquireSpinLock(&CiCacheSegMappingRegionLock, &oldIrql); 00952 /* Deallocate all the pages used. */ 00953 Base = (ULONG)(CacheSeg->BaseAddress - CiCacheSegMappingRegionBase) / PAGE_SIZE; 00954 00955 RtlClearBits(&CiCacheSegMappingRegionAllocMap, Base, RegionSize); 00956 00957 CiCacheSegMappingRegionHint = min (CiCacheSegMappingRegionHint, Base); 00958 00959 KeReleaseSpinLock(&CiCacheSegMappingRegionLock, oldIrql); 00960 #else 00961 MmLockAddressSpace(MmGetKernelAddressSpace()); 00962 MmFreeMemoryArea(MmGetKernelAddressSpace(), 00963 CacheSeg->MemoryArea, 00964 CcFreeCachePage, 00965 NULL); 00966 MmUnlockAddressSpace(MmGetKernelAddressSpace()); 00967 #endif 00968 ExFreeToNPagedLookasideList(&CacheSegLookasideList, CacheSeg); 00969 return(STATUS_SUCCESS); 00970 } 00971 00972 NTSTATUS 00973 NTAPI 00974 CcRosFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg) 00975 { 00976 NTSTATUS Status; 00977 KIRQL oldIrql; 00978 00979 ASSERT(Bcb); 00980 00981 DPRINT("CcRosFreeCacheSegment(Bcb 0x%p, CacheSeg 0x%p)\n", 00982 Bcb, CacheSeg); 00983 00984 KeAcquireGuardedMutex(&ViewLock); 00985 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); 00986 RemoveEntryList(&CacheSeg->BcbSegmentListEntry); 00987 RemoveEntryList(&CacheSeg->CacheSegmentListEntry); 00988 RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry); 00989 if (CacheSeg->Dirty) 00990 { 00991 RemoveEntryList(&CacheSeg->DirtySegmentListEntry); 00992 DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE; 00993 00994 } 00995 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); 00996 KeReleaseGuardedMutex(&ViewLock); 00997 00998 Status = CcRosInternalFreeCacheSegment(CacheSeg); 00999 return(Status); 01000 } 01001 01002 /* 01003 * @implemented 01004 */ 01005 VOID NTAPI 01006 CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointers, 01007 IN PLARGE_INTEGER FileOffset OPTIONAL, 01008 IN ULONG Length, 01009 OUT PIO_STATUS_BLOCK IoStatus) 01010 { 01011 PBCB Bcb; 01012 LARGE_INTEGER Offset; 01013 PCACHE_SEGMENT current; 01014 NTSTATUS Status; 01015 KIRQL oldIrql; 01016 01017 DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %d, IoStatus 0x%p)\n", 01018 SectionObjectPointers, FileOffset, Length, IoStatus); 01019 01020 if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap) 01021 { 01022 Bcb = (PBCB)SectionObjectPointers->SharedCacheMap; 01023 ASSERT(Bcb); 01024 if (FileOffset) 01025 { 01026 Offset = *FileOffset; 01027 } 01028 else 01029 { 01030 Offset.QuadPart = (LONGLONG)0; 01031 Length = Bcb->FileSize.u.LowPart; 01032 } 01033 01034 if (IoStatus) 01035 { 01036 IoStatus->Status = STATUS_SUCCESS; 01037 IoStatus->Information = 0; 01038 } 01039 01040 while (Length > 0) 01041 { 01042 current = CcRosLookupCacheSegment (Bcb, Offset.u.LowPart); 01043 if (current != NULL) 01044 { 01045 if (current->Dirty) 01046 { 01047 Status = CcRosFlushCacheSegment(current); 01048 if (!NT_SUCCESS(Status) && IoStatus != NULL) 01049 { 01050 IoStatus->Status = Status; 01051 } 01052 } 01053 KeReleaseMutex(¤t->Mutex, 0); 01054 01055 KeAcquireGuardedMutex(&ViewLock); 01056 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); 01057 CcRosCacheSegmentDecRefCount(current); 01058 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); 01059 KeReleaseGuardedMutex(&ViewLock); 01060 } 01061 01062 Offset.QuadPart += Bcb->CacheSegmentSize; 01063 if (Length > Bcb->CacheSegmentSize) 01064 { 01065 Length -= Bcb->CacheSegmentSize; 01066 } 01067 else 01068 { 01069 Length = 0; 01070 } 01071 } 01072 } 01073 else 01074 { 01075 if (IoStatus) 01076 { 01077 IoStatus->Status = STATUS_INVALID_PARAMETER; 01078 } 01079 } 01080 } 01081 01082 NTSTATUS 01083 NTAPI 01084 CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb) 01085 /* 01086 * FUNCTION: Releases the BCB associated with a file object 01087 */ 01088 { 01089 PLIST_ENTRY current_entry; 01090 PCACHE_SEGMENT current; 01091 LIST_ENTRY FreeList; 01092 KIRQL oldIrql; 01093 01094 ASSERT(Bcb); 01095 01096 Bcb->RefCount++; 01097 KeReleaseGuardedMutex(&ViewLock); 01098 01099 CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL); 01100 01101 KeAcquireGuardedMutex(&ViewLock); 01102 Bcb->RefCount--; 01103 if (Bcb->RefCount == 0) 01104 { 01105 if (Bcb->BcbRemoveListEntry.Flink != NULL) 01106 { 01107 RemoveEntryList(&Bcb->BcbRemoveListEntry); 01108 Bcb->BcbRemoveListEntry.Flink = NULL; 01109 } 01110 01111 FileObject->SectionObjectPointer->SharedCacheMap = NULL; 01112 01113 /* 01114 * Release all cache segments. 01115 */ 01116 InitializeListHead(&FreeList); 01117 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); 01118 current_entry = Bcb->BcbSegmentListHead.Flink; 01119 while (!IsListEmpty(&Bcb->BcbSegmentListHead)) 01120 { 01121 current_entry = RemoveTailList(&Bcb->BcbSegmentListHead); 01122 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry); 01123 RemoveEntryList(¤t->CacheSegmentListEntry); 01124 RemoveEntryList(¤t->CacheSegmentLRUListEntry); 01125 if (current->Dirty) 01126 { 01127 RemoveEntryList(¤t->DirtySegmentListEntry); 01128 DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE; 01129 DPRINT1("Freeing dirty segment\n"); 01130 } 01131 InsertHeadList(&FreeList, ¤t->BcbSegmentListEntry); 01132 } 01133 #if DBG 01134 Bcb->Trace = FALSE; 01135 #endif 01136 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); 01137 01138 KeReleaseGuardedMutex(&ViewLock); 01139 ObDereferenceObject (Bcb->FileObject); 01140 01141 while (!IsListEmpty(&FreeList)) 01142 { 01143 current_entry = RemoveTailList(&FreeList); 01144 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry); 01145 CcRosInternalFreeCacheSegment(current); 01146 } 01147 ExFreeToNPagedLookasideList(&BcbLookasideList, Bcb); 01148 KeAcquireGuardedMutex(&ViewLock); 01149 } 01150 return(STATUS_SUCCESS); 01151 } 01152 01153 VOID 01154 NTAPI 01155 CcRosReferenceCache(PFILE_OBJECT FileObject) 01156 { 01157 PBCB Bcb; 01158 KeAcquireGuardedMutex(&ViewLock); 01159 Bcb = (PBCB)FileObject->SectionObjectPointer->SharedCacheMap; 01160 ASSERT(Bcb); 01161 if (Bcb->RefCount == 0) 01162 { 01163 ASSERT(Bcb->BcbRemoveListEntry.Flink != NULL); 01164 RemoveEntryList(&Bcb->BcbRemoveListEntry); 01165 Bcb->BcbRemoveListEntry.Flink = NULL; 01166 01167 } 01168 else 01169 { 01170 ASSERT(Bcb->BcbRemoveListEntry.Flink == NULL); 01171 } 01172 Bcb->RefCount++; 01173 KeReleaseGuardedMutex(&ViewLock); 01174 } 01175 01176 VOID 01177 NTAPI 01178 CcRosSetRemoveOnClose(PSECTION_OBJECT_POINTERS SectionObjectPointer) 01179 { 01180 PBCB Bcb; 01181 DPRINT("CcRosSetRemoveOnClose()\n"); 01182 KeAcquireGuardedMutex(&ViewLock); 01183 Bcb = (PBCB)SectionObjectPointer->SharedCacheMap; 01184 if (Bcb) 01185 { 01186 Bcb->RemoveOnClose = TRUE; 01187 if (Bcb->RefCount == 0) 01188 { 01189 CcRosDeleteFileCache(Bcb->FileObject, Bcb); 01190 } 01191 } 01192 KeReleaseGuardedMutex(&ViewLock); 01193 } 01194 01195 01196 VOID 01197 NTAPI 01198 CcRosDereferenceCache(PFILE_OBJECT FileObject) 01199 { 01200 PBCB Bcb; 01201 KeAcquireGuardedMutex(&ViewLock); 01202 Bcb = (PBCB)FileObject->SectionObjectPointer->SharedCacheMap; 01203 ASSERT(Bcb); 01204 if (Bcb->RefCount > 0) 01205 { 01206 Bcb->RefCount--; 01207 if (Bcb->RefCount == 0) 01208 { 01209 MmFreeSectionSegments(Bcb->FileObject); 01210 CcRosDeleteFileCache(FileObject, Bcb); 01211 } 01212 } 01213 KeReleaseGuardedMutex(&ViewLock); 01214 } 01215 01216 NTSTATUS NTAPI 01217 CcRosReleaseFileCache(PFILE_OBJECT FileObject) 01218 /* 01219 * FUNCTION: Called by the file system when a handle to a file object 01220 * has been closed. 01221 */ 01222 { 01223 PBCB Bcb; 01224 01225 KeAcquireGuardedMutex(&ViewLock); 01226 01227 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) 01228 { 01229 Bcb = FileObject->SectionObjectPointer->SharedCacheMap; 01230 if (FileObject->PrivateCacheMap != NULL) 01231 { 01232 FileObject->PrivateCacheMap = NULL; 01233 if (Bcb->RefCount > 0) 01234 { 01235 Bcb->RefCount--; 01236 if (Bcb->RefCount == 0) 01237 { 01238 MmFreeSectionSegments(Bcb->FileObject); 01239 CcRosDeleteFileCache(FileObject, Bcb); 01240 } 01241 } 01242 } 01243 } 01244 KeReleaseGuardedMutex(&ViewLock); 01245 return(STATUS_SUCCESS); 01246 } 01247 01248 NTSTATUS 01249 NTAPI 01250 CcTryToInitializeFileCache(PFILE_OBJECT FileObject) 01251 { 01252 PBCB Bcb; 01253 NTSTATUS Status; 01254 01255 KeAcquireGuardedMutex(&ViewLock); 01256 01257 ASSERT(FileObject->SectionObjectPointer); 01258 Bcb = FileObject->SectionObjectPointer->SharedCacheMap; 01259 if (Bcb == NULL) 01260 { 01261 Status = STATUS_UNSUCCESSFUL; 01262 } 01263 else 01264 { 01265 if (FileObject->PrivateCacheMap == NULL) 01266 { 01267 FileObject->PrivateCacheMap = Bcb; 01268 Bcb->RefCount++; 01269 } 01270 if (Bcb->BcbRemoveListEntry.Flink != NULL) 01271 { 01272 RemoveEntryList(&Bcb->BcbRemoveListEntry); 01273 Bcb->BcbRemoveListEntry.Flink = NULL; 01274 } 01275 Status = STATUS_SUCCESS; 01276 } 01277 KeReleaseGuardedMutex(&ViewLock); 01278 01279 return Status; 01280 } 01281 01282 01283 NTSTATUS NTAPI 01284 CcRosInitializeFileCache(PFILE_OBJECT FileObject, 01285 ULONG CacheSegmentSize, 01286 PCACHE_MANAGER_CALLBACKS CallBacks, 01287 PVOID LazyWriterContext) 01288 /* 01289 * FUNCTION: Initializes a BCB for a file object 01290 */ 01291 { 01292 PBCB Bcb; 01293 01294 Bcb = FileObject->SectionObjectPointer->SharedCacheMap; 01295 DPRINT("CcRosInitializeFileCache(FileObject 0x%p, Bcb 0x%p, CacheSegmentSize %d)\n", 01296 FileObject, Bcb, CacheSegmentSize); 01297 01298 KeAcquireGuardedMutex(&ViewLock); 01299 if (Bcb == NULL) 01300 { 01301 Bcb = ExAllocateFromNPagedLookasideList(&BcbLookasideList); 01302 if (Bcb == NULL) 01303 { 01304 KeReleaseGuardedMutex(&ViewLock); 01305 return(STATUS_UNSUCCESSFUL); 01306 } 01307 memset(Bcb, 0, sizeof(BCB)); 01308 ObReferenceObjectByPointer(FileObject, 01309 FILE_ALL_ACCESS, 01310 NULL, 01311 KernelMode); 01312 Bcb->FileObject = FileObject; 01313 Bcb->CacheSegmentSize = CacheSegmentSize; 01314 Bcb->Callbacks = CallBacks; 01315 Bcb->LazyWriteContext = LazyWriterContext; 01316 if (FileObject->FsContext) 01317 { 01318 Bcb->AllocationSize = 01319 ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->AllocationSize; 01320 Bcb->FileSize = 01321 ((PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)->FileSize; 01322 } 01323 KeInitializeSpinLock(&Bcb->BcbLock); 01324 InitializeListHead(&Bcb->BcbSegmentListHead); 01325 FileObject->SectionObjectPointer->SharedCacheMap = Bcb; 01326 } 01327 if (FileObject->PrivateCacheMap == NULL) 01328 { 01329 FileObject->PrivateCacheMap = Bcb; 01330 Bcb->RefCount++; 01331 } 01332 if (Bcb->BcbRemoveListEntry.Flink != NULL) 01333 { 01334 RemoveEntryList(&Bcb->BcbRemoveListEntry); 01335 Bcb->BcbRemoveListEntry.Flink = NULL; 01336 } 01337 KeReleaseGuardedMutex(&ViewLock); 01338 01339 return(STATUS_SUCCESS); 01340 } 01341 01342 /* 01343 * @implemented 01344 */ 01345 PFILE_OBJECT NTAPI 01346 CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointers) 01347 { 01348 PBCB Bcb; 01349 if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap) 01350 { 01351 Bcb = (PBCB)SectionObjectPointers->SharedCacheMap; 01352 ASSERT(Bcb); 01353 return Bcb->FileObject; 01354 } 01355 return NULL; 01356 } 01357 01358 VOID 01359 INIT_FUNCTION 01360 NTAPI 01361 CcInitView(VOID) 01362 { 01363 #ifdef CACHE_BITMAP 01364 PMEMORY_AREA marea; 01365 PVOID Buffer; 01366 PHYSICAL_ADDRESS BoundaryAddressMultiple; 01367 #endif 01368 01369 DPRINT("CcInitView()\n"); 01370 #ifdef CACHE_BITMAP 01371 BoundaryAddressMultiple.QuadPart = 0; 01372 CiCacheSegMappingRegionHint = 0; 01373 CiCacheSegMappingRegionBase = NULL; 01374 01375 MmLockAddressSpace(MmGetKernelAddressSpace()); 01376 01377 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), 01378 MEMORY_AREA_CACHE_SEGMENT, 01379 &CiCacheSegMappingRegionBase, 01380 CI_CACHESEG_MAPPING_REGION_SIZE, 01381 PAGE_READWRITE, 01382 &marea, 01383 FALSE, 01384 0, 01385 BoundaryAddressMultiple); 01386 MmUnlockAddressSpace(MmGetKernelAddressSpace()); 01387 if (!NT_SUCCESS(Status)) 01388 { 01389 KeBugCheck(CACHE_MANAGER); 01390 } 01391 01392 Buffer = ExAllocatePool(NonPagedPool, CI_CACHESEG_MAPPING_REGION_SIZE / (PAGE_SIZE * 8)); 01393 if (!Buffer) 01394 { 01395 KeBugCheck(CACHE_MANAGER); 01396 } 01397 01398 RtlInitializeBitMap(&CiCacheSegMappingRegionAllocMap, Buffer, CI_CACHESEG_MAPPING_REGION_SIZE / PAGE_SIZE); 01399 RtlClearAllBits(&CiCacheSegMappingRegionAllocMap); 01400 01401 KeInitializeSpinLock(&CiCacheSegMappingRegionLock); 01402 #endif 01403 InitializeListHead(&CacheSegmentListHead); 01404 InitializeListHead(&DirtySegmentListHead); 01405 InitializeListHead(&CacheSegmentLRUListHead); 01406 InitializeListHead(&ClosedListHead); 01407 KeInitializeGuardedMutex(&ViewLock); 01408 ExInitializeNPagedLookasideList (&iBcbLookasideList, 01409 NULL, 01410 NULL, 01411 0, 01412 sizeof(INTERNAL_BCB), 01413 TAG_IBCB, 01414 20); 01415 ExInitializeNPagedLookasideList (&BcbLookasideList, 01416 NULL, 01417 NULL, 01418 0, 01419 sizeof(BCB), 01420 TAG_BCB, 01421 20); 01422 ExInitializeNPagedLookasideList (&CacheSegLookasideList, 01423 NULL, 01424 NULL, 01425 0, 01426 sizeof(CACHE_SEGMENT), 01427 TAG_CSEG, 01428 20); 01429 01430 MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache); 01431 01432 CcInitCacheZeroPage(); 01433 01434 } 01435 01436 /* EOF */ 01437 01438 01439 01440 01441 01442 01443 01444 Generated on Sat May 26 2012 04:20:50 for ReactOS by
1.7.6.1
|