[NTOSKRNL] Move data mapping implementation to an internel helper
[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->Pinned = FALSE;
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->Pinned == FALSE);
219
220 iBcb->Pinned = TRUE;
221 iBcb->Vacb->PinCount++;
222
223 if (BooleanFlagOn(Flags, PIN_EXCLUSIVE))
224 {
225 Result = ExAcquireResourceExclusiveLite(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
226 }
227 else
228 {
229 Result = ExAcquireSharedStarveExclusive(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT));
230 }
231
232 if (!Result)
233 {
234 iBcb->Pinned = FALSE;
235 iBcb->Vacb->PinCount--;
236 }
237
238 return Result;
239 }
240
241 /*
242 * @unimplemented
243 */
244 BOOLEAN
245 NTAPI
246 CcPinRead (
247 IN PFILE_OBJECT FileObject,
248 IN PLARGE_INTEGER FileOffset,
249 IN ULONG Length,
250 IN ULONG Flags,
251 OUT PVOID * Bcb,
252 OUT PVOID * Buffer)
253 {
254 CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Flags=0x%lx\n",
255 FileObject, FileOffset, Length, Flags);
256
257 if (Flags & PIN_WAIT)
258 {
259 ++CcPinReadWait;
260 }
261 else
262 {
263 ++CcPinReadNoWait;
264 }
265
266 /* Map first */
267 if (!CcpMapData(FileObject, FileOffset, Length, Flags, Bcb, Buffer))
268 {
269 return FALSE;
270 }
271
272 /* Pin then */
273 if (!CcPinMappedData(FileObject, FileOffset, Length, Flags, Bcb))
274 {
275 CcUnpinData(*Bcb);
276 return FALSE;
277 }
278
279 return TRUE;
280 }
281
282 /*
283 * @unimplemented
284 */
285 BOOLEAN
286 NTAPI
287 CcPreparePinWrite (
288 IN PFILE_OBJECT FileObject,
289 IN PLARGE_INTEGER FileOffset,
290 IN ULONG Length,
291 IN BOOLEAN Zero,
292 IN ULONG Flags,
293 OUT PVOID * Bcb,
294 OUT PVOID * Buffer)
295 {
296 CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Zero=%d Flags=0x%lx\n",
297 FileObject, FileOffset, Length, Zero, Flags);
298
299 /*
300 * FIXME: This is function is similar to CcPinRead, but doesn't
301 * read the data if they're not present. Instead it should just
302 * prepare the VACBs and zero them out if Zero != FALSE.
303 *
304 * For now calling CcPinRead is better than returning error or
305 * just having UNIMPLEMENTED here.
306 */
307 return CcPinRead(FileObject, FileOffset, Length, Flags, Bcb, Buffer);
308 }
309
310 /*
311 * @implemented
312 */
313 VOID NTAPI
314 CcSetDirtyPinnedData (
315 IN PVOID Bcb,
316 IN PLARGE_INTEGER Lsn)
317 {
318 PINTERNAL_BCB iBcb = Bcb;
319
320 CCTRACE(CC_API_DEBUG, "Bcb=%p Lsn=%p\n",
321 Bcb, Lsn);
322
323 iBcb->Dirty = TRUE;
324 if (!iBcb->Vacb->Dirty)
325 {
326 CcRosMarkDirtyVacb(iBcb->Vacb);
327 }
328 }
329
330
331 /*
332 * @implemented
333 */
334 VOID NTAPI
335 CcUnpinData (
336 IN PVOID Bcb)
337 {
338 CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb);
339
340 CcUnpinDataForThread(Bcb, (ERESOURCE_THREAD)PsGetCurrentThread());
341 }
342
343 /*
344 * @unimplemented
345 */
346 VOID
347 NTAPI
348 CcUnpinDataForThread (
349 IN PVOID Bcb,
350 IN ERESOURCE_THREAD ResourceThreadId)
351 {
352 PINTERNAL_BCB iBcb = Bcb;
353
354 CCTRACE(CC_API_DEBUG, "Bcb=%p ResourceThreadId=%lu\n", Bcb, ResourceThreadId);
355
356 if (iBcb->Pinned)
357 {
358 ExReleaseResourceForThreadLite(&iBcb->Lock, ResourceThreadId);
359 iBcb->Pinned = FALSE;
360 iBcb->Vacb->PinCount--;
361 }
362
363 if (--iBcb->RefCount == 0)
364 {
365 KIRQL OldIrql;
366 PROS_SHARED_CACHE_MAP SharedCacheMap;
367
368 SharedCacheMap = iBcb->Vacb->SharedCacheMap;
369 CcRosReleaseVacb(SharedCacheMap,
370 iBcb->Vacb,
371 TRUE,
372 iBcb->Dirty,
373 FALSE);
374
375 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
376 RemoveEntryList(&iBcb->BcbEntry);
377 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
378
379 ExDeleteResourceLite(&iBcb->Lock);
380 ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb);
381 }
382 }
383
384 /*
385 * @implemented
386 */
387 VOID
388 NTAPI
389 CcRepinBcb (
390 IN PVOID Bcb)
391 {
392 PINTERNAL_BCB iBcb = Bcb;
393
394 CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb);
395
396 iBcb->RefCount++;
397 }
398
399 /*
400 * @unimplemented
401 */
402 VOID
403 NTAPI
404 CcUnpinRepinnedBcb (
405 IN PVOID Bcb,
406 IN BOOLEAN WriteThrough,
407 IN PIO_STATUS_BLOCK IoStatus)
408 {
409 PINTERNAL_BCB iBcb = Bcb;
410 KIRQL OldIrql;
411 PROS_SHARED_CACHE_MAP SharedCacheMap;
412
413 CCTRACE(CC_API_DEBUG, "Bcb=%p WriteThrough=%d\n", Bcb, WriteThrough);
414
415 IoStatus->Status = STATUS_SUCCESS;
416 if (--iBcb->RefCount == 0)
417 {
418 IoStatus->Information = 0;
419 if (WriteThrough)
420 {
421 if (iBcb->Vacb->Dirty)
422 {
423 IoStatus->Status = CcRosFlushVacb(iBcb->Vacb);
424 }
425 else
426 {
427 IoStatus->Status = STATUS_SUCCESS;
428 }
429 }
430 else
431 {
432 IoStatus->Status = STATUS_SUCCESS;
433 }
434
435 if (iBcb->Pinned)
436 {
437 ExReleaseResourceLite(&iBcb->Lock);
438 iBcb->Pinned = FALSE;
439 iBcb->Vacb->PinCount--;
440 ASSERT(iBcb->Vacb->PinCount == 0);
441 }
442
443 SharedCacheMap = iBcb->Vacb->SharedCacheMap;
444 CcRosReleaseVacb(iBcb->Vacb->SharedCacheMap,
445 iBcb->Vacb,
446 TRUE,
447 iBcb->Dirty,
448 FALSE);
449
450 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql);
451 RemoveEntryList(&iBcb->BcbEntry);
452 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql);
453
454 ExDeleteResourceLite(&iBcb->Lock);
455 ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb);
456 }
457 }