[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / cc / view.c
index fcdefc4..7c29a6f 100644 (file)
@@ -225,37 +225,34 @@ CcRosFlushDirtyPages(ULONG Target, PULONG Count)
         current_entry = current_entry->Flink;
 
         Locked = current->Bcb->Callbacks->AcquireForLazyWrite(
-            current->Bcb->LazyWriteContext, FALSE);
+            current->Bcb->LazyWriteContext, TRUE);
         if (!Locked)
         {
             continue;
         }
-        
-        Locked = ExTryToAcquirePushLockExclusive(&current->Lock);
-        if (!Locked)
-        {
-            current->Bcb->Callbacks->ReleaseFromLazyWrite(
-                current->Bcb->LazyWriteContext);
 
-            continue;
-        }
-        
+        KeWaitForSingleObject(&current->Mutex,
+                              Executive,
+                              KernelMode,
+                              FALSE,
+                              NULL);
+
         ASSERT(current->Dirty);
         if (current->ReferenceCount > 1)
         {
-            ExReleasePushLock(&current->Lock);
+            KeReleaseMutex(&current->Mutex, 0);
             current->Bcb->Callbacks->ReleaseFromLazyWrite(
                 current->Bcb->LazyWriteContext);
             continue;
         }
-        
+
         PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE;
 
         KeReleaseGuardedMutex(&ViewLock);
 
         Status = CcRosFlushCacheSegment(current);
 
-        ExReleasePushLock(&current->Lock);
+        KeReleaseMutex(&current->Mutex, 0);
         current->Bcb->Callbacks->ReleaseFromLazyWrite(
             current->Bcb->LazyWriteContext);
 
@@ -302,79 +299,96 @@ CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
     ULONG PagesFreed;
     KIRQL oldIrql;
     LIST_ENTRY FreeList;
-    
+    PFN_NUMBER Page;
+    ULONG i;
+    BOOLEAN FlushedPages = FALSE;
+
     DPRINT("CcRosTrimCache(Target %d)\n", Target);
-    
-    *NrFreed = 0;
-    
+
     InitializeListHead(&FreeList);
 
+    *NrFreed = 0;
+
+retry:
     KeAcquireGuardedMutex(&ViewLock);
+
     current_entry = CacheSegmentLRUListHead.Flink;
-    while (current_entry != &CacheSegmentLRUListHead && Target > 0)
+    while (current_entry != &CacheSegmentLRUListHead)
     {
         current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
                                     CacheSegmentLRUListEntry);
         current_entry = current_entry->Flink;
-        
+
         KeAcquireSpinLock(&current->Bcb->BcbLock, &oldIrql);
 
-        if (current->MappedCount > 0 && !current->Dirty && !current->PageOut)
+        /* Reference the cache segment */
+        CcRosCacheSegmentIncRefCount(current);
+
+        /* Check if it's mapped and not dirty */
+        if (current->MappedCount > 0 && !current->Dirty)
         {
-            ULONG i;
-            
-            CcRosCacheSegmentIncRefCount(current);
-            current->PageOut = TRUE;
+            /* We have to break these locks because Cc sucks */
             KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
             KeReleaseGuardedMutex(&ViewLock);
+
+            /* Page out the segment */
             for (i = 0; i < current->Bcb->CacheSegmentSize / PAGE_SIZE; i++)
             {
-                PFN_NUMBER Page;
-                Page = (PFN_NUMBER)(MmGetPhysicalAddress((char*)current->BaseAddress + i * PAGE_SIZE).QuadPart >> PAGE_SHIFT);
+                Page = (PFN_NUMBER)(MmGetPhysicalAddress((PUCHAR)current->BaseAddress + (i * PAGE_SIZE)).QuadPart >> PAGE_SHIFT);
+
                 MmPageOutPhysicalAddress(Page);
             }
+
+            /* Reacquire the locks */
             KeAcquireGuardedMutex(&ViewLock);
             KeAcquireSpinLock(&current->Bcb->BcbLock, &oldIrql);
-            CcRosCacheSegmentDecRefCount(current);
         }
