ReactOS  r76032
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 
27 Pinsup implements the core of NewCC.
28 
29 A couple of things about this code:
30 
31 I wrote this code over the course of about 2 years, often referring to Rajeev
32 Nagar's Filesystem Internals, book, the msdn pages on the Cc interface, and
33 a few NT filesystems that are open sourced. I went to fairly great lengths to
34 achieve a couple of goals.
35 
36 1) To make a strictly layered facility that relies entirely on Mm to provide
37 maps. There were many ways in which data segments in the legacy Mm were unable
38 to provide what I needed; page maps were only 4 gig, and all offsets were in
39 ULONG, so no mapping at an offset greater than 4 gig was possible. Worse than
40 that, due to a convoluted set of dependencies, it would have been impossible to
41 support any two mappings farther apart than 4 gig, even if the above was
42 corrected. Along with that, the cache system's ownership of some pages was
43 integral to the operation of legacy Mm. All of the above problems, along with
44 an ambiguity about when the size of a file for mapping purposes is acquired,
45 and its inability to allow a file to be resized when any mappings were active
46 led me to rewrite data sections (and all other kinds of sections in the
47 original version), and use that layer to implement the Cc API without regard
48 to any internal, undocumented parts.
49 
50 2) To write the simplest possible code that implements the Cc interface as
51 documented. Again this is without regard to any information that might be
52 gained through reverse engineering the real Cc. All conclusions about workings
53 of Cc here are mine, any failures are mine, any differences to the documented
54 interface were introduced by me due to misreading, misunderstanding or mis
55 remembering while implementing the code. I also implemented some obvious, but
56 not actually specified behaviors of Cc, for example that each cache stripe is
57 represented by a distinct BCB that the user can make decisions about as an
58 opaque pointer.
59 
60 3) To make real filesystems work properly.
61 
62 So about how it works:
63 
64 CcCacheSections is the collection of cache sections that are currently mapped.
65 The cache ranges which are allocated and contain pages is larger, due to the
66 addition of sections containing rmaps and page references, but this array
67 determines the actual mapped pages on behalf of all mapped files for Cc's use.
68 All BCB pointers yielded to a driver are a pointer to one of these cache stripe
69 structures. The data structure is specified as opaque and so it contains
70 information convenient to NEWCC's implementation here. Free entries are
71 summarized in CcpBitmapBuffer, for which bits are set when the entry may be
72 safely evicted and redirected for use by another client. Note that the
73 reference count for an evictable cache section will generally be 1, since
74 we'll keep a reference to wait for any subsequent mapping of the same stripe.
75 We use CcCacheClockHand as a hint to start checking free bits at a point that
76 walks around the cache stripe list, so that we might evict a different stripe
77 every time even if all are awaiting reuse. This is a way to avoid thrashing.
78 
79 CcpBitmapBuffer is the RTL_BITMAP that allows us to quickly decide what buffer
80 to allocate from the mapped buffer set.
81 
82 CcDeleteEvent is an event used to wait for a cache stripe reference count to
83 go to 1, thus making the stripe eligible for eviction. It's used by CcpMapData
84 to wait for a free map when we can't fail.
85 
86 All in all, use of Mm by Cc makes this code into a simple manager that wields
87 sections on behalf of filesystems. As such, its code is fairly high level and
88 no 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 
111 VOID
112 _CcpLock(const char *file,
113  int line)
114 {
115  //DPRINT("<<<---<<< CC In Mutex(%s:%d %x)!\n", file, line, PsGetCurrentThread());
116  ExAcquireFastMutex(&CcMutex);
117 }
118 
119 VOID
120 _CcpUnlock(const char *file,
121  int line)
122 {
123  ExReleaseFastMutex(&CcMutex);
124  //DPRINT(">>>--->>> CC Exit Mutex!\n", file, line);
125 }
126 
128 NTAPI
130 
131 /*
132 
133 Allocate an almost ordinary section object for use by the cache system.
134 The special internal SEC_CACHE flag is used to indicate that the section
135 should not count when determining whether the file can be resized.
136 
137 */
138 
139 NTSTATUS
141  ULONG Length,
142  ULONG Protect,
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 
153  Status = MmCreateSection((PVOID*)Result,
155  NULL,
156  &MaxSize,
157  Protect,
159  NULL,
160  FileObject);
161 
162  return Status;
163 }
164 
166 {
172  PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite;
173  PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite;
177 
178 /*
179 
180 Unmap a cache stripe. Note that cache stripes aren't unmapped when their
181 last reference disappears. We enter this code only if cache for the file
182 is uninitialized in the last file object, or a cache stripe is evicted.
183 
184 */
185 
186 VOID
188 {
189  PWORK_QUEUE_WITH_CONTEXT WorkItem = (PWORK_QUEUE_WITH_CONTEXT)Context;
190  DPRINT("Unmapping (finally) %x\n", WorkItem->ToUnmap);
192  ObDereferenceObject(WorkItem->ToDeref);
193  ExFreePool(WorkItem);
194  DPRINT("Done\n");
195 }
196 
197 /*
198 
199 Somewhat deceptively named function which removes the last reference to a
200 cache stripe and completely removes it using CcUnmapCache. This may be
201 done either inline (if the Immediate BOOLEAN is set), or using a work item
202 at a later time. Whether this is called to unmap immeidately is mainly
203 determined by whether the caller is calling from a place in filesystem code
204 where a deadlock may occur if immediate flushing is required.
205 
206 It's always safe to reuse the Bcb at CcCacheSections[Start] after calling
207 this.
208 
209  */
210 
211 /* Must have acquired the mutex */
212 VOID
214  BOOLEAN Immediate)
215 {
216  PVOID ToUnmap;
217  PNOCC_BCB Bcb;
218  BOOLEAN Dirty;
219  LARGE_INTEGER MappedSize;
220  LARGE_INTEGER BaseOffset;
221  PWORK_QUEUE_WITH_CONTEXT WorkItem;
222 
223  DPRINT("CcpDereferenceCache(#%x)\n", Start);
224 
225  Bcb = &CcCacheSections[Start];
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;
257 
258  CcpUnlock();
260  ObDereferenceObject(ToDeref);
261  CcpLock();
262  }
263  else
264  {
265  WorkItem = ExAllocatePool(NonPagedPool, sizeof(*WorkItem));
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 
276  ExInitializeWorkItem(&WorkItem->WorkItem,
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;
288 
289  CcpUnlock();
291  CcpLock();
292  }
293  DPRINT("Done\n");
294 }
295 
296 /*
297 
298 CcpAllocateCacheSections is called by CcpMapData to obtain a cache stripe,
299 possibly evicting an old stripe by calling CcpDereferenceCache in order to
300 obtain an empty Bcb.
301 
302 This function was named plural due to a question I had at the beginning of
303 this endeavor about whether a map may span a 256k stripe boundary. It can't
304 so this function can only return the index of one Bcb. Returns INVALID_CACHE
305 on failure.
306 
307  */
308 /* Needs mutex */
309 ULONG
312 {
314  PNOCC_CACHE_MAP Map;
315  PNOCC_BCB Bcb;
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 
329  i = RtlFindClearBitsAndSet(CcCacheBitmap, 1, CcCacheClockHand);
330  CcCacheClockHand = (i + 1) % CACHE_NUM_SECTIONS;
331 
332  if (i != INVALID_CACHE)
333  {
334  DPRINT("Setting up Bcb #%x\n", i);
335 
336  Bcb = &CcCacheSections[i];
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 
350  if (!RtlTestBit(CcCacheBitmap, i))
351  {
352  DPRINT1("Somebody stoeled BCB #%x\n", i);
353  }
354  ASSERT(RtlTestBit(CcCacheBitmap, i));
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 */
367 VOID
369 {
370  PNOCC_BCB Bcb;
371  Bcb = &CcCacheSections[Start];
372  ASSERT(Bcb->SectionObject);
373  Bcb->RefCount++;
374  RtlSetBit(CcCacheBitmap, Start);
375 
376 }
377 
378 VOID
380 {
381  PNOCC_BCB Bcb;
382  Bcb = &CcCacheSections[Start];
383  Bcb->ExclusiveWaiter++;
384 }
385 
386 /*
387 
388 Cache stripes have an idea of exclusive access, which would be hard to support
389 properly in the previous code. In our case, it's fairly easy, since we have
390 an event that indicates that the previous exclusive waiter has returned in each
391 Bcb.
392 
393 */
394 /* Must not have the mutex */
395 VOID
397 {
398  PNOCC_BCB Bcb = &CcCacheSections[Start];
399 
401  Executive,
402  KernelMode,
403  FALSE,
404  NULL);
405 
406  CcpLock();
407  ASSERT(Bcb->ExclusiveWaiter);
408  ASSERT(Bcb->SectionObject);
409  Bcb->Exclusive = TRUE;
410  Bcb->ExclusiveWaiter--;
411  RtlSetBit(CcCacheBitmap, Start);
412  CcpUnlock();
413 }
414 
415 /*
416 
417 Find a map that encompasses the target range. This function does not check
418 whether the desired range is partly outside the stripe. This could be
419 implemented with a generic table, but we generally aren't carring around a lot
420 of segments at once for a particular file.
421 
422 When this returns a map for a given file address, then that address is by
423 definition already mapped and can be operated on.
424 
425 Returns a valid index or INVALID_CACHE.
426 
427 */
428 /* Must have the mutex */
429 ULONG
432  ULONG Length)
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 
457 Internal function that's used by all pinning functions.
458 It causes a mapped region to exist and prefaults the pages in it if possible,
459 possibly evicting another stripe in order to get our stripe.
460 
461 */
462 
463 BOOLEAN
464 NTAPI
467  IN ULONG Length,
468  IN ULONG Flags,
469  OUT PVOID *BcbResult,
470  OUT PVOID *Buffer)
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;
477  PNOCC_BCB Bcb = NULL;
480  PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
481  ViewSize = CACHE_STRIPE;
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",
490  FileObject,
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 */
503  BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
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",
513  Bcb - CcCacheSections,
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,
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. */
551  Status = CcpAllocateSection(FileObject,
552  SectionSize,
553 #ifdef PIN_WRITE_ONLY
555 #else
557 #endif
558  &SectionObject);
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 
569 retry:
570  /* Returns a reference */
571  DPRINT("Allocating cache sections: %wZ\n", &FileObject->FileName);
572  BcbHead = CcpAllocateCacheSections(FileObject, SectionObject);
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 
586  KeWaitForSingleObject(&CcDeleteEvent,
587  Executive,
588  KernelMode,
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);
606  ViewSize = CACHE_STRIPE;
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. */
613  Status = MmMapCacheViewInSystemSpaceAtOffset(SectionObject->Segment,
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;
623  ObDereferenceObject(SectionObject);
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,
637  CACHE_STRIPE);
638 
640  Bcb->Map = Map;
641  Bcb->FileOffset = Target;
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",
649  Bcb - CcCacheSections,
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 
661 cleanup:
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  }
681  ASSERT(Bcb >= CcCacheSections &&
682  Bcb < (CcCacheSections + CACHE_NUM_SECTIONS));
683  }
684  else
685  {
686  ASSERT(FALSE);
687  }
688 
689  return Success;
690 }
691 
692 BOOLEAN
693 NTAPI
696  IN ULONG Length,
697  IN ULONG Flags,
698  OUT PVOID *BcbResult,
699  OUT PVOID *Buffer)
700 {
701  BOOLEAN Result;
702 
703  Result = CcpMapData(FileObject,
704  FileOffset,
705  Length,
706  Flags,
707  BcbResult,
708  Buffer);
709 
710  if (Result)
711  {
712  PNOCC_BCB Bcb = (PNOCC_BCB)*BcbResult;
713 
714  ASSERT(Bcb >= CcCacheSections &&
715  Bcb < CcCacheSections + CACHE_NUM_SECTIONS);
716 
717  ASSERT(Bcb->BaseAddress);
718  CcpLock();
719  CcpReferenceCache(Bcb - CcCacheSections);
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. */
728 BOOLEAN
729 NTAPI
732  IN ULONG Length,
733  IN ULONG Flags,
734  IN OUT PVOID *Bcb)
735 {
736  BOOLEAN Exclusive = Flags & PIN_EXCLUSIVE;
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 
772 BOOLEAN
773 NTAPI
776  IN ULONG Length,
777  IN ULONG Flags,
778  IN OUT PVOID *Bcb)
779 {
780  PVOID Buffer;
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 
789  if (CcpMapData(FileObject, FileOffset, Length, Flags, Bcb, &Buffer))
790  {
791  return CcpPinMappedData(Map, FileOffset, Length, Flags, Bcb);
792  }
793  else
794  {
795  DPRINT1("could not map\n");
796  return FALSE;
797  }
798 }
799 
800 BOOLEAN
801 NTAPI
804  IN ULONG Length,
805  IN ULONG Flags,
806  OUT PVOID *Bcb,
807  OUT PVOID *Buffer)
808 {
809  PNOCC_BCB RealBcb;
810  BOOLEAN Result;
811 
812  Result = CcPinMappedData(FileObject, FileOffset, Length, Flags, Bcb);
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 
825 BOOLEAN
826 NTAPI
829  IN ULONG Length,
830  IN BOOLEAN Zero,
831  IN ULONG Flags,
832  OUT PVOID *Bcb,
833  OUT PVOID *Buffer)
834 {
835  BOOLEAN Result;
836  PNOCC_BCB RealBcb;
837 #ifdef PIN_WRITE_ONLY
840  ULONG OldProtect;
841 #endif
842 
843  DPRINT("CcPreparePinWrite(%x:%x)\n", Buffer, Length);
844 
845  Result = CcPinRead(FileObject, FileOffset, Length, Flags, Bcb, Buffer);
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 
857  &BaseAddress,
858  &NumberOfBytes,
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);
876  RtlZeroMemory(*Buffer, Length);
877  }
878  }
879 
880  return Result;
881 }
882 
883 /*
884 
885 CcpUnpinData is the internal function that generally handles unpinning data.
886 It may be a little confusing, because of the way reference counts are handled.
887 
888 A reference count of 2 or greater means that the stripe is still fully pinned
889 and can't be removed. If the owner had taken an exclusive reference, then
890 give one up. Note that it's an error to take more than one exclusive reference
891 or to take a non-exclusive reference after an exclusive reference, so detecting
892 or handling that case is not considered.
893 
894 ReleaseBit is unset if we want to detect when a cache stripe would become
895 evictable without actually giving up our reference. We might want to do that
896 if we were going to flush before formally releasing the cache stripe, although
897 that facility is not used meaningfully at this time.
898 
899 A reference count of exactly 1 means that the stripe could potentially be
900 reused, but could also be evicted for another mapping. In general, most
901 stripes should be in that state most of the time.
902 
903 A reference count of zero means that the Bcb is completely unused. That's the
904 start state and the state of a Bcb formerly owned by a file that is
905 uninitialized.
906 
907 */
908 
909 BOOLEAN
910 NTAPI
911 CcpUnpinData(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--;
929  KeSetEvent(&CcDeleteEvent, IO_DISK_INCREMENT, FALSE);
930  }
931  if (RealBcb->RefCount == 1)
932  {
933  DPRINT("Clearing allocation bit #%x\n", RealBcb - CcCacheSections);
934 
935  RtlClearBit(CcCacheBitmap, RealBcb - CcCacheSections);
936 
937 #ifdef PIN_WRITE_ONLY
938  PVOID BaseAddress = RealBcb->BaseAddress;
939  SIZE_T NumberOfBytes = RealBcb->Length;
940  ULONG OldProtect;
941 
943  &BaseAddress,
944  &NumberOfBytes,
946  &OldProtect);
947 #endif
948  }
949 
950  return TRUE;
951 }
952 
953 VOID
954 NTAPI
956 {
957  PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
958  ULONG Selected = RealBcb - CcCacheSections;
959  BOOLEAN Released;
960 
961  ASSERT(RealBcb >= CcCacheSections &&
962  RealBcb - CcCacheSections < CACHE_NUM_SECTIONS);
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 
977 VOID
978 NTAPI
981 {
982  PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
983  CcpLock();
984  CcpReferenceCache(RealBcb - CcCacheSections);
985  RealBcb->OwnerPointer = OwnerPointer;
986  CcpUnlock();
987 }
988 
989 VOID
990 NTAPI
993 {
994  CcUnpinData(Bcb);
995 }
996 
997 /* EOF */
_Must_inspect_result_ _Outptr_ PVOID * SectionObject
Definition: fsrtlfuncs.h:860
DWORD *typedef PVOID
Definition: winlogon.h:52
NTSTATUS CcpAllocateSection(PFILE_OBJECT FileObject, ULONG Length, ULONG Protect, PROS_SECTION_OBJECT *Result)
Definition: pinsup.c:140
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define INVALID_CACHE
Definition: newcc.h:130
signed char * PCHAR
Definition: retypes.h:7
PRTL_BITMAP CcCacheBitmap
Definition: pinsup.c:100
ULONG CcCacheClockHand
Definition: pinsup.c:104
ULONG_PTR ERESOURCE_THREAD
Definition: extypes.h:208
#define IN
Definition: typedefs.h:38
VOID _CcpUnlock(const char *file, int line)
Definition: pinsup.c:120
KEVENT CcDeleteEvent
Definition: pinsup.c:102
LONG CcOutstandingDeletes
Definition: pinsup.c:105
LARGE_INTEGER FileOffset
Definition: pinsup.c:169
#define TRUE
Definition: types.h:120
VOID NTAPI ExQueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, IN WORK_QUEUE_TYPE QueueType)
Definition: work.c:716
#define ROUND_UP(n, align)
Definition: eventvwr.h:31
struct _RTL_BITMAP RTL_BITMAP
#define CcpLock()
Definition: newcc.h:140
struct _Entry Entry
Definition: kefuncs.h:640
#define DbgPrint
Definition: loader.c:26
NTSTATUS NTAPI MmMapCacheViewInSystemSpaceAtOffset(IN PMM_SECTION_SEGMENT Segment, OUT PVOID *MappedBase, PLARGE_INTEGER FileOffset, IN OUT PULONG ViewSize)
Definition: data.c:796
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
_In_ PVOID OwnerPointer
Definition: exfuncs.h:862
ULONG Length
Definition: newcc.h:11
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:2092
#define CACHE_NUM_SECTIONS
Definition: newcc.h:127
char CHAR
Definition: xmlstorage.h:175
NTSYSAPI VOID NTAPI RtlSetBit(_In_ PRTL_BITMAP BitMapHeader, _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber)
Definition: bitmap.c:304
VOID NTAPI CcUnpinData(IN PVOID Bcb)
Definition: pinsup.c:955
VOID CcpMarkForExclusive(ULONG Start)
Definition: pinsup.c:379
KEVENT CcFinalizeEvent
Definition: pinsup.c:103
FAST_MUTEX CcMutex
Definition: pinsup.c:101
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:267
ULONG RefCount
Definition: newcc.h:17
PVOID BaseAddress
Definition: newcc.h:12
_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:426
#define InsertTailList(ListHead, Entry)
Definition: newcc.h:3
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
VOID FASTCALL ExReleaseFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:31
BOOLEAN NTAPI CcpUnpinData(IN PNOCC_BCB RealBcb, BOOLEAN ReleaseBit)
Definition: pinsup.c:911
#define CACHE_ROUND_DOWN(x)
Definition: newcc.h:129
BOOLEAN Exclusive
Definition: newcc.h:23
T MIN(T a, T b)
Definition: polytest.cpp:79
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
GLenum GLclampf GLint i
Definition: glfuncs.h:14
#define IO_DISK_INCREMENT
Definition: iotypes.h:567
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
#define SEC_CACHE
Definition: newmm.h:36
BOOLEAN Dirty
Definition: newcc.h:13
_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:214
PDEVICE_OBJECT NTAPI MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject)
Definition: io.c:62
long LONG
Definition: pedump.c:60
#define SEC_RESERVE
Definition: nt_native.h:1323
PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite
Definition: pinsup.c:172
NOCC_BCB CcCacheSections[CACHE_NUM_SECTIONS]
Definition: pinsup.c:98
smooth NULL
Definition: ftsmooth.c:557
ULONG ExclusiveWaiter
Definition: newcc.h:22
LARGE_INTEGER MapSize
Definition: pinsup.c:170
_In_ PFILE_OBJECT FileObject
Definition: classpnp.h:1229
VOID CcpUnmapCache(PVOID Context)
Definition: pinsup.c:187
Definition: parser.c:48
void DPRINT(...)
Definition: polytest.cpp:61
VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1469
Definition: bufpool.h:45
LIST_ENTRY AssociatedBcb
Definition: newcc.h:29
NTSTATUS NTAPI MmUnmapCacheViewInSystemSpace(IN PVOID MappedBase)
Definition: data.c:830
#define PCHAR
Definition: match.c:90
#define CACHE_STRIPE
Definition: newcc.h:125
VOID NTAPI CcSetBcbOwnerPointer(IN PVOID Bcb, IN PVOID OwnerPointer)
Definition: pinsup.c:979
FAST_MUTEX
Definition: extypes.h:17
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
unsigned char BOOLEAN
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
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID * BaseAddress
Definition: mmfuncs.h:404
PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite
Definition: pinsup.c:173
ULONG CcpAllocateCacheSections(PFILE_OBJECT FileObject, PROS_SECTION_OBJECT SectionObject)
Definition: pinsup.c:310
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
if(!(yy_init))
Definition: macro.lex.yy.c:704
PROS_SECTION_OBJECT SectionObject
Definition: newcc.h:9
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
CHAR CcpBitmapBuffer[sizeof(RTL_BITMAP)+ROUND_UP((CACHE_NUM_SECTIONS), 32)/8]
Definition: pinsup.c:99
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:4964
#define MiFlushMappedSection(A, O, S, D)
Definition: newmm.h:402
VOID NTAPI RtlClearBit(_In_ PRTL_BITMAP BitMapHeader, _In_ BITMAP_INDEX BitNumber)
Definition: bitmap.c:294
_Must_inspect_result_ NTSYSAPI BOOLEAN NTAPI RtlTestBit(_In_ PRTL_BITMAP BitMapHeader, _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber)
Definition: bitmap.c:434
_Must_inspect_result_ typedef _In_ ULONG _In_ BOOLEAN Target
Definition: iotypes.h:1067
* PFILE_OBJECT
Definition: iotypes.h:1949
UINTN VOID * Buffer
Definition: acefiex.h:370
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
_In_ ERESOURCE_THREAD ResourceThreadId
Definition: exfuncs.h:844
struct _WORK_QUEUE_WITH_CONTEXT * PWORK_QUEUE_WITH_CONTEXT
VOID UINTN Length
Definition: acefiex.h:744
IN SIZE_T NumberOfBytes
Definition: ndis.h:3914
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
ULONG LowPart
Definition: typedefs.h:104
LARGE_INTEGER ValidDataLength
Definition: cctypes.h:17
#define PAGE_SIZE
Definition: env_spec_w32.h:49
Definition: typedefs.h:117
LARGE_INTEGER FileOffset
Definition: newcc.h:10
NTSYSAPI ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP, ULONG, ULONG)
Status
Definition: gdiplustypes.h:24
PETHREAD LastThread
Definition: pinsup.c:109
VOID CcpReferenceCache(ULONG Start)
Definition: pinsup.c:368
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
ULONG_PTR SIZE_T
Definition: typedefs.h:78
CC_FILE_SIZES FileSizes
Definition: newcc.h:33
struct _NOCC_CACHE_MAP * Map
Definition: newcc.h:8
LONG NTSTATUS
Definition: DriverTester.h:11
VOID FASTCALL ExAcquireFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:23
VOID CcpReferenceCacheExclusive(ULONG Start)
Definition: pinsup.c:396
WORK_QUEUE_ITEM WorkItem
Definition: pinsup.c:167
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
#define min(a, b)
Definition: monoChain.cc:55
struct _NOCC_BCB * PNOCC_BCB
struct _RTL_BITMAP * PRTL_BITMAP
#define PAGE_READONLY
Definition: compat.h:127
ULONG CcpFindMatchingMap(PLIST_ENTRY Head, PLARGE_INTEGER FileOffset, ULONG Length)
Definition: pinsup.c:430
#define PIN_EXCLUSIVE
PROS_SECTION_OBJECT ToDeref
Definition: pinsup.c:171
#define DPRINT1
Definition: precomp.h:8
_In_ PLARGE_INTEGER FileOffset
Definition: cctypes.h:53
#define OUT
Definition: typedefs.h:39
PVOID OwnerPointer
Definition: newcc.h:14
_In_ HANDLE _Outptr_result_bytebuffer_ ViewSize PVOID _In_ ULONG_PTR _In_ SIZE_T _Inout_opt_ PLARGE_INTEGER _Inout_ PSIZE_T ViewSize
Definition: mmfuncs.h:404
#define STANDARD_RIGHTS_REQUIRED
Definition: nt_native.h:63
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:565
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:259
LIST_ENTRY ThisFileList
Definition: newcc.h:19
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
char * cleanup(char *str)
Definition: wpickclick.c:99
#define CcpUnlock()
Definition: newcc.h:141
VOID CcpDereferenceCache(ULONG Start, BOOLEAN Immediate)
Definition: pinsup.c:213
KEVENT ExclusiveWait
Definition: newcc.h:21
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
VOID _CcpLock(const char *file, int line)
Definition: pinsup.c:112
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 NTAPI CcUnpinDataForThread(IN PVOID Bcb, IN ERESOURCE_THREAD ResourceThreadId)
Definition: pinsup.c:991
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
Definition: partlist.h:39
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
struct _WORK_QUEUE_WITH_CONTEXT WORK_QUEUE_WITH_CONTEXT
LONGLONG QuadPart
Definition: typedefs.h:112
struct _NOCC_CACHE_MAP * PNOCC_CACHE_MAP
WORKER_THREAD_ROUTINE * PWORKER_THREAD_ROUTINE
Definition: extypes.h:200
_In_ PLARGE_INTEGER _In_ ULONG _In_ ULONG _Outptr_ PVOID * Bcb
Definition: ccfuncs.h:329
#define PAGE_READWRITE
Definition: nt_native.h:1304
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:29
Definition: fci.c:114