cb98eed15372792a43c47a0158ad64ff6282ce38
[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 /* 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 InitializeListHead(&Vacb->VacbLruListEntry);
242 if (Vacb->Dirty)
243 {
244 CcRosUnmarkDirtyVacb(Vacb, FALSE);
245 }
246 RemoveEntryList(&Vacb->CacheMapVacbListEntry);
247 InsertHeadList(&FreeList, &Vacb->CacheMapVacbListEntry);
248 }
249 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
250 KeReleaseGuardedMutex(&ViewLock);
251
252 while (!IsListEmpty(&FreeList))
253 {
254 ULONG Refs;
255
256 Vacb = CONTAINING_RECORD(RemoveHeadList(&FreeList),
257 ROS_VACB,
258 CacheMapVacbListEntry);
259 InitializeListHead(&Vacb->CacheMapVacbListEntry);
260 Refs = CcRosVacbDecRefCount(Vacb);
261 ASSERT(Refs == 0);
262 }
263
264 return Success;
265 }
266
267
268 /*
269 * @implemented
270 */
271 VOID NTAPI
272 CcSetFileSizes (
273 IN PFILE_OBJECT FileObject,
274 IN PCC_FILE_SIZES FileSizes)
275 {
276 KIRQL oldirql;
277 PROS_SHARED_CACHE_MAP SharedCacheMap;
278
279 CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p\n",
280 FileObject, FileSizes);
281
282 DPRINT("CcSetFileSizes(FileObject 0x%p, FileSizes 0x%p)\n",
283 FileObject, FileSizes);
284 DPRINT("AllocationSize %I64d, FileSize %I64d, ValidDataLength %I64d\n",
285 FileSizes->AllocationSize.QuadPart,
286 FileSizes->FileSize.QuadPart,
287 FileSizes->ValidDataLength.QuadPart);
288
289 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
290
291 /*
292 * It is valid to call this function on file objects that weren't
293 * initialized for caching. In this case it's simple no-op.
294 */
295 if (SharedCacheMap == NULL)
296 return;
297
298 if (FileSizes->AllocationSize.QuadPart < SharedCacheMap->SectionSize.QuadPart)
299 {
300 CcPurgeCacheSection(FileObject->SectionObjectPointer,
301 &FileSizes->AllocationSize,
302 0,
303 FALSE);
304 }
305
306 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
307 SharedCacheMap->SectionSize = FileSizes->AllocationSize;
308 SharedCacheMap->FileSize = FileSizes->FileSize;
309 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
310 }
311
312 /*
313 * @unimplemented
314 */
315 VOID
316 NTAPI
317 CcSetLogHandleForFile (
318 IN PFILE_OBJECT FileObject,
319 IN PVOID LogHandle,
320 IN PFLUSH_TO_LSN FlushToLsnRoutine)
321 {
322 CCTRACE(CC_API_DEBUG, "FileObject=%p LogHandle=%p FlushToLsnRoutine=%p\n",
323 FileObject, LogHandle, FlushToLsnRoutine);
324
325 UNIMPLEMENTED;
326 }
327
328 /*
329 * @unimplemented
330 */
331 BOOLEAN
332 NTAPI
333 CcUninitializeCacheMap (
334 IN PFILE_OBJECT FileObject,
335 IN PLARGE_INTEGER TruncateSize OPTIONAL,
336 IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL)
337 {
338 NTSTATUS Status;
339 PROS_SHARED_CACHE_MAP SharedCacheMap;
340 KIRQL OldIrql;
341
342 CCTRACE(CC_API_DEBUG, "FileObject=%p TruncateSize=%p UninitializeCompleteEvent=%p\n",
343 FileObject, TruncateSize, UninitializeCompleteEvent);
344
345 if (TruncateSize != NULL &&
346 FileObject->SectionObjectPointer->SharedCacheMap != NULL)
347 {
348 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
349 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
350 if (SharedCacheMap->FileSize.QuadPart > TruncateSize->QuadPart)
351 {
352 SharedCacheMap->FileSize = *TruncateSize;
353 }
354 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
355 CcPurgeCacheSection(FileObject->SectionObjectPointer,
356 TruncateSize,
357 0,
358 FALSE);
359 }
360
361 Status = CcRosReleaseFileCache(FileObject);
362 if (UninitializeCompleteEvent)
363 {
364 KeSetEvent(&UninitializeCompleteEvent->Event, IO_NO_INCREMENT, FALSE);
365 }
366 return NT_SUCCESS(Status);
367 }
368
369 BOOLEAN
370 NTAPI
371 CcGetFileSizes (
372 IN PFILE_OBJECT FileObject,
373 IN PCC_FILE_SIZES FileSizes)
374 {
375 PROS_SHARED_CACHE_MAP SharedCacheMap;
376
377 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
378
379 if (!SharedCacheMap)
380 return FALSE;
381
382 FileSizes->AllocationSize = SharedCacheMap->SectionSize;
383 FileSizes->FileSize = FileSizes->ValidDataLength = SharedCacheMap->FileSize;
384 return TRUE;
385 }