-        
+
+        /* Dereference the cache segment */
+        CcRosCacheSegmentDecRefCount(current);
+
+        /* Check if we can free this entry now */
         if (current->ReferenceCount == 0)
         {
+            ASSERT(!current->Dirty);
+            ASSERT(!current->MappedCount);
+
+            RemoveEntryList(&current->BcbSegmentListEntry);
+            RemoveEntryList(&current->CacheSegmentListEntry);
+            RemoveEntryList(&current->CacheSegmentLRUListEntry);
+            InsertHeadList(&FreeList, &current->BcbSegmentListEntry);
+
+            /* Calculate how many pages we freed for Mm */
             PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE;
-            //            PagesFreed = PagesPerSegment;
             PagesFreed = min(PagesPerSegment, Target);
             Target -= PagesFreed;
-            (*NrFreed) += PagesFreed;            
+            (*NrFreed) += PagesFreed;
         }
-        
+
         KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
     }
-    
-    current_entry = CacheSegmentLRUListHead.Flink;
-    while (current_entry != &CacheSegmentLRUListHead)
+
+    KeReleaseGuardedMutex(&ViewLock);
+
+    /* Try flushing pages if we haven't met our target */
+    if (Target > 0 && !FlushedPages)
     {
-        current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
-                                    CacheSegmentLRUListEntry);
-        current->PageOut = FALSE;
-        current_entry = current_entry->Flink;
-        
-        KeAcquireSpinLock(&current->Bcb->BcbLock, &oldIrql);
-        if (current->ReferenceCount == 0)
-        {
-            RemoveEntryList(&current->BcbSegmentListEntry);
-            KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
-            RemoveEntryList(&current->CacheSegmentListEntry);
-            RemoveEntryList(&current->CacheSegmentLRUListEntry);
-            InsertHeadList(&FreeList, &current->BcbSegmentListEntry);
-        }
-        else
+        /* Flush dirty pages to disk */
+        CcRosFlushDirtyPages(Target, &PagesFreed);
+        FlushedPages = TRUE;
+
+        /* We can only swap as many pages as we flushed */
+        if (PagesFreed < Target) Target = PagesFreed;
+
+        /* Check if we flushed anything */
+        if (PagesFreed != 0)
         {
-            KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
+            /* Try again after flushing dirty pages */
+            DPRINT("Flushed %d dirty cache pages to disk\n", PagesFreed);
+            goto retry;
         }
     }
-    
-    KeReleaseGuardedMutex(&ViewLock);
-    
+
     while (!IsListEmpty(&FreeList))
     {
         current_entry = RemoveHeadList(&FreeList);
@@ -382,7 +396,9 @@ CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
                                     BcbSegmentListEntry);
         CcRosInternalFreeCacheSegment(current);
     }
-    
+
+    DPRINT("Evicted %d cache pages\n", (*NrFreed));
+
     return(STATUS_SUCCESS);
 }
 
@@ -411,8 +427,6 @@ CcRosReleaseCacheSegment(PBCB Bcb,
       InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
       DirtyPageCount += Bcb->CacheSegmentSize / PAGE_SIZE;
     }
-  RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
-  InsertTailList(&CacheSegmentLRUListHead, &CacheSeg->CacheSegmentLRUListEntry);
 
   if (Mapped)
   {
@@ -430,7 +444,7 @@ CcRosReleaseCacheSegment(PBCB Bcb,
   }
   KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
   KeReleaseGuardedMutex(&ViewLock);
-  ExReleasePushLock(&CacheSeg->Lock);
+  KeReleaseMutex(&CacheSeg->Mutex, 0);
 
   return(STATUS_SUCCESS);
 }
@@ -459,7 +473,11 @@ CcRosLookupCacheSegment(PBCB Bcb, ULONG FileOffset)
         {
             CcRosCacheSegmentIncRefCount(current);
             KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
-            ExAcquirePushLockExclusive(&current->Lock);
+            KeWaitForSingleObject(&current->Mutex,
+                                  Executive,
+                                  KernelMode,
+                                  FALSE,
+                                  NULL);
             return(current);
         }
         current_entry = current_entry->Flink;
@@ -498,9 +516,16 @@ CcRosMarkDirtyCacheSegment(PBCB Bcb, ULONG FileOffset)
      KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
   }
 
+  KeAcquireGuardedMutex(&ViewLock);
+
+  /* Move to the tail of the LRU list */
+  RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
+  InsertTailList(&CacheSegmentLRUListHead, &CacheSeg->CacheSegmentLRUListEntry);
+
+  KeReleaseGuardedMutex(&ViewLock);
 
   CacheSeg->Dirty = TRUE;
