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