[NTOSKRNL] Drop the ViewLock mutex in favour of the master spin lock
[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
305 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
306 SharedCacheMap->SectionSize = FileSizes->AllocationSize;
307 SharedCacheMap->FileSize = FileSizes->FileSize;
308 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
309 }
310
311 /*
312 * @unimplemented
313 */
314 VOID
315 NTAPI
316 CcSetLogHandleForFile (
317 IN PFILE_OBJECT FileObject,
318 IN PVOID LogHandle,
319 IN PFLUSH_TO_LSN FlushToLsnRoutine)
320 {
321 CCTRACE(CC_API_DEBUG, "FileObject=%p LogHandle=%p FlushToLsnRoutine=%p\n",
322 FileObject, LogHandle, FlushToLsnRoutine);
323
324 UNIMPLEMENTED;
325 }
326
327 /*
328 * @unimplemented
329 */
330 BOOLEAN
331 NTAPI
332 CcUninitializeCacheMap (
333 IN PFILE_OBJECT FileObject,
334 IN PLARGE_INTEGER TruncateSize OPTIONAL,
335 IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL)
336 {
337 NTSTATUS Status;
338 PROS_SHARED_CACHE_MAP SharedCacheMap;
339 KIRQL OldIrql;
340
341 CCTRACE(CC_API_DEBUG, "FileObject=%p TruncateSize=%p UninitializeCompleteEvent=%p\n",
342 FileObject, TruncateSize, UninitializeCompleteEvent);
343
344 if (TruncateSize != NULL &&
345 FileObject->SectionObjectPointer->SharedCacheMap != NULL)
346 {
347 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
348 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
349 if (SharedCacheMap->FileSize.QuadPart > TruncateSize->QuadPart)
350 {
351 SharedCacheMap->FileSize = *TruncateSize;
352 }
353 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
354 CcPurgeCacheSection(FileObject->SectionObjectPointer,
355 TruncateSize,
356 0,
357 FALSE);
358 }
359
360 Status = CcRosReleaseFileCache(FileObject);
361 if (UninitializeCompleteEvent)
362 {
363 KeSetEvent(&UninitializeCompleteEvent->Event, IO_NO_INCREMENT, FALSE);
364 }
365 return NT_SUCCESS(Status);
366 }
367
368 BOOLEAN
369 NTAPI
370 CcGetFileSizes (
371 IN PFILE_OBJECT FileObject,
372 IN PCC_FILE_SIZES FileSizes)
373 {
374 PROS_SHARED_CACHE_MAP SharedCacheMap;
375
376 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
377
378 if (!SharedCacheMap)
379 return FALSE;
380
381 FileSizes->AllocationSize = SharedCacheMap->SectionSize;
382 FileSizes->FileSize = FileSizes->ValidDataLength = SharedCacheMap->FileSize;
383 return TRUE;
384 }