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