-  ExReleasePushLock(&CacheSeg->Lock);
+  KeReleaseMutex(&CacheSeg->Mutex, 0);
 
   return(STATUS_SUCCESS);
 }
@@ -549,7 +574,8 @@ CcRosUnmapCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty)
   }
   KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
 
-  ExReleasePushLock(&CacheSeg->Lock);
+  KeReleaseMutex(&CacheSeg->Mutex, 0);
+
   return(STATUS_SUCCESS);
 }
 
@@ -596,8 +622,12 @@ CcRosCreateCacheSegment(PBCB Bcb,
   current->DirtySegmentListEntry.Flink = NULL;
   current->DirtySegmentListEntry.Blink = NULL;
   current->ReferenceCount = 1;
-  ExInitializePushLock((PULONG_PTR)&current->Lock);
-  ExAcquirePushLockExclusive(&current->Lock);
+  KeInitializeMutex(&current->Mutex, 0);
+  KeWaitForSingleObject(&current->Mutex,
+                        Executive,
+                        KernelMode,
+                        FALSE,
+                        NULL);
   KeAcquireGuardedMutex(&ViewLock);
 
   *CacheSeg = current;
@@ -627,11 +657,15 @@ CcRosCreateCacheSegment(PBCB Bcb,
                        current );
        }
 #endif
-       ExReleasePushLock(&(*CacheSeg)->Lock);
+       KeReleaseMutex(&(*CacheSeg)->Mutex, 0);
        KeReleaseGuardedMutex(&ViewLock);
        ExFreeToNPagedLookasideList(&CacheSegLookasideList, *CacheSeg);
        *CacheSeg = current;
-        ExAcquirePushLockExclusive(&current->Lock);
+    KeWaitForSingleObject(&current->Mutex,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
        return STATUS_SUCCESS;
      }
      if (current->FileOffset < FileOffset)
@@ -703,6 +737,18 @@ CcRosCreateCacheSegment(PBCB Bcb,
 #endif
 
   /* Create a virtual mapping for this memory area */
+  MI_SET_USAGE(MI_USAGE_CACHE);
+#if MI_TRACE_PFNS
+  PWCHAR pos = NULL;
+  ULONG len = 0;
+  if ((Bcb->FileObject) && (Bcb->FileObject->FileName.Buffer))
+  {
+    pos = wcsrchr(Bcb->FileObject->FileName.Buffer, '\\');
+    len = wcslen(pos) * sizeof(WCHAR);
+    if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos);
+  }   
+#endif
+
   MmMapMemoryArea(current->BaseAddress, Bcb->CacheSegmentSize,
       MC_CACHE, PAGE_READWRITE);
 
@@ -739,6 +785,14 @@ CcRosGetCacheSegmentChain(PBCB Bcb,
       current = CcRosLookupCacheSegment(Bcb, CurrentOffset);
       if (current != NULL)
        {
+         KeAcquireGuardedMutex(&ViewLock);
+
+         /* Move to tail of LRU list */
+         RemoveEntryList(&current->CacheSegmentLRUListEntry);
+         InsertTailList(&CacheSegmentLRUListHead, &current->CacheSegmentLRUListEntry);
+
+         KeReleaseGuardedMutex(&ViewLock);
+
          CacheSegList[i] = current;
        }
       else
@@ -798,6 +852,15 @@ CcRosGetCacheSegment(PBCB Bcb,
        return Status;
       }
    }
+
+   KeAcquireGuardedMutex(&ViewLock);
+
+   /* Move to the tail of the LRU list */
+   RemoveEntryList(&current->CacheSegmentLRUListEntry);
+   InsertTailList(&CacheSegmentLRUListHead, &current->CacheSegmentLRUListEntry);
+
+   KeReleaseGuardedMutex(&ViewLock);
+
    /*
     * Return information about the segment to the caller.
     */
@@ -846,6 +909,7 @@ CcFreeCachePage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
   ASSERT(SwapEntry == 0);
   if (Page != 0)
     {
+        ASSERT(MmGetReferenceCountPage(Page) == 1);
       MmReleasePageMemoryConsumer(MC_CACHE, Page);
     }
 }
@@ -940,76 +1004,76 @@ CcRosFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg)
  */
 VOID NTAPI
 CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointers,
