ReactOS 0.4.15-dev-7788-g1ad9096
pinsup.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/cache/pinsup.c
5 * PURPOSE: Logging and configuration routines
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Art Yerkes
8 */
9
10/* INCLUDES *******************************************************************/
11
12#include <ntoskrnl.h>
13#include "newcc.h"
14#include "section/newmm.h"
15#define NDEBUG
16#include <debug.h>
17
18/* The following is a test mode that only works with modified filesystems.
19 * it maps the cache sections read only until they're pinned writable, and then
20 * turns them readonly again when they're unpinned.
21 * This helped me determine that a certain bug was not a memory overwrite. */
22
23//#define PIN_WRITE_ONLY
24
25/*
26
27Pinsup implements the core of NewCC.
28
29A couple of things about this code:
30
31I wrote this code over the course of about 2 years, often referring to Rajeev
32Nagar's Filesystem Internals, book, the msdn pages on the Cc interface, and
33a few NT filesystems that are open sourced. I went to fairly great lengths to
34achieve a couple of goals.
35
361) To make a strictly layered facility that relies entirely on Mm to provide
37maps. There were many ways in which data segments in the legacy Mm were unable
38to provide what I needed; page maps were only 4 gig, and all offsets were in
39ULONG, so no mapping at an offset greater than 4 gig was possible. Worse than
40that, due to a convoluted set of dependencies, it would have been impossible to
41support any two mappings farther apart than 4 gig, even if the above was
42corrected. Along with that, the cache system's ownership of some pages was
43integral to the operation of legacy Mm. All of the above problems, along with
44an ambiguity about when the size of a file for mapping purposes is acquired,
45and its inability to allow a file to be resized when any mappings were active
46led me to rewrite data sections (and all other kinds of sections in the
47original version), and use that layer to implement the Cc API without regard
48to any internal, undocumented parts.
49
502) To write the simplest possible code that implements the Cc interface as
51documented. Again this is without regard to any information that might be
52gained through reverse engineering the real Cc. All conclusions about workings
53of Cc here are mine, any failures are mine, any differences to the documented
54interface were introduced by me due to misreading, misunderstanding or mis
55remembering while implementing the code. I also implemented some obvious, but
56not actually specified behaviors of Cc, for example that each cache stripe is
57represented by a distinct BCB that the user can make decisions about as an
58opaque pointer.
59
603) To make real filesystems work properly.
61
62So about how it works:
63
64CcCacheSections is the collection of cache sections that are currently mapped.
65The cache ranges which are allocated and contain pages is larger, due to the
66addition of sections containing rmaps and page references, but this array
67determines the actual mapped pages on behalf of all mapped files for Cc's use.
68All BCB pointers yielded to a driver are a pointer to one of these cache stripe
69structures. The data structure is specified as opaque and so it contains
70information convenient to NEWCC's implementation here. Free entries are
71summarized in CcpBitmapBuffer, for which bits are set when the entry may be
72safely evicted and redirected for use by another client. Note that the
73reference count for an evictable cache section will generally be 1, since
74we'll keep a reference to wait for any subsequent mapping of the same stripe.
75We use CcCacheClockHand as a hint to start checking free bits at a point that
76walks around the cache stripe list, so that we might evict a different stripe
77every time even if all are awaiting reuse. This is a way to avoid thrashing.
78
79CcpBitmapBuffer is the RTL_BITMAP that allows us to quickly decide what buffer
80to allocate from the mapped buffer set.
81
82CcDeleteEvent is an event used to wait for a cache stripe reference count to
83go to 1, thus making the stripe eligible for eviction. It's used by CcpMapData
84to wait for a free map when we can't fail.
85
86All in all, use of Mm by Cc makes this code into a simple manager that wields
87sections on behalf of filesystems. As such, its code is fairly high level and
88no architecture specific changes should be necessary.
89
90*/
91
92/* GLOBALS ********************************************************************/
93
94#define TAG_MAP_SEC TAG('C', 'c', 'S', 'x')
95#define TAG_MAP_READ TAG('M', 'c', 'p', 'y')
96#define TAG_MAP_BCB TAG('B', 'c', 'b', ' ')
97
106
107/* FUNCTIONS ******************************************************************/
108
110
111VOID
112_CcpLock(const char *file,
113 int line)
114{
115 //DPRINT("<<<---<<< CC In Mutex(%s:%d %x)!\n", file, line, PsGetCurrentThread());
117}
118
119VOID
120_CcpUnlock(const char *file,
121 int line)
122{
124 //DPRINT(">>>--->>> CC Exit Mutex!\n", file, line);
125}
126
128NTAPI
130
131/*
132
133Allocate an almost ordinary section object for use by the cache system.
134The special internal SEC_CACHE flag is used to indicate that the section
135should not count when determining whether the file can be resized.
136
137*/
138
143 PROS_SECTION_OBJECT *Result)
144{
146 LARGE_INTEGER MaxSize;
147
148 MaxSize.QuadPart = Length;
149
150 DPRINT("Making Section for File %x\n", FileObject);
151 DPRINT("File name %wZ\n", &FileObject->FileName);
152
155 NULL,
156 &MaxSize,
157 Protect,
159 NULL,
160 FileObject);
161
162 return Status;
163}
164
166{
171 PROS_SECTION_OBJECT ToDeref;
177
178/*
179
180Unmap a cache stripe. Note that cache stripes aren't unmapped when their
181last reference disappears. We enter this code only if cache for the file
182is uninitialized in the last file object, or a cache stripe is evicted.
183
184*/
185
186VOID
188{
190 DPRINT("Unmapping (finally) %x\n", WorkItem->ToUnmap);
194 DPRINT("Done\n");
195}
196
197/*
198
199Somewhat deceptively named function which removes the last reference to a
200cache stripe and completely removes it using CcUnmapCache. This may be
201done either inline (if the Immediate BOOLEAN is set), or using a work item
202at a later time. Whether this is called to unmap immeidately is mainly
203determined by whether the caller is calling from a place in filesystem code
204where a deadlock may occur if immediate flushing is required.
205
206It's always safe to reuse the Bcb at CcCacheSections[Start] after calling
207this.
208
209 */
210
211/* Must have acquired the mutex */
212VOID
214 BOOLEAN Immediate)
215{
216 PVOID ToUnmap;
218 BOOLEAN Dirty;
219 LARGE_INTEGER MappedSize;
220 LARGE_INTEGER BaseOffset;
222
223 DPRINT("CcpDereferenceCache(#%x)\n", Start);
224
226
227 Dirty = Bcb->Dirty;
228 ToUnmap = Bcb->BaseAddress;
229 BaseOffset = Bcb->FileOffset;
230 MappedSize = Bcb->Map->FileSizes.ValidDataLength;
231
232 DPRINT("Dereference #%x (count %d)\n", Start, Bcb->RefCount);
233 ASSERT(Bcb->SectionObject);
234 ASSERT(Bcb->RefCount == 1);
235
236 DPRINT("Firing work item for %x\n", Bcb->BaseAddress);
237
238 if (Dirty) {
239 CcpUnlock();
240 Bcb->RefCount++;
241 MiFlushMappedSection(ToUnmap, &BaseOffset, &MappedSize, Dirty);
242 Bcb->RefCount--;
243 CcpLock();
244 }
245
246 if (Immediate)
247 {
248 PROS_SECTION_OBJECT ToDeref = Bcb->SectionObject;
249 Bcb->Map = NULL;
250 Bcb->SectionObject = NULL;
251 Bcb->BaseAddress = NULL;
252 Bcb->FileOffset.QuadPart = 0;
253 Bcb->Length = 0;
254 Bcb->RefCount = 0;
255 Bcb->Dirty = FALSE;
256 RemoveEntryList(&Bcb->ThisFileList);
257
258 CcpUnlock();
260 ObDereferenceObject(ToDeref);
261 CcpLock();
262 }
263 else
264 {
266 if (!WorkItem) KeBugCheck(0);
267 WorkItem->ToUnmap = Bcb->BaseAddress;
268 WorkItem->FileOffset = Bcb->FileOffset;
269 WorkItem->Dirty = Bcb->Dirty;
270 WorkItem->MapSize = MappedSize;
271 WorkItem->ToDeref = Bcb->SectionObject;
272 WorkItem->AcquireForLazyWrite = Bcb->Map->Callbacks.AcquireForLazyWrite;
273 WorkItem->ReleaseFromLazyWrite = Bcb->Map->Callbacks.ReleaseFromLazyWrite;
274 WorkItem->LazyContext = Bcb->Map->LazyContext;
275
278 WorkItem);
279
280 Bcb->Map = NULL;
281 Bcb->SectionObject = NULL;
282 Bcb->BaseAddress = NULL;
283 Bcb->FileOffset.QuadPart = 0;
284 Bcb->Length = 0;
285 Bcb->RefCount = 0;
286 Bcb->Dirty = FALSE;
287 RemoveEntryList(&Bcb->ThisFileList);
288
289 CcpUnlock();
291 CcpLock();
292 }
293 DPRINT("Done\n");
294}
295
296/*
297
298CcpAllocateCacheSections is called by CcpMapData to obtain a cache stripe,
299possibly evicting an old stripe by calling CcpDereferenceCache in order to
300obtain an empty Bcb.
301
302This function was named plural due to a question I had at the beginning of
303this endeavor about whether a map may span a 256k stripe boundary. It can't
304so this function can only return the index of one Bcb. Returns INVALID_CACHE
305on failure.
306
307 */
308/* Needs mutex */
309ULONG
311 PROS_SECTION_OBJECT SectionObject)
312{
314 PNOCC_CACHE_MAP Map;
316
317 DPRINT("AllocateCacheSections: FileObject %x\n", FileObject);
318
319 if (!FileObject->SectionObjectPointer)
320 return INVALID_CACHE;
321
322 Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
323
324 if (!Map)
325 return INVALID_CACHE;
326
327 DPRINT("Allocating Cache Section\n");
328
331
332 if (i != INVALID_CACHE)
333 {
334 DPRINT("Setting up Bcb #%x\n", i);
335
337
338 ASSERT(Bcb->RefCount < 2);
339
340 if (Bcb->RefCount > 0)
341 {
343 }
344
345 ASSERT(!Bcb->RefCount);
346 Bcb->RefCount = 1;
347
348 DPRINT("Bcb #%x RefCount %d\n", Bcb - CcCacheSections, Bcb->RefCount);
349
351 {
352 DPRINT1("Somebody stoeled BCB #%x\n", i);
353 }
355
356 DPRINT("Allocated #%x\n", i);
357 ASSERT(CcCacheSections[i].RefCount);
358 }
359 else
360 {
361 DPRINT1("Failed to allocate cache segment\n");
362 }
363 return i;
364}
365
366/* Must have acquired the mutex */
367VOID
369{
372 ASSERT(Bcb->SectionObject);
373 Bcb->RefCount++;
375
376}
377
378VOID
380{
383 Bcb->ExclusiveWaiter++;
384}
385
386/*
387
388Cache stripes have an idea of exclusive access, which would be hard to support
389properly in the previous code. In our case, it's fairly easy, since we have
390an event that indicates that the previous exclusive waiter has returned in each
391Bcb.
392
393*/
394/* Must not have the mutex */
395VOID
397{
399
400 KeWaitForSingleObject(&Bcb->ExclusiveWait,
401 Executive,
403 FALSE,
404 NULL);
405
406 CcpLock();
407 ASSERT(Bcb->ExclusiveWaiter);
408 ASSERT(Bcb->SectionObject);
409 Bcb->Exclusive = TRUE;
410 Bcb->ExclusiveWaiter--;
412 CcpUnlock();
413}
414
415/*
416
417Find a map that encompasses the target range. This function does not check
418whether the desired range is partly outside the stripe. This could be
419implemented with a generic table, but we generally aren't carring around a lot
420of segments at once for a particular file.
421
422When this returns a map for a given file address, then that address is by
423definition already mapped and can be operated on.
424
425Returns a valid index or INVALID_CACHE.
426
427*/
428/* Must have the mutex */
429ULONG
433{
435 //DPRINT("Find Matching Map: (%x) %x:%x\n", FileOffset->LowPart, Length);
436 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
437 {
438 //DPRINT("Link @%x\n", Entry);
439 PNOCC_BCB Bcb = CONTAINING_RECORD(Entry, NOCC_BCB, ThisFileList);
440 //DPRINT("Selected BCB %x #%x\n", Bcb, Bcb - CcCacheSections);
441 //DPRINT("This File: %x:%x\n", Bcb->FileOffset.LowPart, Bcb->Length);
442 if (FileOffset->QuadPart >= Bcb->FileOffset.QuadPart &&
443 FileOffset->QuadPart < Bcb->FileOffset.QuadPart + CACHE_STRIPE)
444 {
445 //DPRINT("Found match at #%x\n", Bcb - CcCacheSections);
446 return Bcb - CcCacheSections;
447 }
448 }
449
450 //DPRINT("This region isn't mapped\n");
451
452 return INVALID_CACHE;
453}
454
455/*
456
457Internal function that's used by all pinning functions.
458It causes a mapped region to exist and prefaults the pages in it if possible,
459possibly evicting another stripe in order to get our stripe.
460
461*/
462
464NTAPI
468 IN ULONG Flags,
469 OUT PVOID *BcbResult,
471{
472 BOOLEAN Success = FALSE, FaultIn = FALSE;
473 /* Note: windows 2000 drivers treat this as a bool */
474 //BOOLEAN Wait = (Flags & MAP_WAIT) || (Flags == TRUE);
475 LARGE_INTEGER Target, EndInterval;
476 ULONG BcbHead, SectionSize, ViewSize;
478 PROS_SECTION_OBJECT SectionObject = NULL;
480 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
482
483 if (!Map)
484 {
485 DPRINT1("File object was not mapped\n");
486 return FALSE;
487 }
488
489 DPRINT("CcMapData(F->%x, %I64x:%d)\n",
491 FileOffset->QuadPart,
492 Length);
493
495
496 Target.HighPart = FileOffset->HighPart;
497 Target.LowPart = CACHE_ROUND_DOWN(FileOffset->LowPart);
498
499 CcpLock();
500
501 /* Find out if any range is a superset of what we want */
502 /* Find an accomodating section */
504
505 if (BcbHead != INVALID_CACHE)
506 {
507 Bcb = &CcCacheSections[BcbHead];
508 Success = TRUE;
509 *BcbResult = Bcb;
510 *Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
511
512 DPRINT("Bcb #%x Buffer maps (%I64x) At %x Length %x (Getting %p:%x) %wZ\n",
514 Bcb->FileOffset.QuadPart,
515 Bcb->BaseAddress,
516 Bcb->Length,
517 *Buffer,
518 Length,
519 &FileObject->FileName);
520
521 DPRINT("w1n\n");
522 goto cleanup;
523 }
524
525 DPRINT("File size %I64x\n",
527
528 /* Not all files have length, in fact filesystems often use stream file
529 objects for various internal purposes and are loose about the file
530 length, since the filesystem promises itself to write the right number
531 of bytes to the internal stream. In these cases, we just allow the file
532 to have the full stripe worth of space. */
534 {
535 SectionSize = min(CACHE_STRIPE,
536 Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart);
537 }
538 else
539 {
540 SectionSize = CACHE_STRIPE;
541 }
542
543 DPRINT("Allocating a cache stripe at %x:%d\n",
544 Target.LowPart, SectionSize);
545
546 //ASSERT(SectionSize <= CACHE_STRIPE);
547
548 CcpUnlock();
549 /* CcpAllocateSection doesn't need the lock, so we'll give other action
550 a chance in here. */
552 SectionSize,
553#ifdef PIN_WRITE_ONLY
555#else
557#endif
559 CcpLock();
560
561 if (!NT_SUCCESS(Status))
562 {
563 *BcbResult = NULL;
564 *Buffer = NULL;
565 DPRINT1("End %08x\n", Status);
566 goto cleanup;
567 }
568
569retry:
570 /* Returns a reference */
571 DPRINT("Allocating cache sections: %wZ\n", &FileObject->FileName);
573 /* XXX todo: we should handle the immediate fail case here, but don't */
574 if (BcbHead == INVALID_CACHE)
575 {
576 ULONG i;
577 DbgPrint("Cache Map:");
578 for (i = 0; i < CACHE_NUM_SECTIONS; i++)
579 {
580 if (!(i % 64)) DbgPrint("\n");
581 DbgPrint("%c",
582 CcCacheSections[i].RefCount + (RtlTestBit(CcCacheBitmap, i) ? '@' : '`'));
583 }
584 DbgPrint("\n");
585
587 Executive,
589 FALSE,
590 NULL);
591
592 goto retry;
593 }
594
595 DPRINT("BcbHead #%x (final)\n", BcbHead);
596
597 if (BcbHead == INVALID_CACHE)
598 {
599 *BcbResult = NULL;
600 *Buffer = NULL;
601 DPRINT1("End\n");
602 goto cleanup;
603 }
604
605 DPRINT("Selected BCB #%x\n", BcbHead);
607
608 Bcb = &CcCacheSections[BcbHead];
609 /* MmMapCacheViewInSystemSpaceAtOffset is one of three methods of Mm
610 that are specific to NewCC. In this case, it's implementation
611 exactly mirrors MmMapViewInSystemSpace, but allows an offset to
612 be specified. */
614 &Bcb->BaseAddress,
615 &Target,
616 &ViewSize);
617
618 /* Summary: Failure. Dereference our section and tell the user we failed */
619 if (!NT_SUCCESS(Status))
620 {
621 *BcbResult = NULL;
622 *Buffer = NULL;
624 RemoveEntryList(&Bcb->ThisFileList);
625 RtlZeroMemory(Bcb, sizeof(*Bcb));
626 RtlClearBit(CcCacheBitmap, BcbHead);
627 DPRINT1("Failed to map\n");
628 goto cleanup;
629 }
630
631 /* Summary: Success. Put together a valid Bcb and link it with the others
632 * in the NOCC_CACHE_MAP.
633 */
634 Success = TRUE;
635
636 Bcb->Length = MIN(Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart,
638
639 Bcb->SectionObject = SectionObject;
640 Bcb->Map = Map;
641 Bcb->FileOffset = Target;
642 InsertTailList(&Map->AssociatedBcb, &Bcb->ThisFileList);
643
644 *BcbResult = &CcCacheSections[BcbHead];
645 *Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
646 FaultIn = TRUE;
647
648 DPRINT("Bcb #%x Buffer maps (%I64x) At %x Length %x (Getting %p:%lx) %wZ\n",
650 Bcb->FileOffset.QuadPart,
651 Bcb->BaseAddress,
652 Bcb->Length,
653 *Buffer,
654 Length,
655 &FileObject->FileName);
656
657 EndInterval.QuadPart = Bcb->FileOffset.QuadPart + Bcb->Length - 1;
658 ASSERT((EndInterval.QuadPart & ~(CACHE_STRIPE - 1)) ==
659 (Bcb->FileOffset.QuadPart & ~(CACHE_STRIPE - 1)));
660
661cleanup:
662 CcpUnlock();
663 if (Success)
664 {
665 if (FaultIn)
666 {
667 /* Fault in the pages. This forces reads to happen now. */
668 ULONG i;
669 PCHAR FaultIn = Bcb->BaseAddress;
670
671 DPRINT("Faulting in pages at this point: file %wZ %I64x:%x\n",
672 &FileObject->FileName,
673 Bcb->FileOffset.QuadPart,
674 Bcb->Length);
675
676 for (i = 0; i < Bcb->Length; i += PAGE_SIZE)
677 {
678 FaultIn[i] ^= 0;
679 }
680 }
683 }
684 else
685 {
686 ASSERT(FALSE);
687 }
688
689 return Success;
690}
691
693NTAPI
697 IN ULONG Flags,
698 OUT PVOID *BcbResult,
700{
702
705 Length,
706 Flags,
707 BcbResult,
708 Buffer);
709
710 if (Result)
711 {
712 PNOCC_BCB Bcb = (PNOCC_BCB)*BcbResult;
713
716
717 ASSERT(Bcb->BaseAddress);
718 CcpLock();
720 CcpUnlock();
721 }
722
723 return Result;
724}
725
726/* Used by functions that repin data, CcpPinMappedData does not alter the map,
727 but finds the appropriate stripe and update the accounting. */
729NTAPI
733 IN ULONG Flags,
734 IN OUT PVOID *Bcb)
735{
737 ULONG BcbHead;
738 PNOCC_BCB TheBcb;
739
740 CcpLock();
741
742 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));
743 BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
744 if (BcbHead == INVALID_CACHE)
745 {
746 CcpUnlock();
747 return FALSE;
748 }
749
750 TheBcb = &CcCacheSections[BcbHead];
751
752 if (Exclusive)
753 {
754 DPRINT("Requesting #%x Exclusive\n", BcbHead);
755 CcpMarkForExclusive(BcbHead);
756 }
757 else
758 {
759 DPRINT("Reference #%x\n", BcbHead);
760 CcpReferenceCache(BcbHead);
761 }
762
763 if (Exclusive)
765
766 CcpUnlock();
767
768 *Bcb = TheBcb;
769 return TRUE;
770}
771
773NTAPI
777 IN ULONG Flags,
778 IN OUT PVOID *Bcb)
779{
781 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
782
783 if (!Map)
784 {
785 DPRINT1("Not cached\n");
786 return FALSE;
787 }
788
790 {
792 }
793 else
794 {
795 DPRINT1("could not map\n");
796 return FALSE;
797 }
798}
799
801NTAPI
805 IN ULONG Flags,
806 OUT PVOID *Bcb,
808{
809 PNOCC_BCB RealBcb;
811
813
814 if (Result)
815 {
816 CcpLock();
817 RealBcb = *Bcb;
818 *Buffer = ((PCHAR)RealBcb->BaseAddress) + (int)(FileOffset->QuadPart - RealBcb->FileOffset.QuadPart);
819 CcpUnlock();
820 }
821
822 return Result;
823}
824
826NTAPI
831 IN ULONG Flags,
832 OUT PVOID *Bcb,
834{
836 PNOCC_BCB RealBcb;
837#ifdef PIN_WRITE_ONLY
840 ULONG OldProtect;
841#endif
842
843 DPRINT("CcPreparePinWrite(%x:%x)\n", Buffer, Length);
844
846
847 if (Result)
848 {
849 CcpLock();
850 RealBcb = *Bcb;
851
852#ifdef PIN_WRITE_ONLY
853 BaseAddress = RealBcb->BaseAddress;
854 NumberOfBytes = RealBcb->Length;
855
860 &OldProtect);
861#endif
862
863 CcpUnlock();
864 RealBcb->Dirty = TRUE;
865
866 if (Zero)
867 {
868 DPRINT("Zero fill #%x %I64x:%x Buffer %x %wZ\n",
869 RealBcb - CcCacheSections,
870 FileOffset->QuadPart,
871 Length,
872 *Buffer,
873 &FileObject->FileName);
874
875 DPRINT1("RtlZeroMemory(%p, %lx)\n", *Buffer, Length);
877 }
878 }
879
880 return Result;
881}
882
883/*
884
885CcpUnpinData is the internal function that generally handles unpinning data.
886It may be a little confusing, because of the way reference counts are handled.
887
888A reference count of 2 or greater means that the stripe is still fully pinned
889and can't be removed. If the owner had taken an exclusive reference, then
890give one up. Note that it's an error to take more than one exclusive reference
891or to take a non-exclusive reference after an exclusive reference, so detecting
892or handling that case is not considered.
893
894ReleaseBit is unset if we want to detect when a cache stripe would become
895evictable without actually giving up our reference. We might want to do that
896if we were going to flush before formally releasing the cache stripe, although
897that facility is not used meaningfully at this time.
898
899A reference count of exactly 1 means that the stripe could potentially be
900reused, but could also be evicted for another mapping. In general, most
901stripes should be in that state most of the time.
902
903A reference count of zero means that the Bcb is completely unused. That's the
904start state and the state of a Bcb formerly owned by a file that is
905uninitialized.
906
907*/
908
910NTAPI
911CcpUnpinData(IN PNOCC_BCB RealBcb, BOOLEAN ReleaseBit)
912{
913 if (RealBcb->RefCount <= 2)
914 {
915 RealBcb->Exclusive = FALSE;
916 if (RealBcb->ExclusiveWaiter)
917 {
918 DPRINT("Triggering exclusive waiter\n");
919 KeSetEvent(&RealBcb->ExclusiveWait, IO_NO_INCREMENT, FALSE);
920 return TRUE;
921 }
922 }
923 if (RealBcb->RefCount == 2 && !ReleaseBit)
924 return FALSE;
925 if (RealBcb->RefCount > 1)
926 {
927 DPRINT("Removing one reference #%x\n", RealBcb - CcCacheSections);
928 RealBcb->RefCount--;
930 }
931 if (RealBcb->RefCount == 1)
932 {
933 DPRINT("Clearing allocation bit #%x\n", RealBcb - CcCacheSections);
934
936
937#ifdef PIN_WRITE_ONLY
938 PVOID BaseAddress = RealBcb->BaseAddress;
939 SIZE_T NumberOfBytes = RealBcb->Length;
940 ULONG OldProtect;
941
946 &OldProtect);
947#endif
948 }
949
950 return TRUE;
951}
952
953VOID
954NTAPI
956{
957 PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
958 ULONG Selected = RealBcb - CcCacheSections;
959 BOOLEAN Released;
960
961 ASSERT(RealBcb >= CcCacheSections &&
963
964 DPRINT("CcUnpinData Bcb #%x (RefCount %d)\n", Selected, RealBcb->RefCount);
965
966 CcpLock();
967 Released = CcpUnpinData(RealBcb, FALSE);
968 CcpUnlock();
969
970 if (!Released) {
971 CcpLock();
972 CcpUnpinData(RealBcb, TRUE);
973 CcpUnlock();
974 }
975}
976
977VOID
978NTAPI
981{
982 PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
983 CcpLock();
985 RealBcb->OwnerPointer = OwnerPointer;
986 CcpUnlock();
987}
988
989VOID
990NTAPI
993{
995}
996
997/* EOF */
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define MIN(x, y)
Definition: rdesktop.h:171
#define DPRINT1
Definition: precomp.h:8
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1431
_In_ PFCB _In_ LONGLONG FileOffset
Definition: cdprocs.h:160
Definition: bufpool.h:45
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define PAGE_READONLY
Definition: compat.h:138
static void cleanup(void)
Definition: main.c:1335
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define NonPagedPool
Definition: env_spec_w32.h:307
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
@ Success
Definition: eventcreate.c:712
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
IN PVCB IN VBO IN ULONG OUT PBCB * Bcb
Definition: fatprocs.h:414
IN PVCB IN VBO IN ULONG OUT PBCB OUT PVOID IN BOOLEAN IN BOOLEAN Zero
Definition: fatprocs.h:418
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
_Must_inspect_result_ _Outptr_ PVOID * SectionObject
Definition: fsrtlfuncs.h:860
__in PWDFDEVICE_INIT __in BOOLEAN Exclusive
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
VOID FASTCALL ExAcquireFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:23
VOID FASTCALL ExReleaseFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:31
#define DbgPrint
Definition: hal.h:12
NTSYSAPI ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP, ULONG, ULONG)
if(dx< 0)
Definition: linetemp.h:194
#define PCHAR
Definition: match.c:90
#define ASSERT(a)
Definition: mode.c:44
#define min(a, b)
Definition: monoChain.cc:55
#define KernelMode
Definition: asm.h:34
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER _Inout_ PSIZE_T ViewSize
Definition: mmfuncs.h:408
#define CACHE_ROUND_DOWN(x)
Definition: newcc.h:127
#define CACHE_STRIPE
Definition: newcc.h:123
struct _NOCC_BCB * PNOCC_BCB
struct _NOCC_CACHE_MAP * PNOCC_CACHE_MAP
#define INVALID_CACHE
Definition: newcc.h:128
#define CcpLock()
Definition: newcc.h:138
#define CcpUnlock()
Definition: newcc.h:139
#define CACHE_NUM_SECTIONS
Definition: newcc.h:125
#define SEC_CACHE
Definition: newmm.h:18
NTSTATUS NTAPI MmMapCacheViewInSystemSpaceAtOffset(IN PMM_SECTION_SEGMENT Segment, OUT PVOID *MappedBase, IN PLARGE_INTEGER ViewOffset, IN OUT PULONG ViewSize)
NTSTATUS NTAPI MmUnmapCacheViewInSystemSpace(PVOID Address)
#define MiFlushMappedSection(A, O, S, D)
Definition: newmm.h:333
#define PAGE_READWRITE
Definition: nt_native.h:1304
#define SEC_RESERVE
Definition: nt_native.h:1323
#define STANDARD_RIGHTS_REQUIRED
Definition: nt_native.h:63
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define PIN_EXCLUSIVE
NTSTATUS NTAPI MiProtectVirtualMemory(IN PEPROCESS Process, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T NumberOfBytesToProtect, IN ULONG NewAccessProtection, OUT PULONG OldAccessProtection OPTIONAL)
Definition: virtual.c:2196
long LONG
Definition: pedump.c:60
FAST_MUTEX CcMutex
Definition: pinsup.c:101
BOOLEAN NTAPI CcpMapData(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG Flags, OUT PVOID *BcbResult, OUT PVOID *Buffer)
Definition: pinsup.c:465
struct _WORK_QUEUE_WITH_CONTEXT * PWORK_QUEUE_WITH_CONTEXT
VOID CcpReferenceCacheExclusive(ULONG Start)
Definition: pinsup.c:396
VOID NTAPI CcUnpinData(IN PVOID Bcb)
Definition: pinsup.c:955
ULONG CcCacheClockHand
Definition: pinsup.c:104
NTSTATUS CcpAllocateSection(PFILE_OBJECT FileObject, ULONG Length, ULONG Protect, PROS_SECTION_OBJECT *Result)
Definition: pinsup.c:140
NOCC_BCB CcCacheSections[CACHE_NUM_SECTIONS]
Definition: pinsup.c:98
struct _WORK_QUEUE_WITH_CONTEXT WORK_QUEUE_WITH_CONTEXT
VOID NTAPI CcSetBcbOwnerPointer(IN PVOID Bcb, IN PVOID OwnerPointer)
Definition: pinsup.c:979
ULONG CcpAllocateCacheSections(PFILE_OBJECT FileObject, PROS_SECTION_OBJECT SectionObject)
Definition: pinsup.c:310
BOOLEAN NTAPI CcpPinMappedData(IN PNOCC_CACHE_MAP Map, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG Flags, IN OUT PVOID *Bcb)
Definition: pinsup.c:730
VOID _CcpLock(const char *file, int line)
Definition: pinsup.c:112
PDEVICE_OBJECT NTAPI MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject)
Definition: io.c:57
VOID CcpDereferenceCache(ULONG Start, BOOLEAN Immediate)
Definition: pinsup.c:213
LONG CcOutstandingDeletes
Definition: pinsup.c:105
VOID CcpMarkForExclusive(ULONG Start)
Definition: pinsup.c:379
VOID NTAPI CcUnpinDataForThread(IN PVOID Bcb, IN ERESOURCE_THREAD ResourceThreadId)
Definition: pinsup.c:991
PRTL_BITMAP CcCacheBitmap
Definition: pinsup.c:100
BOOLEAN NTAPI CcPreparePinWrite(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Zero, IN ULONG Flags, OUT PVOID *Bcb, OUT PVOID *Buffer)
Definition: pinsup.c:827
BOOLEAN NTAPI CcPinMappedData(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG Flags, IN OUT PVOID *Bcb)
Definition: pinsup.c:774
PETHREAD LastThread
Definition: pinsup.c:109
ULONG CcpFindMatchingMap(PLIST_ENTRY Head, PLARGE_INTEGER FileOffset, ULONG Length)
Definition: pinsup.c:430
KEVENT CcDeleteEvent
Definition: pinsup.c:102
CHAR CcpBitmapBuffer[sizeof(RTL_BITMAP)+ROUND_UP((CACHE_NUM_SECTIONS), 32)/8]
Definition: pinsup.c:99
VOID CcpUnmapCache(PVOID Context)
Definition: pinsup.c:187
KEVENT CcFinalizeEvent
Definition: pinsup.c:103
BOOLEAN NTAPI CcPinRead(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG Flags, OUT PVOID *Bcb, OUT PVOID *Buffer)
Definition: pinsup.c:802
BOOLEAN NTAPI CcMapData(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN ULONG Flags, OUT PVOID *BcbResult, OUT PVOID *Buffer)
Definition: pinsup.c:694
VOID CcpReferenceCache(ULONG Start)
Definition: pinsup.c:368
BOOLEAN NTAPI CcpUnpinData(IN PNOCC_BCB RealBcb, BOOLEAN ReleaseBit)
Definition: pinsup.c:911
VOID _CcpUnlock(const char *file, int line)
Definition: pinsup.c:120
VOID NTAPI RtlClearBit(_In_ PRTL_BITMAP BitMapHeader, _In_ BITMAP_INDEX BitNumber)
Definition: bitmap.c:294
NTSTATUS NTAPI MmCreateSection(OUT PVOID *Section, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize, IN ULONG SectionPageProtection, IN ULONG AllocationAttributes, IN HANDLE FileHandle OPTIONAL, IN PFILE_OBJECT FileObject OPTIONAL)
Definition: section.c:4620
#define DPRINT
Definition: sndvol32.h:71
base of all file and directory entries
Definition: entries.h:83
LARGE_INTEGER ValidDataLength
Definition: cctypes.h:17
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: newcc.h:4
ULONG Length
Definition: newcc.h:11
BOOLEAN Dirty
Definition: newcc.h:13
PVOID BaseAddress
Definition: newcc.h:12
LARGE_INTEGER FileOffset
Definition: newcc.h:10
ULONG RefCount
Definition: newcc.h:17
PVOID OwnerPointer
Definition: newcc.h:14
CC_FILE_SIZES FileSizes
Definition: newcc.h:33
LIST_ENTRY AssociatedBcb
Definition: newcc.h:29
PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite
Definition: pinsup.c:172
PROS_SECTION_OBJECT ToDeref
Definition: pinsup.c:171
PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite
Definition: pinsup.c:173
WORK_QUEUE_ITEM WorkItem
Definition: pinsup.c:167
LARGE_INTEGER FileOffset
Definition: pinsup.c:169
LARGE_INTEGER MapSize
Definition: pinsup.c:170
Definition: fci.c:127
Definition: parser.c:49
struct _RTL_BITMAP * PRTL_BITMAP
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
struct _RTL_BITMAP RTL_BITMAP
char * PCHAR
Definition: typedefs.h:51
LONGLONG QuadPart
Definition: typedefs.h:114
@ Start
Definition: partlist.h:33
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
_Must_inspect_result_ _In_ PWDF_WORKITEM_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWORKITEM * WorkItem
Definition: wdfworkitem.h:115
VOID NTAPI ExQueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, IN WORK_QUEUE_TYPE QueueType)
Definition: work.c:723
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
VOID(NTAPI * PRELEASE_FROM_LAZY_WRITE)(_In_ PVOID Context)
Definition: cctypes.h:26
BOOLEAN(NTAPI * PACQUIRE_FOR_LAZY_WRITE)(_In_ PVOID Context, _In_ BOOLEAN Wait)
Definition: cctypes.h:21
_In_ ERESOURCE_THREAD ResourceThreadId
Definition: exfuncs.h:1052
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
_In_ PVOID OwnerPointer
Definition: exfuncs.h:1070
FAST_MUTEX
Definition: extypes.h:17
@ DelayedWorkQueue
Definition: extypes.h:190
WORKER_THREAD_ROUTINE * PWORKER_THREAD_ROUTINE
Definition: extypes.h:200
ULONG_PTR ERESOURCE_THREAD
Definition: extypes.h:208
#define IO_NO_INCREMENT
Definition: iotypes.h:598
* PFILE_OBJECT
Definition: iotypes.h:1998
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _Inout_ PLARGE_INTEGER NumberOfBytes
Definition: iotypes.h:1036
@ Executive
Definition: ketypes.h:415
#define ObDereferenceObject
Definition: obfuncs.h:203
NTSYSAPI VOID NTAPI RtlSetBit(_In_ PRTL_BITMAP BitMapHeader, _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber)
Definition: bitmap.c:304
_Must_inspect_result_ NTSYSAPI BOOLEAN NTAPI RtlTestBit(_In_ PRTL_BITMAP BitMapHeader, _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber)
Definition: bitmap.c:434
char CHAR
Definition: xmlstorage.h:175
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER _Inout_ PSIZE_T _In_ SECTION_INHERIT _In_ ULONG _In_ ULONG Protect
Definition: zwfuncs.h:221