Modified some functions, changed the sequence for acquiring some of

the protection elements (VieLock, BcbLock, SegmentLock..) and protected
the access to some elements with the associated locking element.
Implemented CcFlushCache and CcGetFileObjectFromSectionPtrs.

svn path=/trunk/; revision=3596
This commit is contained in:
Hartmut Birr 2002-10-02 19:20:51 +00:00
parent ef773a3f6b
commit 8aca0dc370

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: view.c,v 1.52 2002/10/01 19:27:20 chorns Exp $ /* $Id: view.c,v 1.53 2002/10/02 19:20:51 hbirr Exp $
* *
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/cc/view.c * FILE: ntoskrnl/cc/view.c
@ -78,7 +78,7 @@ static FAST_MUTEX ViewLock;
void * alloca(size_t size); void * alloca(size_t size);
NTSTATUS STDCALL NTSTATUS STDCALL
CcRosInternalFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg); CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg);
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
@ -86,11 +86,17 @@ NTSTATUS STATIC
CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment) CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment)
{ {
NTSTATUS Status; NTSTATUS Status;
KIRQL oldIrql;
Status = WriteCacheSegment(CacheSegment); Status = WriteCacheSegment(CacheSegment);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
ExAcquireFastMutex(&ViewLock);
KeAcquireSpinLock(&CacheSegment->Bcb->BcbLock, &oldIrql);
CacheSegment->Dirty = FALSE; CacheSegment->Dirty = FALSE;
RemoveEntryList(&CacheSegment->DirtySegmentListEntry); RemoveEntryList(&CacheSegment->DirtySegmentListEntry);
CacheSegment->ReferenceCount--;
KeReleaseSpinLock(&CacheSegment->Bcb->BcbLock, oldIrql);
ExReleaseFastMutex(&ViewLock);
} }
return(Status); return(Status);
} }
@ -121,24 +127,24 @@ CcRosFlushDirtyPages(ULONG Target, PULONG Count)
continue; continue;
} }
assert(current->Dirty); assert(current->Dirty);
if (current->ReferenceCount > 0) if (current->ReferenceCount > 1)
{ {
ExReleaseFastMutex(&current->Lock); ExReleaseFastMutex(&current->Lock);
continue; continue;
} }
current->ReferenceCount++;
ExReleaseFastMutex(&ViewLock); ExReleaseFastMutex(&ViewLock);
PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE; PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE;
Status = CcRosFlushCacheSegment(current); Status = CcRosFlushCacheSegment(current);
current->ReferenceCount--;
ExReleaseFastMutex(&current->Lock); ExReleaseFastMutex(&current->Lock);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("CC: Failed to flush cache segment.\n"); DPRINT1("CC: Failed to flush cache segment.\n");
} }
(*Count) += PagesPerSegment; else
Target -= PagesPerSegment; {
(*Count) += PagesPerSegment;
Target -= PagesPerSegment;
}
ExAcquireFastMutex(&ViewLock); ExAcquireFastMutex(&ViewLock);
current_entry = DirtySegmentListHead.Flink; current_entry = DirtySegmentListHead.Flink;
} }
@ -162,12 +168,15 @@ CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
PCACHE_SEGMENT current; PCACHE_SEGMENT current;
ULONG PagesPerSegment; ULONG PagesPerSegment;
ULONG PagesFreed; ULONG PagesFreed;
BOOLEAN Locked; KIRQL oldIrql;
LIST_ENTRY FreeList;
DPRINT("CcRosTrimCache(Target %d)\n", Target); DPRINT("CcRosTrimCache(Target %d)\n", Target);
*NrFreed = 0; *NrFreed = 0;
InitializeListHead(&FreeList);
ExAcquireFastMutex(&ViewLock); ExAcquireFastMutex(&ViewLock);
current_entry = CacheSegmentLRUListHead.Flink; current_entry = CacheSegmentLRUListHead.Flink;
while (current_entry != &CacheSegmentLRUListHead && Target > 0) while (current_entry != &CacheSegmentLRUListHead && Target > 0)
@ -175,28 +184,35 @@ CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
CacheSegmentLRUListEntry); CacheSegmentLRUListEntry);
current_entry = current_entry->Flink; current_entry = current_entry->Flink;
Locked = ExTryToAcquireFastMutex(&current->Lock);
if (!Locked) KeAcquireSpinLock(&current->Bcb->BcbLock, &oldIrql);
{ if (current->ReferenceCount == 0)
continue; {
} RemoveEntryList(&current->BcbSegmentListEntry);
if (current->MappedCount > 0 || current->Dirty || KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
current->ReferenceCount > 0) RemoveEntryList(&current->CacheSegmentListEntry);
{ RemoveEntryList(&current->CacheSegmentLRUListEntry);
ExReleaseFastMutex(&current->Lock); InsertHeadList(&FreeList, &current->BcbSegmentListEntry);
continue; }
} else
ExReleaseFastMutex(&current->Lock); {
DPRINT("current->Bcb->CacheSegmentSize %d\n", KeReleaseSpinLock(&current->Bcb->BcbLock, oldIrql);
current->Bcb->CacheSegmentSize); }
PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE; }
CcRosInternalFreeCacheSegment(current->Bcb, current);
DPRINT("CcRosTrimCache(): Freed %d\n", PagesPerSegment);
PagesFreed = min(PagesPerSegment, Target);
Target = Target - PagesFreed;
(*NrFreed) = (*NrFreed) + PagesFreed;
}
ExReleaseFastMutex(&ViewLock); ExReleaseFastMutex(&ViewLock);
while (!IsListEmpty(&FreeList))
{
current_entry = RemoveHeadList(&FreeList);
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
BcbSegmentListEntry);
PagesPerSegment = current->Bcb->CacheSegmentSize / PAGE_SIZE;
PagesFreed = min(PagesPerSegment, Target);
Target -= PagesFreed;
(*NrFreed) += PagesFreed;
CcRosInternalFreeCacheSegment(current);
}
DPRINT("CcRosTrimCache() finished\n"); DPRINT("CcRosTrimCache() finished\n");
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -209,29 +225,39 @@ CcRosReleaseCacheSegment(PBCB Bcb,
BOOLEAN Mapped) BOOLEAN Mapped)
{ {
BOOLEAN WasDirty = CacheSeg->Dirty; BOOLEAN WasDirty = CacheSeg->Dirty;
KIRQL oldIrql;
DPRINT("CcReleaseCachePage(Bcb %x, CacheSeg %x, Valid %d)\n", DPRINT("CcReleaseCacheSegment(Bcb %x, CacheSeg %x, Valid %d)\n",
Bcb, CacheSeg, Valid); Bcb, CacheSeg, Valid);
CacheSeg->Valid = Valid; CacheSeg->Valid = Valid;
CacheSeg->Dirty = CacheSeg->Dirty || Dirty; CacheSeg->Dirty = CacheSeg->Dirty || Dirty;
if (Mapped)
{
CacheSeg->MappedCount++;
}
ExReleaseFastMutex(&CacheSeg->Lock);
ExAcquireFastMutex(&ViewLock); ExAcquireFastMutex(&ViewLock);
if (!WasDirty && CacheSeg->Dirty) if (!WasDirty && CacheSeg->Dirty)
{ {
InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry); InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
} }
RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry); RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
InsertTailList(&CacheSegmentLRUListHead, InsertTailList(&CacheSegmentLRUListHead, &CacheSeg->CacheSegmentLRUListEntry);
&CacheSeg->CacheSegmentLRUListEntry);
if (Mapped)
{
CacheSeg->MappedCount++;
}
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
CacheSeg->ReferenceCount--;
if (Mapped && CacheSeg->MappedCount == 1)
{
CacheSeg->ReferenceCount++;
}
if (!WasDirty && CacheSeg->Dirty)
{
CacheSeg->ReferenceCount++;
}
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
ExReleaseFastMutex(&ViewLock); ExReleaseFastMutex(&ViewLock);
InterlockedDecrement(&CacheSeg->ReferenceCount); ExReleaseFastMutex(&CacheSeg->Lock);
DPRINT("CcReleaseCachePage() finished\n");
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -242,6 +268,8 @@ PCACHE_SEGMENT CcRosLookupCacheSegment(PBCB Bcb, ULONG FileOffset)
PCACHE_SEGMENT current; PCACHE_SEGMENT current;
KIRQL oldIrql; KIRQL oldIrql;
DPRINT("CcRosLookupCacheSegment(Bcb %x, FileOffset %d)\n", Bcb, FileOffset);
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
current_entry = Bcb->BcbSegmentListHead.Flink; current_entry = Bcb->BcbSegmentListHead.Flink;
while (current_entry != &Bcb->BcbSegmentListHead) while (current_entry != &Bcb->BcbSegmentListHead)
@ -251,6 +279,7 @@ PCACHE_SEGMENT CcRosLookupCacheSegment(PBCB Bcb, ULONG FileOffset)
if (current->FileOffset <= FileOffset && if (current->FileOffset <= FileOffset &&
(current->FileOffset + Bcb->CacheSegmentSize) > FileOffset) (current->FileOffset + Bcb->CacheSegmentSize) > FileOffset)
{ {
current->ReferenceCount++;
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
return(current); return(current);
} }
@ -264,8 +293,10 @@ NTSTATUS
CcRosMarkDirtyCacheSegment(PBCB Bcb, ULONG FileOffset) CcRosMarkDirtyCacheSegment(PBCB Bcb, ULONG FileOffset)
{ {
PCACHE_SEGMENT CacheSeg; PCACHE_SEGMENT CacheSeg;
KIRQL oldIrql;
DPRINT("CcRosMarkDirtyCacheSegment(Bcb %x, FileOffset %d)\n", Bcb, FileOffset);
ExAcquireFastMutex(&ViewLock);
CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset); CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
if (CacheSeg == NULL) if (CacheSeg == NULL)
{ {
@ -274,40 +305,21 @@ CcRosMarkDirtyCacheSegment(PBCB Bcb, ULONG FileOffset)
ExAcquireFastMutex(&CacheSeg->Lock); ExAcquireFastMutex(&CacheSeg->Lock);
if (!CacheSeg->Dirty) if (!CacheSeg->Dirty)
{ {
ExAcquireFastMutex(&ViewLock);
InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry); InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
ExReleaseFastMutex(&ViewLock);
} }
else
{
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
CacheSeg->ReferenceCount--;
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
}
CacheSeg->Dirty = TRUE; CacheSeg->Dirty = TRUE;
ExReleaseFastMutex(&CacheSeg->Lock); ExReleaseFastMutex(&CacheSeg->Lock);
ExReleaseFastMutex(&ViewLock);
return(STATUS_SUCCESS);
}
NTSTATUS
CcRosSuggestFreeCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty)
{
PCACHE_SEGMENT CacheSeg;
ExAcquireFastMutex(&ViewLock);
CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
if (CacheSeg == NULL)
{
KeBugCheck(0);
}
ExAcquireFastMutex(&CacheSeg->Lock);
if (CacheSeg->MappedCount > 0)
{
KeBugCheck(0);
}
CacheSeg->Dirty = CacheSeg->Dirty || NowDirty;
if (CacheSeg->Dirty || CacheSeg->ReferenceCount > 0)
{
ExReleaseFastMutex(&CacheSeg->Lock);
ExReleaseFastMutex(&ViewLock);
return(STATUS_UNSUCCESSFUL);
}
ExReleaseFastMutex(&CacheSeg->Lock);
CcRosInternalFreeCacheSegment(CacheSeg->Bcb, CacheSeg);
ExReleaseFastMutex(&ViewLock);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -315,20 +327,43 @@ NTSTATUS
CcRosUnmapCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty) CcRosUnmapCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty)
{ {
PCACHE_SEGMENT CacheSeg; PCACHE_SEGMENT CacheSeg;
BOOLEAN WasDirty;
KIRQL oldIrql;
DPRINT("CcRosUnmapCacheSegment(Bcb %x, FileOffset %d, NowDirty %d)\n",
Bcb, FileOffset, NowDirty);
ExAcquireFastMutex(&ViewLock);
CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset); CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
if (CacheSeg == NULL) if (CacheSeg == NULL)
{ {
ExReleaseFastMutex(&ViewLock);
return(STATUS_UNSUCCESSFUL); return(STATUS_UNSUCCESSFUL);
} }
CacheSeg->ReferenceCount++;
ExReleaseFastMutex(&ViewLock);
ExAcquireFastMutex(&CacheSeg->Lock); ExAcquireFastMutex(&CacheSeg->Lock);
CacheSeg->MappedCount--;
WasDirty = CacheSeg->Dirty;
CacheSeg->Dirty = CacheSeg->Dirty || NowDirty; CacheSeg->Dirty = CacheSeg->Dirty || NowDirty;
CacheSeg->MappedCount--;
if (!WasDirty && NowDirty)
{
ExAcquireFastMutex(&ViewLock);
InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
ExReleaseFastMutex(&ViewLock);
}
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
CacheSeg->ReferenceCount--; CacheSeg->ReferenceCount--;
if (!WasDirty && NowDirty)
{
CacheSeg->ReferenceCount++;
}
if (CacheSeg->MappedCount == 0)
{
CacheSeg->ReferenceCount--;
}
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
ExReleaseFastMutex(&CacheSeg->Lock); ExReleaseFastMutex(&CacheSeg->Lock);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -341,15 +376,66 @@ CcRosCreateCacheSegment(PBCB Bcb,
{ {
ULONG i; ULONG i;
PCACHE_SEGMENT current; PCACHE_SEGMENT current;
PLIST_ENTRY current_entry;
NTSTATUS Status; NTSTATUS Status;
KIRQL oldIrql; KIRQL oldIrql;
DPRINT("CcRosCreateCacheSegment()\n");
current = ExAllocatePoolWithTag(NonPagedPool, sizeof(CACHE_SEGMENT), current = ExAllocatePoolWithTag(NonPagedPool, sizeof(CACHE_SEGMENT),
TAG_CSEG); TAG_CSEG);
current->Valid = FALSE;
current->Dirty = FALSE;
current->FileOffset = ROUND_DOWN(FileOffset, Bcb->CacheSegmentSize);
current->Bcb = Bcb;
current->MappedCount = 0;
current->DirtySegmentListEntry.Flink = NULL;
current->DirtySegmentListEntry.Blink = NULL;
current->ReferenceCount = 1;
ExInitializeFastMutex(&current->Lock);
ExAcquireFastMutex(&current->Lock);
ExAcquireFastMutex(&ViewLock);
*CacheSeg = current;
/* There is window between the call to CcRosLookupCacheSegment
* and CcRosCreateCacheSegment. We must check if a segment on
* the fileoffset exist. If there exist a segment, we release
* our new created segment and return the existing one.
*/
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
current_entry = Bcb->BcbSegmentListHead.Flink;
while (current_entry != &Bcb->BcbSegmentListHead)
{
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
BcbSegmentListEntry);
if (current->FileOffset <= FileOffset &&
(current->FileOffset + Bcb->CacheSegmentSize) > FileOffset)
{
current->ReferenceCount++;
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
ExReleaseFastMutex(&(*CacheSeg)->Lock);
ExReleaseFastMutex(&ViewLock);
ExFreePool(*CacheSeg);
*CacheSeg = current;
if (Lock)
{
ExAcquireFastMutex(&current->Lock);
}
return STATUS_SUCCESS;
}
current_entry = current_entry->Flink;
}
/* There was no existing segment. */
current = *CacheSeg;
InsertTailList(&Bcb->BcbSegmentListHead, &current->BcbSegmentListEntry);
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
InsertTailList(&CacheSegmentListHead, &current->CacheSegmentListEntry);
InsertTailList(&CacheSegmentLRUListHead, &current->CacheSegmentLRUListEntry);
ExReleaseFastMutex(&ViewLock);
MmLockAddressSpace(MmGetKernelAddressSpace()); MmLockAddressSpace(MmGetKernelAddressSpace());
current->BaseAddress = NULL; current->BaseAddress = NULL;
Status = MmCreateMemoryArea(KernelMode, Status = MmCreateMemoryArea(NULL,
MmGetKernelAddressSpace(), MmGetKernelAddressSpace(),
MEMORY_AREA_CACHE_SEGMENT, MEMORY_AREA_CACHE_SEGMENT,
&current->BaseAddress, &current->BaseAddress,
@ -357,53 +443,36 @@ CcRosCreateCacheSegment(PBCB Bcb,
PAGE_READWRITE, PAGE_READWRITE,
(PMEMORY_AREA*)&current->MemoryArea, (PMEMORY_AREA*)&current->MemoryArea,
FALSE); FALSE);
if (!NT_SUCCESS(Status))
{
MmUnlockAddressSpace(MmGetKernelAddressSpace());
KeBugCheck(0);
}
MmUnlockAddressSpace(MmGetKernelAddressSpace()); MmUnlockAddressSpace(MmGetKernelAddressSpace());
current->Valid = FALSE; if (!NT_SUCCESS(Status))
current->Dirty = FALSE; {
current->FileOffset = ROUND_DOWN(FileOffset, Bcb->CacheSegmentSize); KeBugCheck(0);
current->Bcb = Bcb; }
current->MappedCount = 0;
ExInitializeFastMutex(&current->Lock);
current->ReferenceCount = 1;
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
InsertTailList(&Bcb->BcbSegmentListHead, &current->BcbSegmentListEntry);
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
InsertTailList(&CacheSegmentListHead, &current->CacheSegmentListEntry);
InsertTailList(&CacheSegmentLRUListHead,
&current->CacheSegmentLRUListEntry);
current->DirtySegmentListEntry.Flink =
current->DirtySegmentListEntry.Blink = NULL;
if (Lock)
{
ExAcquireFastMutex(&current->Lock);
}
ExReleaseFastMutex(&ViewLock);
for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++) for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++)
{ {
PHYSICAL_ADDRESS Page; PHYSICAL_ADDRESS Page;
Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page); Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
KeBugCheck(0); KeBugCheck(0);
} }
Status = MmCreateVirtualMapping(NULL, Status = MmCreateVirtualMapping(NULL,
current->BaseAddress + (i * PAGE_SIZE), current->BaseAddress + (i * PAGE_SIZE),
PAGE_READWRITE, PAGE_READWRITE,
Page, Page,
TRUE); TRUE);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
KeBugCheck(0); KeBugCheck(0);
} }
} }
*CacheSeg = current; if (!Lock)
{
ExReleaseFastMutex(&current->Lock);
}
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -418,16 +487,13 @@ CcRosGetCacheSegmentChain(PBCB Bcb,
PCACHE_SEGMENT* CacheSegList; PCACHE_SEGMENT* CacheSegList;
PCACHE_SEGMENT Previous = NULL; PCACHE_SEGMENT Previous = NULL;
DPRINT("CcRosGetCacheSegmentChain()\n");
Length = ROUND_UP(Length, Bcb->CacheSegmentSize); Length = ROUND_UP(Length, Bcb->CacheSegmentSize);
CacheSegList = alloca(sizeof(PCACHE_SEGMENT) * CacheSegList = alloca(sizeof(PCACHE_SEGMENT) *
(Length / Bcb->CacheSegmentSize)); (Length / Bcb->CacheSegmentSize));
/*
* Acquire the global lock.
*/
ExAcquireFastMutex(&ViewLock);
/* /*
* Look for a cache segment already mapping the same data. * Look for a cache segment already mapping the same data.
*/ */
@ -437,20 +503,14 @@ CcRosGetCacheSegmentChain(PBCB Bcb,
current = CcRosLookupCacheSegment(Bcb, CurrentOffset); current = CcRosLookupCacheSegment(Bcb, CurrentOffset);
if (current != NULL) if (current != NULL)
{ {
/*
* Make sure the cache segment can't go away outside of our control.
*/
current->ReferenceCount++;
CacheSegList[i] = current; CacheSegList[i] = current;
} }
else else
{ {
CcRosCreateCacheSegment(Bcb, CurrentOffset, &current, FALSE); CcRosCreateCacheSegment(Bcb, CurrentOffset, &current, FALSE);
CacheSegList[i] = current; CacheSegList[i] = current;
ExAcquireFastMutex(&ViewLock);
} }
} }
ExReleaseFastMutex(&ViewLock);
for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++) for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++)
{ {
@ -482,47 +542,31 @@ CcRosGetCacheSegment(PBCB Bcb,
PCACHE_SEGMENT current; PCACHE_SEGMENT current;
NTSTATUS Status; NTSTATUS Status;
/* DPRINT("CcRosGetCacheSegment()\n");
* Acquire the global lock.
*/
ExAcquireFastMutex(&ViewLock);
/* /*
* Look for a cache segment already mapping the same data. * Look for a cache segment already mapping the same data.
*/ */
current = CcRosLookupCacheSegment(Bcb, FileOffset); current = CcRosLookupCacheSegment(Bcb, FileOffset);
if (current != NULL) if (current != NULL)
{ {
/* ExAcquireFastMutex(&current->Lock);
* Make sure the cache segment can't go away outside of our control. }
*/ else
current->ReferenceCount++; {
/* /*
* Release the global lock and lock the cache segment. * Otherwise create a new segment.
*/ */
ExReleaseFastMutex(&ViewLock); Status = CcRosCreateCacheSegment(Bcb, FileOffset, &current, TRUE);
ExAcquireFastMutex(&current->Lock); }
/*
* Return information about the segment to the caller.
*/
*UptoDate = current->Valid;
*BaseAddress = current->BaseAddress;
DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress);
*CacheSeg = current;
*BaseOffset = current->FileOffset;
return(STATUS_SUCCESS);
}
/* /*
* Otherwise create a new segment. * Return information about the segment to the caller.
*/ */
Status = CcRosCreateCacheSegment(Bcb, FileOffset, &current, TRUE);
*UptoDate = current->Valid; *UptoDate = current->Valid;
*BaseAddress = current->BaseAddress; *BaseAddress = current->BaseAddress;
DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress); DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress);
*CacheSeg = current; *CacheSeg = current;
*BaseOffset = current->FileOffset; *BaseOffset = current->FileOffset;
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -537,7 +581,7 @@ CcRosRequestCacheSegment(PBCB Bcb,
*/ */
{ {
ULONG BaseOffset; ULONG BaseOffset;
if ((FileOffset % Bcb->CacheSegmentSize) != 0) if ((FileOffset % Bcb->CacheSegmentSize) != 0)
{ {
CPRINT("Bad fileoffset %x should be multiple of %x", CPRINT("Bad fileoffset %x should be multiple of %x",
@ -565,19 +609,18 @@ CcFreeCachePage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
} }
NTSTATUS STDCALL NTSTATUS STDCALL
CcRosInternalFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg) CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg)
/* /*
* FUNCTION: Releases a cache segment associated with a BCB * FUNCTION: Releases a cache segment associated with a BCB
*/ */
{ {
DPRINT("Freeing cache segment %x\n", CacheSeg); DPRINT("Freeing cache segment %x\n", CacheSeg);
RemoveEntryList(&CacheSeg->CacheSegmentListEntry);
RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
RemoveEntryList(&CacheSeg->BcbSegmentListEntry);
MmLockAddressSpace(MmGetKernelAddressSpace()); MmLockAddressSpace(MmGetKernelAddressSpace());
MmFreeMemoryArea(MmGetKernelAddressSpace(), MmFreeMemoryArea(MmGetKernelAddressSpace(),
CacheSeg->BaseAddress, CacheSeg->BaseAddress,
Bcb->CacheSegmentSize, CacheSeg->Bcb->CacheSegmentSize,
CcFreeCachePage, CcFreeCachePage,
NULL); NULL);
MmUnlockAddressSpace(MmGetKernelAddressSpace()); MmUnlockAddressSpace(MmGetKernelAddressSpace());
@ -589,12 +632,101 @@ NTSTATUS STDCALL
CcRosFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg) CcRosFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg)
{ {
NTSTATUS Status; NTSTATUS Status;
KIRQL oldIrql;
DPRINT("CcRosFreeCacheSegment(Bcb %x, CacheSeg %x)\n",
Bcb, CacheSeg);
ExAcquireFastMutex(&ViewLock); ExAcquireFastMutex(&ViewLock);
Status = CcRosInternalFreeCacheSegment(Bcb, CacheSeg); KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
RemoveEntryList(&CacheSeg->BcbSegmentListEntry);
RemoveEntryList(&CacheSeg->CacheSegmentListEntry);
RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
if (CacheSeg->Dirty)
{
RemoveEntryList(&CacheSeg->DirtySegmentListEntry);
}
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
ExReleaseFastMutex(&ViewLock); ExReleaseFastMutex(&ViewLock);
Status = CcRosInternalFreeCacheSegment(CacheSeg);
return(Status); return(Status);
} }
VOID STDCALL
CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointers,
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;
DPRINT("CcFlushCache(SectionObjectPointers %x, FileOffset %x, Length %d, IoStatus %x)\n",
SectionObjectPointers, FileOffset, Length, IoStatus);
if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
{
Bcb = (PBCB)SectionObjectPointers->SharedCacheMap;
if (FileOffset)
{
Offset = *FileOffset;
}
else
{
Offset.QuadPart = 0LL;
Length = Bcb->FileSize.u.LowPart;
}
if (IoStatus)
{
IoStatus->Status = STATUS_SUCCESS;
IoStatus->Information = 0;
}
while (Length > 0)
{
current = CcRosLookupCacheSegment (Bcb, Offset.u.LowPart);
if (current != NULL)
{
ExAcquireFastMutex(&current->Lock);
if (current->Dirty)
{
Status = CcRosFlushCacheSegment(current);
if (!NT_SUCCESS(Status) && IoStatus != NULL)
{
IoStatus->Status = Status;
}
}
ExReleaseFastMutex(&current->Lock);
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
current->ReferenceCount--;
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;
}
}
}
NTSTATUS STDCALL NTSTATUS STDCALL
CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb) CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
/* /*
@ -604,72 +736,77 @@ CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
PLIST_ENTRY current_entry; PLIST_ENTRY current_entry;
PCACHE_SEGMENT current; PCACHE_SEGMENT current;
NTSTATUS Status; NTSTATUS Status;
LIST_ENTRY FreeList;
KIRQL oldIrql;
DPRINT("CcRosDeleteFileCache(FileObject %x, Bcb %x)\n", Bcb->FileObject, DPRINT("CcRosDeleteFileCache(FileObject %x, Bcb %x)\n",
Bcb); Bcb->FileObject, Bcb);
MmFreeSectionSegments(Bcb->FileObject); ExReleaseFastMutex(&ViewLock);
/* CcFlushCache(FileObject->SectionObjectPointers, NULL, 0, NULL);
* Write back dirty cache segments.
*/ ExAcquireFastMutex(&ViewLock);
current_entry = Bcb->BcbSegmentListHead.Flink;
while (current_entry != &Bcb->BcbSegmentListHead) if (Bcb->RefCount == 0)
{ {
current = MmFreeSectionSegments(Bcb->FileObject);
CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
if (current->Dirty) /*
* Release all cache segments.
*/
InitializeListHead(&FreeList);
FileObject->SectionObjectPointers->SharedCacheMap = NULL;
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)
{ {
Status = WriteCacheSegment(current); RemoveEntryList(&current->DirtySegmentListEntry);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to write cache segment (Status %X)\n", Status);
}
ExAcquireFastMutex(&ViewLock);
RemoveEntryList(&current->DirtySegmentListEntry);
ExReleaseFastMutex(&ViewLock);
} }
current_entry = current_entry->Flink; InsertHeadList(&FreeList, &current->BcbSegmentListEntry);
}
/*
* Release all cache segments.
*/
current_entry = Bcb->BcbSegmentListHead.Flink;
while (current_entry != &Bcb->BcbSegmentListHead)
{
current =
CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
current_entry = current_entry->Flink;
CcRosFreeCacheSegment(Bcb, current);
}
FileObject->SectionObjectPointers->SharedCacheMap = NULL;
ObDereferenceObject (Bcb->FileObject);
ExFreePool(Bcb);
}
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
while (!IsListEmpty(&FreeList))
{
current_entry = RemoveTailList(&FreeList);
current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
Status = CcRosInternalFreeCacheSegment(current);
}
ObDereferenceObject (Bcb->FileObject);
ExFreePool(Bcb);
}
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
VOID CcRosReferenceCache(PFILE_OBJECT FileObject) VOID CcRosReferenceCache(PFILE_OBJECT FileObject)
{ {
KIRQL oldIrql; PBCB Bcb;
PBCB Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap; ExAcquireFastMutex(&ViewLock);
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap;
Bcb->RefCount++; Bcb->RefCount++;
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql); ExReleaseFastMutex(&ViewLock);
} }
VOID CcRosDereferenceCache(PFILE_OBJECT FileObject) VOID CcRosDereferenceCache(PFILE_OBJECT FileObject)
{ {
KIRQL oldIrql; PBCB Bcb;
PBCB Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap; ExAcquireFastMutex(&ViewLock);
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql); Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap;
Bcb->RefCount--; Bcb->RefCount--;
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
if (Bcb->RefCount == 0) if (Bcb->RefCount == 0)
{ {
CcRosDeleteFileCache(FileObject, Bcb); CcRosDeleteFileCache(FileObject, Bcb);
} }
ExReleaseFastMutex(&ViewLock);
} }
NTSTATUS STDCALL NTSTATUS STDCALL
@ -679,21 +816,21 @@ CcRosReleaseFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
* has been closed. * has been closed.
*/ */
{ {
KIRQL oldIrql; ExAcquireFastMutex(&ViewLock);
if (FileObject->SectionObjectPointers->SharedCacheMap != NULL) if (FileObject->SectionObjectPointers->SharedCacheMap != NULL)
{ {
KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
if (FileObject->PrivateCacheMap != NULL) if (FileObject->PrivateCacheMap != NULL)
{ {
FileObject->PrivateCacheMap = NULL; FileObject->PrivateCacheMap = NULL;
Bcb->RefCount--; Bcb->RefCount--;
} }
KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
if (Bcb->RefCount == 0) if (Bcb->RefCount == 0)
{ {
CcRosDeleteFileCache(FileObject, Bcb); CcRosDeleteFileCache(FileObject, Bcb);
} }
} }
ExReleaseFastMutex(&ViewLock);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -705,7 +842,11 @@ CcRosInitializeFileCache(PFILE_OBJECT FileObject,
* FUNCTION: Initializes a BCB for a file object * FUNCTION: Initializes a BCB for a file object
*/ */
{ {
KIRQL oldIrql; DPRINT("CcRosInitializeFileCache(FileObject %x, *Bcb %x, CacheSegmentSize %d)\n",
FileObject, Bcb, CacheSegmentSize);
ExAcquireFastMutex(&ViewLock);
if (*Bcb == NULL) if (*Bcb == NULL)
{ {
(*Bcb) = ExAllocatePoolWithTag(NonPagedPool, sizeof(BCB), TAG_BCB); (*Bcb) = ExAllocatePoolWithTag(NonPagedPool, sizeof(BCB), TAG_BCB);
@ -731,17 +872,28 @@ CcRosInitializeFileCache(PFILE_OBJECT FileObject,
InitializeListHead(&(*Bcb)->BcbSegmentListHead); InitializeListHead(&(*Bcb)->BcbSegmentListHead);
FileObject->SectionObjectPointers->SharedCacheMap = *Bcb; FileObject->SectionObjectPointers->SharedCacheMap = *Bcb;
} }
KeAcquireSpinLock(&(*Bcb)->BcbLock, &oldIrql);
if (FileObject->PrivateCacheMap == NULL) if (FileObject->PrivateCacheMap == NULL)
{ {
FileObject->PrivateCacheMap = *Bcb; FileObject->PrivateCacheMap = *Bcb;
(*Bcb)->RefCount++; (*Bcb)->RefCount++;
} }
KeReleaseSpinLock(&(*Bcb)->BcbLock, oldIrql); ExReleaseFastMutex(&ViewLock);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
PFILE_OBJECT STDCALL
CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointers)
{
PBCB Bcb;
if (SectionObjectPointers && SectionObjectPointers->SharedCacheMap)
{
Bcb = (PBCB)SectionObjectPointers->SharedCacheMap;
return Bcb->FileObject;
}
return NULL;
}
VOID VOID
CcInitView(VOID) CcInitView(VOID)
{ {