1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/cache/fssup.c
5 * PURPOSE: Logging and configuration routines
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Art Yerkes
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #include "newcc.h"
14 #include "section/newmm.h"
15 #define NDEBUG
16 #include <debug.h>
17
18 /* GLOBALS ********************************************************************/
19
20 PFSN_PREFETCHER_GLOBALS CcPfGlobals;
21 extern LONG CcOutstandingDeletes;
22 extern KEVENT CcpLazyWriteEvent;
23 extern KEVENT CcFinalizeEvent;
24 extern VOID NTAPI CcpUnmapThread(PVOID Unused);
25 extern VOID NTAPI CcpLazyWriteThread(PVOID Unused);
26 HANDLE CcUnmapThreadHandle, CcLazyWriteThreadHandle;
27 CLIENT_ID CcUnmapThreadId, CcLazyWriteThreadId;
28 FAST_MUTEX GlobalPageOperation;
29
30 /*
31
32 A note about private cache maps.
33
34 CcInitializeCacheMap and CcUninitializeCacheMap are not meant to be paired,
35 although they can work that way.
36
37 The actual operation I've gleaned from reading both jan kratchovil's writing
38 and real filesystems is this:
39
40 CcInitializeCacheMap means:
41
42 Make the indicated FILE_OBJECT have a private cache map if it doesn't already
43 and make it have a shared cache map if it doesn't already.
44
45 CcUninitializeCacheMap means:
46
47 Take away the private cache map from this FILE_OBJECT. If it's the last
48 private cache map corresponding to a specific shared cache map (the one that
49 was present in the FILE_OBJECT when it was created), then delete that too,
50 flusing all cached information.
51
52 Using these simple semantics, filesystems can do all the things they actually
53 do:
54
55 - Copy out the shared cache map pointer from a newly initialized file object
56 and store it in the fcb cache.
57 - Copy it back into any file object and call CcInitializeCacheMap to make
58 that file object be associated with the caching of all the other siblings.
59 - Call CcUninitializeCacheMap on a FILE_OBJECT many times, but have only the
60 first one count for each specific FILE_OBJECT.
61 - Have the actual last call to CcUninitializeCacheMap (that is, the one that
62 causes zero private cache maps to be associated with a shared cache map) to
63 delete the cache map and flush.
64
65 So private cache map here is a light weight structure that just remembers
66 what shared cache map it associates with.
67
68 */
69 typedef struct _NOCC_PRIVATE_CACHE_MAP
70 {
71 LIST_ENTRY ListEntry;
72 PFILE_OBJECT FileObject;
73 PNOCC_CACHE_MAP Map;
74 } NOCC_PRIVATE_CACHE_MAP, *PNOCC_PRIVATE_CACHE_MAP;
75
76 LIST_ENTRY CcpAllSharedCacheMaps;
77
78 /* FUNCTIONS ******************************************************************/
79
80 CODE_SEG("INIT")
81 BOOLEAN
82 NTAPI
CcInitializeCacheManager(VOID)83 CcInitializeCacheManager(VOID)
84 {
85 int i;
86
87 DPRINT("Initialize\n");
88 for (i = 0; i < CACHE_NUM_SECTIONS; i++)
89 {
90 KeInitializeEvent(&CcCacheSections[i].ExclusiveWait,
91 SynchronizationEvent,
92 FALSE);
93
94 InitializeListHead(&CcCacheSections[i].ThisFileList);
95 }
96
97 InitializeListHead(&CcpAllSharedCacheMaps);
98
99 KeInitializeEvent(&CcDeleteEvent, SynchronizationEvent, FALSE);
100 KeInitializeEvent(&CcFinalizeEvent, SynchronizationEvent, FALSE);
101 KeInitializeEvent(&CcpLazyWriteEvent, SynchronizationEvent, FALSE);
102
103 CcCacheBitmap->Buffer = ((PULONG)&CcCacheBitmap[1]);
104 CcCacheBitmap->SizeOfBitMap = ROUND_UP(CACHE_NUM_SECTIONS, 32);
105 DPRINT1("Cache has %d entries\n", CcCacheBitmap->SizeOfBitMap);
106 ExInitializeFastMutex(&CcMutex);
107
108 return TRUE;
109 }
110
111 CODE_SEG("INIT")
112 VOID
113 NTAPI
CcPfInitializePrefetcher(VOID)114 CcPfInitializePrefetcher(VOID)
115 {
116 /* Notify debugger */
117 DbgPrintEx(DPFLTR_PREFETCHER_ID,
118 DPFLTR_TRACE_LEVEL,
119 "CCPF: InitializePrefetecher()\n");
120
121 /* Setup the Prefetcher Data */
122 InitializeListHead(&CcPfGlobals.ActiveTraces);
123 InitializeListHead(&CcPfGlobals.CompletedTraces);
124 ExInitializeFastMutex(&CcPfGlobals.CompletedTracesLock);
125
126 /* FIXME: Setup the rest of the prefetecher */
127 }
128
129 BOOLEAN
130 NTAPI
CcpAcquireFileLock(PNOCC_CACHE_MAP Map)131 CcpAcquireFileLock(PNOCC_CACHE_MAP Map)
132 {
133 DPRINT("Calling AcquireForLazyWrite: %x\n", Map->LazyContext);
134 return Map->Callbacks.AcquireForLazyWrite(Map->LazyContext, TRUE);
135 }
136
137 VOID
138 NTAPI
CcpReleaseFileLock(PNOCC_CACHE_MAP Map)139 CcpReleaseFileLock(PNOCC_CACHE_MAP Map)
140 {
141 DPRINT("Releasing Lazy Write %x\n", Map->LazyContext);
142 Map->Callbacks.ReleaseFromLazyWrite(Map->LazyContext);
143 }
144
145 /*
146
147 Cc functions are required to treat alternate streams of a file as the same
148 for the purpose of caching, meaning that we must be able to find the shared
149 cache map associated with the ``real'' stream associated with a stream file
150 object, if one exists. We do that by identifying a private cache map in
151 our gamut that has the same volume, device and fscontext as the stream file
152 object we're holding. It's heavy but it does work. This can probably be
153 improved, although there doesn't seem to be any real association between
154 a stream file object and a sibling file object in the file object struct
155 itself.
156
157 */
158
159 /* Must have CcpLock() */
CcpFindOtherStreamFileObject(PFILE_OBJECT FileObject)160 PFILE_OBJECT CcpFindOtherStreamFileObject(PFILE_OBJECT FileObject)
161 {
162 PLIST_ENTRY Entry, Private;
163 for (Entry = CcpAllSharedCacheMaps.Flink;
164 Entry != &CcpAllSharedCacheMaps;
165 Entry = Entry->Flink)
166 {
167 /* 'Identical' test for other stream file object */
168 PNOCC_CACHE_MAP Map = CONTAINING_RECORD(Entry, NOCC_CACHE_MAP, Entry);
169 for (Private = Map->PrivateCacheMaps.Flink;
170 Private != &Map->PrivateCacheMaps;
171 Private = Private->Flink)
172 {
173 PNOCC_PRIVATE_CACHE_MAP PrivateMap = CONTAINING_RECORD(Private,
174 NOCC_PRIVATE_CACHE_MAP,
175 ListEntry);
176
177 if (PrivateMap->FileObject->Flags & FO_STREAM_FILE &&
178 PrivateMap->FileObject->DeviceObject == FileObject->DeviceObject &&
179 PrivateMap->FileObject->Vpb == FileObject->Vpb &&
180 PrivateMap->FileObject->FsContext == FileObject->FsContext &&
181 PrivateMap->FileObject->FsContext2 == FileObject->FsContext2 &&
182 1)
183 {
184 return PrivateMap->FileObject;
185 }
186 }
187 }
188 return 0;
189 }
190
191 /* Thanks: http://windowsitpro.com/Windows/Articles/ArticleID/3864/pg/2/2.html */
192
193 VOID
194 NTAPI
CcInitializeCacheMap(IN PFILE_OBJECT FileObject,IN PCC_FILE_SIZES FileSizes,IN BOOLEAN PinAccess,IN PCACHE_MANAGER_CALLBACKS Callbacks,IN PVOID LazyWriteContext)195 CcInitializeCacheMap(IN PFILE_OBJECT FileObject,
196 IN PCC_FILE_SIZES FileSizes,
197 IN BOOLEAN PinAccess,
198 IN PCACHE_MANAGER_CALLBACKS Callbacks,
199 IN PVOID LazyWriteContext)
200 {
201 PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
202 PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap;
203
204 CcpLock();
205 /* We don't have a shared cache map. First find out if we have a sibling
206 stream file object we can take it from. */
207 if (!Map && FileObject->Flags & FO_STREAM_FILE)
208 {
209 PFILE_OBJECT IdenticalStreamFileObject = CcpFindOtherStreamFileObject(FileObject);
210 if (IdenticalStreamFileObject)
211 Map = IdenticalStreamFileObject->SectionObjectPointer->SharedCacheMap;
212 if (Map)
213 {
214 DPRINT1("Linking SFO %x to previous SFO %x through cache map %x #\n",
215 FileObject,
216 IdenticalStreamFileObject,
217 Map);
218 }
219 }
220 /* We still don't have a shared cache map. We need to create one. */
221 if (!Map)
222 {
223 DPRINT("Initializing file object for (%p) %wZ\n",
224 FileObject,
225 &FileObject->FileName);
226
227 Map = ExAllocatePool(NonPagedPool, sizeof(NOCC_CACHE_MAP));
228 FileObject->SectionObjectPointer->SharedCacheMap = Map;
229 Map->FileSizes = *FileSizes;
230 Map->LazyContext = LazyWriteContext;
231 Map->ReadAheadGranularity = PAGE_SIZE;
232 RtlCopyMemory(&Map->Callbacks, Callbacks, sizeof(*Callbacks));
233
234 /* For now ... */
235 DPRINT("FileSizes->ValidDataLength %I64x\n",
236 FileSizes->ValidDataLength.QuadPart);
237
238 InitializeListHead(&Map->AssociatedBcb);
239 InitializeListHead(&Map->PrivateCacheMaps);
240 InsertTailList(&CcpAllSharedCacheMaps, &Map->Entry);
241 DPRINT("New Map %p\n", Map);
242 }
243 /* We don't have a private cache map. Link it with the shared cache map
244 to serve as a held reference. When the list in the shared cache map
245 is empty, we know we can delete it. */
246 if (!PrivateCacheMap)
247 {
248 PrivateCacheMap = ExAllocatePool(NonPagedPool,
249 sizeof(*PrivateCacheMap));
250
251 FileObject->PrivateCacheMap = PrivateCacheMap;
252 PrivateCacheMap->FileObject = FileObject;
253 ObReferenceObject(PrivateCacheMap->FileObject);
254 }
255
256 PrivateCacheMap->Map = Map;
257 InsertTailList(&Map->PrivateCacheMaps, &PrivateCacheMap->ListEntry);
258
259 CcpUnlock();
260 }
261
262 /*
263
264 This function is used by NewCC's MM to determine whether any section objects
265 for a given file are not cache sections. If that's true, we're not allowed
266 to resize the file, although nothing actually prevents us from doing ;-)
267
268 */
269
270 ULONG
271 NTAPI
CcpCountCacheSections(IN PNOCC_CACHE_MAP Map)272 CcpCountCacheSections(IN PNOCC_CACHE_MAP Map)
273 {
274 PLIST_ENTRY Entry;
275 ULONG Count;
276
277 for (Count = 0, Entry = Map->AssociatedBcb.Flink;
278 Entry != &Map->AssociatedBcb;
279 Entry = Entry->Flink, Count++);
280
281 return Count;
282 }
283
284 BOOLEAN
285 NTAPI
CcUninitializeCacheMap(IN PFILE_OBJECT FileObject,IN OPTIONAL PLARGE_INTEGER TruncateSize,IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent)286 CcUninitializeCacheMap(IN PFILE_OBJECT FileObject,
287 IN OPTIONAL PLARGE_INTEGER TruncateSize,
288 IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent)
289 {
290 BOOLEAN LastMap = FALSE;
291 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
292 PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap;
293
294 DPRINT("Uninitializing file object for %wZ SectionObjectPointer %x\n",
295 &FileObject->FileName,
296 FileObject->SectionObjectPointer);
297
298 ASSERT(UninitializeEvent == NULL);
299
300 /* It may not be strictly necessary to flush here, but we do just for
301 kicks. */
302 if (Map)
303 CcpFlushCache(Map, NULL, 0, NULL, FALSE);
304
305 CcpLock();
306 /* We have a private cache map, so we've been initialized and haven't been
307 * uninitialized. */
308 if (PrivateCacheMap)
309 {
310 ASSERT(!Map || Map == PrivateCacheMap->Map);
311 ASSERT(PrivateCacheMap->FileObject == FileObject);
312
313 RemoveEntryList(&PrivateCacheMap->ListEntry);
314 /* That was the last private cache map. It's time to delete all
315 cache stripes and all aspects of caching on the file. */
316 if (IsListEmpty(&PrivateCacheMap->Map->PrivateCacheMaps))
317 {
318 /* Get rid of all the cache stripes. */
319 while (!IsListEmpty(&PrivateCacheMap->Map->AssociatedBcb))
320 {
321 PNOCC_BCB Bcb = CONTAINING_RECORD(PrivateCacheMap->Map->AssociatedBcb.Flink,
322 NOCC_BCB,
323 ThisFileList);
324
325 DPRINT("Evicting cache stripe #%x\n", Bcb - CcCacheSections);
326 Bcb->RefCount = 1;
327 CcpDereferenceCache(Bcb - CcCacheSections, TRUE);
328 }
329 RemoveEntryList(&PrivateCacheMap->Map->Entry);
330 ExFreePool(PrivateCacheMap->Map);
331 FileObject->SectionObjectPointer->SharedCacheMap = NULL;
332 LastMap = TRUE;
333 }
334 ObDereferenceObject(PrivateCacheMap->FileObject);
335 FileObject->PrivateCacheMap = NULL;
336 ExFreePool(PrivateCacheMap);
337 }
338 CcpUnlock();
339
340 DPRINT("Uninit complete\n");
341
342 /* The return from CcUninitializeCacheMap means that 'caching was stopped'. */
343 return LastMap;
344 }
345
346 /*
347
348 CcSetFileSizes is used to tell the cache manager that the file changed
349 size. In our case, we use the internal Mm method MmExtendCacheSection
350 to notify Mm that our section potentially changed size, which may mean
351 truncating off data.
352
353 */
354 VOID
355 NTAPI
CcSetFileSizes(IN PFILE_OBJECT FileObject,IN PCC_FILE_SIZES FileSizes)356 CcSetFileSizes(IN PFILE_OBJECT FileObject,
357 IN PCC_FILE_SIZES FileSizes)
358 {
359 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
360 PNOCC_BCB Bcb;
361
362 if (!Map) return;
363 Map->FileSizes = *FileSizes;
364 Bcb = Map->AssociatedBcb.Flink == &Map->AssociatedBcb ?
365 NULL : CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
366 if (!Bcb) return;
367 MmExtendCacheSection(Bcb->SectionObject, &FileSizes->FileSize, FALSE);
368 DPRINT("FileSizes->FileSize %x\n", FileSizes->FileSize.LowPart);
369 DPRINT("FileSizes->AllocationSize %x\n", FileSizes->AllocationSize.LowPart);
370 DPRINT("FileSizes->ValidDataLength %x\n", FileSizes->ValidDataLength.LowPart);
371 }
372
373 BOOLEAN
374 NTAPI
CcGetFileSizes(IN PFILE_OBJECT FileObject,IN PCC_FILE_SIZES FileSizes)375 CcGetFileSizes(IN PFILE_OBJECT FileObject,
376 IN PCC_FILE_SIZES FileSizes)
377 {
378 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
379 if (!Map) return FALSE;
380 *FileSizes = Map->FileSizes;
381 return TRUE;
382 }
383
384 BOOLEAN
385 NTAPI
CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,IN OPTIONAL PLARGE_INTEGER FileOffset,IN ULONG Length,IN BOOLEAN UninitializeCacheMaps)386 CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
387 IN OPTIONAL PLARGE_INTEGER FileOffset,
388 IN ULONG Length,
389 IN BOOLEAN UninitializeCacheMaps)
390 {
391 PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap;
392 if (!Map) return TRUE;
393 CcpFlushCache(Map, NULL, 0, NULL, TRUE);
394 return TRUE;
395 }
396
397 VOID
398 NTAPI
CcSetDirtyPageThreshold(IN PFILE_OBJECT FileObject,IN ULONG DirtyPageThreshold)399 CcSetDirtyPageThreshold(IN PFILE_OBJECT FileObject,
400 IN ULONG DirtyPageThreshold)
401 {
402 UNIMPLEMENTED_DBGBREAK();
403 }
404
405 /*
406
407 This could be implemented much more intelligently by mapping instances
408 of a CoW zero page into the affected regions. We just RtlZeroMemory
409 for now.
410
411 */
412 BOOLEAN
413 NTAPI
CcZeroData(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER StartOffset,IN PLARGE_INTEGER EndOffset,IN BOOLEAN Wait)414 CcZeroData(IN PFILE_OBJECT FileObject,
415 IN PLARGE_INTEGER StartOffset,
416 IN PLARGE_INTEGER EndOffset,
417 IN BOOLEAN Wait)
418 {
419 PNOCC_BCB Bcb = NULL;
420 PLIST_ENTRY ListEntry = NULL;
421 LARGE_INTEGER LowerBound = *StartOffset;
422 LARGE_INTEGER UpperBound = *EndOffset;
423 LARGE_INTEGER Target, End;
424 PVOID PinnedBcb, PinnedBuffer;
425 PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
426
427 DPRINT("S %I64x E %I64x\n",
428 StartOffset->QuadPart,
429 EndOffset->QuadPart);
430
431 if (!Map)
432 {
433 NTSTATUS Status;
434 IO_STATUS_BLOCK IOSB;
435 PCHAR ZeroBuf = ExAllocatePool(PagedPool, PAGE_SIZE);
436 ULONG ToWrite;
437
438 if (!ZeroBuf) RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
439 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE);
440 RtlZeroMemory(ZeroBuf, PAGE_SIZE);
441
442 Target.QuadPart = PAGE_ROUND_DOWN(LowerBound.QuadPart);
443 End.QuadPart = PAGE_ROUND_UP(UpperBound.QuadPart);
444
445 // Handle leading page
446 if (LowerBound.QuadPart != Target.QuadPart)
447 {
448 ToWrite = MIN(UpperBound.QuadPart - LowerBound.QuadPart,
449 (PAGE_SIZE - LowerBound.QuadPart) & (PAGE_SIZE - 1));
450
451 DPRINT("Zero last half %I64x %lx\n",
452 Target.QuadPart,
453 ToWrite);
454
455 Status = MiSimpleRead(FileObject,
456 &Target,
457 ZeroBuf,
458 PAGE_SIZE,
459 TRUE,
460 &IOSB);
461
462 if (!NT_SUCCESS(Status))
463 {
464 ExFreePool(ZeroBuf);
465 RtlRaiseStatus(Status);
466 }
467
468 DPRINT1("RtlZeroMemory(%p, %lx)\n",
469 ZeroBuf + LowerBound.QuadPart - Target.QuadPart,
470 ToWrite);
471
472 RtlZeroMemory(ZeroBuf + LowerBound.QuadPart - Target.QuadPart,
473 ToWrite);
474
475 Status = MiSimpleWrite(FileObject,
476 &Target,
477 ZeroBuf,
478 MIN(PAGE_SIZE,
479 UpperBound.QuadPart-Target.QuadPart),
480 &IOSB);
481
482 if (!NT_SUCCESS(Status))
483 {
484 ExFreePool(ZeroBuf);
485 RtlRaiseStatus(Status);
486 }
487 Target.QuadPart += PAGE_SIZE;
488 }
489
490 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE);
491 RtlZeroMemory(ZeroBuf, PAGE_SIZE);
492
493 while (UpperBound.QuadPart - Target.QuadPart > PAGE_SIZE)
494 {
495 DPRINT("Zero full page %I64x\n",
496 Target.QuadPart);
497
498 Status = MiSimpleWrite(FileObject,
499 &Target,
500 ZeroBuf,
501 PAGE_SIZE,
502 &IOSB);
503
504 if (!NT_SUCCESS(Status))
505 {
506 ExFreePool(ZeroBuf);
507 RtlRaiseStatus(Status);
508 }
509 Target.QuadPart += PAGE_SIZE;
510 }
511
512 if (UpperBound.QuadPart > Target.QuadPart)
513 {
514 ToWrite = UpperBound.QuadPart - Target.QuadPart;
515 DPRINT("Zero first half %I64x %lx\n",
516 Target.QuadPart,
517 ToWrite);
518
519 Status = MiSimpleRead(FileObject,
520 &Target,
521 ZeroBuf,
522 PAGE_SIZE,
523 TRUE,
524 &IOSB);
525
526 if (!NT_SUCCESS(Status))
527 {
528 ExFreePool(ZeroBuf);
529 RtlRaiseStatus(Status);
530 }
531 DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, ToWrite);
532 RtlZeroMemory(ZeroBuf, ToWrite);
533 Status = MiSimpleWrite(FileObject,
534 &Target,
535 ZeroBuf,
536 MIN(PAGE_SIZE,
537 UpperBound.QuadPart-Target.QuadPart),
538 &IOSB);
539 if (!NT_SUCCESS(Status))
540 {
541 ExFreePool(ZeroBuf);
542 RtlRaiseStatus(Status);
543 }
544 Target.QuadPart += PAGE_SIZE;
545 }
546
547 ExFreePool(ZeroBuf);
548 return TRUE;
549 }
550
551 CcpLock();
552 ListEntry = Map->AssociatedBcb.Flink;
553
554 while (ListEntry != &Map->AssociatedBcb)
555 {
556 Bcb = CONTAINING_RECORD(ListEntry, NOCC_BCB, ThisFileList);
557 CcpReferenceCache(Bcb - CcCacheSections);
558
559 if (Bcb->FileOffset.QuadPart + Bcb->Length >= LowerBound.QuadPart &&
560 Bcb->FileOffset.QuadPart < UpperBound.QuadPart)
561 {
562 DPRINT("Bcb #%x (@%I64x)\n",
563 Bcb - CcCacheSections,
564 Bcb->FileOffset.QuadPart);
565
566 Target.QuadPart = MAX(Bcb->FileOffset.QuadPart,
567 LowerBound.QuadPart);
568
569 End.QuadPart = MIN(Map->FileSizes.ValidDataLength.QuadPart,
570 UpperBound.QuadPart);
571
572 End.QuadPart = MIN(End.QuadPart,
573 Bcb->FileOffset.QuadPart + Bcb->Length);
574
575 CcpUnlock();
576
577 if (!CcPreparePinWrite(FileObject,
578 &Target,
579 End.QuadPart - Target.QuadPart,
580 TRUE,
581 Wait,
582 &PinnedBcb,
583 &PinnedBuffer))
584 {
585 return FALSE;
586 }
587
588 ASSERT(PinnedBcb == Bcb);
589
590 CcpLock();
591 ListEntry = ListEntry->Flink;
592 /* Return from pin state */
593 CcpUnpinData(PinnedBcb, TRUE);
594 }
595
596 CcpUnpinData(Bcb, TRUE);
597 }
598
599 CcpUnlock();
600
601 return TRUE;
602 }
603
604 PFILE_OBJECT
605 NTAPI
CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointer)606 CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointer)
607 {
608 PFILE_OBJECT Result = NULL;
609 PNOCC_CACHE_MAP Map = SectionObjectPointer->SharedCacheMap;
610 CcpLock();
611 if (!IsListEmpty(&Map->AssociatedBcb))
612 {
613 PNOCC_BCB Bcb = CONTAINING_RECORD(Map->AssociatedBcb.Flink,
614 NOCC_BCB,
615 ThisFileList);
616
617 Result = MmGetFileObjectForSection((PROS_SECTION_OBJECT)Bcb->SectionObject);
618 }
619 CcpUnlock();
620 return Result;
621 }
622
623 PFILE_OBJECT
624 NTAPI
CcGetFileObjectFromBcb(PVOID Bcb)625 CcGetFileObjectFromBcb(PVOID Bcb)
626 {
627 PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
628 DPRINT("BCB #%x\n", RealBcb - CcCacheSections);
629 return MmGetFileObjectForSection((PROS_SECTION_OBJECT)RealBcb->SectionObject);
630 }
631
632 /* EOF */
633