/* The following is a test mode that only works with modified filesystems.
* it maps the cache sections read only until they're pinned writable, and then
- * turns them readonly again when they're unpinned.
+ * turns them readonly again when they're unpinned.
* This helped me determine that a certain bug was not a memory overwrite. */
+
//#define PIN_WRITE_ONLY
+/*
+
+Pinsup implements the core of NewCC.
+
+A couple of things about this code:
+
+I wrote this code over the course of about 2 years, often referring to Rajeev
+Nagar's Filesystem Internals, book, the msdn pages on the Cc interface, and
+a few NT filesystems that are open sourced. I went to fairly great lengths to
+achieve a couple of goals.
+
+1) To make a strictly layered facility that relies entirely on Mm to provide
+maps. There were many ways in which data segments in the legacy Mm were unable
+to provide what I needed; page maps were only 4 gig, and all offsets were in
+ULONG, so no mapping at an offset greater than 4 gig was possible. Worse than
+that, due to a convoluted set of dependencies, it would have been impossible to
+support any two mappings farther apart than 4 gig, even if the above was
+corrected. Along with that, the cache system's ownership of some pages was
+integral to the operation of legacy Mm. All of the above problems, along with
+an ambiguity about when the size of a file for mapping purposes is acquired,
+and its inability to allow a file to be resized when any mappings were active
+led me to rewrite data sections (and all other kinds of sections in the
+original version), and use that layer to implement the Cc API without regard
+to any internal, undocumented parts.
+
+2) To write the simplest possible code that implements the Cc interface as
+documented. Again this is without regard to any information that might be
+gained through reverse engineering the real Cc. All conclusions about workings
+of Cc here are mine, any failures are mine, any differences to the documented
+interface were introduced by me due to misreading, misunderstanding or mis
+remembering while implementing the code. I also implemented some obvious, but
+not actually specified behaviors of Cc, for example that each cache stripe is
+represented by a distinct BCB that the user can make decisions about as an
+opaque pointer.
+
+3) To make real filesystems work properly.
+
+So about how it works:
+
+CcCacheSections is the collection of cache sections that are currently mapped.
+The cache ranges which are allocated and contain pages is larger, due to the
+addition of sections containing rmaps and page references, but this array
+determines the actual mapped pages on behalf of all mapped files for Cc's use.
+All BCB pointers yielded to a driver are a pointer to one of these cache stripe
+structures. The data structure is specified as opaque and so it contains
+information convenient to NEWCC's implementation here. Free entries are
+summarized in CcpBitmapBuffer, for which bits are set when the entry may be
+safely evicted and redirected for use by another client. Note that the
+reference count for an evictable cache section will generally be 1, since
+we'll keep a reference to wait for any subsequent mapping of the same stripe.
+We use CcCacheClockHand as a hint to start checking free bits at a point that
+walks around the cache stripe list, so that we might evict a different stripe
+every time even if all are awaiting reuse. This is a way to avoid thrashing.
+
+CcpBitmapBuffer is the RTL_BITMAP that allows us to quickly decide what buffer
+to allocate from the mapped buffer set.
+
+CcDeleteEvent is an event used to wait for a cache stripe reference count to
+go to 1, thus making the stripe eligible for eviction. It's used by CcpMapData
+to wait for a free map when we can't fail.
+
+All in all, use of Mm by Cc makes this code into a simple manager that wields
+sections on behalf of filesystems. As such, its code is fairly high level and
+no architecture specific changes should be necessary.
+
+*/
+
/* GLOBALS ********************************************************************/
#define TAG_MAP_SEC TAG('C', 'c', 'S', 'x')
/* FUNCTIONS ******************************************************************/
PETHREAD LastThread;
-VOID _CcpLock(const char *file, int line)
+
+VOID
+_CcpLock(const char *file,
+ int line)
{
//DPRINT("<<<---<<< CC In Mutex(%s:%d %x)!\n", file, line, PsGetCurrentThread());
ExAcquireFastMutex(&CcMutex);
}
-VOID _CcpUnlock(const char *file, int line)
+VOID
+_CcpUnlock(const char *file,
+ int line)
{
ExReleaseFastMutex(&CcMutex);
//DPRINT(">>>--->>> CC Exit Mutex!\n", file, line);
NTAPI
MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject);
-NTSTATUS CcpAllocateSection
-(PFILE_OBJECT FileObject,
- ULONG Length,
- ULONG Protect,
- PMM_CACHE_SECTION_SEGMENT *Result)
+/*
+
+Allocate an almost ordinary section object for use by the cache system.
+The special internal SEC_CACHE flag is used to indicate that the section
+should not count when determining whether the file can be resized.
+
+*/
+
+NTSTATUS
+CcpAllocateSection(PFILE_OBJECT FileObject,
+ ULONG Length,
+ ULONG Protect,
+ PROS_SECTION_OBJECT *Result)
{
NTSTATUS Status;
LARGE_INTEGER MaxSize;
MaxSize.QuadPart = Length;
- DPRINT("Making Section for File %x\n", FileObject);
- DPRINT("File name %wZ\n", &FileObject->FileName);
- Status = MmCreateCacheSection
- (Result,
- STANDARD_RIGHTS_REQUIRED,
- NULL,
- &MaxSize,
- Protect,
- SEC_RESERVE | SEC_CACHE,
- FileObject);
-
+ DPRINT("Making Section for File %x\n", FileObject);
+ DPRINT("File name %wZ\n", &FileObject->FileName);
+
+ Status = MmCreateSection((PVOID*)Result,
+ STANDARD_RIGHTS_REQUIRED,
+ NULL,
+ &MaxSize,
+ Protect,
+ SEC_RESERVE | SEC_CACHE,
+ NULL,
+ FileObject);
+
return Status;
}
-typedef struct _WORK_QUEUE_WITH_CONTEXT
-{
- WORK_QUEUE_ITEM WorkItem;
- PVOID ToUnmap;
- LARGE_INTEGER FileOffset;
- LARGE_INTEGER MapSize;
- PMM_CACHE_SECTION_SEGMENT ToDeref;
- PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite;
- PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite;
- PVOID LazyContext;
- BOOLEAN Dirty;
+typedef struct _WORK_QUEUE_WITH_CONTEXT
+{
+ WORK_QUEUE_ITEM WorkItem;
+ PVOID ToUnmap;
+ LARGE_INTEGER FileOffset;
+ LARGE_INTEGER MapSize;
+ PROS_SECTION_OBJECT ToDeref;
+ PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite;
+ PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite;
+ PVOID LazyContext;
+ BOOLEAN Dirty;
} WORK_QUEUE_WITH_CONTEXT, *PWORK_QUEUE_WITH_CONTEXT;
+/*
+
+Unmap a cache stripe. Note that cache stripes aren't unmapped when their
+last reference disappears. We enter this code only if cache for the file
+is uninitialized in the last file object, or a cache stripe is evicted.
+
+*/
+
VOID
CcpUnmapCache(PVOID Context)
{
- PWORK_QUEUE_WITH_CONTEXT WorkItem = (PWORK_QUEUE_WITH_CONTEXT)Context;
- DPRINT("Unmapping (finally) %x\n", WorkItem->ToUnmap);
- WorkItem->AcquireForLazyWrite(WorkItem->LazyContext, TRUE);
- MiFlushMappedSection(WorkItem->ToUnmap, &WorkItem->FileOffset, &WorkItem->MapSize, WorkItem->Dirty);
- WorkItem->ReleaseFromLazyWrite(WorkItem->LazyContext);
- MmUnmapCacheViewInSystemSpace(WorkItem->ToUnmap);
- MmFinalizeSegment(WorkItem->ToDeref);
- ExFreePool(WorkItem);
- DPRINT("Done\n");
+ PWORK_QUEUE_WITH_CONTEXT WorkItem = (PWORK_QUEUE_WITH_CONTEXT)Context;
+ DPRINT("Unmapping (finally) %x\n", WorkItem->ToUnmap);
+ MmUnmapCacheViewInSystemSpace(WorkItem->ToUnmap);
+ ObDereferenceObject(WorkItem->ToDeref);
+ ExFreePool(WorkItem);
+ DPRINT("Done\n");
}
+/*
+
+Somewhat deceptively named function which removes the last reference to a
+cache stripe and completely removes it using CcUnmapCache. This may be
+done either inline (if the Immediate BOOLEAN is set), or using a work item
+at a later time. Whether this is called to unmap immeidately is mainly
+determined by whether the caller is calling from a place in filesystem code
+where a deadlock may occur if immediate flushing is required.
+
+It's always safe to reuse the Bcb at CcCacheSections[Start] after calling
+this.
+
+ */
+
/* Must have acquired the mutex */
-VOID CcpDereferenceCache(ULONG Start, BOOLEAN Immediate)
+VOID
+CcpDereferenceCache(ULONG Start,
+ BOOLEAN Immediate)
{
- PVOID ToUnmap;
+ PVOID ToUnmap;
PNOCC_BCB Bcb;
- BOOLEAN Dirty;
- LARGE_INTEGER MappedSize;
- LARGE_INTEGER BaseOffset;
- PWORK_QUEUE_WITH_CONTEXT WorkItem;
+ BOOLEAN Dirty;
+ LARGE_INTEGER MappedSize;
+ LARGE_INTEGER BaseOffset;
+ PWORK_QUEUE_WITH_CONTEXT WorkItem;
DPRINT("CcpDereferenceCache(#%x)\n", Start);
Bcb = &CcCacheSections[Start];
- Dirty = Bcb->Dirty;
- ToUnmap = Bcb->BaseAddress;
- BaseOffset = Bcb->FileOffset;
- MappedSize = Bcb->Map->FileSizes.ValidDataLength;
+ Dirty = Bcb->Dirty;
+ ToUnmap = Bcb->BaseAddress;
+ BaseOffset = Bcb->FileOffset;
+ MappedSize = Bcb->Map->FileSizes.ValidDataLength;
DPRINT("Dereference #%x (count %d)\n", Start, Bcb->RefCount);
ASSERT(Bcb->SectionObject);
ASSERT(Bcb->RefCount == 1);
-
- DPRINT("Firing work item for %x\n", Bcb->BaseAddress);
-
- if (Immediate)
- {
- PMM_CACHE_SECTION_SEGMENT ToDeref = Bcb->SectionObject;
- BOOLEAN Dirty = Bcb->Dirty;
-
- Bcb->Map = NULL;
- Bcb->SectionObject = NULL;
- Bcb->BaseAddress = NULL;
- Bcb->FileOffset.QuadPart = 0;
- Bcb->Length = 0;
- Bcb->RefCount = 0;
- Bcb->Dirty = FALSE;
- RemoveEntryList(&Bcb->ThisFileList);
-
- CcpUnlock();
- MiFlushMappedSection(ToUnmap, &BaseOffset, &MappedSize, Dirty);
- MmUnmapCacheViewInSystemSpace(ToUnmap);
- MmFinalizeSegment(ToDeref);
- CcpLock();
- }
- else
- {
- WorkItem = ExAllocatePool(NonPagedPool, sizeof(*WorkItem));
- if (!WorkItem) KeBugCheck(0);
- WorkItem->ToUnmap = Bcb->BaseAddress;
- WorkItem->FileOffset = Bcb->FileOffset;
- WorkItem->Dirty = Bcb->Dirty;
- WorkItem->MapSize = MappedSize;
- WorkItem->ToDeref = Bcb->SectionObject;
- WorkItem->AcquireForLazyWrite = Bcb->Map->Callbacks.AcquireForLazyWrite;
- WorkItem->ReleaseFromLazyWrite = Bcb->Map->Callbacks.ReleaseFromLazyWrite;
- WorkItem->LazyContext = Bcb->Map->LazyContext;
-
- ExInitializeWorkItem(((PWORK_QUEUE_ITEM)WorkItem), (PWORKER_THREAD_ROUTINE)CcpUnmapCache, WorkItem);
-
- Bcb->Map = NULL;
- Bcb->SectionObject = NULL;
- Bcb->BaseAddress = NULL;
- Bcb->FileOffset.QuadPart = 0;
- Bcb->Length = 0;
- Bcb->RefCount = 0;
- Bcb->Dirty = FALSE;
- RemoveEntryList(&Bcb->ThisFileList);
-
- CcpUnlock();
- ExQueueWorkItem((PWORK_QUEUE_ITEM)WorkItem, DelayedWorkQueue);
- CcpLock();
- }
- DPRINT("Done\n");
+
+ DPRINT("Firing work item for %x\n", Bcb->BaseAddress);
+
+ if (Dirty) {
+ CcpUnlock();
+ Bcb->RefCount++;
+ MiFlushMappedSection(ToUnmap, &BaseOffset, &MappedSize, Dirty);
+ Bcb->RefCount--;
+ CcpLock();
+ }
+
+ if (Immediate)
+ {
+ PROS_SECTION_OBJECT ToDeref = Bcb->SectionObject;
+ Bcb->Map = NULL;
+ Bcb->SectionObject = NULL;
+ Bcb->BaseAddress = NULL;
+ Bcb->FileOffset.QuadPart = 0;
+ Bcb->Length = 0;
+ Bcb->RefCount = 0;
+ Bcb->Dirty = FALSE;
+ RemoveEntryList(&Bcb->ThisFileList);
+
+ CcpUnlock();
+ MmUnmapCacheViewInSystemSpace(ToUnmap);
+ ObDereferenceObject(ToDeref);
+ CcpLock();
+ }
+ else
+ {
+ WorkItem = ExAllocatePool(NonPagedPool, sizeof(*WorkItem));
+ if (!WorkItem) KeBugCheck(0);
+ WorkItem->ToUnmap = Bcb->BaseAddress;
+ WorkItem->FileOffset = Bcb->FileOffset;
+ WorkItem->Dirty = Bcb->Dirty;
+ WorkItem->MapSize = MappedSize;
+ WorkItem->ToDeref = Bcb->SectionObject;
+ WorkItem->AcquireForLazyWrite = Bcb->Map->Callbacks.AcquireForLazyWrite;
+ WorkItem->ReleaseFromLazyWrite = Bcb->Map->Callbacks.ReleaseFromLazyWrite;
+ WorkItem->LazyContext = Bcb->Map->LazyContext;
+
+ ExInitializeWorkItem(((PWORK_QUEUE_ITEM)WorkItem),
+ (PWORKER_THREAD_ROUTINE)CcpUnmapCache,
+ WorkItem);
+
+ Bcb->Map = NULL;
+ Bcb->SectionObject = NULL;
+ Bcb->BaseAddress = NULL;
+ Bcb->FileOffset.QuadPart = 0;
+ Bcb->Length = 0;
+ Bcb->RefCount = 0;
+ Bcb->Dirty = FALSE;
+ RemoveEntryList(&Bcb->ThisFileList);
+
+ CcpUnlock();
+ ExQueueWorkItem((PWORK_QUEUE_ITEM)WorkItem, DelayedWorkQueue);
+ CcpLock();
+ }
+ DPRINT("Done\n");
}
+/*
+
+CcpAllocateCacheSections is called by CcpMapData to obtain a cache stripe,
+possibly evicting an old stripe by calling CcpDereferenceCache in order to
+obtain an empty Bcb.
+
+This function was named plural due to a question I had at the beginning of
+this endeavor about whether a map may span a 256k stripe boundary. It can't
+so this function can only return the index of one Bcb. Returns INVALID_CACHE
+on failure.
+
+ */
/* Needs mutex */
-ULONG CcpAllocateCacheSections
-(PFILE_OBJECT FileObject,
- PMM_CACHE_SECTION_SEGMENT SectionObject)
+ULONG
+CcpAllocateCacheSections(PFILE_OBJECT FileObject,
+ PROS_SECTION_OBJECT SectionObject)
{
ULONG i = INVALID_CACHE;
PNOCC_CACHE_MAP Map;
PNOCC_BCB Bcb;
-
+
DPRINT("AllocateCacheSections: FileObject %x\n", FileObject);
-
+
if (!FileObject->SectionObjectPointer)
- return INVALID_CACHE;
+ return INVALID_CACHE;
Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
if (!Map)
- return INVALID_CACHE;
+ return INVALID_CACHE;
DPRINT("Allocating Cache Section\n");
if (i != INVALID_CACHE)
{
- DPRINT("Setting up Bcb #%x\n", i);
-
- Bcb = &CcCacheSections[i];
-
- ASSERT(Bcb->RefCount < 2);
-
- if (Bcb->RefCount > 0)
- {
- CcpDereferenceCache(i, FALSE);
- }
-
- ASSERT(!Bcb->RefCount);
- Bcb->RefCount = 1;
-
- DPRINT("Bcb #%x RefCount %d\n", Bcb - CcCacheSections, Bcb->RefCount);
-
- if (!RtlTestBit(CcCacheBitmap, i))
- {
- DPRINT("Somebody stoeled BCB #%x\n", i);
- }
- ASSERT(RtlTestBit(CcCacheBitmap, i));
-
- DPRINT("Allocated #%x\n", i);
- ASSERT(CcCacheSections[i].RefCount);
+ DPRINT("Setting up Bcb #%x\n", i);
+
+ Bcb = &CcCacheSections[i];
+
+ ASSERT(Bcb->RefCount < 2);
+
+ if (Bcb->RefCount > 0)
+ {
+ CcpDereferenceCache(i, FALSE);
+ }
+
+ ASSERT(!Bcb->RefCount);
+ Bcb->RefCount = 1;
+
+ DPRINT("Bcb #%x RefCount %d\n", Bcb - CcCacheSections, Bcb->RefCount);
+
+ if (!RtlTestBit(CcCacheBitmap, i))
+ {
+ DPRINT1("Somebody stoeled BCB #%x\n", i);
+ }
+ ASSERT(RtlTestBit(CcCacheBitmap, i));
+
+ DPRINT("Allocated #%x\n", i);
+ ASSERT(CcCacheSections[i].RefCount);
}
else
{
- DPRINT("Failed to allocate cache segment\n");
+ DPRINT1("Failed to allocate cache segment\n");
}
return i;
}
/* Must have acquired the mutex */
-VOID CcpReferenceCache(ULONG Start)
+VOID
+CcpReferenceCache(ULONG Start)
{
PNOCC_BCB Bcb;
Bcb = &CcCacheSections[Start];
}
-VOID CcpMarkForExclusive(ULONG Start)
+VOID
+CcpMarkForExclusive(ULONG Start)
{
PNOCC_BCB Bcb;
Bcb = &CcCacheSections[Start];
Bcb->ExclusiveWaiter++;
}
+/*
+
+Cache stripes have an idea of exclusive access, which would be hard to support
+properly in the previous code. In our case, it's fairly easy, since we have
+an event that indicates that the previous exclusive waiter has returned in each
+Bcb.
+
+*/
/* Must not have the mutex */
-VOID CcpReferenceCacheExclusive(ULONG Start)
+VOID
+CcpReferenceCacheExclusive(ULONG Start)
{
PNOCC_BCB Bcb = &CcCacheSections[Start];
- KeWaitForSingleObject(&Bcb->ExclusiveWait, Executive, KernelMode, FALSE, NULL);
+ KeWaitForSingleObject(&Bcb->ExclusiveWait,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
CcpLock();
ASSERT(Bcb->ExclusiveWaiter);
ASSERT(Bcb->SectionObject);
CcpUnlock();
}
-/* Find a map that encompasses the target range */
+/*
+
+Find a map that encompasses the target range. This function does not check
+whether the desired range is partly outside the stripe. This could be
+implemented with a generic table, but we generally aren't carring around a lot
+of segments at once for a particular file.
+
+When this returns a map for a given file address, then that address is by
+definition already mapped and can be operated on.
+
+Returns a valid index or INVALID_CACHE.
+
+*/
/* Must have the mutex */
-ULONG CcpFindMatchingMap(PLIST_ENTRY Head, PLARGE_INTEGER FileOffset, ULONG Length)
+ULONG
+CcpFindMatchingMap(PLIST_ENTRY Head,
+ PLARGE_INTEGER FileOffset,
+ ULONG Length)
{
- PLIST_ENTRY Entry;
+ PLIST_ENTRY Entry;
//DPRINT("Find Matching Map: (%x) %x:%x\n", FileOffset->LowPart, Length);
for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
{
- //DPRINT("Link @%x\n", Entry);
- PNOCC_BCB Bcb = CONTAINING_RECORD(Entry, NOCC_BCB, ThisFileList);
- //DPRINT("Selected BCB %x #%x\n", Bcb, Bcb - CcCacheSections);
- //DPRINT("This File: %x:%x\n", Bcb->FileOffset.LowPart, Bcb->Length);
- if (FileOffset->QuadPart >= Bcb->FileOffset.QuadPart &&
- FileOffset->QuadPart < Bcb->FileOffset.QuadPart + CACHE_STRIPE)
- {
- //DPRINT("Found match at #%x\n", Bcb - CcCacheSections);
- return Bcb - CcCacheSections;
- }
+ //DPRINT("Link @%x\n", Entry);
+ PNOCC_BCB Bcb = CONTAINING_RECORD(Entry, NOCC_BCB, ThisFileList);
+ //DPRINT("Selected BCB %x #%x\n", Bcb, Bcb - CcCacheSections);
+ //DPRINT("This File: %x:%x\n", Bcb->FileOffset.LowPart, Bcb->Length);
+ if (FileOffset->QuadPart >= Bcb->FileOffset.QuadPart &&
+ FileOffset->QuadPart < Bcb->FileOffset.QuadPart + CACHE_STRIPE)
+ {
+ //DPRINT("Found match at #%x\n", Bcb - CcCacheSections);
+ return Bcb - CcCacheSections;
+ }
}
//DPRINT("This region isn't mapped\n");
return INVALID_CACHE;
}
+/*
+
+Internal function that's used by all pinning functions.
+It causes a mapped region to exist and prefaults the pages in it if possible,
+possibly evicting another stripe in order to get our stripe.
+
+*/
+
BOOLEAN
NTAPI
-CcpMapData
-(IN PFILE_OBJECT FileObject,
- IN PLARGE_INTEGER FileOffset,
- IN ULONG Length,
- IN ULONG Flags,
- OUT PVOID *BcbResult,
- OUT PVOID *Buffer)
+CcpMapData(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ OUT PVOID *BcbResult,
+ OUT PVOID *Buffer)
{
BOOLEAN Success = FALSE, FaultIn = FALSE;
/* Note: windows 2000 drivers treat this as a bool */
//BOOLEAN Wait = (Flags & MAP_WAIT) || (Flags == TRUE);
LARGE_INTEGER Target, EndInterval;
- ULONG BcbHead;
+ ULONG BcbHead, SectionSize, ViewSize;
PNOCC_BCB Bcb = NULL;
- PMM_CACHE_SECTION_SEGMENT SectionObject = NULL;
+ PROS_SECTION_OBJECT SectionObject = NULL;
NTSTATUS Status;
- PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
+ ViewSize = CACHE_STRIPE;
- if (!Map)
- {
- DPRINT1("File object was not mapped\n");
- return FALSE;
- }
+ if (!Map)
+ {
+ DPRINT1("File object was not mapped\n");
+ return FALSE;
+ }
- DPRINT("CcMapData(F->%x,%08x%08x:%d)\n", FileObject, FileOffset->HighPart, FileOffset->LowPart, Length);
+ DPRINT("CcMapData(F->%x,%08x%08x:%d)\n",
+ FileObject,
+ FileOffset->HighPart,
+ FileOffset->LowPart,
+ Length);
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
Target.HighPart = FileOffset->HighPart;
- Target.LowPart = CACHE_ROUND_DOWN(FileOffset->LowPart);
+ Target.LowPart = CACHE_ROUND_DOWN(FileOffset->LowPart);
CcpLock();
/* Find out if any range is a superset of what we want */
- /* Find an accomodating section */
- BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
-
- if (BcbHead != INVALID_CACHE)
- {
- Bcb = &CcCacheSections[BcbHead];
- Success = TRUE;
- *BcbResult = Bcb;
- *Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
- DPRINT
- ("Bcb #%x Buffer maps (%08x%08x) At %x Length %x (Getting %x:%x) %wZ\n",
- Bcb - CcCacheSections,
- Bcb->FileOffset.HighPart,
- Bcb->FileOffset.LowPart,
- Bcb->BaseAddress,
- Bcb->Length,
- *Buffer,
- Length,
- &FileObject->FileName);
- DPRINT("w1n\n");
- goto cleanup;
- }
-
- ULONG SectionSize;
-
- DPRINT("File size %08x%08x\n", Map->FileSizes.ValidDataLength.HighPart, Map->FileSizes.ValidDataLength.LowPart);
-
- if (Map->FileSizes.ValidDataLength.QuadPart)
- {
- SectionSize = min(CACHE_STRIPE, Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart);
- }
- else
- {
- SectionSize = CACHE_STRIPE;
- }
-
- DPRINT("Allocating a cache stripe at %x:%d\n",
- Target.LowPart, SectionSize);
- //ASSERT(SectionSize <= CACHE_STRIPE);
-
- CcpUnlock();
- Status = CcpAllocateSection
- (FileObject,
- SectionSize,
+ /* Find an accomodating section */
+ BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
+
+ if (BcbHead != INVALID_CACHE)
+ {
+ Bcb = &CcCacheSections[BcbHead];
+ Success = TRUE;
+ *BcbResult = Bcb;
+ *Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
+
+ DPRINT("Bcb #%x Buffer maps (%08x%08x) At %x Length %x (Getting %x:%x) %wZ\n",
+ Bcb - CcCacheSections,
+ Bcb->FileOffset.HighPart,
+ Bcb->FileOffset.LowPart,
+ Bcb->BaseAddress,
+ Bcb->Length,
+ *Buffer,
+ Length,
+ &FileObject->FileName);
+
+ DPRINT("w1n\n");
+ goto cleanup;
+ }
+
+ DPRINT("File size %08x%08x\n",
+ Map->FileSizes.ValidDataLength.HighPart,
+ Map->FileSizes.ValidDataLength.LowPart);
+
+ /* Not all files have length, in fact filesystems often use stream file
+ objects for various internal purposes and are loose about the file
+ length, since the filesystem promises itself to write the right number
+ of bytes to the internal stream. In these cases, we just allow the file
+ to have the full stripe worth of space. */
+ if (Map->FileSizes.ValidDataLength.QuadPart)
+ {
+ SectionSize = min(CACHE_STRIPE,
+ Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart);
+ }
+ else
+ {
+ SectionSize = CACHE_STRIPE;
+ }
+
+ DPRINT("Allocating a cache stripe at %x:%d\n",
+ Target.LowPart, SectionSize);
+
+ //ASSERT(SectionSize <= CACHE_STRIPE);
+
+ CcpUnlock();
+ /* CcpAllocateSection doesn't need the lock, so we'll give other action
+ a chance in here. */
+ Status = CcpAllocateSection(FileObject,
+ SectionSize,
#ifdef PIN_WRITE_ONLY
- PAGE_READONLY,
+ PAGE_READONLY,
#else
- PAGE_READWRITE,
+ PAGE_READWRITE,
#endif
- &SectionObject);
- CcpLock();
-
- if (!NT_SUCCESS(Status))
- {
- *BcbResult = NULL;
- *Buffer = NULL;
- DPRINT1("End %08x\n", Status);
- goto cleanup;
- }
-
+ &SectionObject);
+ CcpLock();
+
+ if (!NT_SUCCESS(Status))
+ {
+ *BcbResult = NULL;
+ *Buffer = NULL;
+ DPRINT1("End %08x\n", Status);
+ goto cleanup;
+ }
+
retry:
/* Returns a reference */
- DPRINT("Allocating cache sections: %wZ\n", &FileObject->FileName);
- BcbHead = CcpAllocateCacheSections(FileObject, SectionObject);
- if (BcbHead == INVALID_CACHE)
- {
- ULONG i;
- DbgPrint("Cache Map:");
- for (i = 0; i < CACHE_NUM_SECTIONS; i++)
- {
- if (!(i % 64)) DbgPrint("\n");
- DbgPrint("%c", CcCacheSections[i].RefCount + (RtlTestBit(CcCacheBitmap, i) ? '@' : '`'));
- }
- DbgPrint("\n");
- KeWaitForSingleObject(&CcDeleteEvent, Executive, KernelMode, FALSE, NULL);
- goto retry;
- }
-
- DPRINT("BcbHead #%x (final)\n", BcbHead);
+ DPRINT("Allocating cache sections: %wZ\n", &FileObject->FileName);
+ BcbHead = CcpAllocateCacheSections(FileObject, SectionObject);
+ /* XXX todo: we should handle the immediate fail case here, but don't */
+ if (BcbHead == INVALID_CACHE)
+ {
+ ULONG i;
+ DbgPrint("Cache Map:");
+ for (i = 0; i < CACHE_NUM_SECTIONS; i++)
+ {
+ if (!(i % 64)) DbgPrint("\n");
+ DbgPrint("%c",
+ CcCacheSections[i].RefCount + (RtlTestBit(CcCacheBitmap, i) ? '@' : '`'));
+ }
+ DbgPrint("\n");
+
+ KeWaitForSingleObject(&CcDeleteEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ goto retry;
+ }
+
+ DPRINT("BcbHead #%x (final)\n", BcbHead);
if (BcbHead == INVALID_CACHE)
{
- *BcbResult = NULL;
- *Buffer = NULL;
- DPRINT1("End\n");
- goto cleanup;
+ *BcbResult = NULL;
+ *Buffer = NULL;
+ DPRINT1("End\n");
+ goto cleanup;
}
-
+
DPRINT("Selected BCB #%x\n", BcbHead);
- ULONG ViewSize = CACHE_STRIPE;
+ ViewSize = CACHE_STRIPE;
Bcb = &CcCacheSections[BcbHead];
- Status = MmMapCacheViewInSystemSpaceAtOffset
- (SectionObject,
- &Bcb->BaseAddress,
- &Target,
- &ViewSize);
-
+ /* MmMapCacheViewInSystemSpaceAtOffset is one of three methods of Mm
+ that are specific to NewCC. In this case, it's implementation
+ exactly mirrors MmMapViewInSystemSpace, but allows an offset to
+ be specified. */
+ Status = MmMapCacheViewInSystemSpaceAtOffset(SectionObject->Segment,
+ &Bcb->BaseAddress,
+ &Target,
+ &ViewSize);
+
+ /* Summary: Failure. Dereference our section and tell the user we failed */
if (!NT_SUCCESS(Status))
{
- *BcbResult = NULL;
- *Buffer = NULL;
- MmFinalizeSegment(SectionObject);
- RemoveEntryList(&Bcb->ThisFileList);
- RtlZeroMemory(Bcb, sizeof(*Bcb));
- RtlClearBit(CcCacheBitmap, BcbHead);
- DPRINT1("Failed to map\n");
- goto cleanup;
- }
-
- Success = TRUE;
- //DPRINT("w1n\n");
-
- Bcb->Length = MIN(Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart, CACHE_STRIPE);
- Bcb->SectionObject = SectionObject;
- Bcb->Map = Map;
- Bcb->FileOffset = Target;
- InsertTailList(&Map->AssociatedBcb, &Bcb->ThisFileList);
-
- *BcbResult = &CcCacheSections[BcbHead];
- *Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
- FaultIn = TRUE;
-
- DPRINT
- ("Bcb #%x Buffer maps (%08x%08x) At %x Length %x (Getting %x:%x) %wZ\n",
- Bcb - CcCacheSections,
- Bcb->FileOffset.HighPart,
- Bcb->FileOffset.LowPart,
- Bcb->BaseAddress,
- Bcb->Length,
- *Buffer,
- Length,
- &FileObject->FileName);
-
- EndInterval.QuadPart = Bcb->FileOffset.QuadPart + Bcb->Length - 1;
- ASSERT((EndInterval.QuadPart & ~(CACHE_STRIPE - 1)) == (Bcb->FileOffset.QuadPart & ~(CACHE_STRIPE - 1)));
-
+ *BcbResult = NULL;
+ *Buffer = NULL;
+ ObDereferenceObject(SectionObject);
+ RemoveEntryList(&Bcb->ThisFileList);
+ RtlZeroMemory(Bcb, sizeof(*Bcb));
+ RtlClearBit(CcCacheBitmap, BcbHead);
+ DPRINT1("Failed to map\n");
+ goto cleanup;
+ }
+
+ /* Summary: Success. Put together a valid Bcb and link it with the others
+ * in the NOCC_CACHE_MAP.
+ */
+ Success = TRUE;
+ //DPRINT("w1n\n");
+
+ Bcb->Length = MIN(Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart,
+ CACHE_STRIPE);
+
+ Bcb->SectionObject = SectionObject;
+ Bcb->Map = Map;
+ Bcb->FileOffset = Target;
+ InsertTailList(&Map->AssociatedBcb, &Bcb->ThisFileList);
+
+ *BcbResult = &CcCacheSections[BcbHead];
+ *Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
+ FaultIn = TRUE;
+
+ DPRINT("Bcb #%x Buffer maps (%08x%08x) At %x Length %x (Getting %x:%x) %wZ\n",
+ Bcb - CcCacheSections,
+ Bcb->FileOffset.HighPart,
+ Bcb->FileOffset.LowPart,
+ Bcb->BaseAddress,
+ Bcb->Length,
+ *Buffer,
+ Length,
+ &FileObject->FileName);
+
+ EndInterval.QuadPart = Bcb->FileOffset.QuadPart + Bcb->Length - 1;
+ ASSERT((EndInterval.QuadPart & ~(CACHE_STRIPE - 1)) ==
+ (Bcb->FileOffset.QuadPart & ~(CACHE_STRIPE - 1)));
+
//DPRINT("TERM!\n");
-
+
cleanup:
- CcpUnlock();
- if (Success)
- {
- if (FaultIn)
- {
- // Fault in the pages. This forces reads to happen now.
- ULONG i;
- CHAR Dummy;
- PCHAR FaultIn = Bcb->BaseAddress;
- DPRINT1
- ("Faulting in pages at this point: file %wZ %08x%08x:%x\n",
- &FileObject->FileName,
- Bcb->FileOffset.HighPart,
- Bcb->FileOffset.LowPart,
- Bcb->Length);
- for (i = 0; i < Bcb->Length; i++)
- {
- Dummy = FaultIn[i];
- }
- }
- ASSERT(Bcb >= CcCacheSections && Bcb < (CcCacheSections + CACHE_NUM_SECTIONS));
- }
- else
- {
- ASSERT(FALSE);
- }
+ CcpUnlock();
+ if (Success)
+ {
+ if (FaultIn)
+ {
+ /* Fault in the pages. This forces reads to happen now. */
+ ULONG i;
+ PCHAR FaultIn = Bcb->BaseAddress;
+
+ DPRINT("Faulting in pages at this point: file %wZ %08x%08x:%x\n",
+ &FileObject->FileName,
+ Bcb->FileOffset.HighPart,
+ Bcb->FileOffset.LowPart,
+ Bcb->Length);
+
+ for (i = 0; i < Bcb->Length; i += PAGE_SIZE)
+ {
+ FaultIn[i] ^= 0;
+ }
+ }
+ ASSERT(Bcb >= CcCacheSections &&
+ Bcb < (CcCacheSections + CACHE_NUM_SECTIONS));
+ }
+ else
+ {
+ ASSERT(FALSE);
+ }
return Success;
}
BOOLEAN
NTAPI
-CcMapData
-(IN PFILE_OBJECT FileObject,
- IN PLARGE_INTEGER FileOffset,
- IN ULONG Length,
- IN ULONG Flags,
- OUT PVOID *BcbResult,
- OUT PVOID *Buffer)
+CcMapData(IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ OUT PVOID *BcbResult,
+ OUT PVOID *Buffer)
{
BOOLEAN Result;
- Result = CcpMapData
- (FileObject,
- FileOffset,
- Length,
- Flags,
- BcbResult,
- Buffer);
-
- if (Result)
- {
- PNOCC_BCB Bcb = (PNOCC_BCB)*BcbResult;
- ASSERT(Bcb >= CcCacheSections && Bcb < CcCacheSections + CACHE_NUM_SECTIONS);
- ASSERT(Bcb->BaseAddress);
- CcpLock();
- CcpReferenceCache(Bcb - CcCacheSections);
- CcpUnlock();
- }
-
- return Result;
+ Result = CcpMapData(FileObject,
+ FileOffset,
+ Length,
+ Flags,
+ BcbResult,
+ Buffer);
+
+ if (Result)
+ {
+ PNOCC_BCB Bcb = (PNOCC_BCB)*BcbResult;
+
+ ASSERT(Bcb >= CcCacheSections &&
+ Bcb < CcCacheSections + CACHE_NUM_SECTIONS);
+
+ ASSERT(Bcb->BaseAddress);
+ CcpLock();
+ CcpReferenceCache(Bcb - CcCacheSections);
+ CcpUnlock();
+ }
+
+ return Result;
}
+/* Used by functions that repin data, CcpPinMappedData does not alter the map,
+ but finds the appropriate stripe and update the accounting. */
BOOLEAN
NTAPI
CcpPinMappedData(IN PNOCC_CACHE_MAP Map,
- IN PLARGE_INTEGER FileOffset,
- IN ULONG Length,
- IN ULONG Flags,
- IN OUT PVOID *Bcb)
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ IN OUT PVOID *Bcb)
{
BOOLEAN Exclusive = Flags & PIN_EXCLUSIVE;
ULONG BcbHead;
CcpLock();
- ASSERT(Map->AssociatedBcb.Flink == &Map->AssociatedBcb || (CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList) >= CcCacheSections && CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList) < CcCacheSections + CACHE_NUM_SECTIONS));
- BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
- if (BcbHead == INVALID_CACHE)
- {
- CcpUnlock();
- return FALSE;
- }
+ ASSERT(Map->AssociatedBcb.Flink == &Map->AssociatedBcb || (CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList) >= CcCacheSections && CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList) < CcCacheSections + CACHE_NUM_SECTIONS));
+ BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
+ if (BcbHead == INVALID_CACHE)
+ {
+ CcpUnlock();
+ return FALSE;
+ }
- TheBcb = &CcCacheSections[BcbHead];
+ TheBcb = &CcCacheSections[BcbHead];
if (Exclusive)
{
- DPRINT("Requesting #%x Exclusive\n", BcbHead);
- CcpMarkForExclusive(BcbHead);
+ DPRINT("Requesting #%x Exclusive\n", BcbHead);
+ CcpMarkForExclusive(BcbHead);
}
else
{
- DPRINT("Reference #%x\n", BcbHead);
- CcpReferenceCache(BcbHead);
+ DPRINT("Reference #%x\n", BcbHead);
+ CcpReferenceCache(BcbHead);
}
if (Exclusive)
- CcpReferenceCacheExclusive(BcbHead);
+ CcpReferenceCacheExclusive(BcbHead);
- CcpUnlock();
+ CcpUnlock();
- *Bcb = TheBcb;
+ *Bcb = TheBcb;
return TRUE;
}
BOOLEAN
NTAPI
CcPinMappedData(IN PFILE_OBJECT FileObject,
- IN PLARGE_INTEGER FileOffset,
- IN ULONG Length,
- IN ULONG Flags,
- IN OUT PVOID *Bcb)
+ IN PLARGE_INTEGER FileOffset,
+ IN ULONG Length,
+ IN ULONG Flags,
+ IN OUT PVOID *Bcb)
{
- PVOID Buffer;
- PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
-
- if (!Map)
- {
- DPRINT1("Not cached\n");
- return FALSE;
- }
-
- if (CcpMapData(FileObject, FileOffset, Length, Flags, Bcb, &Buffer))
- {
- return CcpPinMappedData(Map, FileOffset, Length, Flags, Bcb);
- }
- else
- {
- DPRINT1("could not map\n");
- return FALSE;
- }
+ PVOID Buffer;
+ PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
+
+ if (!Map)
+ {
+ DPRINT1("Not cached\n");
+ return FALSE;
+ }
+
+ if (CcpMapData(FileObject, FileOffset, Length, Flags, Bcb, &Buffer))
+ {
+ return CcpPinMappedData(Map, FileOffset, Length, Flags, Bcb);
+ }
+ else
+ {
+ DPRINT1("could not map\n");
+ return FALSE;
+ }
}
BOOLEAN
PNOCC_BCB RealBcb;
BOOLEAN Result;
- Result = CcPinMappedData
- (FileObject,
- FileOffset,
- Length,
- Flags,
- Bcb);
+ Result = CcPinMappedData(FileObject, FileOffset, Length, Flags, Bcb);
if (Result)
{
- CcpLock();
- RealBcb = *Bcb;
- *Buffer = ((PCHAR)RealBcb->BaseAddress) + (int)(FileOffset->QuadPart - RealBcb->FileOffset.QuadPart);
- CcpUnlock();
+ CcpLock();
+ RealBcb = *Bcb;
+ *Buffer = ((PCHAR)RealBcb->BaseAddress) + (int)(FileOffset->QuadPart - RealBcb->FileOffset.QuadPart);
+ CcpUnlock();
}
return Result;
}
-\f
+
BOOLEAN
NTAPI
CcPreparePinWrite(IN PFILE_OBJECT FileObject,
BOOLEAN Result;
PNOCC_BCB RealBcb;
#ifdef PIN_WRITE_ONLY
- PVOID BaseAddress;
- SIZE_T NumberOfBytes;
- ULONG OldProtect;
+ PVOID BaseAddress;
+ SIZE_T NumberOfBytes;
+ ULONG OldProtect;
#endif
- DPRINT1("CcPreparePinWrite(%x:%x)\n", Buffer, Length);
+ DPRINT("CcPreparePinWrite(%x:%x)\n", Buffer, Length);
+
+ Result = CcPinRead(FileObject, FileOffset, Length, Flags, Bcb, Buffer);
- Result = CcPinRead
- (FileObject,
- FileOffset,
- Length,
- Flags,
- Bcb,
- Buffer);
-
if (Result)
{
- CcpLock();
- RealBcb = *Bcb;
+ CcpLock();
+ RealBcb = *Bcb;
#ifdef PIN_WRITE_ONLY
- BaseAddress = RealBcb->BaseAddress;
- NumberOfBytes = RealBcb->Length;
-
- MiProtectVirtualMemory
- (NULL,
- &BaseAddress,
- &NumberOfBytes,
- PAGE_READWRITE,
- &OldProtect);
+ BaseAddress = RealBcb->BaseAddress;
+ NumberOfBytes = RealBcb->Length;
+
+ MiProtectVirtualMemory(NULL,
+ &BaseAddress,
+ &NumberOfBytes,
+ PAGE_READWRITE,
+ &OldProtect);
#endif
- CcpUnlock();
- RealBcb->Dirty = TRUE;
-
- if (Zero)
- {
- DPRINT
- ("Zero fill #%x %08x%08x:%x Buffer %x %wZ\n",
- RealBcb - CcCacheSections,
- FileOffset->u.HighPart,
- FileOffset->u.LowPart,
- Length,
- *Buffer,
- &FileObject->FileName);
-
- DPRINT1("RtlZeroMemory(%x,%x)\n", *Buffer, Length);
- RtlZeroMemory(*Buffer, Length);
- }
- }
+ CcpUnlock();
+ RealBcb->Dirty = TRUE;
+
+ if (Zero)
+ {
+ DPRINT("Zero fill #%x %08x%08x:%x Buffer %x %wZ\n",
+ RealBcb - CcCacheSections,
+ FileOffset->u.HighPart,
+ FileOffset->u.LowPart,
+ Length,
+ *Buffer,
+ &FileObject->FileName);
+
+ DPRINT1("RtlZeroMemory(%x,%x)\n", *Buffer, Length);
+ RtlZeroMemory(*Buffer, Length);
+ }
+ }
return Result;
}
+/*
+
+CcpUnpinData is the internal function that generally handles unpinning data.
+It may be a little confusing, because of the way reference counts are handled.
+
+A reference count of 2 or greater means that the stripe is still fully pinned
+and can't be removed. If the owner had taken an exclusive reference, then
+give one up. Note that it's an error to take more than one exclusive reference
+or to take a non-exclusive reference after an exclusive reference, so detecting
+or handling that case is not considered.
+
+ReleaseBit is unset if we want to detect when a cache stripe would become
+evictable without actually giving up our reference. We might want to do that
+if we were going to flush before formally releasing the cache stripe, although
+that facility is not used meaningfully at this time.
+
+A reference count of exactly 1 means that the stripe could potentially be
+reused, but could also be evicted for another mapping. In general, most
+stripes should be in that state most of the time.
+
+A reference count of zero means that the Bcb is completely unused. That's the
+start state and the state of a Bcb formerly owned by a file that is
+uninitialized.
+
+*/
+
BOOLEAN
NTAPI
CcpUnpinData(IN PNOCC_BCB RealBcb, BOOLEAN ReleaseBit)
{
if (RealBcb->RefCount <= 2)
{
- RealBcb->Exclusive = FALSE;
- if (RealBcb->ExclusiveWaiter)
- {
- DPRINT("Triggering exclusive waiter\n");
- KeSetEvent(&RealBcb->ExclusiveWait, IO_NO_INCREMENT, FALSE);
- return TRUE;
- }
+ RealBcb->Exclusive = FALSE;
+ if (RealBcb->ExclusiveWaiter)
+ {
+ DPRINT("Triggering exclusive waiter\n");
+ KeSetEvent(&RealBcb->ExclusiveWait, IO_NO_INCREMENT, FALSE);
+ return TRUE;
+ }
}
- if (RealBcb->RefCount == 2 && !ReleaseBit)
- return FALSE;
+ if (RealBcb->RefCount == 2 && !ReleaseBit)
+ return FALSE;
if (RealBcb->RefCount > 1)
{
- DPRINT("Removing one reference #%x\n", RealBcb - CcCacheSections);
- RealBcb->RefCount--;
- KeSetEvent(&CcDeleteEvent, IO_DISK_INCREMENT, FALSE);
+ DPRINT("Removing one reference #%x\n", RealBcb - CcCacheSections);
+ RealBcb->RefCount--;
+ KeSetEvent(&CcDeleteEvent, IO_DISK_INCREMENT, FALSE);
}
- if (RealBcb->RefCount == 1)
- {
- DPRINT("Clearing allocation bit #%x\n", RealBcb - CcCacheSections);
+ if (RealBcb->RefCount == 1)
+ {
+ DPRINT("Clearing allocation bit #%x\n", RealBcb - CcCacheSections);
- RtlClearBit(CcCacheBitmap, RealBcb - CcCacheSections);
+ RtlClearBit(CcCacheBitmap, RealBcb - CcCacheSections);
#ifdef PIN_WRITE_ONLY
- PVOID BaseAddress = RealBcb->BaseAddress;
- SIZE_T NumberOfBytes = RealBcb->Length;
- ULONG OldProtect;
-
- MiProtectVirtualMemory
- (NULL,
- &BaseAddress,
- &NumberOfBytes,
- PAGE_READONLY,
- &OldProtect);
+ PVOID BaseAddress = RealBcb->BaseAddress;
+ SIZE_T NumberOfBytes = RealBcb->Length;
+ ULONG OldProtect;
+
+ MiProtectVirtualMemory(NULL,
+ &BaseAddress,
+ &NumberOfBytes,
+ PAGE_READONLY,
+ &OldProtect);
#endif
- }
+ }
- return TRUE;
+ return TRUE;
}
-\f
+
VOID
NTAPI
CcUnpinData(IN PVOID Bcb)
{
PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
ULONG Selected = RealBcb - CcCacheSections;
- BOOLEAN Released;
+ BOOLEAN Released;
+
+ ASSERT(RealBcb >= CcCacheSections &&
+ RealBcb - CcCacheSections < CACHE_NUM_SECTIONS);
- ASSERT(RealBcb >= CcCacheSections && RealBcb - CcCacheSections < CACHE_NUM_SECTIONS);
DPRINT("CcUnpinData Bcb #%x (RefCount %d)\n", Selected, RealBcb->RefCount);
CcpLock();
- Released = CcpUnpinData(RealBcb, FALSE);
+ Released = CcpUnpinData(RealBcb, FALSE);
CcpUnlock();
- if (!Released) {
- MiFlushMappedSection(RealBcb->BaseAddress, &RealBcb->FileOffset, &RealBcb->Map->FileSizes.FileSize, RealBcb->Dirty);
- CcpLock();
- CcpUnpinData(RealBcb, TRUE);
- CcpUnlock();
- }
+ if (!Released) {
+ CcpLock();
+ CcpUnpinData(RealBcb, TRUE);
+ CcpUnlock();
+ }
}
VOID
CcpLock();
CcpReferenceCache(RealBcb - CcCacheSections);
RealBcb->OwnerPointer = OwnerPointer;
- CcpUnlock();
+ CcpUnlock();
}
-\f
+
VOID
NTAPI
CcUnpinDataForThread(IN PVOID Bcb,