[NTOSKRNL] Move the PinCount out of the VACB to the BCB
[reactos.git] / ntoskrnl / cc / pin.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cc/pin.c
5 * PURPOSE: Implements cache managers pinning interface
6 *
7 * PROGRAMMERS: ?
8 Pierre Schweitzer (pierre@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 extern NPAGED_LOOKASIDE_LIST iBcbLookasideList;
20
21 /* Counters:
22 * - Number of calls to CcMapData that could wait
23 * - Number of calls to CcMapData that couldn't wait
24 * - Number of calls to CcPinRead that could wait
25 * - Number of calls to CcPinRead that couldn't wait
26 */
27 ULONG CcMapDataWait = 0;
28 ULONG CcMapDataNoWait = 0;
29 ULONG CcPinReadWait = 0;
30 ULONG CcPinReadNoWait = 0;
31
32 /* FUNCTIONS *****************************************************************/
33
34 static
35 BOOLEAN
36 NTAPI
37 CcpMapData(
38 IN PFILE_OBJECT FileObject,
39 IN PLARGE_INTEGER FileOffset,
40 IN ULONG Length,
41 IN ULONG Flags,
42 OUT PVOID *pBcb,
43 OUT PVOID *pBuffer)
44 {
45 LONGLONG ReadOffset;
46 BOOLEAN Valid;
47 PROS_SHARED_CACHE_MAP SharedCacheMap;
48 PROS_VACB Vacb;
49 NTSTATUS Status;
50 PINTERNAL_BCB iBcb;
51 LONGLONG ROffset;
52 KIRQL OldIrql;
53
54 ReadOffset = FileOffset->QuadPart;
55
56 ASSERT(FileObject);
57 ASSERT(FileObject->SectionObjectPointer);
58 ASSERT(FileObject->SectionObjectPointer->SharedCacheMap);
59
60 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
61 ASSERT(SharedCacheMap);
62
63 DPRINT("SectionSize %I64x, FileSize %I64x\n",
64 SharedCacheMap->SectionSize.QuadPart,
65 SharedCacheMap->FileSize.QuadPart);
66
67 if (ReadOffset % VACB_MAPPING_GRANULARITY + Length > VACB_MAPPING_GRANULARITY)
68 {
69 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n",
70 FileObject, FileOffset, Length, Flags);
71 return FALSE;
72 }
73
74 if (!BooleanFlagOn(Flags, MAP_NO_READ))
75 {
76 static int Warned = 0;
77
78 SetFlag(Flags, MAP_NO_READ);
79 if (!Warned)
80 {
81 DPRINT1("Mapping/pinning with no read not implemented. Forcing read, might fail if wait not allowed\n");
82 Warned++;
83 }
84 }
85
86 ROffset = ROUND_DOWN(ReadOffset, VACB_MAPPING_GRANULARITY);
87 Status = CcRosRequestVacb(SharedCacheMap,
88 ROffset,
89 pBuffer,
90 &Valid,
91 &Vacb);
92 if (!NT_SUCCESS(Status))
93 {
94 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n",
95 FileObject, FileOffset, Length, Flags);
96 ExRaiseStatus(Status);
97 return FALSE;
98 }
99
100 if (!Valid && BooleanFlagOn(Flags, MAP_NO_READ))
101 {
102 if (!BooleanFlagOn(Flags, MAP_WAIT))
103 {
104 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
105 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n",
106 FileObject, FileOffset, Length, Flags);
107 return FALSE;
108 }
109
110 Status = CcReadVirtualAddress(Vacb);
111 if (!NT_SUCCESS(Status))
112 {
113 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
114 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n",
115 FileObject, FileOffset, Length, Flags);
116 ExRaiseStatus(Status);
117 return FALSE;
118 }
119 }
120
121 *pBuffer = (PUCHAR)*pBuffer + ReadOffset % VACB_MAPPING_GRANULARITY;
122 iBcb = ExAllocateFromNPagedLookasideList(&iBcbLookasideList);
123 if (iBcb == NULL)
124 {
125 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
126 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n",
127 FileObject, FileOffset, Length, Flags);
128 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
129 return FALSE;
130 }
131
132 RtlZeroMemory(iBcb, sizeof(*iBcb));
133 iBcb->PFCB.NodeTypeCode = 0xDE45; /* Undocumented (CAPTIVE_PUBLIC_BCB_NODETYPECODE) */
134 iBcb->PFCB.NodeByteSize = sizeof(PUBLIC_BCB);
135 iBcb->PFCB.MappedLength = Length;
136 iBcb->PFCB.MappedFileOffset = *FileOffset;
137 iBcb->Vacb = Vacb;
138 iBcb->Dirty = FALSE;
139 iBcb->PinCount = 0;
140 iBcb->RefCount = 1;
141 ExInitializeResourceLite(&iBcb->Lock);
142 *pBcb = (PVOID)iBcb;
143
144 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
145 InsertTailList(&SharedCacheMap->BcbList, &iBcb->BcbEntry);
146 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
147
148 return TRUE;
149 }
150
151 /*
152 * @implemented
153 */
154 BOOLEAN
155 NTAPI
156 CcMapData (
157 IN PFILE_OBJECT FileObject,
158 IN PLARGE_INTEGER FileOffset,
159 IN ULONG Length,
160 IN ULONG Flags,
161 OUT PVOID *pBcb,
162 OUT PVOID *pBuffer)
163 {
164 BOOLEAN Ret;
165
166 DPRINT("CcMapData(FileObject 0x%p, FileOffset %I64x, Length %lu, Flags 0x%lx,"
167 " pBcb 0x%p, pBuffer 0x%p)\n", FileObject, FileOffset->QuadPart,
168 Length, Flags, pBcb, pBuffer);
169
170 if (Flags & MAP_WAIT)
171 {
172 ++CcMapDataWait;
173 }
174 else
175 {
176 ++CcMapDataNoWait;
177 }
178
179 Ret = CcpMapData(FileObject, FileOffset, Length, Flags, pBcb, pBuffer);
180
181 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> %d Bcb=%p\n",
182 FileObject, FileOffset, Length, Flags, Ret, *pBcb);
183 return Ret;
184 }
185
186 /*
187 * @unimplemented
188 */
189 BOOLEAN
190 NTAPI
191 CcPinMappedData (
192 IN PFILE_OBJECT FileObject,
193 IN PLARGE_INTEGER FileOffset,
194 IN ULONG Length,
195 IN ULONG Flags,
196 OUT PVOID * Bcb)
197 {
198 BOOLEAN Result;
199 PINTERNAL_BCB iBcb;
200 PROS_SHARED_CACHE_MAP SharedCacheMap;
201
202 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx\n",
203 FileObject, FileOffset, Length, Flags);
204
205 ASSERT(FileObject);
206 ASSERT(FileObject->SectionObjectPointer);
207 ASSERT(FileObject->SectionObjectPointer->SharedCacheMap);
208
209 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
210 ASSERT(SharedCacheMap);
211 if (!SharedCacheMap->PinAccess)
212 {
213 DPRINT1("FIXME: Pinning a file with no pin access!\n");
214 return FALSE;
215 }
216
217 iBcb = *Bcb;
218 ASSERT(iBcb->PinCount == 0);
219
220 iBcb->PinCount++;
221
222 if (BooleanFlagOn(Flags, PIN_EXCLUSIVE))
223 {
224 Result = ExAcquireResourceExclusiveLite(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
225 }
226 else
227 {
228 Result = ExAcquireSharedStarveExclusive(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
229 }
230
231 if (!Result)
232 {
233 iBcb->PinCount--;
234 }
235
236 return Result;
237 }
238
239 /*
240 * @unimplemented
241 */
242 BOOLEAN
243 NTAPI
244 CcPinRead (
245 IN PFILE_OBJECT FileObject,
246 IN PLARGE_INTEGER FileOffset,
247 IN ULONG Length,
248 IN ULONG Flags,
249 OUT PVOID * Bcb,
250 OUT PVOID * Buffer)
251 {
252 CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Flags=0x%lx\n",
253 FileObject, FileOffset, Length, Flags);
254
255 if (Flags & PIN_WAIT)
256 {
257 ++CcPinReadWait;
258 }
259 else
260 {
261 ++CcPinReadNoWait;
262 }
263
264 /* Map first */
265 if (!CcpMapData(FileObject, FileOffset, Length, Flags, Bcb, Buffer))
266 {
267 return FALSE;
268 }
269
270 /* Pin then */
271 if (!CcPinMappedData(FileObject, FileOffset, Length, Flags, Bcb))
272 {
273 CcUnpinData(*Bcb);
274 return FALSE;
275 }
276
277 return TRUE;
278 }
279
280 /*
281 * @unimplemented
282 */
283 BOOLEAN
284 NTAPI
285 CcPreparePinWrite (
286 IN PFILE_OBJECT FileObject,
287 IN PLARGE_INTEGER FileOffset,
288 IN ULONG Length,
289 IN BOOLEAN Zero,
290 IN ULONG Flags,
291 OUT PVOID * Bcb,
292 OUT PVOID * Buffer)
293 {
294 CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Zero=%d Flags=0x%lx\n",
295 FileObject, FileOffset, Length, Zero, Flags);
296
297 /*
298 * FIXME: This is function is similar to CcPinRead, but doesn't
299 * read the data if they're not present. Instead it should just
300 * prepare the VACBs and zero them out if Zero != FALSE.
301 *
302 * For now calling CcPinRead is better than returning error or
303 * just having UNIMPLEMENTED here.
304 */
305 return CcPinRead(FileObject, FileOffset, Length, Flags, Bcb, Buffer);
306 }
307
308 /*
309 * @implemented
310 */
311 VOID NTAPI
312 CcSetDirtyPinnedData (
313 IN PVOID Bcb,
314 IN PLARGE_INTEGER Lsn)
315 {
316 PINTERNAL_BCB iBcb = Bcb;
317
318 CCTRACE(CC_API_DEBUG, "Bcb=%p Lsn=%p\n",
319 Bcb, Lsn);
320
321 iBcb->Dirty = TRUE;
322 if (!iBcb->Vacb->Dirty)
323 {
324 CcRosMarkDirtyVacb(iBcb->Vacb);
325 }
326 }
327
328
329 /*
330 * @implemented
331 */
332 VOID NTAPI
333 CcUnpinData (
334 IN PVOID Bcb)
335 {
336 CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb);
337
338 CcUnpinDataForThread(Bcb, (ERESOURCE_THREAD)PsGetCurrentThread());
339 }
340
341 /*
342 * @unimplemented
343 */
344 VOID
345 NTAPI
346 CcUnpinDataForThread (
347 IN PVOID Bcb,
348 IN ERESOURCE_THREAD ResourceThreadId)
349 {
350 PINTERNAL_BCB iBcb = Bcb;
351
352 CCTRACE(CC_API_DEBUG, "Bcb=%p ResourceThreadId=%lu\n", Bcb, ResourceThreadId);
353
354 if (iBcb->PinCount != 0)
355 {
356 ExReleaseResourceForThreadLite(&iBcb->Lock, ResourceThreadId);
357 iBcb->PinCount--;
358 }
359
360 if (--iBcb->RefCount == 0)
361 {
362 KIRQL OldIrql;
363 PROS_SHARED_CACHE_MAP SharedCacheMap;
364
365 ASSERT(iBcb->PinCount == 0);
366 SharedCacheMap = iBcb->Vacb->SharedCacheMap;
367 CcRosReleaseVacb(SharedCacheMap,
368 iBcb->Vacb,
369 TRUE,
370 iBcb->Dirty,
371 FALSE);
372
373 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
374 RemoveEntryList(&iBcb->BcbEntry);
375 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
376
377 ExDeleteResourceLite(&iBcb->Lock);
378 ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb);
379 }
380 }
381
382 /*
383 * @implemented
384 */
385 VOID
386 NTAPI
387 CcRepinBcb (
388 IN PVOID Bcb)
389 {
390 PINTERNAL_BCB iBcb = Bcb;
391
392 CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb);
393
394 iBcb->RefCount++;
395 }
396
397 /*
398 * @unimplemented
399 */
400 VOID
401 NTAPI
402 CcUnpinRepinnedBcb (
403 IN PVOID Bcb,
404 IN BOOLEAN WriteThrough,
405 IN PIO_STATUS_BLOCK IoStatus)
406 {
407 PINTERNAL_BCB iBcb = Bcb;
408 KIRQL OldIrql;
409 PROS_SHARED_CACHE_MAP SharedCacheMap;
410
411 CCTRACE(CC_API_DEBUG, "Bcb=%p WriteThrough=%d\n", Bcb, WriteThrough);
412
413 IoStatus->Status = STATUS_SUCCESS;
414 if (--iBcb->RefCount == 0)
415 {
416 IoStatus->Information = 0;
417 if (WriteThrough)
418 {
419 if (iBcb->Vacb->Dirty)
420 {
421 IoStatus->Status = CcRosFlushVacb(iBcb->Vacb);
422 }
423 else
424 {
425 IoStatus->Status = STATUS_SUCCESS;
426 }
427 }
428 else
429 {
430 IoStatus->Status = STATUS_SUCCESS;
431 }
432
433 if (iBcb->PinCount != 0)
434 {
435 ExReleaseResourceLite(&iBcb->Lock);
436 iBcb->PinCount--;
437 ASSERT(iBcb->PinCount == 0);
438 }
439
440 SharedCacheMap = iBcb->Vacb->SharedCacheMap;
441 CcRosReleaseVacb(iBcb->Vacb->SharedCacheMap,
442 iBcb->Vacb,
443 TRUE,
444 iBcb->Dirty,
445 FALSE);
446
447 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
448 RemoveEntryList(&iBcb->BcbEntry);
449 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
450
451 ExDeleteResourceLite(&iBcb->Lock);
452 ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb);
453 }
454 }