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