mirror of
https://github.com/reactos/reactos.git
synced 2024-12-13 14:13:36 +08:00
631 lines
20 KiB
C
631 lines
20 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel
|
|
* FILE: ntoskrnl/cache/fssup.c
|
|
* PURPOSE: Logging and configuration routines
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
* Art Yerkes
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#include "newcc.h"
|
|
#include "section/newmm.h"
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
PFSN_PREFETCHER_GLOBALS CcPfGlobals;
|
|
extern LONG CcOutstandingDeletes;
|
|
extern KEVENT CcpLazyWriteEvent;
|
|
extern KEVENT CcFinalizeEvent;
|
|
extern VOID NTAPI CcpUnmapThread(PVOID Unused);
|
|
extern VOID NTAPI CcpLazyWriteThread(PVOID Unused);
|
|
HANDLE CcUnmapThreadHandle, CcLazyWriteThreadHandle;
|
|
CLIENT_ID CcUnmapThreadId, CcLazyWriteThreadId;
|
|
FAST_MUTEX GlobalPageOperation;
|
|
|
|
/*
|
|
|
|
A note about private cache maps.
|
|
|
|
CcInitializeCacheMap and CcUninitializeCacheMap are not meant to be paired,
|
|
although they can work that way.
|
|
|
|
The actual operation I've gleaned from reading both jan kratchovil's writing
|
|
and real filesystems is this:
|
|
|
|
CcInitializeCacheMap means:
|
|
|
|
Make the indicated FILE_OBJECT have a private cache map if it doesn't already
|
|
and make it have a shared cache map if it doesn't already.
|
|
|
|
CcUninitializeCacheMap means:
|
|
|
|
Take away the private cache map from this FILE_OBJECT. If it's the last
|
|
private cache map corresponding to a specific shared cache map (the one that
|
|
was present in the FILE_OBJECT when it was created), then delete that too,
|
|
flusing all cached information.
|
|
|
|
Using these simple semantics, filesystems can do all the things they actually
|
|
do:
|
|
|
|
- Copy out the shared cache map pointer from a newly initialized file object
|
|
and store it in the fcb cache.
|
|
- Copy it back into any file object and call CcInitializeCacheMap to make
|
|
that file object be associated with the caching of all the other siblings.
|
|
- Call CcUninitializeCacheMap on a FILE_OBJECT many times, but have only the
|
|
first one count for each specific FILE_OBJECT.
|
|
- Have the actual last call to CcUninitializeCacheMap (that is, the one that
|
|
causes zero private cache maps to be associated with a shared cache map) to
|
|
delete the cache map and flush.
|
|
|
|
So private cache map here is a light weight structure that just remembers
|
|
what shared cache map it associates with.
|
|
|
|
*/
|
|
typedef struct _NOCC_PRIVATE_CACHE_MAP
|
|
{
|
|
LIST_ENTRY ListEntry;
|
|
PFILE_OBJECT FileObject;
|
|
PNOCC_CACHE_MAP Map;
|
|
} NOCC_PRIVATE_CACHE_MAP, *PNOCC_PRIVATE_CACHE_MAP;
|
|
|
|
LIST_ENTRY CcpAllSharedCacheMaps;
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
CcInitializeCacheManager(VOID)
|
|
{
|
|
int i;
|
|
|
|
DPRINT("Initialize\n");
|
|
for (i = 0; i < CACHE_NUM_SECTIONS; i++)
|
|
{
|
|
KeInitializeEvent(&CcCacheSections[i].ExclusiveWait,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
InitializeListHead(&CcCacheSections[i].ThisFileList);
|
|
}
|
|
|
|
InitializeListHead(&CcpAllSharedCacheMaps);
|
|
|
|
KeInitializeEvent(&CcDeleteEvent, SynchronizationEvent, FALSE);
|
|
KeInitializeEvent(&CcFinalizeEvent, SynchronizationEvent, FALSE);
|
|
KeInitializeEvent(&CcpLazyWriteEvent, SynchronizationEvent, FALSE);
|
|
|
|
CcCacheBitmap->Buffer = ((PULONG)&CcCacheBitmap[1]);
|
|
CcCacheBitmap->SizeOfBitMap = ROUND_UP(CACHE_NUM_SECTIONS, 32);
|
|
DPRINT1("Cache has %d entries\n", CcCacheBitmap->SizeOfBitMap);
|
|
ExInitializeFastMutex(&CcMutex);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
CcPfInitializePrefetcher(VOID)
|
|
{
|
|
/* Notify debugger */
|
|
DbgPrintEx(DPFLTR_PREFETCHER_ID,
|
|
DPFLTR_TRACE_LEVEL,
|
|
"CCPF: InitializePrefetecher()\n");
|
|
|
|
/* Setup the Prefetcher Data */
|
|
InitializeListHead(&CcPfGlobals.ActiveTraces);
|
|
InitializeListHead(&CcPfGlobals.CompletedTraces);
|
|
ExInitializeFastMutex(&CcPfGlobals.CompletedTracesLock);
|
|
|
|
/* FIXME: Setup the rest of the prefetecher */
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
CcpAcquireFileLock(PNOCC_CACHE_MAP Map)
|
|
{
|
|
DPRINT("Calling AcquireForLazyWrite: %x\n", Map->LazyContext);
|
|
return Map->Callbacks.AcquireForLazyWrite(Map->LazyContext, TRUE);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
CcpReleaseFileLock(PNOCC_CACHE_MAP Map)
|
|
{
|
|
DPRINT("Releasing Lazy Write %x\n", Map->LazyContext);
|
|
Map->Callbacks.ReleaseFromLazyWrite(Map->LazyContext);
|
|
}
|
|
|
|
/*
|
|
|
|
Cc functions are required to treat alternate streams of a file as the same
|
|
for the purpose of caching, meaning that we must be able to find the shared
|
|
cache map associated with the ``real'' stream associated with a stream file
|
|
object, if one exists. We do that by identifying a private cache map in
|
|
our gamut that has the same volume, device and fscontext as the stream file
|
|
object we're holding. It's heavy but it does work. This can probably be
|
|
improved, although there doesn't seem to be any real association between
|
|
a stream file object and a sibling file object in the file object struct
|
|
itself.
|
|
|
|
*/
|
|
|
|
/* Must have CcpLock() */
|
|
PFILE_OBJECT CcpFindOtherStreamFileObject(PFILE_OBJECT FileObject)
|
|
{
|
|
PLIST_ENTRY Entry, Private;
|
|
for (Entry = CcpAllSharedCacheMaps.Flink;
|
|
Entry != &CcpAllSharedCacheMaps;
|
|
Entry = Entry->Flink)
|
|
{
|
|
/* 'Identical' test for other stream file object */
|
|
PNOCC_CACHE_MAP Map = CONTAINING_RECORD(Entry, NOCC_CACHE_MAP, Entry);
|
|
for (Private = Map->PrivateCacheMaps.Flink;
|
|
Private != &Map->PrivateCacheMaps;
|
|
Private = Private->Flink)
|
|
{
|
|
PNOCC_PRIVATE_CACHE_MAP PrivateMap = CONTAINING_RECORD(Private,
|
|
NOCC_PRIVATE_CACHE_MAP,
|
|
ListEntry);
|
|
|
|
if (PrivateMap->FileObject->Flags & FO_STREAM_FILE &&
|
|
PrivateMap->FileObject->DeviceObject == FileObject->DeviceObject &&
|
|
PrivateMap->FileObject->Vpb == FileObject->Vpb &&
|
|
PrivateMap->FileObject->FsContext == FileObject->FsContext &&
|
|
PrivateMap->FileObject->FsContext2 == FileObject->FsContext2 &&
|
|
1)
|
|
{
|
|
return PrivateMap->FileObject;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Thanks: http://windowsitpro.com/Windows/Articles/ArticleID/3864/pg/2/2.html */
|
|
|
|
VOID
|
|
NTAPI
|
|
CcInitializeCacheMap(IN PFILE_OBJECT FileObject,
|
|
IN PCC_FILE_SIZES FileSizes,
|
|
IN BOOLEAN PinAccess,
|
|
IN PCACHE_MANAGER_CALLBACKS Callbacks,
|
|
IN PVOID LazyWriteContext)
|
|
{
|
|
PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
|
|
PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap;
|
|
|
|
CcpLock();
|
|
/* We don't have a shared cache map. First find out if we have a sibling
|
|
stream file object we can take it from. */
|
|
if (!Map && FileObject->Flags & FO_STREAM_FILE)
|
|
{
|
|
PFILE_OBJECT IdenticalStreamFileObject = CcpFindOtherStreamFileObject(FileObject);
|
|
if (IdenticalStreamFileObject)
|
|
Map = IdenticalStreamFileObject->SectionObjectPointer->SharedCacheMap;
|
|
if (Map)
|
|
{
|
|
DPRINT1("Linking SFO %x to previous SFO %x through cache map %x #\n",
|
|
FileObject,
|
|
IdenticalStreamFileObject,
|
|
Map);
|
|
}
|
|
}
|
|
/* We still don't have a shared cache map. We need to create one. */
|
|
if (!Map)
|
|
{
|
|
DPRINT("Initializing file object for (%p) %wZ\n",
|
|
FileObject,
|
|
&FileObject->FileName);
|
|
|
|
Map = ExAllocatePool(NonPagedPool, sizeof(NOCC_CACHE_MAP));
|
|
FileObject->SectionObjectPointer->SharedCacheMap = Map;
|
|
Map->FileSizes = *FileSizes;
|
|
Map->LazyContext = LazyWriteContext;
|
|
Map->ReadAheadGranularity = PAGE_SIZE;
|
|
RtlCopyMemory(&Map->Callbacks, Callbacks, sizeof(*Callbacks));
|
|
|
|
/* For now ... */
|
|
DPRINT("FileSizes->ValidDataLength %I64x\n",
|
|
FileSizes->ValidDataLength.QuadPart);
|
|
|
|
InitializeListHead(&Map->AssociatedBcb);
|
|
InitializeListHead(&Map->PrivateCacheMaps);
|
|
InsertTailList(&CcpAllSharedCacheMaps, &Map->Entry);
|
|
DPRINT("New Map %p\n", Map);
|
|
}
|
|
/* We don't have a private cache map. Link it with the shared cache map
|
|
to serve as a held reference. When the list in the shared cache map
|
|
is empty, we know we can delete it. */
|
|
if (!PrivateCacheMap)
|
|
{
|
|
PrivateCacheMap = ExAllocatePool(NonPagedPool,
|
|
sizeof(*PrivateCacheMap));
|
|
|
|
FileObject->PrivateCacheMap = PrivateCacheMap;
|
|
PrivateCacheMap->FileObject = FileObject;
|
|
ObReferenceObject(PrivateCacheMap->FileObject);
|
|
}
|
|
|
|
PrivateCacheMap->Map = Map;
|
|
InsertTailList(&Map->PrivateCacheMaps, &PrivateCacheMap->ListEntry);
|
|
|
|
CcpUnlock();
|
|
}
|
|
|
|
/*
|
|
|
|
This function is used by NewCC's MM to determine whether any section objects
|
|
for a given file are not cache sections. If that's true, we're not allowed
|
|
to resize the file, although nothing actually prevents us from doing ;-)
|
|
|
|
*/
|
|
|
|
ULONG
|
|
NTAPI
|
|
CcpCountCacheSections(IN PNOCC_CACHE_MAP Map)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
ULONG Count;
|
|
|
|
for (Count = 0, Entry = Map->AssociatedBcb.Flink;
|
|
Entry != &Map->AssociatedBcb;
|
|
Entry = Entry->Flink, Count++);
|
|
|
|
return Count;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
CcUninitializeCacheMap(IN PFILE_OBJECT FileObject,
|
|
IN OPTIONAL PLARGE_INTEGER TruncateSize,
|
|
IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent)
|
|
{
|
|
BOOLEAN LastMap = FALSE;
|
|
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
|
|
PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap;
|
|
|
|
DPRINT("Uninitializing file object for %wZ SectionObjectPointer %x\n",
|
|
&FileObject->FileName,
|
|
FileObject->SectionObjectPointer);
|
|
|
|
ASSERT(UninitializeEvent == NULL);
|
|
|
|
/* It may not be strictly necessary to flush here, but we do just for
|
|
kicks. */
|
|
if (Map)
|
|
CcpFlushCache(Map, NULL, 0, NULL, FALSE);
|
|
|
|
CcpLock();
|
|
/* We have a private cache map, so we've been initialized and haven't been
|
|
* uninitialized. */
|
|
if (PrivateCacheMap)
|
|
{
|
|
ASSERT(!Map || Map == PrivateCacheMap->Map);
|
|
ASSERT(PrivateCacheMap->FileObject == FileObject);
|
|
|
|
RemoveEntryList(&PrivateCacheMap->ListEntry);
|
|
/* That was the last private cache map. It's time to delete all
|
|
cache stripes and all aspects of caching on the file. */
|
|
if (IsListEmpty(&PrivateCacheMap->Map->PrivateCacheMaps))
|
|
{
|
|
/* Get rid of all the cache stripes. */
|
|
while (!IsListEmpty(&PrivateCacheMap->Map->AssociatedBcb))
|
|
{
|
|
PNOCC_BCB Bcb = CONTAINING_RECORD(PrivateCacheMap->Map->AssociatedBcb.Flink,
|
|
NOCC_BCB,
|
|
ThisFileList);
|
|
|
|
DPRINT("Evicting cache stripe #%x\n", Bcb - CcCacheSections);
|
|
Bcb->RefCount = 1;
|
|
CcpDereferenceCache(Bcb - CcCacheSections, TRUE);
|
|
}
|
|
RemoveEntryList(&PrivateCacheMap->Map->Entry);
|
|
ExFreePool(PrivateCacheMap->Map);
|
|
FileObject->SectionObjectPointer->SharedCacheMap = NULL;
|
|
LastMap = TRUE;
|
|
}
|
|
ObDereferenceObject(PrivateCacheMap->FileObject);
|
|
FileObject->PrivateCacheMap = NULL;
|
|
ExFreePool(PrivateCacheMap);
|
|
}
|
|
CcpUnlock();
|
|
|
|
DPRINT("Uninit complete\n");
|
|
|
|
/* The return from CcUninitializeCacheMap means that 'caching was stopped'. */
|
|
return LastMap;
|
|
}
|
|
|
|
/*
|
|
|
|
CcSetFileSizes is used to tell the cache manager that the file changed
|
|
size. In our case, we use the internal Mm method MmExtendCacheSection
|
|
to notify Mm that our section potentially changed size, which may mean
|
|
truncating off data.
|
|
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
CcSetFileSizes(IN PFILE_OBJECT FileObject,
|
|
IN PCC_FILE_SIZES FileSizes)
|
|
{
|
|
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
|
|
PNOCC_BCB Bcb;
|
|
|
|
if (!Map) return;
|
|
Map->FileSizes = *FileSizes;
|
|
Bcb = Map->AssociatedBcb.Flink == &Map->AssociatedBcb ?
|
|
NULL : CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
|
|
if (!Bcb) return;
|
|
MmExtendCacheSection(Bcb->SectionObject, &FileSizes->FileSize, FALSE);
|
|
DPRINT("FileSizes->FileSize %x\n", FileSizes->FileSize.LowPart);
|
|
DPRINT("FileSizes->AllocationSize %x\n", FileSizes->AllocationSize.LowPart);
|
|
DPRINT("FileSizes->ValidDataLength %x\n", FileSizes->ValidDataLength.LowPart);
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
CcGetFileSizes(IN PFILE_OBJECT FileObject,
|
|
IN PCC_FILE_SIZES FileSizes)
|
|
{
|
|
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
|
|
if (!Map) return FALSE;
|
|
*FileSizes = Map->FileSizes;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
|
IN OPTIONAL PLARGE_INTEGER FileOffset,
|
|
IN ULONG Length,
|
|
IN BOOLEAN UninitializeCacheMaps)
|
|
{
|
|
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap;
|
|
if (!Map) return TRUE;
|
|
CcpFlushCache(Map, NULL, 0, NULL, TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
CcSetDirtyPageThreshold(IN PFILE_OBJECT FileObject,
|
|
IN ULONG DirtyPageThreshold)
|
|
{
|
|
UNIMPLEMENTED_DBGBREAK();
|
|
}
|
|
|
|
/*
|
|
|
|
This could be implemented much more intelligently by mapping instances
|
|
of a CoW zero page into the affected regions. We just RtlZeroMemory
|
|
for now.
|
|
|
|
*/
|
|
BOOLEAN
|
|
NTAPI
|
|
CcZeroData(IN PFILE_OBJECT FileObject,
|
|
IN PLARGE_INTEGER StartOffset,
|
|
IN PLARGE_INTEGER EndOffset,
|
|
IN BOOLEAN Wait)
|
|
{
|
|
PNOCC_BCB Bcb = NULL;
|
|
PLIST_ENTRY ListEntry = NULL;
|
|
LARGE_INTEGER LowerBound = *StartOffset;
|
|
LARGE_INTEGER UpperBound = *EndOffset;
|
|
LARGE_INTEGER Target, End;
|
|
PVOID PinnedBcb, PinnedBuffer;
|
|
PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
|
|
|
|
DPRINT("S %I64x E %I64x\n",
|
|
StartOffset->QuadPart,
|
|
EndOffset->QuadPart);
|
|
|
|
if (!Map)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK IOSB;
|
|
PCHAR ZeroBuf = ExAllocatePool(PagedPool, PAGE_SIZE);
|
|
ULONG ToWrite;
|
|
|
|
if (!ZeroBuf) RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
|
|
DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE);
|
|
RtlZeroMemory(ZeroBuf, PAGE_SIZE);
|
|
|
|
Target.QuadPart = PAGE_ROUND_DOWN(LowerBound.QuadPart);
|
|
End.QuadPart = PAGE_ROUND_UP(UpperBound.QuadPart);
|
|
|
|
// Handle leading page
|
|
if (LowerBound.QuadPart != Target.QuadPart)
|
|
{
|
|
ToWrite = MIN(UpperBound.QuadPart - LowerBound.QuadPart,
|
|
(PAGE_SIZE - LowerBound.QuadPart) & (PAGE_SIZE - 1));
|
|
|
|
DPRINT("Zero last half %I64x %lx\n",
|
|
Target.QuadPart,
|
|
ToWrite);
|
|
|
|
Status = MiSimpleRead(FileObject,
|
|
&Target,
|
|
ZeroBuf,
|
|
PAGE_SIZE,
|
|
TRUE,
|
|
&IOSB);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(ZeroBuf);
|
|
RtlRaiseStatus(Status);
|
|
}
|
|
|
|
DPRINT1("RtlZeroMemory(%p, %lx)\n",
|
|
ZeroBuf + LowerBound.QuadPart - Target.QuadPart,
|
|
ToWrite);
|
|
|
|
RtlZeroMemory(ZeroBuf + LowerBound.QuadPart - Target.QuadPart,
|
|
ToWrite);
|
|
|
|
Status = MiSimpleWrite(FileObject,
|
|
&Target,
|
|
ZeroBuf,
|
|
MIN(PAGE_SIZE,
|
|
UpperBound.QuadPart-Target.QuadPart),
|
|
&IOSB);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(ZeroBuf);
|
|
RtlRaiseStatus(Status);
|
|
}
|
|
Target.QuadPart += PAGE_SIZE;
|
|
}
|
|
|
|
DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE);
|
|
RtlZeroMemory(ZeroBuf, PAGE_SIZE);
|
|
|
|
while (UpperBound.QuadPart - Target.QuadPart > PAGE_SIZE)
|
|
{
|
|
DPRINT("Zero full page %I64x\n",
|
|
Target.QuadPart);
|
|
|
|
Status = MiSimpleWrite(FileObject,
|
|
&Target,
|
|
ZeroBuf,
|
|
PAGE_SIZE,
|
|
&IOSB);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(ZeroBuf);
|
|
RtlRaiseStatus(Status);
|
|
}
|
|
Target.QuadPart += PAGE_SIZE;
|
|
}
|
|
|
|
if (UpperBound.QuadPart > Target.QuadPart)
|
|
{
|
|
ToWrite = UpperBound.QuadPart - Target.QuadPart;
|
|
DPRINT("Zero first half %I64x %lx\n",
|
|
Target.QuadPart,
|
|
ToWrite);
|
|
|
|
Status = MiSimpleRead(FileObject,
|
|
&Target,
|
|
ZeroBuf,
|
|
PAGE_SIZE,
|
|
TRUE,
|
|
&IOSB);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(ZeroBuf);
|
|
RtlRaiseStatus(Status);
|
|
}
|
|
DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, ToWrite);
|
|
RtlZeroMemory(ZeroBuf, ToWrite);
|
|
Status = MiSimpleWrite(FileObject,
|
|
&Target,
|
|
ZeroBuf,
|
|
MIN(PAGE_SIZE,
|
|
UpperBound.QuadPart-Target.QuadPart),
|
|
&IOSB);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ExFreePool(ZeroBuf);
|
|
RtlRaiseStatus(Status);
|
|
}
|
|
Target.QuadPart += PAGE_SIZE;
|
|
}
|
|
|
|
ExFreePool(ZeroBuf);
|
|
return TRUE;
|
|
}
|
|
|
|
CcpLock();
|
|
ListEntry = Map->AssociatedBcb.Flink;
|
|
|
|
while (ListEntry != &Map->AssociatedBcb)
|
|
{
|
|
Bcb = CONTAINING_RECORD(ListEntry, NOCC_BCB, ThisFileList);
|
|
CcpReferenceCache(Bcb - CcCacheSections);
|
|
|
|
if (Bcb->FileOffset.QuadPart + Bcb->Length >= LowerBound.QuadPart &&
|
|
Bcb->FileOffset.QuadPart < UpperBound.QuadPart)
|
|
{
|
|
DPRINT("Bcb #%x (@%I64x)\n",
|
|
Bcb - CcCacheSections,
|
|
Bcb->FileOffset.QuadPart);
|
|
|
|
Target.QuadPart = MAX(Bcb->FileOffset.QuadPart,
|
|
LowerBound.QuadPart);
|
|
|
|
End.QuadPart = MIN(Map->FileSizes.ValidDataLength.QuadPart,
|
|
UpperBound.QuadPart);
|
|
|
|
End.QuadPart = MIN(End.QuadPart,
|
|
Bcb->FileOffset.QuadPart + Bcb->Length);
|
|
|
|
CcpUnlock();
|
|
|
|
if (!CcPreparePinWrite(FileObject,
|
|
&Target,
|
|
End.QuadPart - Target.QuadPart,
|
|
TRUE,
|
|
Wait,
|
|
&PinnedBcb,
|
|
&PinnedBuffer))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ASSERT(PinnedBcb == Bcb);
|
|
|
|
CcpLock();
|
|
ListEntry = ListEntry->Flink;
|
|
/* Return from pin state */
|
|
CcpUnpinData(PinnedBcb, TRUE);
|
|
}
|
|
|
|
CcpUnpinData(Bcb, TRUE);
|
|
}
|
|
|
|
CcpUnlock();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PFILE_OBJECT
|
|
NTAPI
|
|
CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointer)
|
|
{
|
|
PFILE_OBJECT Result = NULL;
|
|
PNOCC_CACHE_MAP Map = SectionObjectPointer->SharedCacheMap;
|
|
CcpLock();
|
|
if (!IsListEmpty(&Map->AssociatedBcb))
|
|
{
|
|
PNOCC_BCB Bcb = CONTAINING_RECORD(Map->AssociatedBcb.Flink,
|
|
NOCC_BCB,
|
|
ThisFileList);
|
|
|
|
Result = MmGetFileObjectForSection((PROS_SECTION_OBJECT)Bcb->SectionObject);
|
|
}
|
|
CcpUnlock();
|
|
return Result;
|
|
}
|
|
|
|
PFILE_OBJECT
|
|
NTAPI
|
|
CcGetFileObjectFromBcb(PVOID Bcb)
|
|
{
|
|
PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
|
|
DPRINT("BCB #%x\n", RealBcb - CcCacheSections);
|
|
return MmGetFileObjectForSection((PROS_SECTION_OBJECT)RealBcb->SectionObject);
|
|
}
|
|
|
|
/* EOF */
|