xref: /reactos/ntoskrnl/cc/fs.c (revision b917d826)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/cc/fs.c
5  * PURPOSE:         Implements cache managers functions useful for File Systems
6  *
7  * PROGRAMMERS:     Alex Ionescu
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS   *****************************************************************/
17 
18 extern KGUARDED_MUTEX ViewLock;
19 
20 NTSTATUS CcRosInternalFreeVacb(PROS_VACB Vacb);
21 
22 /* FUNCTIONS *****************************************************************/
23 
24 /*
25  * @unimplemented
26  */
27 LARGE_INTEGER
28 NTAPI
29 CcGetDirtyPages (
30     IN PVOID LogHandle,
31     IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine,
32     IN PVOID Context1,
33     IN PVOID Context2)
34 {
35     LARGE_INTEGER i;
36 
37     CCTRACE(CC_API_DEBUG, "LogHandle=%p DirtyPageRoutine=%p Context1=%p Context2=%p\n",
38         LogHandle, DirtyPageRoutine, Context1, Context2);
39 
40     UNIMPLEMENTED;
41     i.QuadPart = 0;
42     return i;
43 }
44 
45 /*
46  * @implemented
47  */
48 PFILE_OBJECT
49 NTAPI
50 CcGetFileObjectFromBcb (
51     IN PVOID Bcb)
52 {
53     PINTERNAL_BCB iBcb = (PINTERNAL_BCB)Bcb;
54 
55     CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb);
56 
57     return iBcb->Vacb->SharedCacheMap->FileObject;
58 }
59 
60 /*
61  * @unimplemented
62  */
63 LARGE_INTEGER
64 NTAPI
65 CcGetLsnForFileObject (
66     IN PFILE_OBJECT FileObject,
67     OUT PLARGE_INTEGER OldestLsn OPTIONAL)
68 {
69     LARGE_INTEGER i;
70 
71     CCTRACE(CC_API_DEBUG, "FileObject=%p\n", FileObject);
72 
73     UNIMPLEMENTED;
74     i.QuadPart = 0;
75     return i;
76 }
77 
78 /*
79  * @unimplemented
80  */
81 VOID
82 NTAPI
83 CcInitializeCacheMap (
84     IN PFILE_OBJECT FileObject,
85     IN PCC_FILE_SIZES FileSizes,
86     IN BOOLEAN PinAccess,
87     IN PCACHE_MANAGER_CALLBACKS CallBacks,
88     IN PVOID LazyWriterContext)
89 {
90     NTSTATUS Status;
91 
92     ASSERT(FileObject);
93     ASSERT(FileSizes);
94 
95     CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p PinAccess=%d CallBacks=%p LazyWriterContext=%p\n",
96         FileObject, FileSizes, PinAccess, CallBacks, LazyWriterContext);
97 
98     /* Call old ROS cache init function */
99     Status = CcRosInitializeFileCache(FileObject,
100                                       FileSizes,
101                                       PinAccess,
102                                       CallBacks,
103                                       LazyWriterContext);
104     if (!NT_SUCCESS(Status))
105         ExRaiseStatus(Status);
106 }
107 
108 /*
109  * @implemented
110  */
111 BOOLEAN
112 NTAPI
113 CcIsThereDirtyData (
114     IN PVPB Vpb)
115 {
116     PROS_VACB Vacb;
117     PLIST_ENTRY Entry;
118     /* Assume no dirty data */
119     BOOLEAN Dirty = FALSE;
120 
121     CCTRACE(CC_API_DEBUG, "Vpb=%p\n", Vpb);
122 
123     KeAcquireGuardedMutex(&ViewLock);
124 
125     /* Browse dirty VACBs */
126     for (Entry = DirtyVacbListHead.Flink; Entry != &DirtyVacbListHead; Entry = Entry->Flink)
127     {
128         Vacb = CONTAINING_RECORD(Entry, ROS_VACB, DirtyVacbListEntry);
129         /* Look for these associated with our volume */
130         if (Vacb->SharedCacheMap->FileObject->Vpb != Vpb)
131         {
132             continue;
133         }
134 
135         /* From now on, we are associated with our VPB */
136 
137         /* Temporary files are not counted as dirty */
138         if (BooleanFlagOn(Vacb->SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE))
139         {
140             continue;
141         }
142 
143         /* A single dirty VACB is enough to have dirty data */
144         if (Vacb->Dirty)
145         {
146             Dirty = TRUE;
147             break;
148         }
149     }
150 
151     KeReleaseGuardedMutex(&ViewLock);
152 
153     return Dirty;
154 }
155 
156 /*
157  * @unimplemented
158  */
159 BOOLEAN
160 NTAPI
161 CcPurgeCacheSection (
162     IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
163     IN PLARGE_INTEGER FileOffset OPTIONAL,
164     IN ULONG Length,
165     IN BOOLEAN UninitializeCacheMaps)
166 {
167     PROS_SHARED_CACHE_MAP SharedCacheMap;
168     LONGLONG StartOffset;
169     LONGLONG EndOffset;
170     LIST_ENTRY FreeList;
171     KIRQL OldIrql;
172     PLIST_ENTRY ListEntry;
173     PROS_VACB Vacb;
174     LONGLONG ViewEnd;
175     BOOLEAN Success;
176 
177     CCTRACE(CC_API_DEBUG, "SectionObjectPointer=%p\n FileOffset=%p Length=%lu UninitializeCacheMaps=%d",
178         SectionObjectPointer, FileOffset, Length, UninitializeCacheMaps);
179 
180     if (UninitializeCacheMaps)
181     {
182         DPRINT1("FIXME: CcPurgeCacheSection not uninitializing private cache maps\n");
183     }
184 
185     SharedCacheMap = SectionObjectPointer->SharedCacheMap;
186     if (!SharedCacheMap)
187         return FALSE;
188 
189     StartOffset = FileOffset != NULL ? FileOffset->QuadPart : 0;
190     if (Length == 0 || FileOffset == NULL)
191     {
192         EndOffset = MAXLONGLONG;
193     }
194     else
195     {
196         EndOffset = StartOffset + Length;
197         ASSERT(EndOffset > StartOffset);
198     }
199 
200     InitializeListHead(&FreeList);
201 
202     /* Assume success */
203     Success = TRUE;
204 
205     KeAcquireGuardedMutex(&ViewLock);
206     KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
207     ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink;
208     while (ListEntry != &SharedCacheMap->CacheMapVacbListHead)
209     {
210         Vacb = CONTAINING_RECORD(ListEntry, ROS_VACB, CacheMapVacbListEntry);
211         ListEntry = ListEntry->Flink;
212 
213         /* Skip VACBs outside the range, or only partially in range */
214         if (Vacb->FileOffset.QuadPart < StartOffset)
215         {
216             continue;
217         }
218         ViewEnd = min(Vacb->FileOffset.QuadPart + VACB_MAPPING_GRANULARITY,
219                       SharedCacheMap->SectionSize.QuadPart);
220         if (ViewEnd >= EndOffset)
221         {
222             break;
223         }
224 
225         /* Still in use, it cannot be purged, fail */
226         if (Vacb->ReferenceCount != 0 && !Vacb->Dirty)
227         {
228             Success = FALSE;
229             break;
230         }
231 
232         /* This VACB is in range, so unlink it and mark for free */
233         RemoveEntryList(&Vacb->VacbLruListEntry);
234         if (Vacb->Dirty)
235         {
236             RemoveEntryList(&Vacb->DirtyVacbListEntry);
237             CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE;
238         }
239         RemoveEntryList(&Vacb->CacheMapVacbListEntry);
240         InsertHeadList(&FreeList, &Vacb->CacheMapVacbListEntry);
241     }
242     KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
243     KeReleaseGuardedMutex(&ViewLock);
244 
245     while (!IsListEmpty(&FreeList))
246     {
247         Vacb = CONTAINING_RECORD(RemoveHeadList(&FreeList),
248                                  ROS_VACB,
249                                  CacheMapVacbListEntry);
250         CcRosInternalFreeVacb(Vacb);
251     }
252 
253     return Success;
254 }
255 
256 
257 /*
258  * @implemented
259  */
260 VOID NTAPI
261 CcSetFileSizes (
262     IN PFILE_OBJECT FileObject,
263     IN PCC_FILE_SIZES FileSizes)
264 {
265     KIRQL oldirql;
266     PROS_SHARED_CACHE_MAP SharedCacheMap;
267 
268     CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p\n",
269         FileObject, FileSizes);
270 
271     DPRINT("CcSetFileSizes(FileObject 0x%p, FileSizes 0x%p)\n",
272            FileObject, FileSizes);
273     DPRINT("AllocationSize %I64d, FileSize %I64d, ValidDataLength %I64d\n",
274            FileSizes->AllocationSize.QuadPart,
275            FileSizes->FileSize.QuadPart,
276            FileSizes->ValidDataLength.QuadPart);
277 
278     SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
279 
280     /*
281      * It is valid to call this function on file objects that weren't
282      * initialized for caching. In this case it's simple no-op.
283      */
284     if (SharedCacheMap == NULL)
285         return;
286 
287     if (FileSizes->AllocationSize.QuadPart < SharedCacheMap->SectionSize.QuadPart)
288     {
289         CcPurgeCacheSection(FileObject->SectionObjectPointer,
290                             &FileSizes->AllocationSize,
291                             0,
292                             FALSE);
293     }
294 
295     KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
296     SharedCacheMap->SectionSize = FileSizes->AllocationSize;
297     SharedCacheMap->FileSize = FileSizes->FileSize;
298     KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
299 }
300 
301 /*
302  * @unimplemented
303  */
304 VOID
305 NTAPI
306 CcSetLogHandleForFile (
307     IN PFILE_OBJECT FileObject,
308     IN PVOID LogHandle,
309     IN PFLUSH_TO_LSN FlushToLsnRoutine)
310 {
311     CCTRACE(CC_API_DEBUG, "FileObject=%p LogHandle=%p FlushToLsnRoutine=%p\n",
312         FileObject, LogHandle, FlushToLsnRoutine);
313 
314     UNIMPLEMENTED;
315 }
316 
317 /*
318  * @unimplemented
319  */
320 BOOLEAN
321 NTAPI
322 CcUninitializeCacheMap (
323     IN PFILE_OBJECT FileObject,
324     IN PLARGE_INTEGER TruncateSize OPTIONAL,
325     IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL)
326 {
327     NTSTATUS Status;
328     PROS_SHARED_CACHE_MAP SharedCacheMap;
329     KIRQL OldIrql;
330 
331     CCTRACE(CC_API_DEBUG, "FileObject=%p TruncateSize=%p UninitializeCompleteEvent=%p\n",
332         FileObject, TruncateSize, UninitializeCompleteEvent);
333 
334     if (TruncateSize != NULL &&
335         FileObject->SectionObjectPointer->SharedCacheMap != NULL)
336     {
337         SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
338         KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
339         if (SharedCacheMap->FileSize.QuadPart > TruncateSize->QuadPart)
340         {
341             SharedCacheMap->FileSize = *TruncateSize;
342         }
343         KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
344         CcPurgeCacheSection(FileObject->SectionObjectPointer,
345                             TruncateSize,
346                             0,
347                             FALSE);
348     }
349 
350     Status = CcRosReleaseFileCache(FileObject);
351     if (UninitializeCompleteEvent)
352     {
353         KeSetEvent(&UninitializeCompleteEvent->Event, IO_NO_INCREMENT, FALSE);
354     }
355     return NT_SUCCESS(Status);
356 }
357 
358 BOOLEAN
359 NTAPI
360 CcGetFileSizes (
361     IN PFILE_OBJECT FileObject,
362     IN PCC_FILE_SIZES FileSizes)
363 {
364     PROS_SHARED_CACHE_MAP SharedCacheMap;
365 
366     SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
367 
368     if (!SharedCacheMap)
369         return FALSE;
370 
371     FileSizes->AllocationSize = SharedCacheMap->SectionSize;
372     FileSizes->FileSize = FileSizes->ValidDataLength = SharedCacheMap->FileSize;
373     return TRUE;
374 }
375