-            IN PLARGE_INTEGER FileOffset OPTIONAL,
-            IN ULONG Length,
-            OUT PIO_STATUS_BLOCK IoStatus)
+             IN PLARGE_INTEGER FileOffset OPTIONAL,
+             IN ULONG Length,
+             OUT PIO_STATUS_BLOCK IoStatus)
 {
-   PBCB Bcb;
-   LARGE_INTEGER Offset;
-   PCACHE_SEGMENT current;
-   NTSTATUS Status;
-   KIRQL oldIrql;
+    PBCB Bcb;
+    LARGE_INTEGER Offset;
+    PCACHE_SEGMENT current;
+    NTSTATUS Status;
+    KIRQL oldIrql;
 
-   DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %d, IoStatus 0x%p)\n",
+    DPRINT("CcFlushCache(SectionObjectPointers 0x%p, FileOffset 0x%p, Length %d, IoStatus 0x%p)\n",
            SectionObjectPointers, FileOffset, Length, IoStatus);
 
-   if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
-   {
-      Bcb = (PBCB)SectionObjectPointers->SharedCacheMap;
-      ASSERT(Bcb);
-      if (FileOffset)
-      {
-        Offset = *FileOffset;
-      }
-      else
-      {
-        Offset.QuadPart = (LONGLONG)0;
-        Length = Bcb->FileSize.u.LowPart;
-      }
+    if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
+    {
+        Bcb = (PBCB)SectionObjectPointers->SharedCacheMap;
+        ASSERT(Bcb);
+        if (FileOffset)
+        {
+            Offset = *FileOffset;
+        }
+        else
+        {
+            Offset.QuadPart = (LONGLONG)0;
+            Length = Bcb->FileSize.u.LowPart;
+        }
 
-      if (IoStatus)
-      {
-        IoStatus->Status = STATUS_SUCCESS;
-        IoStatus->Information = 0;
-      }
+        if (IoStatus)
+        {
+            IoStatus->Status = STATUS_SUCCESS;
+            IoStatus->Information = 0;
+        }
 
-      while (Length > 0)
-      {
-        current = CcRosLookupCacheSegment (Bcb, Offset.u.LowPart);
-        if (current != NULL)
-        {
-           if (current->Dirty)
-           {
-              Status = CcRosFlushCacheSegment(current);
-              if (!NT_SUCCESS(Status) && IoStatus != NULL)
-              {
-                  IoStatus->Status = Status;
-              }
-           }
-            KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
-           ExReleasePushLock(&current->Lock);
-            CcRosCacheSegmentDecRefCount(current);
-           KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
-        }
+        while (Length > 0)
+        {
+            current = CcRosLookupCacheSegment (Bcb, Offset.u.LowPart);
+            if (current != NULL)
+            {
+                if (current->Dirty)
+                {
+                    Status = CcRosFlushCacheSegment(current);
+                    if (!NT_SUCCESS(Status) && IoStatus != NULL)
+                    {
+                        IoStatus->Status = Status;
+                    }
+                }
+                KeReleaseMutex(&current->Mutex, 0);
+                KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
+                CcRosCacheSegmentDecRefCount(current);
+                KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
+            }
 
-        Offset.QuadPart += Bcb->CacheSegmentSize;
-        if (Length > Bcb->CacheSegmentSize)
-        {
-           Length -= Bcb->CacheSegmentSize;
-        }
-        else
-        {
-           Length = 0;
-        }
-      }
-   }
-   else
-   {
-      if (IoStatus)
-      {
-        IoStatus->Status = STATUS_INVALID_PARAMETER;
-      }
-   }
+            Offset.QuadPart += Bcb->CacheSegmentSize;
+            if (Length > Bcb->CacheSegmentSize)
+            {
+                Length -= Bcb->CacheSegmentSize;
+            }
+            else
+            {
+                Length = 0;
+            }
+        }
+    }
+    else
+    {
+        if (IoStatus)
+        {
+            IoStatus->Status = STATUS_INVALID_PARAMETER;
+        }
+    }
 }
 
 NTSTATUS
