2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cc/copy.c
5 * PURPOSE: Implements cache managers copy interface
10 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 static PFN_NUMBER CcZeroPage
= 0;
20 #define MAX_ZERO_LENGTH (256 * 1024)
21 #define MAX_RW_LENGTH (256 * 1024)
23 ULONG CcFastMdlReadWait
;
24 ULONG CcFastMdlReadNotPossible
;
25 ULONG CcFastReadNotPossible
;
27 ULONG CcFastReadNoWait
;
28 ULONG CcFastReadResourceMiss
;
30 /* FUNCTIONS *****************************************************************/
35 IN PFN_NUMBER PageFrameIndex
45 MI_SET_USAGE(MI_USAGE_CACHE
);
46 //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
47 Status
= MmRequestPageMemoryConsumer(MC_SYSTEM
, TRUE
, &CcZeroPage
);
48 if (!NT_SUCCESS(Status
))
50 DbgPrint("Can't allocate CcZeroPage.\n");
51 KeBugCheck(CACHE_MANAGER
);
53 MiZeroPhysicalPage(CcZeroPage
);
58 ReadCacheSegmentChain (
65 PCACHE_SEGMENT current
;
66 PCACHE_SEGMENT previous
;
68 LARGE_INTEGER SegOffset
;
74 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_RW_LENGTH
));
76 Status
= CcRosGetCacheSegmentChain(Bcb
, ReadOffset
, Length
, &head
);
77 if (!NT_SUCCESS(Status
))
82 while (current
!= NULL
)
85 * If the current segment is valid then copy it into the
90 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
91 memcpy(Buffer
, current
->BaseAddress
, TempLength
);
93 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
95 Length
= Length
- TempLength
;
97 current
= current
->NextInChain
;
98 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
101 * Otherwise read in as much as we can.
105 PCACHE_SEGMENT current2
;
108 PPFN_NUMBER MdlPages
;
111 * Count the maximum number of bytes we could read starting
112 * from the current segment.
116 while ((current2
!= NULL
) && !current2
->Valid
&& (current_size
< MAX_RW_LENGTH
))
118 current2
= current2
->NextInChain
;
119 current_size
+= Bcb
->CacheSegmentSize
;
123 * Create an MDL which contains all their pages.
125 MmInitializeMdl(Mdl
, NULL
, current_size
);
126 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
129 MdlPages
= (PPFN_NUMBER
)(Mdl
+ 1);
130 while ((current2
!= NULL
) && !current2
->Valid
&& (current_size
< MAX_RW_LENGTH
))
132 PVOID address
= current2
->BaseAddress
;
133 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++, address
= RVA(address
, PAGE_SIZE
))
135 *MdlPages
++ = MmGetPfnForProcess(NULL
, address
);
137 current2
= current2
->NextInChain
;
138 current_size
+= Bcb
->CacheSegmentSize
;
142 * Read in the information.
144 SegOffset
.QuadPart
= current
->FileOffset
;
145 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
146 Status
= IoPageRead(Bcb
->FileObject
,
151 if (Status
== STATUS_PENDING
)
153 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
154 Status
= Iosb
.Status
;
156 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
158 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
160 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
162 while (current
!= NULL
)
165 current
= current
->NextInChain
;
166 CcRosReleaseCacheSegment(Bcb
, previous
, FALSE
, FALSE
, FALSE
);
171 while (current
!= NULL
&& !current
->Valid
&& current_size
< MAX_RW_LENGTH
)
174 current
= current
->NextInChain
;
175 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
176 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
178 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
180 Length
= Length
- TempLength
;
181 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
182 current_size
+= Bcb
->CacheSegmentSize
;
186 return STATUS_SUCCESS
;
192 PCACHE_SEGMENT CacheSeg
)
197 LARGE_INTEGER SegOffset
;
198 IO_STATUS_BLOCK IoStatus
;
201 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
202 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
203 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
205 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
208 Mdl
= IoAllocateMdl(CacheSeg
->BaseAddress
, Size
, FALSE
, FALSE
, NULL
);
211 return STATUS_INSUFFICIENT_RESOURCES
;
214 MmBuildMdlForNonPagedPool(Mdl
);
215 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
216 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
217 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
218 if (Status
== STATUS_PENDING
)
220 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
221 Status
= IoStatus
.Status
;
226 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
228 DPRINT1("IoPageRead failed, Status %x\n", Status
);
232 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
234 RtlZeroMemory((char*)CacheSeg
->BaseAddress
+ Size
,
235 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
238 return STATUS_SUCCESS
;
244 PCACHE_SEGMENT CacheSeg
)
249 IO_STATUS_BLOCK IoStatus
;
250 LARGE_INTEGER SegOffset
;
253 CacheSeg
->Dirty
= FALSE
;
254 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
255 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
256 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
258 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
261 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
262 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
268 MmGetPfnForProcess(NULL
, (PVOID
)((ULONG_PTR
)CacheSeg
->BaseAddress
+ (i
<< PAGE_SHIFT
)));
269 } while (++i
< (Size
>> PAGE_SHIFT
));
272 Mdl
= IoAllocateMdl(CacheSeg
->BaseAddress
, Size
, FALSE
, FALSE
, NULL
);
275 return STATUS_INSUFFICIENT_RESOURCES
;
277 MmBuildMdlForNonPagedPool(Mdl
);
278 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
279 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
280 Status
= IoSynchronousPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
281 if (Status
== STATUS_PENDING
)
283 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
284 Status
= IoStatus
.Status
;
287 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
289 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
290 CacheSeg
->Dirty
= TRUE
;
294 return STATUS_SUCCESS
;
304 IN PFILE_OBJECT FileObject
,
305 IN ULONG BytesToWrite
,
320 IN PFILE_OBJECT FileObject
,
321 IN PLARGE_INTEGER FileOffset
,
325 OUT PIO_STATUS_BLOCK IoStatus
)
329 NTSTATUS Status
= STATUS_SUCCESS
;
331 PCACHE_SEGMENT CacheSeg
;
333 ULONG ReadLength
= 0;
336 PLIST_ENTRY current_entry
;
337 PCACHE_SEGMENT current
;
339 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
340 "Length %lu, Wait %u, Buffer 0x%p, IoStatus 0x%p)\n",
341 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
344 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
345 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
347 DPRINT("AllocationSize %I64d, FileSize %I64d\n",
348 Bcb
->AllocationSize
.QuadPart
,
349 Bcb
->FileSize
.QuadPart
);
352 * Check for the nowait case that all the cache segments that would
353 * cover this read are in memory.
357 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
358 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
359 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
361 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
362 BcbSegmentListEntry
);
363 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
364 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
366 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
367 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
368 IoStatus
->Information
= 0;
371 current_entry
= current_entry
->Flink
;
373 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
376 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
379 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
380 Status
= CcRosRequestCacheSegment(Bcb
,
381 ROUND_DOWN(ReadOffset
,
382 Bcb
->CacheSegmentSize
),
383 &BaseAddress
, &Valid
, &CacheSeg
);
384 if (!NT_SUCCESS(Status
))
386 IoStatus
->Information
= 0;
387 IoStatus
->Status
= Status
;
388 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
393 Status
= ReadCacheSegment(CacheSeg
);
394 if (!NT_SUCCESS(Status
))
396 IoStatus
->Information
= 0;
397 IoStatus
->Status
= Status
;
398 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
402 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
404 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
405 ReadLength
+= TempLength
;
406 Length
-= TempLength
;
407 ReadOffset
+= TempLength
;
408 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
413 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
414 Status
= ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
415 if (!NT_SUCCESS(Status
))
417 IoStatus
->Information
= 0;
418 IoStatus
->Status
= Status
;
419 DPRINT("ReadCacheSegmentChain failed, Status %x\n", Status
);
423 ReadLength
+= TempLength
;
424 Length
-= TempLength
;
425 ReadOffset
+= TempLength
;
427 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
430 IoStatus
->Status
= STATUS_SUCCESS
;
431 IoStatus
->Information
= ReadLength
;
432 DPRINT("CcCopyRead O.K.\n");
442 IN PFILE_OBJECT FileObject
,
443 IN PLARGE_INTEGER FileOffset
,
452 PLIST_ENTRY current_entry
;
453 PCACHE_SEGMENT CacheSeg
;
458 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
459 "Length %lu, Wait %u, Buffer 0x%p)\n",
460 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
462 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
463 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
467 /* testing, if the requested datas are available */
468 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
469 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
470 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
472 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
473 BcbSegmentListEntry
);
474 if (!CacheSeg
->Valid
)
476 if (((WriteOffset
>= CacheSeg
->FileOffset
) &&
477 (WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
478 || ((WriteOffset
+ Length
> CacheSeg
->FileOffset
) &&
479 (WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
480 Bcb
->CacheSegmentSize
)))
482 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
483 /* datas not available */
487 current_entry
= current_entry
->Flink
;
489 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
492 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
496 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
497 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
498 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
499 &BaseAddress
, &Valid
, &CacheSeg
);
500 if (!NT_SUCCESS(Status
))
506 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
511 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
513 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
515 Length
-= TempLength
;
516 WriteOffset
+= TempLength
;
518 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
523 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
524 Status
= CcRosRequestCacheSegment(Bcb
,
529 if (!NT_SUCCESS(Status
))
533 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
535 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
537 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
541 memcpy (BaseAddress
, Buffer
, TempLength
);
542 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
543 Length
-= TempLength
;
544 WriteOffset
+= TempLength
;
546 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
557 IN PFILE_OBJECT FileObject
,
558 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
561 IN ULONG BytesToWrite
,
573 IN PFILE_OBJECT FileObject
,
578 OUT PIO_STATUS_BLOCK IoStatus
)
588 IN PFILE_OBJECT FileObject
,
601 CcWaitForCurrentLazyWriterActivity (
605 return STATUS_NOT_IMPLEMENTED
;
614 IN PFILE_OBJECT FileObject
,
615 IN PLARGE_INTEGER StartOffset
,
616 IN PLARGE_INTEGER EndOffset
,
620 LARGE_INTEGER WriteOffset
;
625 IO_STATUS_BLOCK Iosb
;
628 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
629 "Wait %u)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
632 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
633 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
635 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
637 /* File is not cached */
639 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
643 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
645 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
649 CurrentLength
= Length
;
651 MmInitializeMdl(Mdl
, (PVOID
)(ULONG_PTR
)WriteOffset
.QuadPart
, CurrentLength
);
652 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
653 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
655 ((PPFN_NUMBER
)(Mdl
+ 1))[i
] = CcZeroPage
;
657 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
658 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
659 if (Status
== STATUS_PENDING
)
661 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
662 Status
= Iosb
.Status
;
664 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
666 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
668 if (!NT_SUCCESS(Status
))
672 WriteOffset
.QuadPart
+= CurrentLength
;
673 Length
-= CurrentLength
;
681 PLIST_ENTRY current_entry
;
682 PCACHE_SEGMENT CacheSeg
, current
, previous
;
685 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
688 /* testing, if the requested datas are available */
689 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
690 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
691 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
693 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
694 BcbSegmentListEntry
);
695 if (!CacheSeg
->Valid
)
697 if (((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
) &&
698 (WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
699 || ((WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
) &&
700 (WriteOffset
.u
.LowPart
+ Length
<=
701 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)))
703 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
704 /* datas not available */
708 current_entry
= current_entry
->Flink
;
710 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
716 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
717 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
719 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
723 CurrentLength
= Length
;
725 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
726 Offset
+ CurrentLength
, &CacheSeg
);
727 if (!NT_SUCCESS(Status
))
733 while (current
!= NULL
)
735 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
737 (Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
))
741 /* read the segment */
742 Status
= ReadCacheSegment(current
);
743 if (!NT_SUCCESS(Status
))
745 DPRINT1("ReadCacheSegment failed, status %x\n",
749 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
753 TempLength
= Bcb
->CacheSegmentSize
;
755 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
757 WriteOffset
.QuadPart
+= TempLength
;
758 CurrentLength
-= TempLength
;
759 Length
-= TempLength
;
761 current
= current
->NextInChain
;
765 while (current
!= NULL
)
768 current
= current
->NextInChain
;
769 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);