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