2002-09-30 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / cc / view.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: view.c,v 1.51 2002/09/30 20:55:33 chorns Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/cc/view.c
23 * PURPOSE: Cache manager
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * PORTABILITY: Checked
26 * UPDATE HISTORY:
27 * Created 22/05/98
28 */
29
30 /* NOTES **********************************************************************
31 *
32 * This is not the NT implementation of a file cache nor anything much like
33 * it.
34 *
35 * The general procedure for a filesystem to implement a read or write
36 * dispatch routine is as follows
37 *
38 * (1) If caching for the FCB hasn't been initiated then so do by calling
39 * CcInitializeFileCache.
40 *
41 * (2) For each 4k region which is being read or written obtain a cache page
42 * by calling CcRequestCachePage.
43 *
44 * (3) If either the page is being read or not completely written, and it is
45 * not up to date then read its data from the underlying medium. If the read
46 * fails then call CcReleaseCachePage with VALID as FALSE and return a error.
47 *
48 * (4) Copy the data into or out of the page as necessary.
49 *
50 * (5) Release the cache page
51 */
52 /* INCLUDES ******************************************************************/
53
54 #include <ddk/ntddk.h>
55 #include <ddk/ntifs.h>
56 #include <internal/mm.h>
57 #include <internal/cc.h>
58 #include <internal/pool.h>
59 #include <ntos/minmax.h>
60
61 #define NDEBUG
62 #include <internal/debug.h>
63
64 /* GLOBALS *******************************************************************/
65
66 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
67 #define ROUND_DOWN(N, S) (((N) % (S)) ? ROUND_UP(N, S) - S : N)
68
69 #define TAG_CSEG TAG('C', 'S', 'E', 'G')
70 #define TAG_BCB TAG('B', 'C', 'B', ' ')
71
72 static LIST_ENTRY DirtySegmentListHead;
73 static LIST_ENTRY CacheSegmentListHead;
74 static LIST_ENTRY CacheSegmentLRUListHead;
75
76 static FAST_MUTEX ViewLock;
77
78 void * alloca(size_t size);
79
80 NTSTATUS STDCALL
81 CcRosInternalFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg);
82
83 /* FUNCTIONS *****************************************************************/
84
85 NTSTATUS STATIC
86 CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment)
87 {
88 NTSTATUS Status;
89 Status = WriteCacheSegment(CacheSegment);
90 if (NT_SUCCESS(Status))
91 {
92 CacheSegment->Dirty = FALSE;
93 RemoveEntryList(&CacheSegment->DirtySegmentListEntry);
94 }
95 return(Status);
96 }
97
98 NTSTATUS
99 CcRosFlushDirtyPages(ULONG Target, PULONG Count)
100 {
101 PLIST_ENTRY current_entry;
102 PCACHE_SEGMENT current;
103 ULONG PagesPerSegment;
104 BOOLEAN Locked;
105 NTSTATUS Status;
106
107 DPRINT("CcRosFlushDirtyPages(Target %d)\n", Target);
108
109 (*Count) = 0;
110
111 ExAcquireFastMutex(&ViewLock);
112 current_entry = DirtySegmentListHead.Flink;
113 while (current_entry != &DirtySegmentListHead && Target > 0)
114 {
115 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
116 DirtySegmentListEntry);
117 current_entry = current_entry->Flink;
118 Locked = ExTryToAcquireFastMutex(&current->Lock);
119 if (!Locked)
120 {
121 continue;
122 }
123 assert(current->Dirty);
124 if (current->ReferenceCount > 0)
125 {
126 ExReleaseFastMutex(&current->Lock);
127 continue;
128 }
129 current->ReferenceCount++;
130 ExReleaseFastMutex(&ViewLock);
131 PagesPerSegment = current->Bcb->CacheSegmentSize / PAGESIZE;
132 Status = CcRosFlushCacheSegment(current);
133 current->ReferenceCount--;
134 ExReleaseFastMutex(&current->Lock);
135 if (!NT_SUCCESS(Status))
136 {
137 DPRINT1("CC: Failed to flush cache segment.\n");
138 }
139 (*Count) += PagesPerSegment;
140 Target -= PagesPerSegment;
141
142 ExAcquireFastMutex(&ViewLock);
143 current_entry = DirtySegmentListHead.Flink;
144 }
145 ExReleaseFastMutex(&ViewLock);
146 DPRINT("CcRosTrimCache() finished\n");
147 return(STATUS_SUCCESS);
148 }
149
150 NTSTATUS
151 CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
152 /*
153 * FUNCTION: Try to free some memory from the file cache.
154 * ARGUMENTS:
155 * Target - The number of pages to be freed.
156 * Priority - The priority of free (currently unused).
157 * NrFreed - Points to a variable where the number of pages
158 * actually freed is returned.
159 */
160 {
161 PLIST_ENTRY current_entry;
162 PCACHE_SEGMENT current;
163 ULONG PagesPerSegment;
164 ULONG PagesFreed;
165 BOOLEAN Locked;
166
167 DPRINT("CcRosTrimCache(Target %d)\n", Target);
168
169 *NrFreed = 0;
170
171 ExAcquireFastMutex(&ViewLock);
172 current_entry = CacheSegmentLRUListHead.Flink;
173 while (current_entry != &CacheSegmentLRUListHead && Target > 0)
174 {
175 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
176 CacheSegmentLRUListEntry);
177 current_entry = current_entry->Flink;
178 Locked = ExTryToAcquireFastMutex(&current->Lock);
179 if (!Locked)
180 {
181 continue;
182 }
183 if (current->MappedCount > 0 || current->Dirty ||
184 current->ReferenceCount > 0)
185 {
186 ExReleaseFastMutex(&current->Lock);
187 continue;
188 }
189 ExReleaseFastMutex(&current->Lock);
190 DPRINT("current->Bcb->CacheSegmentSize %d\n",
191 current->Bcb->CacheSegmentSize);
192 PagesPerSegment = current->Bcb->CacheSegmentSize / PAGESIZE;
193 CcRosInternalFreeCacheSegment(current->Bcb, current);
194 DPRINT("CcRosTrimCache(): Freed %d\n", PagesPerSegment);
195 PagesFreed = min(PagesPerSegment, Target);
196 Target = Target - PagesFreed;
197 (*NrFreed) = (*NrFreed) + PagesFreed;
198 }
199 ExReleaseFastMutex(&ViewLock);
200 DPRINT("CcRosTrimCache() finished\n");
201 return(STATUS_SUCCESS);
202 }
203
204 NTSTATUS STDCALL
205 CcRosReleaseCacheSegment(PBCB Bcb,
206 PCACHE_SEGMENT CacheSeg,
207 BOOLEAN Valid,
208 BOOLEAN Dirty,
209 BOOLEAN Mapped)
210 {
211 BOOLEAN WasDirty = CacheSeg->Dirty;
212
213 DPRINT("CcReleaseCachePage(Bcb %x, CacheSeg %x, Valid %d)\n",
214 Bcb, CacheSeg, Valid);
215
216 CacheSeg->Valid = Valid;
217 CacheSeg->Dirty = CacheSeg->Dirty || Dirty;
218 if (Mapped)
219 {
220 CacheSeg->MappedCount++;
221 }
222 ExReleaseFastMutex(&CacheSeg->Lock);
223 ExAcquireFastMutex(&ViewLock);
224 if (!WasDirty && CacheSeg->Dirty)
225 {
226 InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
227 }
228 RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
229 InsertTailList(&CacheSegmentLRUListHead,
230 &CacheSeg->CacheSegmentLRUListEntry);
231 ExReleaseFastMutex(&ViewLock);
232 InterlockedDecrement(&CacheSeg->ReferenceCount);
233
234 DPRINT("CcReleaseCachePage() finished\n");
235
236 return(STATUS_SUCCESS);
237 }
238
239 PCACHE_SEGMENT CcRosLookupCacheSegment(PBCB Bcb, ULONG FileOffset)
240 {
241 PLIST_ENTRY current_entry;
242 PCACHE_SEGMENT current;
243 KIRQL oldIrql;
244
245 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
246 current_entry = Bcb->BcbSegmentListHead.Flink;
247 while (current_entry != &Bcb->BcbSegmentListHead)
248 {
249 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
250 BcbSegmentListEntry);
251 if (current->FileOffset <= FileOffset &&
252 (current->FileOffset + Bcb->CacheSegmentSize) > FileOffset)
253 {
254 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
255 return(current);
256 }
257 current_entry = current_entry->Flink;
258 }
259 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
260 return(NULL);
261 }
262
263 NTSTATUS
264 CcRosMarkDirtyCacheSegment(PBCB Bcb, ULONG FileOffset)
265 {
266 PCACHE_SEGMENT CacheSeg;
267
268 ExAcquireFastMutex(&ViewLock);
269 CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
270 if (CacheSeg == NULL)
271 {
272 KeBugCheck(0);
273 }
274 ExAcquireFastMutex(&CacheSeg->Lock);
275 if (!CacheSeg->Dirty)
276 {
277 InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
278 }
279 CacheSeg->Dirty = TRUE;
280 ExReleaseFastMutex(&CacheSeg->Lock);
281 ExReleaseFastMutex(&ViewLock);
282 return(STATUS_SUCCESS);
283 }
284
285 NTSTATUS
286 CcRosSuggestFreeCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty)
287 {
288 PCACHE_SEGMENT CacheSeg;
289
290 ExAcquireFastMutex(&ViewLock);
291 CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
292 if (CacheSeg == NULL)
293 {
294 KeBugCheck(0);
295 }
296 ExAcquireFastMutex(&CacheSeg->Lock);
297 if (CacheSeg->MappedCount > 0)
298 {
299 KeBugCheck(0);
300 }
301 CacheSeg->Dirty = CacheSeg->Dirty || NowDirty;
302 if (CacheSeg->Dirty || CacheSeg->ReferenceCount > 0)
303 {
304 ExReleaseFastMutex(&CacheSeg->Lock);
305 ExReleaseFastMutex(&ViewLock);
306 return(STATUS_UNSUCCESSFUL);
307 }
308 ExReleaseFastMutex(&CacheSeg->Lock);
309 CcRosInternalFreeCacheSegment(CacheSeg->Bcb, CacheSeg);
310 ExReleaseFastMutex(&ViewLock);
311 return(STATUS_SUCCESS);
312 }
313
314 NTSTATUS
315 CcRosUnmapCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty)
316 {
317 PCACHE_SEGMENT CacheSeg;
318
319 ExAcquireFastMutex(&ViewLock);
320 CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
321 if (CacheSeg == NULL)
322 {
323 ExReleaseFastMutex(&ViewLock);
324 return(STATUS_UNSUCCESSFUL);
325 }
326 CacheSeg->ReferenceCount++;
327 ExReleaseFastMutex(&ViewLock);
328 ExAcquireFastMutex(&CacheSeg->Lock);
329 CacheSeg->MappedCount--;
330 CacheSeg->Dirty = CacheSeg->Dirty || NowDirty;
331 CacheSeg->ReferenceCount--;
332 ExReleaseFastMutex(&CacheSeg->Lock);
333 return(STATUS_SUCCESS);
334 }
335
336 NTSTATUS STATIC
337 CcRosCreateCacheSegment(PBCB Bcb,
338 ULONG FileOffset,
339 PCACHE_SEGMENT* CacheSeg,
340 BOOLEAN Lock)
341 {
342 ULONG i;
343 PCACHE_SEGMENT current;
344 NTSTATUS Status;
345 KIRQL oldIrql;
346
347 current = ExAllocatePoolWithTag(NonPagedPool, sizeof(CACHE_SEGMENT),
348 TAG_CSEG);
349
350 MmLockAddressSpace(MmGetKernelAddressSpace());
351 current->BaseAddress = NULL;
352 Status = MmCreateMemoryArea(KernelMode,
353 MmGetKernelAddressSpace(),
354 MEMORY_AREA_CACHE_SEGMENT,
355 &current->BaseAddress,
356 Bcb->CacheSegmentSize,
357 PAGE_READWRITE,
358 (PMEMORY_AREA*)&current->MemoryArea,
359 FALSE);
360 if (!NT_SUCCESS(Status))
361 {
362 MmUnlockAddressSpace(MmGetKernelAddressSpace());
363 KeBugCheck(0);
364 }
365 MmUnlockAddressSpace(MmGetKernelAddressSpace());
366 current->Valid = FALSE;
367 current->Dirty = FALSE;
368 current->FileOffset = ROUND_DOWN(FileOffset, Bcb->CacheSegmentSize);
369 current->Bcb = Bcb;
370 current->MappedCount = 0;
371 ExInitializeFastMutex(&current->Lock);
372 current->ReferenceCount = 1;
373 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
374 InsertTailList(&Bcb->BcbSegmentListHead, &current->BcbSegmentListEntry);
375 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
376 InsertTailList(&CacheSegmentListHead, &current->CacheSegmentListEntry);
377 InsertTailList(&CacheSegmentLRUListHead,
378 &current->CacheSegmentLRUListEntry);
379 current->DirtySegmentListEntry.Flink =
380 current->DirtySegmentListEntry.Blink = NULL;
381 if (Lock)
382 {
383 ExAcquireFastMutex(&current->Lock);
384 }
385 ExReleaseFastMutex(&ViewLock);
386 for (i = 0; i < (Bcb->CacheSegmentSize / PAGESIZE); i++)
387 {
388 PHYSICAL_ADDRESS Page;
389
390 Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page);
391 if (!NT_SUCCESS(Status))
392 {
393 KeBugCheck(0);
394 }
395
396 Status = MmCreateVirtualMapping(NULL,
397 current->BaseAddress + (i * PAGESIZE),
398 PAGE_READWRITE,
399 Page,
400 TRUE);
401 if (!NT_SUCCESS(Status))
402 {
403 KeBugCheck(0);
404 }
405 }
406 *CacheSeg = current;
407 return(STATUS_SUCCESS);
408 }
409
410 NTSTATUS
411 CcRosGetCacheSegmentChain(PBCB Bcb,
412 ULONG FileOffset,
413 ULONG Length,
414 PCACHE_SEGMENT* CacheSeg)
415 {
416 PCACHE_SEGMENT current;
417 ULONG i;
418 PCACHE_SEGMENT* CacheSegList;
419 PCACHE_SEGMENT Previous = NULL;
420
421 Length = ROUND_UP(Length, Bcb->CacheSegmentSize);
422
423 CacheSegList = alloca(sizeof(PCACHE_SEGMENT) *
424 (Length / Bcb->CacheSegmentSize));
425
426 /*
427 * Acquire the global lock.
428 */
429 ExAcquireFastMutex(&ViewLock);
430
431 /*
432 * Look for a cache segment already mapping the same data.
433 */
434 for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++)
435 {
436 ULONG CurrentOffset = FileOffset + (i * Bcb->CacheSegmentSize);
437 current = CcRosLookupCacheSegment(Bcb, CurrentOffset);
438 if (current != NULL)
439 {
440 /*
441 * Make sure the cache segment can't go away outside of our control.
442 */
443 current->ReferenceCount++;
444 CacheSegList[i] = current;
445 }
446 else
447 {
448 CcRosCreateCacheSegment(Bcb, CurrentOffset, &current, FALSE);
449 CacheSegList[i] = current;
450 ExAcquireFastMutex(&ViewLock);
451 }
452 }
453 ExReleaseFastMutex(&ViewLock);
454
455 for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++)
456 {
457 ExAcquireFastMutex(&CacheSegList[i]->Lock);
458 if (i == 0)
459 {
460 *CacheSeg = CacheSegList[i];
461 Previous = CacheSegList[i];
462 }
463 else
464 {
465 Previous->NextInChain = CacheSegList[i];
466 Previous = CacheSegList[i];
467 }
468 }
469 Previous->NextInChain = NULL;
470
471 return(STATUS_SUCCESS);
472 }
473
474 NTSTATUS
475 CcRosGetCacheSegment(PBCB Bcb,
476 ULONG FileOffset,
477 PULONG BaseOffset,
478 PVOID* BaseAddress,
479 PBOOLEAN UptoDate,
480 PCACHE_SEGMENT* CacheSeg)
481 {
482 PCACHE_SEGMENT current;
483 NTSTATUS Status;
484
485 /*
486 * Acquire the global lock.
487 */
488 ExAcquireFastMutex(&ViewLock);
489
490 /*
491 * Look for a cache segment already mapping the same data.
492 */
493 current = CcRosLookupCacheSegment(Bcb, FileOffset);
494 if (current != NULL)
495 {
496 /*
497 * Make sure the cache segment can't go away outside of our control.
498 */
499 current->ReferenceCount++;
500 /*
501 * Release the global lock and lock the cache segment.
502 */
503 ExReleaseFastMutex(&ViewLock);
504 ExAcquireFastMutex(&current->Lock);
505 /*
506 * Return information about the segment to the caller.
507 */
508 *UptoDate = current->Valid;
509 *BaseAddress = current->BaseAddress;
510 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress);
511 *CacheSeg = current;
512 *BaseOffset = current->FileOffset;
513 return(STATUS_SUCCESS);
514 }
515
516 /*
517 * Otherwise create a new segment.
518 */
519 Status = CcRosCreateCacheSegment(Bcb, FileOffset, &current, TRUE);
520 *UptoDate = current->Valid;
521 *BaseAddress = current->BaseAddress;
522 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress);
523 *CacheSeg = current;
524 *BaseOffset = current->FileOffset;
525
526 return(STATUS_SUCCESS);
527 }
528
529 NTSTATUS STDCALL
530 CcRosRequestCacheSegment(PBCB Bcb,
531 ULONG FileOffset,
532 PVOID* BaseAddress,
533 PBOOLEAN UptoDate,
534 PCACHE_SEGMENT* CacheSeg)
535 /*
536 * FUNCTION: Request a page mapping for a BCB
537 */
538 {
539 ULONG BaseOffset;
540
541 if ((FileOffset % Bcb->CacheSegmentSize) != 0)
542 {
543 CPRINT("Bad fileoffset %x should be multiple of %x",
544 FileOffset, Bcb->CacheSegmentSize);
545 KeBugCheck(0);
546 }
547
548 return(CcRosGetCacheSegment(Bcb,
549 FileOffset,
550 &BaseOffset,
551 BaseAddress,
552 UptoDate,
553 CacheSeg));
554 }
555
556 STATIC VOID
557 CcFreeCachePage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
558 PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry, BOOLEAN Dirty)
559 {
560 assert(SwapEntry == 0);
561 if (PhysAddr.QuadPart != 0)
562 {
563 MmReleasePageMemoryConsumer(MC_CACHE, PhysAddr);
564 }
565 }
566
567 NTSTATUS STDCALL
568 CcRosInternalFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg)
569 /*
570 * FUNCTION: Releases a cache segment associated with a BCB
571 */
572 {
573 DPRINT("Freeing cache segment %x\n", CacheSeg);
574 RemoveEntryList(&CacheSeg->CacheSegmentListEntry);
575 RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
576 RemoveEntryList(&CacheSeg->BcbSegmentListEntry);
577 MmLockAddressSpace(MmGetKernelAddressSpace());
578 MmFreeMemoryArea(MmGetKernelAddressSpace(),
579 CacheSeg->BaseAddress,
580 Bcb->CacheSegmentSize,
581 CcFreeCachePage,
582 NULL);
583 MmUnlockAddressSpace(MmGetKernelAddressSpace());
584 ExFreePool(CacheSeg);
585 return(STATUS_SUCCESS);
586 }
587
588 NTSTATUS STDCALL
589 CcRosFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg)
590 {
591 NTSTATUS Status;
592 ExAcquireFastMutex(&ViewLock);
593 Status = CcRosInternalFreeCacheSegment(Bcb, CacheSeg);
594 ExReleaseFastMutex(&ViewLock);
595 return(Status);
596 }
597
598 NTSTATUS STDCALL
599 CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
600 /*
601 * FUNCTION: Releases the BCB associated with a file object
602 */
603 {
604 PLIST_ENTRY current_entry;
605 PCACHE_SEGMENT current;
606 NTSTATUS Status;
607
608 DPRINT("CcRosDeleteFileCache(FileObject %x, Bcb %x)\n", Bcb->FileObject,
609 Bcb);
610
611 MmFreeSectionSegments(Bcb->FileObject);
612
613 /*
614 * Write back dirty cache segments.
615 */
616 current_entry = Bcb->BcbSegmentListHead.Flink;
617 while (current_entry != &Bcb->BcbSegmentListHead)
618 {
619 current =
620 CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
621 if (current->Dirty)
622 {
623 Status = WriteCacheSegment(current);
624 if (!NT_SUCCESS(Status))
625 {
626 DPRINT1("Failed to write cache segment (Status %X)\n", Status);
627 }
628 ExAcquireFastMutex(&ViewLock);
629 RemoveEntryList(&current->DirtySegmentListEntry);
630 ExReleaseFastMutex(&ViewLock);
631 }
632 current_entry = current_entry->Flink;
633 }
634
635 /*
636 * Release all cache segments.
637 */
638 current_entry = Bcb->BcbSegmentListHead.Flink;
639 while (current_entry != &Bcb->BcbSegmentListHead)
640 {
641 current =
642 CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
643 current_entry = current_entry->Flink;
644 CcRosFreeCacheSegment(Bcb, current);
645 }
646 FileObject->SectionObjectPointers->SharedCacheMap = NULL;
647 ObDereferenceObject (Bcb->FileObject);
648 ExFreePool(Bcb);
649
650 return(STATUS_SUCCESS);
651 }
652
653 VOID CcRosReferenceCache(PFILE_OBJECT FileObject)
654 {
655 KIRQL oldIrql;
656 PBCB Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap;
657 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
658 Bcb->RefCount++;
659 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
660 }
661
662 VOID CcRosDereferenceCache(PFILE_OBJECT FileObject)
663 {
664 KIRQL oldIrql;
665 PBCB Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap;
666 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
667 Bcb->RefCount--;
668 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
669 if (Bcb->RefCount == 0)
670 {
671 CcRosDeleteFileCache(FileObject, Bcb);
672 }
673 }
674
675 NTSTATUS STDCALL
676 CcRosReleaseFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
677 /*
678 * FUNCTION: Called by the file system when a handle to a file object
679 * has been closed.
680 */
681 {
682 KIRQL oldIrql;
683 if (FileObject->SectionObjectPointers->SharedCacheMap != NULL)
684 {
685 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
686 if (FileObject->PrivateCacheMap != NULL)
687 {
688 FileObject->PrivateCacheMap = NULL;
689 Bcb->RefCount--;
690 }
691 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
692 if (Bcb->RefCount == 0)
693 {
694 CcRosDeleteFileCache(FileObject, Bcb);
695 }
696 }
697 return(STATUS_SUCCESS);
698 }
699
700 NTSTATUS STDCALL
701 CcRosInitializeFileCache(PFILE_OBJECT FileObject,
702 PBCB* Bcb,
703 ULONG CacheSegmentSize)
704 /*
705 * FUNCTION: Initializes a BCB for a file object
706 */
707 {
708 KIRQL oldIrql;
709 if (*Bcb == NULL)
710 {
711 (*Bcb) = ExAllocatePoolWithTag(NonPagedPool, sizeof(BCB), TAG_BCB);
712 if ((*Bcb) == NULL)
713 {
714 return(STATUS_UNSUCCESSFUL);
715 }
716
717 ObReferenceObjectByPointer(FileObject,
718 FILE_ALL_ACCESS,
719 NULL,
720 KernelMode);
721 (*Bcb)->FileObject = FileObject;
722 (*Bcb)->CacheSegmentSize = CacheSegmentSize;
723 if (FileObject->FsContext)
724 {
725 (*Bcb)->AllocationSize =
726 ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->AllocationSize;
727 (*Bcb)->FileSize =
728 ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->FileSize;
729 }
730 KeInitializeSpinLock(&(*Bcb)->BcbLock);
731 InitializeListHead(&(*Bcb)->BcbSegmentListHead);
732 FileObject->SectionObjectPointers->SharedCacheMap = *Bcb;
733 }
734 KeAcquireSpinLock(&(*Bcb)->BcbLock, &oldIrql);
735 if (FileObject->PrivateCacheMap == NULL)
736 {
737 FileObject->PrivateCacheMap = *Bcb;
738 (*Bcb)->RefCount++;
739 }
740 KeReleaseSpinLock(&(*Bcb)->BcbLock, oldIrql);
741
742 return(STATUS_SUCCESS);
743 }
744
745 VOID
746 CcInitView(VOID)
747 {
748 DPRINT("CcInitView()\n");
749 InitializeListHead(&CacheSegmentListHead);
750 InitializeListHead(&DirtySegmentListHead);
751 InitializeListHead(&CacheSegmentLRUListHead);
752 ExInitializeFastMutex(&ViewLock);
753 MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache);
754 CcInitCacheZeroPage();
755 }
756
757 /* EOF */
758
759
760
761
762
763
764