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