ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

view.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(&current->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(&current->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(&current->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(&current->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(&current->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(&current->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(&current->BcbSegmentListEntry);
00347             RemoveEntryList(&current->CacheSegmentListEntry);
00348             RemoveEntryList(&current->CacheSegmentLRUListEntry);
00349             InsertHeadList(&FreeList, &current->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(&current->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(&current->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(&current->Mutex, 0);
00626   KeWaitForSingleObject(&current->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(&current->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, &current->BcbSegmentListEntry);
00692   }
00693   else
00694   {
00695      InsertHeadList(&Bcb->BcbSegmentListHead, &current->BcbSegmentListEntry);
00696   }
00697   KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
00698   InsertTailList(&CacheSegmentListHead, &current->CacheSegmentListEntry);
00699   InsertTailList(&CacheSegmentLRUListHead, &current->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                   &current->BaseAddress,
00726                   Bcb->CacheSegmentSize,
00727                   PAGE_READWRITE,
00728                   (PMEMORY_AREA*)&current->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(&current->CacheSegmentLRUListEntry);
00792       InsertTailList(&CacheSegmentLRUListHead, &current->CacheSegmentLRUListEntry);
00793 
00794       KeReleaseGuardedMutex(&ViewLock);
00795 
00796       CacheSegList[i] = current;
00797     }
00798       else
00799     {
00800       CcRosCreateCacheSegment(Bcb, CurrentOffset, &current);
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, &current);
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(&current->CacheSegmentLRUListEntry);
00860    InsertTailList(&CacheSegmentLRUListHead, &current->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(&current->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(&current->CacheSegmentListEntry);
01124             RemoveEntryList(&current->CacheSegmentLRUListEntry);
01125             if (current->Dirty)
01126             {
01127                 RemoveEntryList(&current->DirtySegmentListEntry);
01128                 DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE;
01129                 DPRINT1("Freeing dirty segment\n");
01130             }
01131             InsertHeadList(&FreeList, &current->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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.