xref: /reactos/ntoskrnl/cc/fs.c (revision 5100859e)
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         ULONG Refs;
211 
212         Vacb = CONTAINING_RECORD(ListEntry, ROS_VACB, CacheMapVacbListEntry);
213         ListEntry = ListEntry->Flink;
214 
215         /* Skip VACBs outside the range, or only partially in range */
216         if (Vacb->FileOffset.QuadPart < StartOffset)
217         {
218             continue;
219         }
220         ViewEnd = min(Vacb->FileOffset.QuadPart + VACB_MAPPING_GRANULARITY,
221                       SharedCacheMap->SectionSize.QuadPart);
222         if (ViewEnd >= EndOffset)
223         {
224             break;
225         }
226 
227         /* Still in use, it cannot be purged, fail
228          * Allow one ref: VACB is supposed to be always 1-referenced
229          */
230         Refs = CcRosVacbGetRefCount(Vacb);
231         if ((Refs > 1 && !Vacb->Dirty) ||
232             (Refs > 2 && Vacb->Dirty))
233         {
234             Success = FALSE;
235             break;
236         }
237 
238         /* This VACB is in range, so unlink it and mark for free */
239         ASSERT(Refs == 1 || Vacb->Dirty);
240         RemoveEntryList(&Vacb->VacbLruListEntry);
241         if (Vacb->Dirty)
242         {
243             CcRosUnmarkDirtyVacb(Vacb, FALSE);
244         }
245         RemoveEntryList(&Vacb->CacheMapVacbListEntry);
246         InsertHeadList(&FreeList, &Vacb->CacheMapVacbListEntry);
247     }
248     KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
249     KeReleaseGuardedMutex(&ViewLock);
250 
251     while (!IsListEmpty(&FreeList))
252     {
253         Vacb = CONTAINING_RECORD(RemoveHeadList(&FreeList),
254                                  ROS_VACB,
255                                  CacheMapVacbListEntry);
256         CcRosVacbDecRefCount(Vacb);
257         CcRosInternalFreeVacb(Vacb);
258     }
259 
260     return Success;
261 }
262 
263 
264 /*
265  * @implemented
266  */
267 VOID NTAPI
268 CcSetFileSizes (
269     IN PFILE_OBJECT FileObject,
270     IN PCC_FILE_SIZES FileSizes)
271 {
272     KIRQL oldirql;
273     PROS_SHARED_CACHE_MAP SharedCacheMap;
274 
275     CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p\n",
276         FileObject, FileSizes);
277 
278     DPRINT("CcSetFileSizes(FileObject 0x%p, FileSizes 0x%p)\n",
279            FileObject, FileSizes);
280     DPRINT("AllocationSize %I64d, FileSize %I64d, ValidDataLength %I64d\n",
281            FileSizes->AllocationSize.QuadPart,
282            FileSizes->FileSize.QuadPart,
283            FileSizes->ValidDataLength.QuadPart);
284 
285     SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
286 
287     /*
288      * It is valid to call this function on file objects that weren't
289      * initialized for caching. In this case it's simple no-op.
290      */
291     if (SharedCacheMap == NULL)
292         return;
293 
294     if (FileSizes->AllocationSize.QuadPart < SharedCacheMap->SectionSize.QuadPart)
295     {
296         CcPurgeCacheSection(FileObject->SectionObjectPointer,
297                             &FileSizes->AllocationSize,
298                             0,
299                             FALSE);
300     }
301 
302     KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
303     SharedCacheMap->SectionSize = FileSizes->AllocationSize;
304     SharedCacheMap->FileSize = FileSizes->FileSize;
305     KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
306 }
307 
308 /*
309  * @unimplemented
310  */
311 VOID
312 NTAPI
313 CcSetLogHandleForFile (
314     IN PFILE_OBJECT FileObject,
315     IN PVOID LogHandle,
316     IN PFLUSH_TO_LSN FlushToLsnRoutine)
317 {
318     CCTRACE(CC_API_DEBUG, "FileObject=%p LogHandle=%p FlushToLsnRoutine=%p\n",
319         FileObject, LogHandle, FlushToLsnRoutine);
320 
321     UNIMPLEMENTED;
322 }
323 
324 /*
325  * @unimplemented
326  */
327 BOOLEAN
328 NTAPI
329 CcUninitializeCacheMap (
330     IN PFILE_OBJECT FileObject,
331     IN PLARGE_INTEGER TruncateSize OPTIONAL,
332     IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL)
333 {
334     NTSTATUS Status;
335     PROS_SHARED_CACHE_MAP SharedCacheMap;
336     KIRQL OldIrql;
337 
338     CCTRACE(CC_API_DEBUG, "FileObject=%p TruncateSize=%p UninitializeCompleteEvent=%p\n",
339         FileObject, TruncateSize, UninitializeCompleteEvent);
340 
341     if (TruncateSize != NULL &&
342         FileObject->SectionObjectPointer->SharedCacheMap != NULL)
343     {
344         SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
345         KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
346         if (SharedCacheMap->FileSize.QuadPart > TruncateSize->QuadPart)
347         {
348             SharedCacheMap->FileSize = *TruncateSize;
349         }
350         KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
351         CcPurgeCacheSection(FileObject->SectionObjectPointer,
352                             TruncateSize,
353                             0,
354                             FALSE);
355     }
356 
357     Status = CcRosReleaseFileCache(FileObject);
358     if (UninitializeCompleteEvent)
359     {
360         KeSetEvent(&UninitializeCompleteEvent->Event, IO_NO_INCREMENT, FALSE);
361     }
362     return NT_SUCCESS(Status);
363 }
364 
365 BOOLEAN
366 NTAPI
367 CcGetFileSizes (
368     IN PFILE_OBJECT FileObject,
369     IN PCC_FILE_SIZES FileSizes)
370 {
371     PROS_SHARED_CACHE_MAP SharedCacheMap;
372 
373     SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
374 
375     if (!SharedCacheMap)
376         return FALSE;
377 
378     FileSizes->AllocationSize = SharedCacheMap->SectionSize;
379     FileSizes->FileSize = FileSizes->ValidDataLength = SharedCacheMap->FileSize;
380     return TRUE;
381 }
382