* Sync to trunk HEAD (r53298).
[reactos.git] / ntoskrnl / cache / pinsup.c
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 //#define PIN_WRITE_ONLY
23
24 /* GLOBALS ********************************************************************/
25
26 #define TAG_MAP_SEC TAG('C', 'c', 'S', 'x')
27 #define TAG_MAP_READ TAG('M', 'c', 'p', 'y')
28 #define TAG_MAP_BCB TAG('B', 'c', 'b', ' ')
29
30 NOCC_BCB CcCacheSections[CACHE_NUM_SECTIONS];
31 CHAR CcpBitmapBuffer[sizeof(RTL_BITMAP) + ROUND_UP((CACHE_NUM_SECTIONS), 32) / 8];
32 PRTL_BITMAP CcCacheBitmap = (PRTL_BITMAP)&CcpBitmapBuffer;
33 FAST_MUTEX CcMutex;
34 KEVENT CcDeleteEvent;
35 KEVENT CcFinalizeEvent;
36 ULONG CcCacheClockHand;
37 LONG CcOutstandingDeletes;
38
39 /* FUNCTIONS ******************************************************************/
40
41 PETHREAD LastThread;
42 VOID _CcpLock(const char *file, int line)
43 {
44 //DPRINT("<<<---<<< CC In Mutex(%s:%d %x)!\n", file, line, PsGetCurrentThread());
45 ExAcquireFastMutex(&CcMutex);
46 }
47
48 VOID _CcpUnlock(const char *file, int line)
49 {
50 ExReleaseFastMutex(&CcMutex);
51 //DPRINT(">>>--->>> CC Exit Mutex!\n", file, line);
52 }
53
54 PDEVICE_OBJECT
55 NTAPI
56 MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject);
57
58 NTSTATUS CcpAllocateSection
59 (PFILE_OBJECT FileObject,
60 ULONG Length,
61 ULONG Protect,
62 PMM_CACHE_SECTION_SEGMENT *Result)
63 {
64 NTSTATUS Status;
65 LARGE_INTEGER MaxSize;
66
67 MaxSize.QuadPart = Length;
68
69 DPRINT("Making Section for File %x\n", FileObject);
70 DPRINT("File name %wZ\n", &FileObject->FileName);
71 Status = MmCreateCacheSection
72 (Result,
73 STANDARD_RIGHTS_REQUIRED,
74 NULL,
75 &MaxSize,
76 Protect,
77 SEC_RESERVE | SEC_CACHE,
78 FileObject);
79
80 return Status;
81 }
82
83 typedef struct _WORK_QUEUE_WITH_CONTEXT
84 {
85 WORK_QUEUE_ITEM WorkItem;
86 PVOID ToUnmap;
87 LARGE_INTEGER FileOffset;
88 LARGE_INTEGER MapSize;
89 PMM_CACHE_SECTION_SEGMENT ToDeref;
90 PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite;
91 PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite;
92 PVOID LazyContext;
93 BOOLEAN Dirty;
94 } WORK_QUEUE_WITH_CONTEXT, *PWORK_QUEUE_WITH_CONTEXT;
95
96 VOID
97 CcpUnmapCache(PVOID Context)
98 {
99 PWORK_QUEUE_WITH_CONTEXT WorkItem = (PWORK_QUEUE_WITH_CONTEXT)Context;
100 DPRINT("Unmapping (finally) %x\n", WorkItem->ToUnmap);
101 WorkItem->AcquireForLazyWrite(WorkItem->LazyContext, TRUE);
102 MiFlushMappedSection(WorkItem->ToUnmap, &WorkItem->FileOffset, &WorkItem->MapSize, WorkItem->Dirty);
103 WorkItem->ReleaseFromLazyWrite(WorkItem->LazyContext);
104 MmUnmapCacheViewInSystemSpace(WorkItem->ToUnmap);
105 MmFinalizeSegment(WorkItem->ToDeref);
106 ExFreePool(WorkItem);
107 DPRINT("Done\n");
108 }
109
110 /* Must have acquired the mutex */
111 VOID CcpDereferenceCache(ULONG Start, BOOLEAN Immediate)
112 {
113 PVOID ToUnmap;
114 PNOCC_BCB Bcb;
115 BOOLEAN Dirty;
116 LARGE_INTEGER MappedSize;
117 LARGE_INTEGER BaseOffset;
118 PWORK_QUEUE_WITH_CONTEXT WorkItem;
119
120 DPRINT("CcpDereferenceCache(#%x)\n", Start);
121
122 Bcb = &CcCacheSections[Start];
123
124 Dirty = Bcb->Dirty;
125 ToUnmap = Bcb->BaseAddress;
126 BaseOffset = Bcb->FileOffset;
127 MappedSize = Bcb->Map->FileSizes.ValidDataLength;
128
129 DPRINT("Dereference #%x (count %d)\n", Start, Bcb->RefCount);
130 ASSERT(Bcb->SectionObject);
131 ASSERT(Bcb->RefCount == 1);
132
133 DPRINT("Firing work item for %x\n", Bcb->BaseAddress);
134
135 if (Immediate)
136 {
137 PMM_CACHE_SECTION_SEGMENT ToDeref = Bcb->SectionObject;
138 BOOLEAN Dirty = Bcb->Dirty;
139
140 Bcb->Map = NULL;
141 Bcb->SectionObject = NULL;
142 Bcb->BaseAddress = NULL;
143 Bcb->FileOffset.QuadPart = 0;
144 Bcb->Length = 0;
145 Bcb->RefCount = 0;
146 Bcb->Dirty = FALSE;
147 RemoveEntryList(&Bcb->ThisFileList);
148
149 CcpUnlock();
150 MiFlushMappedSection(ToUnmap, &BaseOffset, &MappedSize, Dirty);
151 MmUnmapCacheViewInSystemSpace(ToUnmap);
152 MmFinalizeSegment(ToDeref);
153 CcpLock();
154 }
155 else
156 {
157 WorkItem = ExAllocatePool(NonPagedPool, sizeof(*WorkItem));
158 if (!WorkItem) KeBugCheck(0);
159 WorkItem->ToUnmap = Bcb->BaseAddress;
160 WorkItem->FileOffset = Bcb->FileOffset;
161 WorkItem->Dirty = Bcb->Dirty;
162 WorkItem->MapSize = MappedSize;
163 WorkItem->ToDeref = Bcb->SectionObject;
164 WorkItem->AcquireForLazyWrite = Bcb->Map->Callbacks.AcquireForLazyWrite;
165 WorkItem->ReleaseFromLazyWrite = Bcb->Map->Callbacks.ReleaseFromLazyWrite;
166 WorkItem->LazyContext = Bcb->Map->LazyContext;
167
168 ExInitializeWorkItem(((PWORK_QUEUE_ITEM)WorkItem), (PWORKER_THREAD_ROUTINE)CcpUnmapCache, WorkItem);
169
170 Bcb->Map = NULL;
171 Bcb->SectionObject = NULL;
172 Bcb->BaseAddress = NULL;
173 Bcb->FileOffset.QuadPart = 0;
174 Bcb->Length = 0;
175 Bcb->RefCount = 0;
176 Bcb->Dirty = FALSE;
177 RemoveEntryList(&Bcb->ThisFileList);
178
179 CcpUnlock();
180 ExQueueWorkItem((PWORK_QUEUE_ITEM)WorkItem, DelayedWorkQueue);
181 CcpLock();
182 }
183 DPRINT("Done\n");
184 }
185
186 /* Needs mutex */
187 ULONG CcpAllocateCacheSections
188 (PFILE_OBJECT FileObject,
189 PMM_CACHE_SECTION_SEGMENT SectionObject)
190 {
191 ULONG i = INVALID_CACHE;
192 PNOCC_CACHE_MAP Map;
193 PNOCC_BCB Bcb;
194
195 DPRINT("AllocateCacheSections: FileObject %x\n", FileObject);
196
197 if (!FileObject->SectionObjectPointer)
198 return INVALID_CACHE;
199
200 Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
201
202 if (!Map)
203 return INVALID_CACHE;
204
205 DPRINT("Allocating Cache Section\n");
206
207 i = RtlFindClearBitsAndSet(CcCacheBitmap, 1, CcCacheClockHand);
208 CcCacheClockHand = (i + 1) % CACHE_NUM_SECTIONS;
209
210 if (i != INVALID_CACHE)
211 {
212 DPRINT("Setting up Bcb #%x\n", i);
213
214 Bcb = &CcCacheSections[i];
215
216 ASSERT(Bcb->RefCount < 2);
217
218 if (Bcb->RefCount > 0)
219 {
220 CcpDereferenceCache(i, FALSE);
221 }
222
223 ASSERT(!Bcb->RefCount);
224 Bcb->RefCount = 1;
225
226 DPRINT("Bcb #%x RefCount %d\n", Bcb - CcCacheSections, Bcb->RefCount);
227
228 if (!RtlTestBit(CcCacheBitmap, i))
229 {
230 DPRINT("Somebody stoeled BCB #%x\n", i);
231 }
232 ASSERT(RtlTestBit(CcCacheBitmap, i));
233
234 DPRINT("Allocated #%x\n", i);
235 ASSERT(CcCacheSections[i].RefCount);
236 }
237 else
238 {
239 DPRINT("Failed to allocate cache segment\n");
240 }
241 return i;
242 }
243
244 /* Must have acquired the mutex */
245 VOID CcpReferenceCache(ULONG Start)
246 {
247 PNOCC_BCB Bcb;
248 Bcb = &CcCacheSections[Start];
249 ASSERT(Bcb->SectionObject);
250 Bcb->RefCount++;
251 RtlSetBit(CcCacheBitmap, Start);
252
253 }
254
255 VOID CcpMarkForExclusive(ULONG Start)
256 {
257 PNOCC_BCB Bcb;
258 Bcb = &CcCacheSections[Start];
259 Bcb->ExclusiveWaiter++;
260 }
261
262 /* Must not have the mutex */
263 VOID CcpReferenceCacheExclusive(ULONG Start)
264 {
265 PNOCC_BCB Bcb = &CcCacheSections[Start];
266
267 KeWaitForSingleObject(&Bcb->ExclusiveWait, Executive, KernelMode, FALSE, NULL);
268 CcpLock();
269 ASSERT(Bcb->ExclusiveWaiter);
270 ASSERT(Bcb->SectionObject);
271 Bcb->Exclusive = TRUE;
272 Bcb->ExclusiveWaiter--;
273 RtlSetBit(CcCacheBitmap, Start);
274 CcpUnlock();
275 }
276
277 /* Find a map that encompasses the target range */
278 /* Must have the mutex */
279 ULONG CcpFindMatchingMap(PLIST_ENTRY Head, PLARGE_INTEGER FileOffset, ULONG Length)
280 {
281 PLIST_ENTRY Entry;
282 //DPRINT("Find Matching Map: (%x) %x:%x\n", FileOffset->LowPart, Length);
283 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
284 {
285 //DPRINT("Link @%x\n", Entry);
286 PNOCC_BCB Bcb = CONTAINING_RECORD(Entry, NOCC_BCB, ThisFileList);
287 //DPRINT("Selected BCB %x #%x\n", Bcb, Bcb - CcCacheSections);
288 //DPRINT("This File: %x:%x\n", Bcb->FileOffset.LowPart, Bcb->Length);
289 if (FileOffset->QuadPart >= Bcb->FileOffset.QuadPart &&
290 FileOffset->QuadPart < Bcb->FileOffset.QuadPart + CACHE_STRIPE)
291 {
292 //DPRINT("Found match at #%x\n", Bcb - CcCacheSections);
293 return Bcb - CcCacheSections;
294 }
295 }
296
297 //DPRINT("This region isn't mapped\n");
298
299 return INVALID_CACHE;
300 }
301
302 BOOLEAN
303 NTAPI
304 CcpMapData
305 (IN PFILE_OBJECT FileObject,
306 IN PLARGE_INTEGER FileOffset,
307 IN ULONG Length,
308 IN ULONG Flags,
309 OUT PVOID *BcbResult,
310 OUT PVOID *Buffer)
311 {
312 BOOLEAN Success = FALSE, FaultIn = FALSE;
313 /* Note: windows 2000 drivers treat this as a bool */
314 //BOOLEAN Wait = (Flags & MAP_WAIT) || (Flags == TRUE);
315 LARGE_INTEGER Target, EndInterval;
316 ULONG BcbHead;
317 PNOCC_BCB Bcb = NULL;
318 PMM_CACHE_SECTION_SEGMENT SectionObject = NULL;
319 NTSTATUS Status;
320 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
321
322 if (!Map)
323 {
324 DPRINT1("File object was not mapped\n");
325 return FALSE;
326 }
327
328 DPRINT("CcMapData(F->%x,%08x%08x:%d)\n", FileObject, FileOffset->HighPart, FileOffset->LowPart, Length);
329
330 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
331
332 Target.HighPart = FileOffset->HighPart;
333 Target.LowPart = CACHE_ROUND_DOWN(FileOffset->LowPart);
334
335 CcpLock();
336
337 /* Find out if any range is a superset of what we want */
338 /* Find an accomodating section */
339 BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
340
341 if (BcbHead != INVALID_CACHE)
342 {
343 Bcb = &CcCacheSections[BcbHead];
344 Success = TRUE;
345 *BcbResult = Bcb;
346 *Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
347 DPRINT
348 ("Bcb #%x Buffer maps (%08x%08x) At %x Length %x (Getting %x:%x) %wZ\n",
349 Bcb - CcCacheSections,
350 Bcb->FileOffset.HighPart,
351 Bcb->FileOffset.LowPart,
352 Bcb->BaseAddress,
353 Bcb->Length,
354 *Buffer,
355 Length,
356 &FileObject->FileName);
357 DPRINT("w1n\n");
358 goto cleanup;
359 }
360
361 ULONG SectionSize;
362
363 DPRINT("File size %08x%08x\n", Map->FileSizes.ValidDataLength.HighPart, Map->FileSizes.ValidDataLength.LowPart);
364
365 if (Map->FileSizes.ValidDataLength.QuadPart)
366 {
367 SectionSize = min(CACHE_STRIPE, Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart);
368 }
369 else
370 {
371 SectionSize = CACHE_STRIPE;
372 }
373
374 DPRINT("Allocating a cache stripe at %x:%d\n",
375 Target.LowPart, SectionSize);
376 //ASSERT(SectionSize <= CACHE_STRIPE);
377
378 CcpUnlock();
379 Status = CcpAllocateSection
380 (FileObject,
381 SectionSize,
382 #ifdef PIN_WRITE_ONLY
383 PAGE_READONLY,
384 #else
385 PAGE_READWRITE,
386 #endif
387 &SectionObject);
388 CcpLock();
389
390 if (!NT_SUCCESS(Status))
391 {
392 *BcbResult = NULL;
393 *Buffer = NULL;
394 DPRINT1("End %08x\n", Status);
395 goto cleanup;
396 }
397
398 retry:
399 /* Returns a reference */
400 DPRINT("Allocating cache sections: %wZ\n", &FileObject->FileName);
401 BcbHead = CcpAllocateCacheSections(FileObject, SectionObject);
402 if (BcbHead == INVALID_CACHE)
403 {
404 ULONG i;
405 DbgPrint("Cache Map:");
406 for (i = 0; i < CACHE_NUM_SECTIONS; i++)
407 {
408 if (!(i % 64)) DbgPrint("\n");
409 DbgPrint("%c", CcCacheSections[i].RefCount + (RtlTestBit(CcCacheBitmap, i) ? '@' : '`'));
410 }
411 DbgPrint("\n");
412 KeWaitForSingleObject(&CcDeleteEvent, Executive, KernelMode, FALSE, NULL);
413 goto retry;
414 }
415
416 DPRINT("BcbHead #%x (final)\n", BcbHead);
417
418 if (BcbHead == INVALID_CACHE)
419 {
420 *BcbResult = NULL;
421 *Buffer = NULL;
422 DPRINT1("End\n");
423 goto cleanup;
424 }
425
426 DPRINT("Selected BCB #%x\n", BcbHead);
427 ULONG ViewSize = CACHE_STRIPE;
428
429 Bcb = &CcCacheSections[BcbHead];
430 Status = MmMapCacheViewInSystemSpaceAtOffset
431 (SectionObject,
432 &Bcb->BaseAddress,
433 &Target,
434 &ViewSize);
435
436 if (!NT_SUCCESS(Status))
437 {
438 *BcbResult = NULL;
439 *Buffer = NULL;
440 MmFinalizeSegment(SectionObject);
441 RemoveEntryList(&Bcb->ThisFileList);
442 RtlZeroMemory(Bcb, sizeof(*Bcb));
443 RtlClearBit(CcCacheBitmap, BcbHead);
444 DPRINT1("Failed to map\n");
445 goto cleanup;
446 }
447
448 Success = TRUE;
449 //DPRINT("w1n\n");
450
451 Bcb->Length = MIN(Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart, CACHE_STRIPE);
452 Bcb->SectionObject = SectionObject;
453 Bcb->Map = Map;
454 Bcb->FileOffset = Target;
455 InsertTailList(&Map->AssociatedBcb, &Bcb->ThisFileList);
456
457 *BcbResult = &CcCacheSections[BcbHead];
458 *Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
459 FaultIn = TRUE;
460
461 DPRINT
462 ("Bcb #%x Buffer maps (%08x%08x) At %x Length %x (Getting %x:%x) %wZ\n",
463 Bcb - CcCacheSections,
464 Bcb->FileOffset.HighPart,
465 Bcb->FileOffset.LowPart,
466 Bcb->BaseAddress,
467 Bcb->Length,
468 *Buffer,
469 Length,
470 &FileObject->FileName);
471
472 EndInterval.QuadPart = Bcb->FileOffset.QuadPart + Bcb->Length - 1;
473 ASSERT((EndInterval.QuadPart & ~(CACHE_STRIPE - 1)) == (Bcb->FileOffset.QuadPart & ~(CACHE_STRIPE - 1)));
474
475 //DPRINT("TERM!\n");
476
477 cleanup:
478 CcpUnlock();
479 if (Success)
480 {
481 if (FaultIn)
482 {
483 // Fault in the pages. This forces reads to happen now.
484 ULONG i;
485 CHAR Dummy;
486 PCHAR FaultIn = Bcb->BaseAddress;
487 DPRINT1
488 ("Faulting in pages at this point: file %wZ %08x%08x:%x\n",
489 &FileObject->FileName,
490 Bcb->FileOffset.HighPart,
491 Bcb->FileOffset.LowPart,
492 Bcb->Length);
493 for (i = 0; i < Bcb->Length; i++)
494 {
495 Dummy = FaultIn[i];
496 }
497 }
498 ASSERT(Bcb >= CcCacheSections && Bcb < (CcCacheSections + CACHE_NUM_SECTIONS));
499 }
500 else
501 {
502 ASSERT(FALSE);
503 }
504
505 return Success;
506 }
507
508 BOOLEAN
509 NTAPI
510 CcMapData
511 (IN PFILE_OBJECT FileObject,
512 IN PLARGE_INTEGER FileOffset,
513 IN ULONG Length,
514 IN ULONG Flags,
515 OUT PVOID *BcbResult,
516 OUT PVOID *Buffer)
517 {
518 BOOLEAN Result;
519
520 Result = CcpMapData
521 (FileObject,
522 FileOffset,
523 Length,
524 Flags,
525 BcbResult,
526 Buffer);
527
528 if (Result)
529 {
530 PNOCC_BCB Bcb = (PNOCC_BCB)*BcbResult;
531 ASSERT(Bcb >= CcCacheSections && Bcb < CcCacheSections + CACHE_NUM_SECTIONS);
532 ASSERT(Bcb->BaseAddress);
533 CcpLock();
534 CcpReferenceCache(Bcb - CcCacheSections);
535 CcpUnlock();
536 }
537
538 return Result;
539 }
540
541 BOOLEAN
542 NTAPI
543 CcpPinMappedData(IN PNOCC_CACHE_MAP Map,
544 IN PLARGE_INTEGER FileOffset,
545 IN ULONG Length,
546 IN ULONG Flags,
547 IN OUT PVOID *Bcb)
548 {
549 BOOLEAN Exclusive = Flags & PIN_EXCLUSIVE;
550 ULONG BcbHead;
551 PNOCC_BCB TheBcb;
552
553 CcpLock();
554
555 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));
556 BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
557 if (BcbHead == INVALID_CACHE)
558 {
559 CcpUnlock();
560 return FALSE;
561 }
562
563 TheBcb = &CcCacheSections[BcbHead];
564
565 if (Exclusive)
566 {
567 DPRINT("Requesting #%x Exclusive\n", BcbHead);
568 CcpMarkForExclusive(BcbHead);
569 }
570 else
571 {
572 DPRINT("Reference #%x\n", BcbHead);
573 CcpReferenceCache(BcbHead);
574 }
575
576 if (Exclusive)
577 CcpReferenceCacheExclusive(BcbHead);
578
579 CcpUnlock();
580
581 *Bcb = TheBcb;
582 return TRUE;
583 }
584
585 BOOLEAN
586 NTAPI
587 CcPinMappedData(IN PFILE_OBJECT FileObject,
588 IN PLARGE_INTEGER FileOffset,
589 IN ULONG Length,
590 IN ULONG Flags,
591 IN OUT PVOID *Bcb)
592 {
593 PVOID Buffer;
594 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
595
596 if (!Map)
597 {
598 DPRINT1("Not cached\n");
599 return FALSE;
600 }
601
602 if (CcpMapData(FileObject, FileOffset, Length, Flags, Bcb, &Buffer))
603 {
604 return CcpPinMappedData(Map, FileOffset, Length, Flags, Bcb);
605 }
606 else
607 {
608 DPRINT1("could not map\n");
609 return FALSE;
610 }
611 }
612
613 BOOLEAN
614 NTAPI
615 CcPinRead(IN PFILE_OBJECT FileObject,
616 IN PLARGE_INTEGER FileOffset,
617 IN ULONG Length,
618 IN ULONG Flags,
619 OUT PVOID *Bcb,
620 OUT PVOID *Buffer)
621 {
622 PNOCC_BCB RealBcb;
623 BOOLEAN Result;
624
625 Result = CcPinMappedData
626 (FileObject,
627 FileOffset,
628 Length,
629 Flags,
630 Bcb);
631
632 if (Result)
633 {
634 CcpLock();
635 RealBcb = *Bcb;
636 *Buffer = ((PCHAR)RealBcb->BaseAddress) + (int)(FileOffset->QuadPart - RealBcb->FileOffset.QuadPart);
637 CcpUnlock();
638 }
639
640 return Result;
641 }
642 \f
643 BOOLEAN
644 NTAPI
645 CcPreparePinWrite(IN PFILE_OBJECT FileObject,
646 IN PLARGE_INTEGER FileOffset,
647 IN ULONG Length,
648 IN BOOLEAN Zero,
649 IN ULONG Flags,
650 OUT PVOID *Bcb,
651 OUT PVOID *Buffer)
652 {
653 BOOLEAN Result;
654 PNOCC_BCB RealBcb;
655 #ifdef PIN_WRITE_ONLY
656 PVOID BaseAddress;
657 SIZE_T NumberOfBytes;
658 ULONG OldProtect;
659 #endif
660
661 DPRINT1("CcPreparePinWrite(%x:%x)\n", Buffer, Length);
662
663 Result = CcPinRead
664 (FileObject,
665 FileOffset,
666 Length,
667 Flags,
668 Bcb,
669 Buffer);
670
671 if (Result)
672 {
673 CcpLock();
674 RealBcb = *Bcb;
675
676 #ifdef PIN_WRITE_ONLY
677 BaseAddress = RealBcb->BaseAddress;
678 NumberOfBytes = RealBcb->Length;
679
680 MiProtectVirtualMemory
681 (NULL,
682 &BaseAddress,
683 &NumberOfBytes,
684 PAGE_READWRITE,
685 &OldProtect);
686 #endif
687
688 CcpUnlock();
689 RealBcb->Dirty = TRUE;
690
691 if (Zero)
692 {
693 DPRINT
694 ("Zero fill #%x %08x%08x:%x Buffer %x %wZ\n",
695 RealBcb - CcCacheSections,
696 FileOffset->u.HighPart,
697 FileOffset->u.LowPart,
698 Length,
699 *Buffer,
700 &FileObject->FileName);
701
702 DPRINT1("RtlZeroMemory(%x,%x)\n", *Buffer, Length);
703 RtlZeroMemory(*Buffer, Length);
704 }
705 }
706
707 return Result;
708 }
709
710 BOOLEAN
711 NTAPI
712 CcpUnpinData(IN PNOCC_BCB RealBcb, BOOLEAN ReleaseBit)
713 {
714 if (RealBcb->RefCount <= 2)
715 {
716 RealBcb->Exclusive = FALSE;
717 if (RealBcb->ExclusiveWaiter)
718 {
719 DPRINT("Triggering exclusive waiter\n");
720 KeSetEvent(&RealBcb->ExclusiveWait, IO_NO_INCREMENT, FALSE);
721 return TRUE;
722 }
723 }
724 if (RealBcb->RefCount == 2 && !ReleaseBit)
725 return FALSE;
726 if (RealBcb->RefCount > 1)
727 {
728 DPRINT("Removing one reference #%x\n", RealBcb - CcCacheSections);
729 RealBcb->RefCount--;
730 KeSetEvent(&CcDeleteEvent, IO_DISK_INCREMENT, FALSE);
731 }
732 if (RealBcb->RefCount == 1)
733 {
734 DPRINT("Clearing allocation bit #%x\n", RealBcb - CcCacheSections);
735
736 RtlClearBit(CcCacheBitmap, RealBcb - CcCacheSections);
737
738 #ifdef PIN_WRITE_ONLY
739 PVOID BaseAddress = RealBcb->BaseAddress;
740 SIZE_T NumberOfBytes = RealBcb->Length;
741 ULONG OldProtect;
742
743 MiProtectVirtualMemory
744 (NULL,
745 &BaseAddress,
746 &NumberOfBytes,
747 PAGE_READONLY,
748 &OldProtect);
749 #endif
750 }
751
752 return TRUE;
753 }
754 \f
755 VOID
756 NTAPI
757 CcUnpinData(IN PVOID Bcb)
758 {
759 PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
760 ULONG Selected = RealBcb - CcCacheSections;
761 BOOLEAN Released;
762
763 ASSERT(RealBcb >= CcCacheSections && RealBcb - CcCacheSections < CACHE_NUM_SECTIONS);
764 DPRINT("CcUnpinData Bcb #%x (RefCount %d)\n", Selected, RealBcb->RefCount);
765
766 CcpLock();
767 Released = CcpUnpinData(RealBcb, FALSE);
768 CcpUnlock();
769
770 if (!Released) {
771 MiFlushMappedSection(RealBcb->BaseAddress, &RealBcb->FileOffset, &RealBcb->Map->FileSizes.FileSize, RealBcb->Dirty);
772 CcpLock();
773 CcpUnpinData(RealBcb, TRUE);
774 CcpUnlock();
775 }
776 }
777
778 VOID
779 NTAPI
780 CcSetBcbOwnerPointer(IN PVOID Bcb,
781 IN PVOID OwnerPointer)
782 {
783 PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
784 CcpLock();
785 CcpReferenceCache(RealBcb - CcCacheSections);
786 RealBcb->OwnerPointer = OwnerPointer;
787 CcpUnlock();
788 }
789 \f
790 VOID
791 NTAPI
792 CcUnpinDataForThread(IN PVOID Bcb,
793 IN ERESOURCE_THREAD ResourceThreadId)
794 {
795 CcUnpinData(Bcb);
796 }
797
798 /* EOF */