- Disabled write caching for meta data (FAT, directories) in
[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.47 2002/08/17 15:14:26 hbirr 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 NTSTATUS STDCALL
79 CcRosInternalFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg);
80
81 /* FUNCTIONS *****************************************************************/
82
83 NTSTATUS STATIC
84 CcRosFlushCacheSegment(PCACHE_SEGMENT CacheSegment)
85 {
86 NTSTATUS Status;
87 Status = WriteCacheSegment(CacheSegment);
88 if (NT_SUCCESS(Status))
89 {
90 CacheSegment->Dirty = FALSE;
91 RemoveEntryList(&CacheSegment->DirtySegmentListEntry);
92 }
93 return(Status);
94 }
95
96 NTSTATUS
97 CcRosFlushDirtyPages(ULONG Target, PULONG Count)
98 {
99 PLIST_ENTRY current_entry;
100 PCACHE_SEGMENT current;
101 ULONG PagesPerSegment;
102 BOOLEAN Locked;
103 NTSTATUS Status;
104
105 DPRINT("CcRosFlushDirtyPages(Target %d)\n", Target);
106
107 (*Count) = 0;
108
109 ExAcquireFastMutex(&ViewLock);
110 current_entry = DirtySegmentListHead.Flink;
111 while (current_entry != &DirtySegmentListHead && Target > 0)
112 {
113 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
114 DirtySegmentListEntry);
115 current_entry = current_entry->Flink;
116 Locked = ExTryToAcquireFastMutex(&current->Lock);
117 if (!Locked)
118 {
119 continue;
120 }
121 assert(current->Dirty);
122 if (current->ReferenceCount > 0)
123 {
124 ExReleaseFastMutex(&current->Lock);
125 continue;
126 }
127 current->ReferenceCount++;
128 ExReleaseFastMutex(&ViewLock);
129 PagesPerSegment = current->Bcb->CacheSegmentSize / PAGESIZE;
130 Status = CcRosFlushCacheSegment(current);
131 current->ReferenceCount--;
132 ExReleaseFastMutex(&current->Lock);
133 if (!NT_SUCCESS(Status))
134 {
135 DPRINT1("CC: Failed to flush cache segment.\n");
136 }
137 (*Count) += PagesPerSegment;
138 Target -= PagesPerSegment;
139
140 ExAcquireFastMutex(&ViewLock);
141 current_entry = DirtySegmentListHead.Flink;
142 }
143 ExReleaseFastMutex(&ViewLock);
144 DPRINT("CcRosTrimCache() finished\n");
145 return(STATUS_SUCCESS);
146 }
147
148 NTSTATUS
149 CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
150 /*
151 * FUNCTION: Try to free some memory from the file cache.
152 * ARGUMENTS:
153 * Target - The number of pages to be freed.
154 * Priority - The priority of free (currently unused).
155 * NrFreed - Points to a variable where the number of pages
156 * actually freed is returned.
157 */
158 {
159 PLIST_ENTRY current_entry;
160 PCACHE_SEGMENT current;
161 ULONG PagesPerSegment;
162 ULONG PagesFreed;
163 BOOLEAN Locked;
164
165 DPRINT("CcRosTrimCache(Target %d)\n", Target);
166
167 *NrFreed = 0;
168
169 ExAcquireFastMutex(&ViewLock);
170 current_entry = CacheSegmentLRUListHead.Flink;
171 while (current_entry != &CacheSegmentLRUListHead && Target > 0)
172 {
173 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
174 CacheSegmentLRUListEntry);
175 current_entry = current_entry->Flink;
176 Locked = ExTryToAcquireFastMutex(&current->Lock);
177 if (!Locked)
178 {
179 continue;
180 }
181 if (current->MappedCount > 0 || current->Dirty ||
182 current->ReferenceCount > 0)
183 {
184 ExReleaseFastMutex(&current->Lock);
185 continue;
186 }
187 ExReleaseFastMutex(&current->Lock);
188 DPRINT("current->Bcb->CacheSegmentSize %d\n",
189 current->Bcb->CacheSegmentSize);
190 PagesPerSegment = current->Bcb->CacheSegmentSize / PAGESIZE;
191 CcRosInternalFreeCacheSegment(current->Bcb, current);
192 DPRINT("CcRosTrimCache(): Freed %d\n", PagesPerSegment);
193 PagesFreed = min(PagesPerSegment, Target);
194 Target = Target - PagesFreed;
195 (*NrFreed) = (*NrFreed) + PagesFreed;
196 }
197 ExReleaseFastMutex(&ViewLock);
198 DPRINT("CcRosTrimCache() finished\n");
199 return(STATUS_SUCCESS);
200 }
201
202 NTSTATUS STDCALL
203 CcRosReleaseCacheSegment(PBCB Bcb,
204 PCACHE_SEGMENT CacheSeg,
205 BOOLEAN Valid,
206 BOOLEAN Dirty,
207 BOOLEAN Mapped)
208 {
209 BOOLEAN WasDirty = CacheSeg->Dirty;
210
211 DPRINT("CcReleaseCachePage(Bcb %x, CacheSeg %x, Valid %d)\n",
212 Bcb, CacheSeg, Valid);
213
214 CacheSeg->Valid = Valid;
215 CacheSeg->Dirty = CacheSeg->Dirty || Dirty;
216 if (Mapped)
217 {
218 CacheSeg->MappedCount++;
219 }
220 ExReleaseFastMutex(&CacheSeg->Lock);
221 ExAcquireFastMutex(&ViewLock);
222 if (!WasDirty && CacheSeg->Dirty)
223 {
224 InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
225 }
226 RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
227 InsertTailList(&CacheSegmentLRUListHead,
228 &CacheSeg->CacheSegmentLRUListEntry);
229 ExReleaseFastMutex(&ViewLock);
230 InterlockedDecrement(&CacheSeg->ReferenceCount);
231
232 DPRINT("CcReleaseCachePage() finished\n");
233
234 return(STATUS_SUCCESS);
235 }
236
237 PCACHE_SEGMENT CcRosLookupCacheSegment(PBCB Bcb, ULONG FileOffset)
238 {
239 PLIST_ENTRY current_entry;
240 PCACHE_SEGMENT current;
241 KIRQL oldIrql;
242
243 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
244 current_entry = Bcb->BcbSegmentListHead.Flink;
245 while (current_entry != &Bcb->BcbSegmentListHead)
246 {
247 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
248 BcbSegmentListEntry);
249 if (current->FileOffset <= FileOffset &&
250 (current->FileOffset + Bcb->CacheSegmentSize) > FileOffset)
251 {
252 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
253 return(current);
254 }
255 current_entry = current_entry->Flink;
256 }
257 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
258 return(NULL);
259 }
260
261 NTSTATUS
262 CcRosMarkDirtyCacheSegment(PBCB Bcb, ULONG FileOffset)
263 {
264 PCACHE_SEGMENT CacheSeg;
265
266 ExAcquireFastMutex(&ViewLock);
267 CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
268 if (CacheSeg == NULL)
269 {
270 KeBugCheck(0);
271 }
272 ExAcquireFastMutex(&CacheSeg->Lock);
273 if (!CacheSeg->Dirty)
274 {
275 InsertTailList(&DirtySegmentListHead, &CacheSeg->DirtySegmentListEntry);
276 }
277 CacheSeg->Dirty = TRUE;
278 ExReleaseFastMutex(&CacheSeg->Lock);
279 ExReleaseFastMutex(&ViewLock);
280 return(STATUS_SUCCESS);
281 }
282
283 NTSTATUS
284 CcRosSuggestFreeCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty)
285 {
286 PCACHE_SEGMENT CacheSeg;
287
288 ExAcquireFastMutex(&ViewLock);
289 CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
290 if (CacheSeg == NULL)
291 {
292 KeBugCheck(0);
293 }
294 ExAcquireFastMutex(&CacheSeg->Lock);
295 if (CacheSeg->MappedCount > 0)
296 {
297 KeBugCheck(0);
298 }
299 CacheSeg->Dirty = CacheSeg->Dirty || NowDirty;
300 if (CacheSeg->Dirty || CacheSeg->ReferenceCount > 0)
301 {
302 ExReleaseFastMutex(&CacheSeg->Lock);
303 ExReleaseFastMutex(&ViewLock);
304 return(STATUS_UNSUCCESSFUL);
305 }
306 ExReleaseFastMutex(&CacheSeg->Lock);
307 CcRosInternalFreeCacheSegment(CacheSeg->Bcb, CacheSeg);
308 ExReleaseFastMutex(&ViewLock);
309 return(STATUS_SUCCESS);
310 }
311
312 NTSTATUS
313 CcRosUnmapCacheSegment(PBCB Bcb, ULONG FileOffset, BOOLEAN NowDirty)
314 {
315 PCACHE_SEGMENT CacheSeg;
316
317 ExAcquireFastMutex(&ViewLock);
318 CacheSeg = CcRosLookupCacheSegment(Bcb, FileOffset);
319 if (CacheSeg == NULL)
320 {
321 ExReleaseFastMutex(&ViewLock);
322 return(STATUS_UNSUCCESSFUL);
323 }
324 CacheSeg->ReferenceCount++;
325 ExReleaseFastMutex(&ViewLock);
326 ExAcquireFastMutex(&CacheSeg->Lock);
327 CacheSeg->MappedCount--;
328 CacheSeg->Dirty = CacheSeg->Dirty || NowDirty;
329 CacheSeg->ReferenceCount--;
330 ExReleaseFastMutex(&CacheSeg->Lock);
331 return(STATUS_SUCCESS);
332 }
333
334 NTSTATUS STATIC
335 CcRosCreateCacheSegment(PBCB Bcb,
336 ULONG FileOffset,
337 PCACHE_SEGMENT* CacheSeg,
338 BOOLEAN Lock)
339 {
340 ULONG i;
341 PCACHE_SEGMENT current;
342 NTSTATUS Status;
343 KIRQL oldIrql;
344
345 current = ExAllocatePoolWithTag(NonPagedPool, sizeof(CACHE_SEGMENT),
346 TAG_CSEG);
347
348 MmLockAddressSpace(MmGetKernelAddressSpace());
349 current->BaseAddress = NULL;
350 Status = MmCreateMemoryArea(KernelMode,
351 MmGetKernelAddressSpace(),
352 MEMORY_AREA_CACHE_SEGMENT,
353 &current->BaseAddress,
354 Bcb->CacheSegmentSize,
355 PAGE_READWRITE,
356 (PMEMORY_AREA*)&current->MemoryArea,
357 FALSE);
358 if (!NT_SUCCESS(Status))
359 {
360 MmUnlockAddressSpace(MmGetKernelAddressSpace());
361 KeBugCheck(0);
362 }
363 MmUnlockAddressSpace(MmGetKernelAddressSpace());
364 current->Valid = FALSE;
365 current->Dirty = FALSE;
366 current->FileOffset = ROUND_DOWN(FileOffset, Bcb->CacheSegmentSize);
367 current->Bcb = Bcb;
368 current->MappedCount = 0;
369 ExInitializeFastMutex(&current->Lock);
370 current->ReferenceCount = 1;
371 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
372 InsertTailList(&Bcb->BcbSegmentListHead, &current->BcbSegmentListEntry);
373 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
374 InsertTailList(&CacheSegmentListHead, &current->CacheSegmentListEntry);
375 InsertTailList(&CacheSegmentLRUListHead,
376 &current->CacheSegmentLRUListEntry);
377 current->DirtySegmentListEntry.Flink =
378 current->DirtySegmentListEntry.Blink = NULL;
379 if (Lock)
380 {
381 ExAcquireFastMutex(&current->Lock);
382 }
383 ExReleaseFastMutex(&ViewLock);
384 for (i = 0; i < (Bcb->CacheSegmentSize / PAGESIZE); i++)
385 {
386 PHYSICAL_ADDRESS Page;
387
388 Status = MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page);
389 if (!NT_SUCCESS(Status))
390 {
391 KeBugCheck(0);
392 }
393
394 Status = MmCreateVirtualMapping(NULL,
395 current->BaseAddress + (i * PAGESIZE),
396 PAGE_READWRITE,
397 Page,
398 TRUE);
399 if (!NT_SUCCESS(Status))
400 {
401 KeBugCheck(0);
402 }
403 }
404 *CacheSeg = current;
405 return(STATUS_SUCCESS);
406 }
407
408 NTSTATUS
409 CcRosGetCacheSegmentChain(PBCB Bcb,
410 ULONG FileOffset,
411 ULONG Length,
412 PCACHE_SEGMENT* CacheSeg)
413 {
414 PCACHE_SEGMENT current;
415 ULONG i;
416 PCACHE_SEGMENT* CacheSegList;
417 PCACHE_SEGMENT Previous;
418
419 Length = ROUND_UP(Length, Bcb->CacheSegmentSize);
420
421 CacheSegList = alloca(sizeof(PCACHE_SEGMENT) *
422 (Length / Bcb->CacheSegmentSize));
423
424 /*
425 * Acquire the global lock.
426 */
427 ExAcquireFastMutex(&ViewLock);
428
429 /*
430 * Look for a cache segment already mapping the same data.
431 */
432 for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++)
433 {
434 ULONG CurrentOffset = FileOffset + (i * Bcb->CacheSegmentSize);
435 current = CcRosLookupCacheSegment(Bcb, CurrentOffset);
436 if (current != NULL)
437 {
438 /*
439 * Make sure the cache segment can't go away outside of our control.
440 */
441 current->ReferenceCount++;
442 CacheSegList[i] = current;
443 }
444 else
445 {
446 CcRosCreateCacheSegment(Bcb, CurrentOffset, &current, FALSE);
447 CacheSegList[i] = current;
448 ExAcquireFastMutex(&ViewLock);
449 }
450 }
451 ExReleaseFastMutex(&ViewLock);
452
453 for (i = 0; i < (Length / Bcb->CacheSegmentSize); i++)
454 {
455 ExAcquireFastMutex(&CacheSegList[i]->Lock);
456 if (i == 0)
457 {
458 *CacheSeg = CacheSegList[i];
459 Previous = CacheSegList[i];
460 }
461 else
462 {
463 Previous->NextInChain = CacheSegList[i];
464 Previous = CacheSegList[i];
465 }
466 }
467 Previous->NextInChain = NULL;
468
469 return(STATUS_SUCCESS);
470 }
471
472 NTSTATUS
473 CcRosGetCacheSegment(PBCB Bcb,
474 ULONG FileOffset,
475 PULONG BaseOffset,
476 PVOID* BaseAddress,
477 PBOOLEAN UptoDate,
478 PCACHE_SEGMENT* CacheSeg)
479 {
480 PCACHE_SEGMENT current;
481 NTSTATUS Status;
482
483 /*
484 * Acquire the global lock.
485 */
486 ExAcquireFastMutex(&ViewLock);
487
488 /*
489 * Look for a cache segment already mapping the same data.
490 */
491 current = CcRosLookupCacheSegment(Bcb, FileOffset);
492 if (current != NULL)
493 {
494 /*
495 * Make sure the cache segment can't go away outside of our control.
496 */
497 current->ReferenceCount++;
498 /*
499 * Release the global lock and lock the cache segment.
500 */
501 ExReleaseFastMutex(&ViewLock);
502 ExAcquireFastMutex(&current->Lock);
503 /*
504 * Return information about the segment to the caller.
505 */
506 *UptoDate = current->Valid;
507 *BaseAddress = current->BaseAddress;
508 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress);
509 *CacheSeg = current;
510 *BaseOffset = current->FileOffset;
511 return(STATUS_SUCCESS);
512 }
513
514 /*
515 * Otherwise create a new segment.
516 */
517 Status = CcRosCreateCacheSegment(Bcb, FileOffset, &current, TRUE);
518 *UptoDate = current->Valid;
519 *BaseAddress = current->BaseAddress;
520 DPRINT("*BaseAddress 0x%.8X\n", *BaseAddress);
521 *CacheSeg = current;
522 *BaseOffset = current->FileOffset;
523
524 return(STATUS_SUCCESS);
525 }
526
527 NTSTATUS STDCALL
528 CcRosRequestCacheSegment(PBCB Bcb,
529 ULONG FileOffset,
530 PVOID* BaseAddress,
531 PBOOLEAN UptoDate,
532 PCACHE_SEGMENT* CacheSeg)
533 /*
534 * FUNCTION: Request a page mapping for a BCB
535 */
536 {
537 ULONG BaseOffset;
538
539 if ((FileOffset % Bcb->CacheSegmentSize) != 0)
540 {
541 CPRINT("Bad fileoffset %x should be multiple of %x",
542 FileOffset, Bcb->CacheSegmentSize);
543 KeBugCheck(0);
544 }
545
546 return(CcRosGetCacheSegment(Bcb,
547 FileOffset,
548 &BaseOffset,
549 BaseAddress,
550 UptoDate,
551 CacheSeg));
552 }
553
554 STATIC VOID
555 CcFreeCachePage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
556 PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry, BOOLEAN Dirty)
557 {
558 assert(SwapEntry == 0);
559 if (PhysAddr.QuadPart != 0)
560 {
561 MmReleasePageMemoryConsumer(MC_CACHE, PhysAddr);
562 }
563 }
564
565 NTSTATUS STDCALL
566 CcRosInternalFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg)
567 /*
568 * FUNCTION: Releases a cache segment associated with a BCB
569 */
570 {
571 DPRINT("Freeing cache segment %x\n", CacheSeg);
572 RemoveEntryList(&CacheSeg->CacheSegmentListEntry);
573 RemoveEntryList(&CacheSeg->CacheSegmentLRUListEntry);
574 RemoveEntryList(&CacheSeg->BcbSegmentListEntry);
575 MmLockAddressSpace(MmGetKernelAddressSpace());
576 MmFreeMemoryArea(MmGetKernelAddressSpace(),
577 CacheSeg->BaseAddress,
578 Bcb->CacheSegmentSize,
579 CcFreeCachePage,
580 NULL);
581 MmUnlockAddressSpace(MmGetKernelAddressSpace());
582 ExFreePool(CacheSeg);
583 return(STATUS_SUCCESS);
584 }
585
586 NTSTATUS STDCALL
587 CcRosFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg)
588 {
589 NTSTATUS Status;
590 ExAcquireFastMutex(&ViewLock);
591 Status = CcRosInternalFreeCacheSegment(Bcb, CacheSeg);
592 ExReleaseFastMutex(&ViewLock);
593 return(Status);
594 }
595
596 NTSTATUS STDCALL
597 CcRosDeleteFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
598 /*
599 * FUNCTION: Releases the BCB associated with a file object
600 */
601 {
602 PLIST_ENTRY current_entry;
603 PCACHE_SEGMENT current;
604 NTSTATUS Status;
605
606 DPRINT("CcRosDeleteFileCache(FileObject %x, Bcb %x)\n", Bcb->FileObject,
607 Bcb);
608
609 MmFreeSectionSegments(Bcb->FileObject);
610
611 /*
612 * Write back dirty cache segments.
613 */
614 current_entry = Bcb->BcbSegmentListHead.Flink;
615 while (current_entry != &Bcb->BcbSegmentListHead)
616 {
617 current =
618 CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
619 if (current->Dirty)
620 {
621 Status = WriteCacheSegment(current);
622 if (!NT_SUCCESS(Status))
623 {
624 DPRINT1("Failed to write cache segment (Status %X)\n", Status);
625 }
626 ExAcquireFastMutex(&ViewLock);
627 RemoveEntryList(&current->DirtySegmentListEntry);
628 ExReleaseFastMutex(&ViewLock);
629 }
630 current_entry = current_entry->Flink;
631 }
632
633 /*
634 * Release all cache segments.
635 */
636 current_entry = Bcb->BcbSegmentListHead.Flink;
637 while (current_entry != &Bcb->BcbSegmentListHead)
638 {
639 current =
640 CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
641 current_entry = current_entry->Flink;
642 CcRosFreeCacheSegment(Bcb, current);
643 }
644 FileObject->SectionObjectPointers->SharedCacheMap = NULL;
645 ObDereferenceObject (Bcb->FileObject);
646 ExFreePool(Bcb);
647
648 return(STATUS_SUCCESS);
649 }
650
651 VOID CcRosReferenceCache(PFILE_OBJECT FileObject)
652 {
653 KIRQL oldIrql;
654 PBCB Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap;
655 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
656 Bcb->RefCount++;
657 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
658 }
659
660 VOID CcRosDereferenceCache(PFILE_OBJECT FileObject)
661 {
662 KIRQL oldIrql;
663 PBCB Bcb = (PBCB)FileObject->SectionObjectPointers->SharedCacheMap;
664 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
665 Bcb->RefCount--;
666 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
667 if (Bcb->RefCount == 0)
668 {
669 CcRosDeleteFileCache(FileObject, Bcb);
670 }
671 }
672
673 NTSTATUS STDCALL
674 CcRosReleaseFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
675 /*
676 * FUNCTION: Called by the file system when a handle to a file object
677 * has been closed.
678 */
679 {
680 KIRQL oldIrql;
681 if (FileObject->SectionObjectPointers->SharedCacheMap != NULL)
682 {
683 KeAcquireSpinLock(&Bcb->BcbLock, &oldIrql);
684 if (FileObject->PrivateCacheMap != NULL)
685 {
686 FileObject->PrivateCacheMap = NULL;
687 Bcb->RefCount--;
688 }
689 KeReleaseSpinLock(&Bcb->BcbLock, oldIrql);
690 if (Bcb->RefCount == 0)
691 {
692 CcRosDeleteFileCache(FileObject, Bcb);
693 }
694 }
695 return(STATUS_SUCCESS);
696 }
697
698 NTSTATUS STDCALL
699 CcRosInitializeFileCache(PFILE_OBJECT FileObject,
700 PBCB* Bcb,
701 ULONG CacheSegmentSize)
702 /*
703 * FUNCTION: Initializes a BCB for a file object
704 */
705 {
706 KIRQL oldIrql;
707 if (*Bcb == NULL)
708 {
709 (*Bcb) = ExAllocatePoolWithTag(NonPagedPool, sizeof(BCB), TAG_BCB);
710 if ((*Bcb) == NULL)
711 {
712 return(STATUS_UNSUCCESSFUL);
713 }
714
715 ObReferenceObjectByPointer(FileObject,
716 FILE_ALL_ACCESS,
717 NULL,
718 KernelMode);
719 (*Bcb)->FileObject = FileObject;
720 (*Bcb)->CacheSegmentSize = CacheSegmentSize;
721 if (FileObject->FsContext)
722 {
723 (*Bcb)->AllocationSize =
724 ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->AllocationSize;
725 (*Bcb)->FileSize =
726 ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->FileSize;
727 }
728 KeInitializeSpinLock(&(*Bcb)->BcbLock);
729 InitializeListHead(&(*Bcb)->BcbSegmentListHead);
730 FileObject->SectionObjectPointers->SharedCacheMap = *Bcb;
731 }
732 KeAcquireSpinLock(&(*Bcb)->BcbLock, &oldIrql);
733 if (FileObject->PrivateCacheMap == NULL)
734 {
735 FileObject->PrivateCacheMap = *Bcb;
736 (*Bcb)->RefCount++;
737 }
738 KeReleaseSpinLock(&(*Bcb)->BcbLock, oldIrql);
739
740 return(STATUS_SUCCESS);
741 }
742
743 VOID
744 CcInitView(VOID)
745 {
746 DPRINT("CcInitView()\n");
747 InitializeListHead(&CacheSegmentListHead);
748 InitializeListHead(&DirtySegmentListHead);
749 InitializeListHead(&CacheSegmentLRUListHead);
750 ExInitializeFastMutex(&ViewLock);
751 MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache);
752 CcInitCacheZeroPage();
753 }
754
755 /* EOF */
756
757
758
759
760
761
762