3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
19 /* $Id: view.c,v 1.53 2002/10/02 19:20:51 hbirr Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/cc/view.c
23 * PURPOSE: Cache manager
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * PORTABILITY: Checked
30 /* NOTES **********************************************************************
32 * This is not the NT implementation of a file cache nor anything much like
35 * The general procedure for a filesystem to implement a read or write
36 * dispatch routine is as follows
38 * (1) If caching for the FCB hasn't been initiated then so do by calling
39 * CcInitializeFileCache.
41 * (2) For each 4k region which is being read or written obtain a cache page
42 * by calling CcRequestCachePage.
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.
48 * (4) Copy the data into or out of the page as necessary.
50 * (5) Release the cache page
52 /* INCLUDES ******************************************************************/
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>
62 #include <internal/debug.h>
64 /* GLOBALS *******************************************************************/
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)
69 #define TAG_CSEG TAG('C', 'S', 'E', 'G')
70 #define TAG_BCB TAG('B', 'C', 'B', ' ')
72 static LIST_ENTRY DirtySegmentListHead
;
73 static LIST_ENTRY CacheSegmentListHead
;
74 static LIST_ENTRY CacheSegmentLRUListHead
;
76 static FAST_MUTEX ViewLock
;
78 void * alloca(size_t size
);
81 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg
);
83 /* FUNCTIONS *****************************************************************/
86 CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment
)
90 Status
= WriteCacheSegment(CacheSegment
);
91 if (NT_SUCCESS(Status
))
93 ExAcquireFastMutex(&ViewLock
);
94 KeAcquireSpinLock(&CacheSegment
->Bcb
->BcbLock
, &oldIrql
);
95 CacheSegment
->Dirty
= FALSE
;
96 RemoveEntryList(&CacheSegment
->DirtySegmentListEntry
);
97 CacheSegment
->ReferenceCount
--;
98 KeReleaseSpinLock(&CacheSegment
->Bcb
->BcbLock
, oldIrql
);
99 ExReleaseFastMutex(&ViewLock
);
105 CcRosFlushDirtyPages(ULONG Target
, PULONG Count
)
107 PLIST_ENTRY current_entry
;
108 PCACHE_SEGMENT current
;
109 ULONG PagesPerSegment
;
113 DPRINT("CcRosFlushDirtyPages(Target %d)\n", Target
);
117 ExAcquireFastMutex(&ViewLock
);
118 current_entry
= DirtySegmentListHead
.Flink
;
119 while (current_entry
!= &DirtySegmentListHead
&& Target
> 0)
121 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
122 DirtySegmentListEntry
);
123 current_entry
= current_entry
->Flink
;
124 Locked
= ExTryToAcquireFastMutex(¤t
->Lock
);
129 assert(current
->Dirty
);
130 if (current
->ReferenceCount
> 1)
132 ExReleaseFastMutex(¤t
->Lock
);
135 ExReleaseFastMutex(&ViewLock
);
136 PagesPerSegment
= current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
137 Status
= CcRosFlushCacheSegment(current
);
138 ExReleaseFastMutex(¤t
->Lock
);
139 if (!NT_SUCCESS(Status
))
141 DPRINT1("CC: Failed to flush cache segment.\n");
145 (*Count
) += PagesPerSegment
;
146 Target
-= PagesPerSegment
;
148 ExAcquireFastMutex(&ViewLock
);
149 current_entry
= DirtySegmentListHead
.Flink
;
151 ExReleaseFastMutex(&ViewLock
);
152 DPRINT("CcRosTrimCache() finished\n");
153 return(STATUS_SUCCESS
);
157 CcRosTrimCache(ULONG Target
, ULONG Priority
, PULONG NrFreed
)
159 * FUNCTION: Try to free some memory from the file cache.
161 * Target - The number of pages to be freed.
162 * Priority - The priority of free (currently unused).
163 * NrFreed - Points to a variable where the number of pages
164 * actually freed is returned.
167 PLIST_ENTRY current_entry
;
168 PCACHE_SEGMENT current
;
169 ULONG PagesPerSegment
;
174 DPRINT("CcRosTrimCache(Target %d)\n", Target
);
178 InitializeListHead(&FreeList
);
180 ExAcquireFastMutex(&ViewLock
);
181 current_entry
= CacheSegmentLRUListHead
.Flink
;
182 while (current_entry
!= &CacheSegmentLRUListHead
&& Target
> 0)
184 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
185 CacheSegmentLRUListEntry
);
186 current_entry
= current_entry
->Flink
;
188 KeAcquireSpinLock(¤t
->Bcb
->BcbLock
, &oldIrql
);
189 if (current
->ReferenceCount
== 0)
191 RemoveEntryList(¤t
->BcbSegmentListEntry
);
192 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
193 RemoveEntryList(¤t
->CacheSegmentListEntry
);
194 RemoveEntryList(¤t
->CacheSegmentLRUListEntry
);
195 InsertHeadList(&FreeList
, ¤t
->BcbSegmentListEntry
);
199 KeReleaseSpinLock(¤t
->Bcb
->BcbLock
, oldIrql
);
202 ExReleaseFastMutex(&ViewLock
);
204 while (!IsListEmpty(&FreeList
))
206 current_entry
= RemoveHeadList(&FreeList
);
207 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
208 BcbSegmentListEntry
);
209 PagesPerSegment
= current
->Bcb
->CacheSegmentSize
/ PAGE_SIZE
;
210 PagesFreed
= min(PagesPerSegment
, Target
);
211 Target
-= PagesFreed
;
212 (*NrFreed
) += PagesFreed
;
213 CcRosInternalFreeCacheSegment(current
);
216 DPRINT("CcRosTrimCache() finished\n");
217 return(STATUS_SUCCESS
);
221 CcRosReleaseCacheSegment(PBCB Bcb
,
222 PCACHE_SEGMENT CacheSeg
,
227 BOOLEAN WasDirty
= CacheSeg
->Dirty
;
230 DPRINT("CcReleaseCacheSegment(Bcb %x, CacheSeg %x, Valid %d)\n",
231 Bcb
, CacheSeg
, Valid
);
233 CacheSeg
->Valid
= Valid
;
234 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| Dirty
;
236 ExAcquireFastMutex(&ViewLock
);
237 if (!WasDirty
&& CacheSeg
->Dirty
)
239 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
241 RemoveEntryList(&CacheSeg
->CacheSegmentLRUListEntry
);
242 InsertTailList(&CacheSegmentLRUListHead
, &CacheSeg
->CacheSegmentLRUListEntry
);
246 CacheSeg
->MappedCount
++;
248 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
249 CacheSeg
->ReferenceCount
--;
250 if (Mapped
&& CacheSeg
->MappedCount
== 1)
252 CacheSeg
->ReferenceCount
++;
254 if (!WasDirty
&& CacheSeg
->Dirty
)
256 CacheSeg
->ReferenceCount
++;
258 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
259 ExReleaseFastMutex(&ViewLock
);
260 ExReleaseFastMutex(&CacheSeg
->Lock
);
262 return(STATUS_SUCCESS
);
265 PCACHE_SEGMENT
CcRosLookupCacheSegment(PBCB Bcb
, ULONG FileOffset
)
267 PLIST_ENTRY current_entry
;
268 PCACHE_SEGMENT current
;
271 DPRINT("CcRosLookupCacheSegment(Bcb %x, FileOffset %d)\n", Bcb
, FileOffset
);
273 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
274 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
275 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
277 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
278 BcbSegmentListEntry
);
279 if (current
->FileOffset
<= FileOffset
&&
280 (current
->FileOffset
+ Bcb
->CacheSegmentSize
) > FileOffset
)
282 current
->ReferenceCount
++;
283 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
286 current_entry
= current_entry
->Flink
;
288 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
293 CcRosMarkDirtyCacheSegment(PBCB Bcb
, ULONG FileOffset
)
295 PCACHE_SEGMENT CacheSeg
;
298 DPRINT("CcRosMarkDirtyCacheSegment(Bcb %x, FileOffset %d)\n", Bcb
, FileOffset
);
300 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
301 if (CacheSeg
== NULL
)
305 ExAcquireFastMutex(&CacheSeg
->Lock
);
306 if (!CacheSeg
->Dirty
)
308 ExAcquireFastMutex(&ViewLock
);
309 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
310 ExReleaseFastMutex(&ViewLock
);
314 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
315 CacheSeg
->ReferenceCount
--;
316 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
320 CacheSeg
->Dirty
= TRUE
;
321 ExReleaseFastMutex(&CacheSeg
->Lock
);
323 return(STATUS_SUCCESS
);
327 CcRosUnmapCacheSegment(PBCB Bcb
, ULONG FileOffset
, BOOLEAN NowDirty
)
329 PCACHE_SEGMENT CacheSeg
;
333 DPRINT("CcRosUnmapCacheSegment(Bcb %x, FileOffset %d, NowDirty %d)\n",
334 Bcb
, FileOffset
, NowDirty
);
336 CacheSeg
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
337 if (CacheSeg
== NULL
)
339 return(STATUS_UNSUCCESSFUL
);
341 ExAcquireFastMutex(&CacheSeg
->Lock
);
343 WasDirty
= CacheSeg
->Dirty
;
344 CacheSeg
->Dirty
= CacheSeg
->Dirty
|| NowDirty
;
346 CacheSeg
->MappedCount
--;
348 if (!WasDirty
&& NowDirty
)
350 ExAcquireFastMutex(&ViewLock
);
351 InsertTailList(&DirtySegmentListHead
, &CacheSeg
->DirtySegmentListEntry
);
352 ExReleaseFastMutex(&ViewLock
);
355 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
356 CacheSeg
->ReferenceCount
--;
357 if (!WasDirty
&& NowDirty
)
359 CacheSeg
->ReferenceCount
++;
361 if (CacheSeg
->MappedCount
== 0)
363 CacheSeg
->ReferenceCount
--;
365 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
367 ExReleaseFastMutex(&CacheSeg
->Lock
);
368 return(STATUS_SUCCESS
);
372 CcRosCreateCacheSegment(PBCB Bcb
,
374 PCACHE_SEGMENT
* CacheSeg
,
378 PCACHE_SEGMENT current
;
379 PLIST_ENTRY current_entry
;
383 DPRINT("CcRosCreateCacheSegment()\n");
385 current
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(CACHE_SEGMENT
),
387 current
->Valid
= FALSE
;
388 current
->Dirty
= FALSE
;
389 current
->FileOffset
= ROUND_DOWN(FileOffset
, Bcb
->CacheSegmentSize
);
391 current
->MappedCount
= 0;
392 current
->DirtySegmentListEntry
.Flink
= NULL
;
393 current
->DirtySegmentListEntry
.Blink
= NULL
;
394 current
->ReferenceCount
= 1;
395 ExInitializeFastMutex(¤t
->Lock
);
396 ExAcquireFastMutex(¤t
->Lock
);
397 ExAcquireFastMutex(&ViewLock
);
400 /* There is window between the call to CcRosLookupCacheSegment
401 * and CcRosCreateCacheSegment. We must check if a segment on
402 * the fileoffset exist. If there exist a segment, we release
403 * our new created segment and return the existing one.
405 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
406 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
407 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
409 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
410 BcbSegmentListEntry
);
411 if (current
->FileOffset
<= FileOffset
&&
412 (current
->FileOffset
+ Bcb
->CacheSegmentSize
) > FileOffset
)
414 current
->ReferenceCount
++;
415 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
416 ExReleaseFastMutex(&(*CacheSeg
)->Lock
);
417 ExReleaseFastMutex(&ViewLock
);
418 ExFreePool(*CacheSeg
);
422 ExAcquireFastMutex(¤t
->Lock
);
424 return STATUS_SUCCESS
;
426 current_entry
= current_entry
->Flink
;
428 /* There was no existing segment. */
430 InsertTailList(&Bcb
->BcbSegmentListHead
, ¤t
->BcbSegmentListEntry
);
431 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
432 InsertTailList(&CacheSegmentListHead
, ¤t
->CacheSegmentListEntry
);
433 InsertTailList(&CacheSegmentLRUListHead
, ¤t
->CacheSegmentLRUListEntry
);
434 ExReleaseFastMutex(&ViewLock
);
436 MmLockAddressSpace(MmGetKernelAddressSpace());
437 current
->BaseAddress
= NULL
;
438 Status
= MmCreateMemoryArea(NULL
,
439 MmGetKernelAddressSpace(),
440 MEMORY_AREA_CACHE_SEGMENT
,
441 ¤t
->BaseAddress
,
442 Bcb
->CacheSegmentSize
,
444 (PMEMORY_AREA
*)¤t
->MemoryArea
,
446 MmUnlockAddressSpace(MmGetKernelAddressSpace());
447 if (!NT_SUCCESS(Status
))
451 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++)
453 PHYSICAL_ADDRESS Page
;
455 Status
= MmRequestPageMemoryConsumer(MC_CACHE
, TRUE
, &Page
);
456 if (!NT_SUCCESS(Status
))
461 Status
= MmCreateVirtualMapping(NULL
,
462 current
->BaseAddress
+ (i
* PAGE_SIZE
),
466 if (!NT_SUCCESS(Status
))
473 ExReleaseFastMutex(¤t
->Lock
);
476 return(STATUS_SUCCESS
);
480 CcRosGetCacheSegmentChain(PBCB Bcb
,
483 PCACHE_SEGMENT
* CacheSeg
)
485 PCACHE_SEGMENT current
;
487 PCACHE_SEGMENT
* CacheSegList
;
488 PCACHE_SEGMENT Previous
= NULL
;
490 DPRINT("CcRosGetCacheSegmentChain()\n");
492 Length
= ROUND_UP(Length
, Bcb
->CacheSegmentSize
);
494 CacheSegList
= alloca(sizeof(PCACHE_SEGMENT
) *
495 (Length
/ Bcb
->CacheSegmentSize
));
498 * Look for a cache segment already mapping the same data.
500 for (i
= 0; i
< (Length
/ Bcb
->CacheSegmentSize
); i
++)
502 ULONG CurrentOffset
= FileOffset
+ (i
* Bcb
->CacheSegmentSize
);
503 current
= CcRosLookupCacheSegment(Bcb
, CurrentOffset
);
506 CacheSegList
[i
] = current
;
510 CcRosCreateCacheSegment(Bcb
, CurrentOffset
, ¤t
, FALSE
);
511 CacheSegList
[i
] = current
;
515 for (i
= 0; i
< (Length
/ Bcb
->CacheSegmentSize
); i
++)
517 ExAcquireFastMutex(&CacheSegList
[i
]->Lock
);
520 *CacheSeg
= CacheSegList
[i
];
521 Previous
= CacheSegList
[i
];
525 Previous
->NextInChain
= CacheSegList
[i
];
526 Previous
= CacheSegList
[i
];
529 Previous
->NextInChain
= NULL
;
531 return(STATUS_SUCCESS
);
535 CcRosGetCacheSegment(PBCB Bcb
,
540 PCACHE_SEGMENT
* CacheSeg
)
542 PCACHE_SEGMENT current
;
545 DPRINT("CcRosGetCacheSegment()\n");
548 * Look for a cache segment already mapping the same data.
550 current
= CcRosLookupCacheSegment(Bcb
, FileOffset
);
553 ExAcquireFastMutex(¤t
->Lock
);
558 * Otherwise create a new segment.
560 Status
= CcRosCreateCacheSegment(Bcb
, FileOffset
, ¤t
, TRUE
);
563 * Return information about the segment to the caller.
565 *UptoDate
= current
->Valid
;
566 *BaseAddress
= current
->BaseAddress
;
567 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress
);
569 *BaseOffset
= current
->FileOffset
;
570 return(STATUS_SUCCESS
);
574 CcRosRequestCacheSegment(PBCB Bcb
,
578 PCACHE_SEGMENT
* CacheSeg
)
580 * FUNCTION: Request a page mapping for a BCB
585 if ((FileOffset
% Bcb
->CacheSegmentSize
) != 0)
587 CPRINT("Bad fileoffset %x should be multiple of %x",
588 FileOffset
, Bcb
->CacheSegmentSize
);
592 return(CcRosGetCacheSegment(Bcb
,
601 CcFreeCachePage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
602 PHYSICAL_ADDRESS PhysAddr
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
604 assert(SwapEntry
== 0);
605 if (PhysAddr
.QuadPart
!= 0)
607 MmReleasePageMemoryConsumer(MC_CACHE
, PhysAddr
);
612 CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg
)
614 * FUNCTION: Releases a cache segment associated with a BCB
618 DPRINT("Freeing cache segment %x\n", CacheSeg
);
620 MmLockAddressSpace(MmGetKernelAddressSpace());
621 MmFreeMemoryArea(MmGetKernelAddressSpace(),
622 CacheSeg
->BaseAddress
,
623 CacheSeg
->Bcb
->CacheSegmentSize
,
626 MmUnlockAddressSpace(MmGetKernelAddressSpace());
627 ExFreePool(CacheSeg
);
628 return(STATUS_SUCCESS
);
632 CcRosFreeCacheSegment(PBCB Bcb
, PCACHE_SEGMENT CacheSeg
)
637 DPRINT("CcRosFreeCacheSegment(Bcb %x, CacheSeg %x)\n",
640 ExAcquireFastMutex(&ViewLock
);
641 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
642 RemoveEntryList(&CacheSeg
->BcbSegmentListEntry
);
643 RemoveEntryList(&CacheSeg
->CacheSegmentListEntry
);
644 RemoveEntryList(&CacheSeg
->CacheSegmentLRUListEntry
);
647 RemoveEntryList(&CacheSeg
->DirtySegmentListEntry
);
649 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
650 ExReleaseFastMutex(&ViewLock
);
652 Status
= CcRosInternalFreeCacheSegment(CacheSeg
);
657 CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointers
,
658 IN PLARGE_INTEGER FileOffset OPTIONAL
,
660 OUT PIO_STATUS_BLOCK IoStatus
)
663 LARGE_INTEGER Offset
;
664 PCACHE_SEGMENT current
;
668 DPRINT("CcFlushCache(SectionObjectPointers %x, FileOffset %x, Length %d, IoStatus %x)\n",
669 SectionObjectPointers
, FileOffset
, Length
, IoStatus
);
671 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
673 Bcb
= (PBCB
)SectionObjectPointers
->SharedCacheMap
;
676 Offset
= *FileOffset
;
680 Offset
.QuadPart
= 0LL;
681 Length
= Bcb
->FileSize
.u
.LowPart
;
686 IoStatus
->Status
= STATUS_SUCCESS
;
687 IoStatus
->Information
= 0;
692 current
= CcRosLookupCacheSegment (Bcb
, Offset
.u
.LowPart
);
695 ExAcquireFastMutex(¤t
->Lock
);
698 Status
= CcRosFlushCacheSegment(current
);
699 if (!NT_SUCCESS(Status
) && IoStatus
!= NULL
)
701 IoStatus
->Status
= Status
;
704 ExReleaseFastMutex(¤t
->Lock
);
705 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
706 current
->ReferenceCount
--;
707 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
710 Offset
.QuadPart
+= Bcb
->CacheSegmentSize
;
711 if (Length
> Bcb
->CacheSegmentSize
)
713 Length
-= Bcb
->CacheSegmentSize
;
725 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
731 CcRosDeleteFileCache(PFILE_OBJECT FileObject
, PBCB Bcb
)
733 * FUNCTION: Releases the BCB associated with a file object
736 PLIST_ENTRY current_entry
;
737 PCACHE_SEGMENT current
;
742 DPRINT("CcRosDeleteFileCache(FileObject %x, Bcb %x)\n",
743 Bcb
->FileObject
, Bcb
);
745 ExReleaseFastMutex(&ViewLock
);
747 CcFlushCache(FileObject
->SectionObjectPointers
, NULL
, 0, NULL
);
749 ExAcquireFastMutex(&ViewLock
);
751 if (Bcb
->RefCount
== 0)
753 MmFreeSectionSegments(Bcb
->FileObject
);
756 * Release all cache segments.
758 InitializeListHead(&FreeList
);
760 FileObject
->SectionObjectPointers
->SharedCacheMap
= NULL
;
761 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldIrql
);
762 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
763 while (!IsListEmpty(&Bcb
->BcbSegmentListHead
))
765 current_entry
= RemoveTailList(&Bcb
->BcbSegmentListHead
);
766 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
767 RemoveEntryList(¤t
->CacheSegmentListEntry
);
768 RemoveEntryList(¤t
->CacheSegmentLRUListEntry
);
771 RemoveEntryList(¤t
->DirtySegmentListEntry
);
773 InsertHeadList(&FreeList
, ¤t
->BcbSegmentListEntry
);
776 KeReleaseSpinLock(&Bcb
->BcbLock
, oldIrql
);
777 while (!IsListEmpty(&FreeList
))
779 current_entry
= RemoveTailList(&FreeList
);
780 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
, BcbSegmentListEntry
);
781 Status
= CcRosInternalFreeCacheSegment(current
);
784 ObDereferenceObject (Bcb
->FileObject
);
787 return(STATUS_SUCCESS
);
790 VOID
CcRosReferenceCache(PFILE_OBJECT FileObject
)
793 ExAcquireFastMutex(&ViewLock
);
794 Bcb
= (PBCB
)FileObject
->SectionObjectPointers
->SharedCacheMap
;
796 ExReleaseFastMutex(&ViewLock
);
799 VOID
CcRosDereferenceCache(PFILE_OBJECT FileObject
)
802 ExAcquireFastMutex(&ViewLock
);
803 Bcb
= (PBCB
)FileObject
->SectionObjectPointers
->SharedCacheMap
;
805 if (Bcb
->RefCount
== 0)
807 CcRosDeleteFileCache(FileObject
, Bcb
);
809 ExReleaseFastMutex(&ViewLock
);
813 CcRosReleaseFileCache(PFILE_OBJECT FileObject
, PBCB Bcb
)
815 * FUNCTION: Called by the file system when a handle to a file object
819 ExAcquireFastMutex(&ViewLock
);
821 if (FileObject
->SectionObjectPointers
->SharedCacheMap
!= NULL
)
823 if (FileObject
->PrivateCacheMap
!= NULL
)
825 FileObject
->PrivateCacheMap
= NULL
;
828 if (Bcb
->RefCount
== 0)
830 CcRosDeleteFileCache(FileObject
, Bcb
);
833 ExReleaseFastMutex(&ViewLock
);
834 return(STATUS_SUCCESS
);
838 CcRosInitializeFileCache(PFILE_OBJECT FileObject
,
840 ULONG CacheSegmentSize
)
842 * FUNCTION: Initializes a BCB for a file object
845 DPRINT("CcRosInitializeFileCache(FileObject %x, *Bcb %x, CacheSegmentSize %d)\n",
846 FileObject
, Bcb
, CacheSegmentSize
);
848 ExAcquireFastMutex(&ViewLock
);
852 (*Bcb
) = ExAllocatePoolWithTag(NonPagedPool
, sizeof(BCB
), TAG_BCB
);
855 return(STATUS_UNSUCCESSFUL
);
858 ObReferenceObjectByPointer(FileObject
,
862 (*Bcb
)->FileObject
= FileObject
;
863 (*Bcb
)->CacheSegmentSize
= CacheSegmentSize
;
864 if (FileObject
->FsContext
)
866 (*Bcb
)->AllocationSize
=
867 ((REACTOS_COMMON_FCB_HEADER
*)FileObject
->FsContext
)->AllocationSize
;
869 ((REACTOS_COMMON_FCB_HEADER
*)FileObject
->FsContext
)->FileSize
;
871 KeInitializeSpinLock(&(*Bcb
)->BcbLock
);
872 InitializeListHead(&(*Bcb
)->BcbSegmentListHead
);
873 FileObject
->SectionObjectPointers
->SharedCacheMap
= *Bcb
;
875 if (FileObject
->PrivateCacheMap
== NULL
)
877 FileObject
->PrivateCacheMap
= *Bcb
;
880 ExReleaseFastMutex(&ViewLock
);
882 return(STATUS_SUCCESS
);
886 CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointers
)
889 if (SectionObjectPointers
&& SectionObjectPointers
->SharedCacheMap
)
891 Bcb
= (PBCB
)SectionObjectPointers
->SharedCacheMap
;
892 return Bcb
->FileObject
;
900 DPRINT("CcInitView()\n");
901 InitializeListHead(&CacheSegmentListHead
);
902 InitializeListHead(&DirtySegmentListHead
);
903 InitializeListHead(&CacheSegmentLRUListHead
);
904 ExInitializeFastMutex(&ViewLock
);
905 MmInitializeMemoryConsumer(MC_CACHE
, CcRosTrimCache
);
906 CcInitCacheZeroPage();