1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/cc/view.c 5 * PURPOSE: Cache manager 6 * 7 * PROGRAMMERS: David Welch (welch@mcmail.com) 8 * Pierre Schweitzer (pierre@reactos.org) 9 */ 10 11 /* NOTES ********************************************************************** 12 * 13 * This is not the NT implementation of a file cache nor anything much like 14 * it. 15 * 16 * The general procedure for a filesystem to implement a read or write 17 * dispatch routine is as follows 18 * 19 * (1) If caching for the FCB hasn't been initiated then so do by calling 20 * CcInitializeFileCache. 21 * 22 * (2) For each 4k region which is being read or written obtain a cache page 23 * by calling CcRequestCachePage. 24 * 25 * (3) If either the page is being read or not completely written, and it is 26 * not up to date then read its data from the underlying medium. If the read 27 * fails then call CcReleaseCachePage with VALID as FALSE and return a error. 28 * 29 * (4) Copy the data into or out of the page as necessary. 30 * 31 * (5) Release the cache page 32 */ 33 /* INCLUDES ******************************************************************/ 34 35 #include <ntoskrnl.h> 36 #define NDEBUG 37 #include <debug.h> 38 39 #if defined (ALLOC_PRAGMA) 40 #pragma alloc_text(INIT, CcInitView) 41 #endif 42 43 /* GLOBALS *******************************************************************/ 44 45 LIST_ENTRY DirtyVacbListHead; 46 static LIST_ENTRY VacbLruListHead; 47 48 KGUARDED_MUTEX ViewLock; 49 50 NPAGED_LOOKASIDE_LIST iBcbLookasideList; 51 static NPAGED_LOOKASIDE_LIST SharedCacheMapLookasideList; 52 static NPAGED_LOOKASIDE_LIST VacbLookasideList; 53 54 /* Internal vars (MS): 55 * - Threshold above which lazy writer will start action 56 * - Amount of dirty pages 57 * - List for deferred writes 58 * - Spinlock when dealing with the deferred list 59 * - List for "clean" shared cache maps 60 */ 61 ULONG CcDirtyPageThreshold = 0; 62 ULONG CcTotalDirtyPages = 0; 63 LIST_ENTRY CcDeferredWrites; 64 KSPIN_LOCK CcDeferredWriteSpinLock; 65 LIST_ENTRY CcCleanSharedCacheMapList; 66 67 #if DBG 68 ULONG CcRosVacbIncRefCount_(PROS_VACB vacb, PCSTR file, INT line) 69 { 70 ULONG Refs; 71 72 Refs = InterlockedIncrement((PLONG)&vacb->ReferenceCount); 73 if (vacb->SharedCacheMap->Trace) 74 { 75 DbgPrint("(%s:%i) VACB %p ++RefCount=%lu, Dirty %u, PageOut %lu\n", 76 file, line, vacb, Refs, vacb->Dirty, vacb->PageOut); 77 } 78 79 return Refs; 80 } 81 ULONG CcRosVacbDecRefCount_(PROS_VACB vacb, PCSTR file, INT line) 82 { 83 ULONG Refs; 84 85 Refs = InterlockedDecrement((PLONG)&vacb->ReferenceCount); 86 ASSERT(!(Refs == 0 && vacb->Dirty)); 87 if (vacb->SharedCacheMap->Trace) 88 { 89 DbgPrint("(%s:%i) VACB %p --RefCount=%lu, Dirty %u, PageOut %lu\n", 90 file, line, vacb, Refs, vacb->Dirty, vacb->PageOut); 91 } 92 93 return Refs; 94 } 95 ULONG CcRosVacbGetRefCount_(PROS_VACB vacb, PCSTR file, INT line) 96 { 97 ULONG Refs; 98 99 Refs = InterlockedCompareExchange((PLONG)&vacb->ReferenceCount, 0, 0); 100 if (vacb->SharedCacheMap->Trace) 101 { 102 DbgPrint("(%s:%i) VACB %p ==RefCount=%lu, Dirty %u, PageOut %lu\n", 103 file, line, vacb, Refs, vacb->Dirty, vacb->PageOut); 104 } 105 106 return Refs; 107 } 108 #endif 109 110 NTSTATUS 111 CcRosInternalFreeVacb(PROS_VACB Vacb); 112 113 114 /* FUNCTIONS *****************************************************************/ 115 116 VOID 117 NTAPI 118 CcRosTraceCacheMap ( 119 PROS_SHARED_CACHE_MAP SharedCacheMap, 120 BOOLEAN Trace ) 121 { 122 #if DBG 123 KIRQL oldirql; 124 PLIST_ENTRY current_entry; 125 PROS_VACB current; 126 127 if (!SharedCacheMap) 128 return; 129 130 SharedCacheMap->Trace = Trace; 131 132 if (Trace) 133 { 134 DPRINT1("Enabling Tracing for CacheMap 0x%p:\n", SharedCacheMap); 135 136 KeAcquireGuardedMutex(&ViewLock); 137 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql); 138 139 current_entry = SharedCacheMap->CacheMapVacbListHead.Flink; 140 while (current_entry != &SharedCacheMap->CacheMapVacbListHead) 141 { 142 current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry); 143 current_entry = current_entry->Flink; 144 145 DPRINT1(" VACB 0x%p enabled, RefCount %lu, Dirty %u, PageOut %lu\n", 146 current, current->ReferenceCount, current->Dirty, current->PageOut ); 147 } 148 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql); 149 KeReleaseGuardedMutex(&ViewLock); 150 } 151 else 152 { 153 DPRINT1("Disabling Tracing for CacheMap 0x%p:\n", SharedCacheMap); 154 } 155 156 #else 157 UNREFERENCED_PARAMETER(SharedCacheMap); 158 UNREFERENCED_PARAMETER(Trace); 159 #endif 160 } 161 162 NTSTATUS 163 NTAPI 164 CcRosFlushVacb ( 165 PROS_VACB Vacb) 166 { 167 NTSTATUS Status; 168 169 Status = CcWriteVirtualAddress(Vacb); 170 if (NT_SUCCESS(Status)) 171 { 172 CcRosUnmarkDirtyVacb(Vacb, TRUE); 173 } 174 175 return Status; 176 } 177 178 NTSTATUS 179 NTAPI 180 CcRosFlushDirtyPages ( 181 ULONG Target, 182 PULONG Count, 183 BOOLEAN Wait, 184 BOOLEAN CalledFromLazy) 185 { 186 PLIST_ENTRY current_entry; 187 PROS_VACB current; 188 BOOLEAN Locked; 189 NTSTATUS Status; 190 LARGE_INTEGER ZeroTimeout; 191 192 DPRINT("CcRosFlushDirtyPages(Target %lu)\n", Target); 193 194 (*Count) = 0; 195 ZeroTimeout.QuadPart = 0; 196 197 KeEnterCriticalRegion(); 198 KeAcquireGuardedMutex(&ViewLock); 199 200 current_entry = DirtyVacbListHead.Flink; 201 if (current_entry == &DirtyVacbListHead) 202 { 203 DPRINT("No Dirty pages\n"); 204 } 205 206 while ((current_entry != &DirtyVacbListHead) && (Target > 0)) 207 { 208 current = CONTAINING_RECORD(current_entry, 209 ROS_VACB, 210 DirtyVacbListEntry); 211 current_entry = current_entry->Flink; 212 213 CcRosVacbIncRefCount(current); 214 215 /* When performing lazy write, don't handle temporary files */ 216 if (CalledFromLazy && 217 BooleanFlagOn(current->SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE)) 218 { 219 CcRosVacbDecRefCount(current); 220 continue; 221 } 222 223 Locked = current->SharedCacheMap->Callbacks->AcquireForLazyWrite( 224 current->SharedCacheMap->LazyWriteContext, Wait); 225 if (!Locked) 226 { 227 CcRosVacbDecRefCount(current); 228 continue; 229 } 230 231 Status = CcRosAcquireVacbLock(current, 232 Wait ? NULL : &ZeroTimeout); 233 if (Status != STATUS_SUCCESS) 234 { 235 current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite( 236 current->SharedCacheMap->LazyWriteContext); 237 CcRosVacbDecRefCount(current); 238 continue; 239 } 240 241 ASSERT(current->Dirty); 242 243 /* One reference is added above */ 244 if (CcRosVacbGetRefCount(current) > 2) 245 { 246 CcRosReleaseVacbLock(current); 247 current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite( 248 current->SharedCacheMap->LazyWriteContext); 249 CcRosVacbDecRefCount(current); 250 continue; 251 } 252 253 KeReleaseGuardedMutex(&ViewLock); 254 255 Status = CcRosFlushVacb(current); 256 257 CcRosReleaseVacbLock(current); 258 current->SharedCacheMap->Callbacks->ReleaseFromLazyWrite( 259 current->SharedCacheMap->LazyWriteContext); 260 261 KeAcquireGuardedMutex(&ViewLock); 262 CcRosVacbDecRefCount(current); 263 264 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE) && 265 (Status != STATUS_MEDIA_WRITE_PROTECTED)) 266 { 267 DPRINT1("CC: Failed to flush VACB.\n"); 268 } 269 else 270 { 271 ULONG PagesFreed; 272 273 /* How many pages did we free? */ 274 PagesFreed = VACB_MAPPING_GRANULARITY / PAGE_SIZE; 275 (*Count) += PagesFreed; 276 277 /* Make sure we don't overflow target! */ 278 if (Target < PagesFreed) 279 { 280 /* If we would have, jump to zero directly */ 281 Target = 0; 282 } 283 else 284 { 285 Target -= PagesFreed; 286 } 287 } 288 289 current_entry = DirtyVacbListHead.Flink; 290 } 291 292 KeReleaseGuardedMutex(&ViewLock); 293 KeLeaveCriticalRegion(); 294 295 DPRINT("CcRosFlushDirtyPages() finished\n"); 296 return STATUS_SUCCESS; 297 } 298 299 NTSTATUS 300 CcRosTrimCache ( 301 ULONG Target, 302 ULONG Priority, 303 PULONG NrFreed) 304 /* 305 * FUNCTION: Try to free some memory from the file cache. 306 * ARGUMENTS: 307 * Target - The number of pages to be freed. 308 * Priority - The priority of free (currently unused). 309 * NrFreed - Points to a variable where the number of pages 310 * actually freed is returned. 311 */ 312 { 313 PLIST_ENTRY current_entry; 314 PROS_VACB current; 315 ULONG PagesFreed; 316 KIRQL oldIrql; 317 LIST_ENTRY FreeList; 318 PFN_NUMBER Page; 319 ULONG i; 320 BOOLEAN FlushedPages = FALSE; 321 322 DPRINT("CcRosTrimCache(Target %lu)\n", Target); 323 324 InitializeListHead(&FreeList); 325 326 *NrFreed = 0; 327 328 retry: 329 KeAcquireGuardedMutex(&ViewLock); 330 331 current_entry = VacbLruListHead.Flink; 332 while (current_entry != &VacbLruListHead) 333 { 334 ULONG Refs; 335 336 current = CONTAINING_RECORD(current_entry, 337 ROS_VACB, 338 VacbLruListEntry); 339 current_entry = current_entry->Flink; 340 341 KeAcquireSpinLock(¤t->SharedCacheMap->CacheMapLock, &oldIrql); 342 343 /* Reference the VACB */ 344 CcRosVacbIncRefCount(current); 345 346 /* Check if it's mapped and not dirty */ 347 if (current->MappedCount > 0 && !current->Dirty) 348 { 349 /* We have to break these locks because Cc sucks */ 350 KeReleaseSpinLock(¤t->SharedCacheMap->CacheMapLock, oldIrql); 351 KeReleaseGuardedMutex(&ViewLock); 352 353 /* Page out the VACB */ 354 for (i = 0; i < VACB_MAPPING_GRANULARITY / PAGE_SIZE; i++) 355 { 356 Page = (PFN_NUMBER)(MmGetPhysicalAddress((PUCHAR)current->BaseAddress + (i * PAGE_SIZE)).QuadPart >> PAGE_SHIFT); 357 358 MmPageOutPhysicalAddress(Page); 359 } 360 361 /* Reacquire the locks */ 362 KeAcquireGuardedMutex(&ViewLock); 363 KeAcquireSpinLock(¤t->SharedCacheMap->CacheMapLock, &oldIrql); 364 } 365 366 /* Dereference the VACB */ 367 Refs = CcRosVacbDecRefCount(current); 368 369 /* Check if we can free this entry now */ 370 if (Refs < 2) 371 { 372 ASSERT(!current->Dirty); 373 ASSERT(!current->MappedCount); 374 ASSERT(Refs == 1); 375 376 RemoveEntryList(¤t->CacheMapVacbListEntry); 377 RemoveEntryList(¤t->VacbLruListEntry); 378 InsertHeadList(&FreeList, ¤t->CacheMapVacbListEntry); 379 380 /* Calculate how many pages we freed for Mm */ 381 PagesFreed = min(VACB_MAPPING_GRANULARITY / PAGE_SIZE, Target); 382 Target -= PagesFreed; 383 (*NrFreed) += PagesFreed; 384 } 385 386 KeReleaseSpinLock(¤t->SharedCacheMap->CacheMapLock, oldIrql); 387 } 388 389 KeReleaseGuardedMutex(&ViewLock); 390 391 /* Try flushing pages if we haven't met our target */ 392 if ((Target > 0) && !FlushedPages) 393 { 394 /* Flush dirty pages to disk */ 395 CcRosFlushDirtyPages(Target, &PagesFreed, FALSE, FALSE); 396 FlushedPages = TRUE; 397 398 /* We can only swap as many pages as we flushed */ 399 if (PagesFreed < Target) Target = PagesFreed; 400 401 /* Check if we flushed anything */ 402 if (PagesFreed != 0) 403 { 404 /* Try again after flushing dirty pages */ 405 DPRINT("Flushed %lu dirty cache pages to disk\n", PagesFreed); 406 goto retry; 407 } 408 } 409 410 while (!IsListEmpty(&FreeList)) 411 { 412 current_entry = RemoveHeadList(&FreeList); 413 current = CONTAINING_RECORD(current_entry, 414 ROS_VACB, 415 CacheMapVacbListEntry); 416 CcRosVacbDecRefCount(current); 417 CcRosInternalFreeVacb(current); 418 } 419 420 DPRINT("Evicted %lu cache pages\n", (*NrFreed)); 421 422 return STATUS_SUCCESS; 423 } 424 425 NTSTATUS 426 NTAPI 427 CcRosReleaseVacb ( 428 PROS_SHARED_CACHE_MAP SharedCacheMap, 429 PROS_VACB Vacb, 430 BOOLEAN Valid, 431 BOOLEAN Dirty, 432 BOOLEAN Mapped) 433 { 434 ULONG Refs; 435 ASSERT(SharedCacheMap); 436 437 DPRINT("CcRosReleaseVacb(SharedCacheMap 0x%p, Vacb 0x%p, Valid %u)\n", 438 SharedCacheMap, Vacb, Valid); 439 440 Vacb->Valid = Valid; 441 442 if (Dirty && !Vacb->Dirty) 443 { 444 CcRosMarkDirtyVacb(Vacb); 445 } 446 447 if (Mapped) 448 { 449 Vacb->MappedCount++; 450 } 451 Refs = CcRosVacbDecRefCount(Vacb); 452 if (Mapped && (Vacb->MappedCount == 1)) 453 { 454 CcRosVacbIncRefCount(Vacb); 455 } 456 457 ASSERT(Refs > 0); 458 459 CcRosReleaseVacbLock(Vacb); 460 461 return STATUS_SUCCESS; 462 } 463 464 /* Returns with VACB Lock Held! */ 465 PROS_VACB 466 NTAPI 467 CcRosLookupVacb ( 468 PROS_SHARED_CACHE_MAP SharedCacheMap, 469 LONGLONG FileOffset) 470 { 471 PLIST_ENTRY current_entry; 472 PROS_VACB current; 473 KIRQL oldIrql; 474 475 ASSERT(SharedCacheMap); 476 477 DPRINT("CcRosLookupVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n", 478 SharedCacheMap, FileOffset); 479 480 KeAcquireGuardedMutex(&ViewLock); 481 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); 482 483 current_entry = SharedCacheMap->CacheMapVacbListHead.Flink; 484 while (current_entry != &SharedCacheMap->CacheMapVacbListHead) 485 { 486 current = CONTAINING_RECORD(current_entry, 487 ROS_VACB, 488 CacheMapVacbListEntry); 489 if (IsPointInRange(current->FileOffset.QuadPart, 490 VACB_MAPPING_GRANULARITY, 491 FileOffset)) 492 { 493 CcRosVacbIncRefCount(current); 494 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); 495 KeReleaseGuardedMutex(&ViewLock); 496 CcRosAcquireVacbLock(current, NULL); 497 return current; 498 } 499 if (current->FileOffset.QuadPart > FileOffset) 500 break; 501 current_entry = current_entry->Flink; 502 } 503 504 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); 505 KeReleaseGuardedMutex(&ViewLock); 506 507 return NULL; 508 } 509 510 VOID 511 NTAPI 512 CcRosMarkDirtyVacb ( 513 PROS_VACB Vacb) 514 { 515 KIRQL oldIrql; 516 PROS_SHARED_CACHE_MAP SharedCacheMap; 517 518 SharedCacheMap = Vacb->SharedCacheMap; 519 520 KeAcquireGuardedMutex(&ViewLock); 521 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); 522 523 ASSERT(!Vacb->Dirty); 524 525 InsertTailList(&DirtyVacbListHead, &Vacb->DirtyVacbListEntry); 526 CcTotalDirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; 527 Vacb->SharedCacheMap->DirtyPages += VACB_MAPPING_GRANULARITY / PAGE_SIZE; 528 CcRosVacbIncRefCount(Vacb); 529 530 /* Move to the tail of the LRU list */ 531 RemoveEntryList(&Vacb->VacbLruListEntry); 532 InsertTailList(&VacbLruListHead, &Vacb->VacbLruListEntry); 533 534 Vacb->Dirty = TRUE; 535 536 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); 537 KeReleaseGuardedMutex(&ViewLock); 538 539 /* Schedule a lazy writer run to now that we have dirty VACB */ 540 oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); 541 if (!LazyWriter.ScanActive) 542 { 543 CcScheduleLazyWriteScan(FALSE); 544 } 545 KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql); 546 } 547 548 VOID 549 NTAPI 550 CcRosUnmarkDirtyVacb ( 551 PROS_VACB Vacb, 552 BOOLEAN LockViews) 553 { 554 KIRQL oldIrql; 555 PROS_SHARED_CACHE_MAP SharedCacheMap; 556 557 SharedCacheMap = Vacb->SharedCacheMap; 558 559 if (LockViews) 560 { 561 KeAcquireGuardedMutex(&ViewLock); 562 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); 563 } 564 565 ASSERT(Vacb->Dirty); 566 567 Vacb->Dirty = FALSE; 568 569 RemoveEntryList(&Vacb->DirtyVacbListEntry); 570 CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; 571 Vacb->SharedCacheMap->DirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; 572 CcRosVacbDecRefCount(Vacb); 573 574 if (LockViews) 575 { 576 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); 577 KeReleaseGuardedMutex(&ViewLock); 578 } 579 } 580 581 NTSTATUS 582 NTAPI 583 CcRosMarkDirtyFile ( 584 PROS_SHARED_CACHE_MAP SharedCacheMap, 585 LONGLONG FileOffset) 586 { 587 PROS_VACB Vacb; 588 589 ASSERT(SharedCacheMap); 590 591 DPRINT("CcRosMarkDirtyVacb(SharedCacheMap 0x%p, FileOffset %I64u)\n", 592 SharedCacheMap, FileOffset); 593 594 Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset); 595 if (Vacb == NULL) 596 { 597 KeBugCheck(CACHE_MANAGER); 598 } 599 600 CcRosReleaseVacb(SharedCacheMap, Vacb, Vacb->Valid, TRUE, FALSE); 601 602 return STATUS_SUCCESS; 603 } 604 605 /* 606 * Note: this is not the contrary function of 607 * CcRosMapVacbInKernelSpace() 608 */ 609 NTSTATUS 610 NTAPI 611 CcRosUnmapVacb ( 612 PROS_SHARED_CACHE_MAP SharedCacheMap, 613 LONGLONG FileOffset, 614 BOOLEAN NowDirty) 615 { 616 PROS_VACB Vacb; 617 618 ASSERT(SharedCacheMap); 619 620 DPRINT("CcRosUnmapVacb(SharedCacheMap 0x%p, FileOffset %I64u, NowDirty %u)\n", 621 SharedCacheMap, FileOffset, NowDirty); 622 623 Vacb = CcRosLookupVacb(SharedCacheMap, FileOffset); 624 if (Vacb == NULL) 625 { 626 return STATUS_UNSUCCESSFUL; 627 } 628 629 ASSERT(Vacb->MappedCount != 0); 630 Vacb->MappedCount--; 631 632 if (Vacb->MappedCount == 0) 633 { 634 CcRosVacbDecRefCount(Vacb); 635 } 636 637 CcRosReleaseVacb(SharedCacheMap, Vacb, Vacb->Valid, NowDirty, FALSE); 638 639 return STATUS_SUCCESS; 640 } 641 642 static 643 NTSTATUS 644 CcRosMapVacbInKernelSpace( 645 PROS_VACB Vacb) 646 { 647 ULONG i; 648 NTSTATUS Status; 649 ULONG_PTR NumberOfPages; 650 PVOID BaseAddress = NULL; 651 652 /* Create a memory area. */ 653 MmLockAddressSpace(MmGetKernelAddressSpace()); 654 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), 655 0, // nothing checks for VACB mareas, so set to 0 656 &BaseAddress, 657 VACB_MAPPING_GRANULARITY, 658 PAGE_READWRITE, 659 (PMEMORY_AREA*)&Vacb->MemoryArea, 660 0, 661 PAGE_SIZE); 662 ASSERT(Vacb->BaseAddress == NULL); 663 Vacb->BaseAddress = BaseAddress; 664 MmUnlockAddressSpace(MmGetKernelAddressSpace()); 665 if (!NT_SUCCESS(Status)) 666 { 667 DPRINT1("MmCreateMemoryArea failed with %lx for VACB %p\n", Status, Vacb); 668 return Status; 669 } 670 671 ASSERT(((ULONG_PTR)Vacb->BaseAddress % PAGE_SIZE) == 0); 672 ASSERT((ULONG_PTR)Vacb->BaseAddress > (ULONG_PTR)MmSystemRangeStart); 673 ASSERT((ULONG_PTR)Vacb->BaseAddress + VACB_MAPPING_GRANULARITY - 1 > (ULONG_PTR)MmSystemRangeStart); 674 675 /* Create a virtual mapping for this memory area */ 676 NumberOfPages = BYTES_TO_PAGES(VACB_MAPPING_GRANULARITY); 677 for (i = 0; i < NumberOfPages; i++) 678 { 679 PFN_NUMBER PageFrameNumber; 680 681 MI_SET_USAGE(MI_USAGE_CACHE); 682 Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &PageFrameNumber); 683 if (PageFrameNumber == 0) 684 { 685 DPRINT1("Unable to allocate page\n"); 686 KeBugCheck(MEMORY_MANAGEMENT); 687 } 688 689 ASSERT(BaseAddress == Vacb->BaseAddress); 690 ASSERT(i * PAGE_SIZE < VACB_MAPPING_GRANULARITY); 691 ASSERT((ULONG_PTR)Vacb->BaseAddress + (i * PAGE_SIZE) >= (ULONG_PTR)BaseAddress); 692 ASSERT((ULONG_PTR)Vacb->BaseAddress + (i * PAGE_SIZE) > (ULONG_PTR)MmSystemRangeStart); 693 694 Status = MmCreateVirtualMapping(NULL, 695 (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i * PAGE_SIZE)), 696 PAGE_READWRITE, 697 &PageFrameNumber, 698 1); 699 if (!NT_SUCCESS(Status)) 700 { 701 DPRINT1("Unable to create virtual mapping\n"); 702 KeBugCheck(MEMORY_MANAGEMENT); 703 } 704 } 705 706 return STATUS_SUCCESS; 707 } 708 709 static 710 NTSTATUS 711 CcRosCreateVacb ( 712 PROS_SHARED_CACHE_MAP SharedCacheMap, 713 LONGLONG FileOffset, 714 PROS_VACB *Vacb) 715 { 716 PROS_VACB current; 717 PROS_VACB previous; 718 PLIST_ENTRY current_entry; 719 NTSTATUS Status; 720 KIRQL oldIrql; 721 722 ASSERT(SharedCacheMap); 723 724 DPRINT("CcRosCreateVacb()\n"); 725 726 if (FileOffset >= SharedCacheMap->SectionSize.QuadPart) 727 { 728 *Vacb = NULL; 729 return STATUS_INVALID_PARAMETER; 730 } 731 732 current = ExAllocateFromNPagedLookasideList(&VacbLookasideList); 733 current->BaseAddress = NULL; 734 current->Valid = FALSE; 735 current->Dirty = FALSE; 736 current->PageOut = FALSE; 737 current->FileOffset.QuadPart = ROUND_DOWN(FileOffset, VACB_MAPPING_GRANULARITY); 738 current->SharedCacheMap = SharedCacheMap; 739 #if DBG 740 if (SharedCacheMap->Trace) 741 { 742 DPRINT1("CacheMap 0x%p: new VACB: 0x%p\n", SharedCacheMap, current); 743 } 744 #endif 745 current->MappedCount = 0; 746 current->DirtyVacbListEntry.Flink = NULL; 747 current->DirtyVacbListEntry.Blink = NULL; 748 current->ReferenceCount = 0; 749 current->PinCount = 0; 750 KeInitializeMutex(¤t->Mutex, 0); 751 CcRosAcquireVacbLock(current, NULL); 752 KeAcquireGuardedMutex(&ViewLock); 753 754 *Vacb = current; 755 /* There is window between the call to CcRosLookupVacb 756 * and CcRosCreateVacb. We must check if a VACB for the 757 * file offset exist. If there is a VACB, we release 758 * our newly created VACB and return the existing one. 759 */ 760 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); 761 current_entry = SharedCacheMap->CacheMapVacbListHead.Flink; 762 previous = NULL; 763 while (current_entry != &SharedCacheMap->CacheMapVacbListHead) 764 { 765 current = CONTAINING_RECORD(current_entry, 766 ROS_VACB, 767 CacheMapVacbListEntry); 768 if (IsPointInRange(current->FileOffset.QuadPart, 769 VACB_MAPPING_GRANULARITY, 770 FileOffset)) 771 { 772 CcRosVacbIncRefCount(current); 773 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); 774 #if DBG 775 if (SharedCacheMap->Trace) 776 { 777 DPRINT1("CacheMap 0x%p: deleting newly created VACB 0x%p ( found existing one 0x%p )\n", 778 SharedCacheMap, 779 (*Vacb), 780 current); 781 } 782 #endif 783 CcRosReleaseVacbLock(*Vacb); 784 KeReleaseGuardedMutex(&ViewLock); 785 ExFreeToNPagedLookasideList(&VacbLookasideList, *Vacb); 786 *Vacb = current; 787 CcRosAcquireVacbLock(current, NULL); 788 return STATUS_SUCCESS; 789 } 790 if (current->FileOffset.QuadPart < FileOffset) 791 { 792 ASSERT(previous == NULL || 793 previous->FileOffset.QuadPart < current->FileOffset.QuadPart); 794 previous = current; 795 } 796 if (current->FileOffset.QuadPart > FileOffset) 797 break; 798 current_entry = current_entry->Flink; 799 } 800 /* There was no existing VACB. */ 801 current = *Vacb; 802 if (previous) 803 { 804 InsertHeadList(&previous->CacheMapVacbListEntry, ¤t->CacheMapVacbListEntry); 805 } 806 else 807 { 808 InsertHeadList(&SharedCacheMap->CacheMapVacbListHead, ¤t->CacheMapVacbListEntry); 809 } 810 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); 811 InsertTailList(&VacbLruListHead, ¤t->VacbLruListEntry); 812 CcRosVacbIncRefCount(current); 813 KeReleaseGuardedMutex(&ViewLock); 814 815 MI_SET_USAGE(MI_USAGE_CACHE); 816 #if MI_TRACE_PFNS 817 if ((SharedCacheMap->FileObject) && (SharedCacheMap->FileObject->FileName.Buffer)) 818 { 819 PWCHAR pos; 820 ULONG len = 0; 821 pos = wcsrchr(SharedCacheMap->FileObject->FileName.Buffer, '\\'); 822 if (pos) 823 { 824 len = wcslen(pos) * sizeof(WCHAR); 825 snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos); 826 } 827 else 828 { 829 snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%wZ", &SharedCacheMap->FileObject->FileName); 830 } 831 } 832 #endif 833 834 /* Reference it to allow release */ 835 CcRosVacbIncRefCount(current); 836 837 Status = CcRosMapVacbInKernelSpace(current); 838 if (!NT_SUCCESS(Status)) 839 { 840 RemoveEntryList(¤t->CacheMapVacbListEntry); 841 RemoveEntryList(¤t->VacbLruListEntry); 842 CcRosReleaseVacb(SharedCacheMap, current, FALSE, 843 FALSE, FALSE); 844 CcRosVacbDecRefCount(current); 845 ExFreeToNPagedLookasideList(&VacbLookasideList, current); 846 } 847 848 return Status; 849 } 850 851 NTSTATUS 852 NTAPI 853 CcRosGetVacb ( 854 PROS_SHARED_CACHE_MAP SharedCacheMap, 855 LONGLONG FileOffset, 856 PLONGLONG BaseOffset, 857 PVOID* BaseAddress, 858 PBOOLEAN UptoDate, 859 PROS_VACB *Vacb) 860 { 861 PROS_VACB current; 862 NTSTATUS Status; 863 ULONG Refs; 864 865 ASSERT(SharedCacheMap); 866 867 DPRINT("CcRosGetVacb()\n"); 868 869 /* 870 * Look for a VACB already mapping the same data. 871 */ 872 current = CcRosLookupVacb(SharedCacheMap, FileOffset); 873 if (current == NULL) 874 { 875 /* 876 * Otherwise create a new VACB. 877 */ 878 Status = CcRosCreateVacb(SharedCacheMap, FileOffset, ¤t); 879 if (!NT_SUCCESS(Status)) 880 { 881 return Status; 882 } 883 } 884 885 Refs = CcRosVacbGetRefCount(current); 886 887 KeAcquireGuardedMutex(&ViewLock); 888 889 /* Move to the tail of the LRU list */ 890 RemoveEntryList(¤t->VacbLruListEntry); 891 InsertTailList(&VacbLruListHead, ¤t->VacbLruListEntry); 892 893 KeReleaseGuardedMutex(&ViewLock); 894 895 /* 896 * Return information about the VACB to the caller. 897 */ 898 *UptoDate = current->Valid; 899 *BaseAddress = current->BaseAddress; 900 DPRINT("*BaseAddress %p\n", *BaseAddress); 901 *Vacb = current; 902 *BaseOffset = current->FileOffset.QuadPart; 903 904 ASSERT(Refs > 1); 905 906 return STATUS_SUCCESS; 907 } 908 909 NTSTATUS 910 NTAPI 911 CcRosRequestVacb ( 912 PROS_SHARED_CACHE_MAP SharedCacheMap, 913 LONGLONG FileOffset, 914 PVOID* BaseAddress, 915 PBOOLEAN UptoDate, 916 PROS_VACB *Vacb) 917 /* 918 * FUNCTION: Request a page mapping for a shared cache map 919 */ 920 { 921 LONGLONG BaseOffset; 922 923 ASSERT(SharedCacheMap); 924 925 if (FileOffset % VACB_MAPPING_GRANULARITY != 0) 926 { 927 DPRINT1("Bad fileoffset %I64x should be multiple of %x", 928 FileOffset, VACB_MAPPING_GRANULARITY); 929 KeBugCheck(CACHE_MANAGER); 930 } 931 932 return CcRosGetVacb(SharedCacheMap, 933 FileOffset, 934 &BaseOffset, 935 BaseAddress, 936 UptoDate, 937 Vacb); 938 } 939 940 static 941 VOID 942 CcFreeCachePage ( 943 PVOID Context, 944 MEMORY_AREA* MemoryArea, 945 PVOID Address, 946 PFN_NUMBER Page, 947 SWAPENTRY SwapEntry, 948 BOOLEAN Dirty) 949 { 950 ASSERT(SwapEntry == 0); 951 if (Page != 0) 952 { 953 ASSERT(MmGetReferenceCountPage(Page) == 1); 954 MmReleasePageMemoryConsumer(MC_CACHE, Page); 955 } 956 } 957 958 NTSTATUS 959 CcRosInternalFreeVacb ( 960 PROS_VACB Vacb) 961 /* 962 * FUNCTION: Releases a VACB associated with a shared cache map 963 */ 964 { 965 DPRINT("Freeing VACB 0x%p\n", Vacb); 966 #if DBG 967 if (Vacb->SharedCacheMap->Trace) 968 { 969 DPRINT1("CacheMap 0x%p: deleting VACB: 0x%p\n", Vacb->SharedCacheMap, Vacb); 970 } 971 #endif 972 973 MmLockAddressSpace(MmGetKernelAddressSpace()); 974 MmFreeMemoryArea(MmGetKernelAddressSpace(), 975 Vacb->MemoryArea, 976 CcFreeCachePage, 977 NULL); 978 MmUnlockAddressSpace(MmGetKernelAddressSpace()); 979 980 if (Vacb->PinCount != 0 || Vacb->ReferenceCount != 0) 981 { 982 DPRINT1("Invalid free: %ld, %ld\n", Vacb->ReferenceCount, Vacb->PinCount); 983 if (Vacb->SharedCacheMap->FileObject && Vacb->SharedCacheMap->FileObject->FileName.Length) 984 { 985 DPRINT1("For file: %wZ\n", &Vacb->SharedCacheMap->FileObject->FileName); 986 } 987 } 988 989 ASSERT(Vacb->PinCount == 0); 990 ASSERT(Vacb->ReferenceCount == 0); 991 RtlFillMemory(Vacb, sizeof(Vacb), 0xfd); 992 ExFreeToNPagedLookasideList(&VacbLookasideList, Vacb); 993 return STATUS_SUCCESS; 994 } 995 996 /* 997 * @implemented 998 */ 999 VOID 1000 NTAPI 1001 CcFlushCache ( 1002 IN PSECTION_OBJECT_POINTERS SectionObjectPointers, 1003 IN PLARGE_INTEGER FileOffset OPTIONAL, 1004 IN ULONG Length, 1005 OUT PIO_STATUS_BLOCK IoStatus) 1006 { 1007 PROS_SHARED_CACHE_MAP SharedCacheMap; 1008 LARGE_INTEGER Offset; 1009 LONGLONG RemainingLength; 1010 PROS_VACB current; 1011 NTSTATUS Status; 1012 1013 CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p FileOffset=%p Length=%lu\n", 1014 SectionObjectPointers, FileOffset, Length); 1015 1016 DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %lu, IoStatus 0x%p)\n", 1017 SectionObjectPointers, FileOffset, Length, IoStatus); 1018 1019 if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap) 1020 { 1021 SharedCacheMap = SectionObjectPointers->SharedCacheMap; 1022 ASSERT(SharedCacheMap); 1023 if (FileOffset) 1024 { 1025 Offset = *FileOffset; 1026 RemainingLength = Length; 1027 } 1028 else 1029 { 1030 Offset.QuadPart = 0; 1031 RemainingLength = SharedCacheMap->FileSize.QuadPart; 1032 } 1033 1034 if (IoStatus) 1035 { 1036 IoStatus->Status = STATUS_SUCCESS; 1037 IoStatus->Information = 0; 1038 } 1039 1040 while (RemainingLength > 0) 1041 { 1042 current = CcRosLookupVacb(SharedCacheMap, Offset.QuadPart); 1043 if (current != NULL) 1044 { 1045 if (current->Dirty) 1046 { 1047 Status = CcRosFlushVacb(current); 1048 if (!NT_SUCCESS(Status) && IoStatus != NULL) 1049 { 1050 IoStatus->Status = Status; 1051 } 1052 } 1053 1054 CcRosReleaseVacb(SharedCacheMap, current, current->Valid, current->Dirty, FALSE); 1055 } 1056 1057 Offset.QuadPart += VACB_MAPPING_GRANULARITY; 1058 RemainingLength -= min(RemainingLength, VACB_MAPPING_GRANULARITY); 1059 } 1060 } 1061 else 1062 { 1063 if (IoStatus) 1064 { 1065 IoStatus->Status = STATUS_INVALID_PARAMETER; 1066 } 1067 } 1068 } 1069 1070 NTSTATUS 1071 NTAPI 1072 CcRosDeleteFileCache ( 1073 PFILE_OBJECT FileObject, 1074 PROS_SHARED_CACHE_MAP SharedCacheMap) 1075 /* 1076 * FUNCTION: Releases the shared cache map associated with a file object 1077 */ 1078 { 1079 PLIST_ENTRY current_entry; 1080 PROS_VACB current; 1081 LIST_ENTRY FreeList; 1082 KIRQL oldIrql; 1083 1084 ASSERT(SharedCacheMap); 1085 1086 SharedCacheMap->OpenCount++; 1087 KeReleaseGuardedMutex(&ViewLock); 1088 1089 CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL); 1090 1091 KeAcquireGuardedMutex(&ViewLock); 1092 SharedCacheMap->OpenCount--; 1093 if (SharedCacheMap->OpenCount == 0) 1094 { 1095 KIRQL OldIrql; 1096 1097 FileObject->SectionObjectPointer->SharedCacheMap = NULL; 1098 1099 /* 1100 * Release all VACBs 1101 */ 1102 InitializeListHead(&FreeList); 1103 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); 1104 while (!IsListEmpty(&SharedCacheMap->CacheMapVacbListHead)) 1105 { 1106 current_entry = RemoveTailList(&SharedCacheMap->CacheMapVacbListHead); 1107 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); 1108 1109 current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry); 1110 CcRosAcquireVacbLock(current, NULL); 1111 RemoveEntryList(¤t->VacbLruListEntry); 1112 if (current->Dirty) 1113 { 1114 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); 1115 CcRosUnmarkDirtyVacb(current, FALSE); 1116 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); 1117 DPRINT1("Freeing dirty VACB\n"); 1118 } 1119 InsertHeadList(&FreeList, ¤t->CacheMapVacbListEntry); 1120 CcRosReleaseVacbLock(current); 1121 1122 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldIrql); 1123 } 1124 #if DBG 1125 SharedCacheMap->Trace = FALSE; 1126 #endif 1127 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldIrql); 1128 1129 KeReleaseGuardedMutex(&ViewLock); 1130 ObDereferenceObject(SharedCacheMap->FileObject); 1131 1132 while (!IsListEmpty(&FreeList)) 1133 { 1134 current_entry = RemoveTailList(&FreeList); 1135 current = CONTAINING_RECORD(current_entry, ROS_VACB, CacheMapVacbListEntry); 1136 CcRosVacbDecRefCount(current); 1137 CcRosInternalFreeVacb(current); 1138 } 1139 1140 OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); 1141 RemoveEntryList(&SharedCacheMap->SharedCacheMapLinks); 1142 KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); 1143 1144 ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap); 1145 KeAcquireGuardedMutex(&ViewLock); 1146 } 1147 return STATUS_SUCCESS; 1148 } 1149 1150 VOID 1151 NTAPI 1152 CcRosReferenceCache ( 1153 PFILE_OBJECT FileObject) 1154 { 1155 PROS_SHARED_CACHE_MAP SharedCacheMap; 1156 KeAcquireGuardedMutex(&ViewLock); 1157 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 1158 ASSERT(SharedCacheMap); 1159 ASSERT(SharedCacheMap->OpenCount != 0); 1160 SharedCacheMap->OpenCount++; 1161 KeReleaseGuardedMutex(&ViewLock); 1162 } 1163 1164 VOID 1165 NTAPI 1166 CcRosRemoveIfClosed ( 1167 PSECTION_OBJECT_POINTERS SectionObjectPointer) 1168 { 1169 PROS_SHARED_CACHE_MAP SharedCacheMap; 1170 DPRINT("CcRosRemoveIfClosed()\n"); 1171 KeAcquireGuardedMutex(&ViewLock); 1172 SharedCacheMap = SectionObjectPointer->SharedCacheMap; 1173 if (SharedCacheMap && SharedCacheMap->OpenCount == 0) 1174 { 1175 CcRosDeleteFileCache(SharedCacheMap->FileObject, SharedCacheMap); 1176 } 1177 KeReleaseGuardedMutex(&ViewLock); 1178 } 1179 1180 1181 VOID 1182 NTAPI 1183 CcRosDereferenceCache ( 1184 PFILE_OBJECT FileObject) 1185 { 1186 PROS_SHARED_CACHE_MAP SharedCacheMap; 1187 KeAcquireGuardedMutex(&ViewLock); 1188 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 1189 ASSERT(SharedCacheMap); 1190 if (SharedCacheMap->OpenCount > 0) 1191 { 1192 SharedCacheMap->OpenCount--; 1193 if (SharedCacheMap->OpenCount == 0) 1194 { 1195 MmFreeSectionSegments(SharedCacheMap->FileObject); 1196 CcRosDeleteFileCache(FileObject, SharedCacheMap); 1197 } 1198 } 1199 KeReleaseGuardedMutex(&ViewLock); 1200 } 1201 1202 NTSTATUS 1203 NTAPI 1204 CcRosReleaseFileCache ( 1205 PFILE_OBJECT FileObject) 1206 /* 1207 * FUNCTION: Called by the file system when a handle to a file object 1208 * has been closed. 1209 */ 1210 { 1211 KIRQL OldIrql; 1212 PPRIVATE_CACHE_MAP PrivateMap; 1213 PROS_SHARED_CACHE_MAP SharedCacheMap; 1214 1215 KeAcquireGuardedMutex(&ViewLock); 1216 1217 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL) 1218 { 1219 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 1220 1221 /* Closing the handle, so kill the private cache map 1222 * Before you event try to remove it from FO, always 1223 * lock the master lock, to be sure not to race 1224 * with a potential read ahead ongoing! 1225 */ 1226 OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); 1227 PrivateMap = FileObject->PrivateCacheMap; 1228 FileObject->PrivateCacheMap = NULL; 1229 KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); 1230 1231 if (PrivateMap != NULL) 1232 { 1233 /* Remove it from the file */ 1234 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); 1235 RemoveEntryList(&PrivateMap->PrivateLinks); 1236 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); 1237 1238 /* And free it. */ 1239 if (PrivateMap != &SharedCacheMap->PrivateCacheMap) 1240 { 1241 ExFreePoolWithTag(PrivateMap, TAG_PRIVATE_CACHE_MAP); 1242 } 1243 else 1244 { 1245 PrivateMap->NodeTypeCode = 0; 1246 } 1247 1248 if (SharedCacheMap->OpenCount > 0) 1249 { 1250 SharedCacheMap->OpenCount--; 1251 if (SharedCacheMap->OpenCount == 0) 1252 { 1253 MmFreeSectionSegments(SharedCacheMap->FileObject); 1254 CcRosDeleteFileCache(FileObject, SharedCacheMap); 1255 } 1256 } 1257 } 1258 } 1259 KeReleaseGuardedMutex(&ViewLock); 1260 return STATUS_SUCCESS; 1261 } 1262 1263 NTSTATUS 1264 NTAPI 1265 CcRosInitializeFileCache ( 1266 PFILE_OBJECT FileObject, 1267 PCC_FILE_SIZES FileSizes, 1268 BOOLEAN PinAccess, 1269 PCACHE_MANAGER_CALLBACKS CallBacks, 1270 PVOID LazyWriterContext) 1271 /* 1272 * FUNCTION: Initializes a shared cache map for a file object 1273 */ 1274 { 1275 KIRQL OldIrql; 1276 BOOLEAN Allocated; 1277 PROS_SHARED_CACHE_MAP SharedCacheMap; 1278 1279 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 1280 DPRINT("CcRosInitializeFileCache(FileObject 0x%p, SharedCacheMap 0x%p)\n", 1281 FileObject, SharedCacheMap); 1282 1283 Allocated = FALSE; 1284 KeAcquireGuardedMutex(&ViewLock); 1285 if (SharedCacheMap == NULL) 1286 { 1287 Allocated = TRUE; 1288 SharedCacheMap = ExAllocateFromNPagedLookasideList(&SharedCacheMapLookasideList); 1289 if (SharedCacheMap == NULL) 1290 { 1291 KeReleaseGuardedMutex(&ViewLock); 1292 return STATUS_INSUFFICIENT_RESOURCES; 1293 } 1294 RtlZeroMemory(SharedCacheMap, sizeof(*SharedCacheMap)); 1295 ObReferenceObjectByPointer(FileObject, 1296 FILE_ALL_ACCESS, 1297 NULL, 1298 KernelMode); 1299 SharedCacheMap->NodeTypeCode = NODE_TYPE_SHARED_MAP; 1300 SharedCacheMap->NodeByteSize = sizeof(*SharedCacheMap); 1301 SharedCacheMap->FileObject = FileObject; 1302 SharedCacheMap->Callbacks = CallBacks; 1303 SharedCacheMap->LazyWriteContext = LazyWriterContext; 1304 SharedCacheMap->SectionSize = FileSizes->AllocationSize; 1305 SharedCacheMap->FileSize = FileSizes->FileSize; 1306 SharedCacheMap->PinAccess = PinAccess; 1307 SharedCacheMap->DirtyPageThreshold = 0; 1308 SharedCacheMap->DirtyPages = 0; 1309 InitializeListHead(&SharedCacheMap->PrivateList); 1310 KeInitializeSpinLock(&SharedCacheMap->CacheMapLock); 1311 InitializeListHead(&SharedCacheMap->CacheMapVacbListHead); 1312 FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap; 1313 1314 OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); 1315 InsertTailList(&CcCleanSharedCacheMapList, &SharedCacheMap->SharedCacheMapLinks); 1316 KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); 1317 } 1318 if (FileObject->PrivateCacheMap == NULL) 1319 { 1320 PPRIVATE_CACHE_MAP PrivateMap; 1321 1322 /* Allocate the private cache map for this handle */ 1323 if (SharedCacheMap->PrivateCacheMap.NodeTypeCode != 0) 1324 { 1325 PrivateMap = ExAllocatePoolWithTag(NonPagedPool, sizeof(PRIVATE_CACHE_MAP), TAG_PRIVATE_CACHE_MAP); 1326 } 1327 else 1328 { 1329 PrivateMap = &SharedCacheMap->PrivateCacheMap; 1330 } 1331 1332 if (PrivateMap == NULL) 1333 { 1334 /* If we also allocated the shared cache map for this file, kill it */ 1335 if (Allocated) 1336 { 1337 OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); 1338 RemoveEntryList(&SharedCacheMap->SharedCacheMapLinks); 1339 KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); 1340 1341 FileObject->SectionObjectPointer->SharedCacheMap = NULL; 1342 ObDereferenceObject(FileObject); 1343 ExFreeToNPagedLookasideList(&SharedCacheMapLookasideList, SharedCacheMap); 1344 } 1345 1346 KeReleaseGuardedMutex(&ViewLock); 1347 return STATUS_INSUFFICIENT_RESOURCES; 1348 } 1349 1350 /* Initialize it */ 1351 RtlZeroMemory(PrivateMap, sizeof(PRIVATE_CACHE_MAP)); 1352 PrivateMap->NodeTypeCode = NODE_TYPE_PRIVATE_MAP; 1353 PrivateMap->ReadAheadMask = PAGE_SIZE - 1; 1354 PrivateMap->FileObject = FileObject; 1355 KeInitializeSpinLock(&PrivateMap->ReadAheadSpinLock); 1356 1357 /* Link it to the file */ 1358 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); 1359 InsertTailList(&SharedCacheMap->PrivateList, &PrivateMap->PrivateLinks); 1360 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); 1361 1362 FileObject->PrivateCacheMap = PrivateMap; 1363 SharedCacheMap->OpenCount++; 1364 } 1365 KeReleaseGuardedMutex(&ViewLock); 1366 1367 return STATUS_SUCCESS; 1368 } 1369 1370 /* 1371 * @implemented 1372 */ 1373 PFILE_OBJECT 1374 NTAPI 1375 CcGetFileObjectFromSectionPtrs ( 1376 IN PSECTION_OBJECT_POINTERS SectionObjectPointers) 1377 { 1378 PROS_SHARED_CACHE_MAP SharedCacheMap; 1379 1380 CCTRACE(CC_API_DEBUG, "SectionObjectPointers=%p\n", SectionObjectPointers); 1381 1382 if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap) 1383 { 1384 SharedCacheMap = SectionObjectPointers->SharedCacheMap; 1385 ASSERT(SharedCacheMap); 1386 return SharedCacheMap->FileObject; 1387 } 1388 return NULL; 1389 } 1390 1391 VOID 1392 INIT_FUNCTION 1393 NTAPI 1394 CcInitView ( 1395 VOID) 1396 { 1397 DPRINT("CcInitView()\n"); 1398 1399 InitializeListHead(&DirtyVacbListHead); 1400 InitializeListHead(&VacbLruListHead); 1401 InitializeListHead(&CcDeferredWrites); 1402 InitializeListHead(&CcCleanSharedCacheMapList); 1403 KeInitializeSpinLock(&CcDeferredWriteSpinLock); 1404 KeInitializeGuardedMutex(&ViewLock); 1405 ExInitializeNPagedLookasideList(&iBcbLookasideList, 1406 NULL, 1407 NULL, 1408 0, 1409 sizeof(INTERNAL_BCB), 1410 TAG_BCB, 1411 20); 1412 ExInitializeNPagedLookasideList(&SharedCacheMapLookasideList, 1413 NULL, 1414 NULL, 1415 0, 1416 sizeof(ROS_SHARED_CACHE_MAP), 1417 TAG_SHARED_CACHE_MAP, 1418 20); 1419 ExInitializeNPagedLookasideList(&VacbLookasideList, 1420 NULL, 1421 NULL, 1422 0, 1423 sizeof(ROS_VACB), 1424 TAG_VACB, 1425 20); 1426 1427 MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache); 1428 1429 CcInitCacheZeroPage(); 1430 } 1431 1432 #if DBG && defined(KDBG) 1433 BOOLEAN 1434 ExpKdbgExtFileCache(ULONG Argc, PCHAR Argv[]) 1435 { 1436 PLIST_ENTRY ListEntry; 1437 UNICODE_STRING NoName = RTL_CONSTANT_STRING(L"No name for File"); 1438 1439 KdbpPrint(" Usage Summary (in kb)\n"); 1440 KdbpPrint("Shared\t\tValid\tDirty\tName\n"); 1441 /* No need to lock the spin lock here, we're in DBG */ 1442 for (ListEntry = CcCleanSharedCacheMapList.Flink; 1443 ListEntry != &CcCleanSharedCacheMapList; 1444 ListEntry = ListEntry->Flink) 1445 { 1446 PLIST_ENTRY Vacbs; 1447 ULONG Valid = 0, Dirty = 0; 1448 PROS_SHARED_CACHE_MAP SharedCacheMap; 1449 PUNICODE_STRING FileName; 1450 1451 SharedCacheMap = CONTAINING_RECORD(ListEntry, ROS_SHARED_CACHE_MAP, SharedCacheMapLinks); 1452 1453 /* Dirty size */ 1454 Dirty = (SharedCacheMap->DirtyPages * PAGE_SIZE) / 1024; 1455 1456 /* First, count for all the associated VACB */ 1457 for (Vacbs = SharedCacheMap->CacheMapVacbListHead.Flink; 1458 Vacbs != &SharedCacheMap->CacheMapVacbListHead; 1459 Vacbs = Vacbs->Flink) 1460 { 1461 PROS_VACB Vacb; 1462 1463 Vacb = CONTAINING_RECORD(Vacbs, ROS_VACB, CacheMapVacbListEntry); 1464 if (Vacb->Valid) 1465 { 1466 Valid += VACB_MAPPING_GRANULARITY / 1024; 1467 } 1468 } 1469 1470 /* Setup name */ 1471 if (SharedCacheMap->FileObject != NULL && 1472 SharedCacheMap->FileObject->FileName.Length != 0) 1473 { 1474 FileName = &SharedCacheMap->FileObject->FileName; 1475 } 1476 else 1477 { 1478 FileName = &NoName; 1479 } 1480 1481 /* And print */ 1482 KdbpPrint("%p\t%d\t%d\t%wZ\n", SharedCacheMap, Valid, Dirty, FileName); 1483 } 1484 1485 return TRUE; 1486 } 1487 1488 BOOLEAN 1489 ExpKdbgExtDefWrites(ULONG Argc, PCHAR Argv[]) 1490 { 1491 KdbpPrint("CcTotalDirtyPages:\t%lu (%lu Kb)\n", CcTotalDirtyPages, 1492 (CcTotalDirtyPages * PAGE_SIZE) / 1024); 1493 KdbpPrint("CcDirtyPageThreshold:\t%lu (%lu Kb)\n", CcDirtyPageThreshold, 1494 (CcDirtyPageThreshold * PAGE_SIZE) / 1024); 1495 KdbpPrint("MmAvailablePages:\t%lu (%lu Kb)\n", MmAvailablePages, 1496 (MmAvailablePages * PAGE_SIZE) / 1024); 1497 KdbpPrint("MmThrottleTop:\t\t%lu (%lu Kb)\n", MmThrottleTop, 1498 (MmThrottleTop * PAGE_SIZE) / 1024); 1499 KdbpPrint("MmThrottleBottom:\t%lu (%lu Kb)\n", MmThrottleBottom, 1500 (MmThrottleBottom * PAGE_SIZE) / 1024); 1501 KdbpPrint("MmModifiedPageListHead.Total:\t%lu (%lu Kb)\n", MmModifiedPageListHead.Total, 1502 (MmModifiedPageListHead.Total * PAGE_SIZE) / 1024); 1503 1504 if (CcTotalDirtyPages >= CcDirtyPageThreshold) 1505 { 1506 KdbpPrint("CcTotalDirtyPages above the threshold, writes should be throttled\n"); 1507 } 1508 else if (CcTotalDirtyPages + 64 >= CcDirtyPageThreshold) 1509 { 1510 KdbpPrint("CcTotalDirtyPages within 64 (max charge) pages of the threshold, writes may be throttled\n"); 1511 } 1512 else 1513 { 1514 KdbpPrint("CcTotalDirtyPages below the threshold, writes should not be throttled\n"); 1515 } 1516 1517 return TRUE; 1518 } 1519 #endif 1520 1521 /* EOF */ 1522