xref: /reactos/ntoskrnl/cc/pin.c (revision e08ae510)
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 }
458