@@ -1019,68 +1083,68 @@ CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
  * FUNCTION: Releases the BCB associated with a file object
  */
 {
-   PLIST_ENTRY current_entry;
-   PCACHE_SEGMENT current;
-   LIST_ENTRY FreeList;
-   KIRQL oldIrql;
+    PLIST_ENTRY current_entry;
+    PCACHE_SEGMENT current;
+    LIST_ENTRY FreeList;
+    KIRQL oldIrql;
 
-   ASSERT(Bcb);
+    ASSERT(Bcb);
 
-   Bcb->RefCount++;
-   KeReleaseGuardedMutex(&ViewLock);
+    Bcb->RefCount++;
+    KeReleaseGuardedMutex(&ViewLock);
 
-   CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL);
+    CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, NULL);
 
-   KeAcquireGuardedMutex(&ViewLock);
-   Bcb->RefCount--;
-   if (Bcb->RefCount == 0)
-   {
-      if (Bcb->BcbRemoveListEntry.Flink != NULL)
-      {
-        RemoveEntryList(&Bcb->BcbRemoveListEntry);
-         Bcb->BcbRemoveListEntry.Flink = NULL;
-      }
+    KeAcquireGuardedMutex(&ViewLock);
+    Bcb->RefCount--;
+    if (Bcb->RefCount == 0)
+    {
+        if (Bcb->BcbRemoveListEntry.Flink != NULL)
+        {
+            RemoveEntryList(&Bcb->BcbRemoveListEntry);
+            Bcb->BcbRemoveListEntry.Flink = NULL;
+        }
 
-      FileObject->SectionObjectPointer->SharedCacheMap = NULL;
+        FileObject->SectionObjectPointer->SharedCacheMap = NULL;
 
-      /*
-       * Release all cache segments.
-       */
-      InitializeListHead(&FreeList);
-      KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
-      current_entry = Bcb->BcbSegmentListHead.Flink;
-      while (!IsListEmpty(&Bcb->BcbSegmentListHead))
-      {
-         current_entry = RemoveTailList(&Bcb->BcbSegmentListHead);
-         current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
-         RemoveEntryList(&current->CacheSegmentListEntry);
-         RemoveEntryList(&current->CacheSegmentLRUListEntry);
-         if (current->Dirty)
-        {
-            RemoveEntryList(&current->DirtySegmentListEntry);
-            DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE;
-           DPRINT1("Freeing dirty segment\n");
-        }
-         InsertHeadList(&FreeList, &current->BcbSegmentListEntry);
-      }
+        /*
+         * Release all cache segments.
+         */
+        InitializeListHead(&FreeList);
+        KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
+        current_entry = Bcb->BcbSegmentListHead.Flink;
+        while (!IsListEmpty(&Bcb->BcbSegmentListHead))
+        {
+            current_entry = RemoveTailList(&Bcb->BcbSegmentListHead);
+            current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
+            RemoveEntryList(&current->CacheSegmentListEntry);
+            RemoveEntryList(&current->CacheSegmentLRUListEntry);
+            if (current->Dirty)
+            {
+                RemoveEntryList(&current->DirtySegmentListEntry);
+                DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE;
+                DPRINT1("Freeing dirty segment\n");
+            }
+            InsertHeadList(&FreeList, &current->BcbSegmentListEntry);
+        }
 #if DBG
-      Bcb->Trace = FALSE;
+        Bcb->Trace = FALSE;
 #endif
-      KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
+        KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
 
-      KeReleaseGuardedMutex(&ViewLock);
-      ObDereferenceObject (Bcb->FileObject);
+        KeReleaseGuardedMutex(&ViewLock);
+        ObDereferenceObject (Bcb->FileObject);
 
-      while (!IsListEmpty(&FreeList))
-      {
-         current_entry = RemoveTailList(&FreeList);
-         current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
-         CcRosInternalFreeCacheSegment(current);
-      }
-      ExFreeToNPagedLookasideList(&BcbLookasideList, Bcb);
-      KeAcquireGuardedMutex(&ViewLock);
-   }
-   return(STATUS_SUCCESS);
+        while (!IsListEmpty(&FreeList))
+        {
+            current_entry = RemoveTailList(&FreeList);
+            current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
+            CcRosInternalFreeCacheSegment(current);
+        }
+        ExFreeToNPagedLookasideList(&BcbLookasideList, Bcb);
+        KeAcquireGuardedMutex(&ViewLock);
+    }
+    return(STATUS_SUCCESS);
 }
 
 VOID