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
40 CcInitCacheZeroPage(VOID
)
44 Status
= MmRequestPageMemoryConsumer(MC_SYSTEM
, TRUE
, &CcZeroPage
);
45 if (!NT_SUCCESS(Status
))
47 DbgPrint("Can't allocate CcZeroPage.\n");
48 KeBugCheck(CACHE_MANAGER
);
50 MiZeroPhysicalPage(CcZeroPage
);
55 ReadCacheSegmentChain(PBCB Bcb
, ULONG ReadOffset
, ULONG Length
,
59 PCACHE_SEGMENT current
;
60 PCACHE_SEGMENT previous
;
62 LARGE_INTEGER SegOffset
;
68 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_RW_LENGTH
));
70 Status
= CcRosGetCacheSegmentChain(Bcb
, ReadOffset
, Length
, &head
);
71 if (!NT_SUCCESS(Status
))
76 while (current
!= NULL
)
79 * If the current segment is valid then copy it into the
84 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
85 memcpy(Buffer
, current
->BaseAddress
, TempLength
);
87 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
89 Length
= Length
- TempLength
;
91 current
= current
->NextInChain
;
92 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
95 * Otherwise read in as much as we can.
99 PCACHE_SEGMENT current2
;
102 PPFN_NUMBER MdlPages
;
105 * Count the maximum number of bytes we could read starting
106 * from the current segment.
110 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
112 current2
= current2
->NextInChain
;
113 current_size
+= Bcb
->CacheSegmentSize
;
117 * Create an MDL which contains all their pages.
119 MmInitializeMdl(Mdl
, NULL
, current_size
);
120 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
123 MdlPages
= (PPFN_NUMBER
)(Mdl
+ 1);
124 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
126 PVOID address
= current2
->BaseAddress
;
127 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++, address
= RVA(address
, PAGE_SIZE
))
129 *MdlPages
++ = MmGetPfnForProcess(NULL
, address
);
131 current2
= current2
->NextInChain
;
132 current_size
+= Bcb
->CacheSegmentSize
;
136 * Read in the information.
138 SegOffset
.QuadPart
= current
->FileOffset
;
139 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
140 Status
= IoPageRead(Bcb
->FileObject
,
145 if (Status
== STATUS_PENDING
)
147 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
148 Status
= Iosb
.Status
;
150 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
152 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
154 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
156 while (current
!= NULL
)
159 current
= current
->NextInChain
;
160 CcRosReleaseCacheSegment(Bcb
, previous
, FALSE
, FALSE
, FALSE
);
165 while (current
!= NULL
&& !current
->Valid
&& current_size
< MAX_RW_LENGTH
)
168 current
= current
->NextInChain
;
169 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
170 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
172 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
174 Length
= Length
- TempLength
;
175 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
176 current_size
+= Bcb
->CacheSegmentSize
;
180 return(STATUS_SUCCESS
);
185 ReadCacheSegment(PCACHE_SEGMENT CacheSeg
)
190 LARGE_INTEGER SegOffset
;
191 IO_STATUS_BLOCK IoStatus
;
194 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
195 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
196 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
198 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
200 Mdl
= _alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
201 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
202 MmBuildMdlForNonPagedPool(Mdl
);
203 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
204 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
205 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, & Event
, &IoStatus
);
206 if (Status
== STATUS_PENDING
)
208 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
209 Status
= IoStatus
.Status
;
212 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
214 DPRINT1("IoPageRead failed, Status %x\n", Status
);
217 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
219 memset ((char*)CacheSeg
->BaseAddress
+ Size
, 0,
220 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
222 return STATUS_SUCCESS
;
227 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
232 IO_STATUS_BLOCK IoStatus
;
233 LARGE_INTEGER SegOffset
;
236 CacheSeg
->Dirty
= FALSE
;
237 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
238 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
239 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
241 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
244 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
245 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
251 MmGetPfnForProcess(NULL
, (PVOID
)((ULONG_PTR
)CacheSeg
->BaseAddress
+ (i
<< PAGE_SHIFT
)));
252 } while (++i
< (Size
>> PAGE_SHIFT
));
254 Mdl
= _alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
255 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
256 MmBuildMdlForNonPagedPool(Mdl
);
257 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
258 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
259 Status
= IoSynchronousPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
260 if (Status
== STATUS_PENDING
)
262 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
263 Status
= IoStatus
.Status
;
265 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
267 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
268 CacheSeg
->Dirty
= TRUE
;
271 return(STATUS_SUCCESS
);
280 IN PFILE_OBJECT FileObject
,
281 IN ULONG BytesToWrite
,
294 CcCopyRead (IN PFILE_OBJECT FileObject
,
295 IN PLARGE_INTEGER FileOffset
,
299 OUT PIO_STATUS_BLOCK IoStatus
)
303 NTSTATUS Status
= STATUS_SUCCESS
;
305 PCACHE_SEGMENT CacheSeg
;
307 ULONG ReadLength
= 0;
310 PLIST_ENTRY current_entry
;
311 PCACHE_SEGMENT current
;
313 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
314 "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n",
315 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
318 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
319 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
321 DPRINT("AllocationSize %d, FileSize %d\n",
322 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
323 (ULONG
)Bcb
->FileSize
.QuadPart
);
326 * Check for the nowait case that all the cache segments that would
327 * cover this read are in memory.
331 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
332 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
333 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
335 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
336 BcbSegmentListEntry
);
337 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
338 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
340 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
341 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
342 IoStatus
->Information
= 0;
345 current_entry
= current_entry
->Flink
;
347 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
350 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
353 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
354 Status
= CcRosRequestCacheSegment(Bcb
,
355 ROUND_DOWN(ReadOffset
,
356 Bcb
->CacheSegmentSize
),
357 &BaseAddress
, &Valid
, &CacheSeg
);
358 if (!NT_SUCCESS(Status
))
360 IoStatus
->Information
= 0;
361 IoStatus
->Status
= Status
;
362 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
367 Status
= ReadCacheSegment(CacheSeg
);
368 if (!NT_SUCCESS(Status
))
370 IoStatus
->Information
= 0;
371 IoStatus
->Status
= Status
;
372 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
376 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
378 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
379 ReadLength
+= TempLength
;
380 Length
-= TempLength
;
381 ReadOffset
+= TempLength
;
382 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
386 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
387 Status
= ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
388 if (!NT_SUCCESS(Status
))
390 IoStatus
->Information
= 0;
391 IoStatus
->Status
= Status
;
392 DPRINT1("ReadCacheSegmentChain failed, Status %x\n", Status
);
396 ReadLength
+= TempLength
;
397 Length
-= TempLength
;
398 ReadOffset
+= TempLength
;
400 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
402 IoStatus
->Status
= STATUS_SUCCESS
;
403 IoStatus
->Information
= ReadLength
;
404 DPRINT("CcCopyRead O.K.\n");
412 CcCopyWrite (IN PFILE_OBJECT FileObject
,
413 IN PLARGE_INTEGER FileOffset
,
422 PLIST_ENTRY current_entry
;
423 PCACHE_SEGMENT CacheSeg
;
428 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
429 "Length %d, Wait %d, Buffer 0x%p)\n",
430 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
432 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
433 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
437 /* testing, if the requested datas are available */
438 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
439 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
440 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
442 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
443 BcbSegmentListEntry
);
444 if (!CacheSeg
->Valid
)
446 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
447 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
448 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
449 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
450 Bcb
->CacheSegmentSize
))
452 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
453 /* datas not available */
457 current_entry
= current_entry
->Flink
;
459 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
462 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
466 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
467 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
468 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
469 &BaseAddress
, &Valid
, &CacheSeg
);
470 if (!NT_SUCCESS(Status
))
476 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
481 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
483 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
485 Length
-= TempLength
;
486 WriteOffset
+= TempLength
;
488 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
493 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
494 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
495 &BaseAddress
, &Valid
, &CacheSeg
);
496 if (!NT_SUCCESS(Status
))
500 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
502 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
504 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
508 memcpy (BaseAddress
, Buffer
, TempLength
);
509 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
510 Length
-= TempLength
;
511 WriteOffset
+= TempLength
;
513 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
524 IN PFILE_OBJECT FileObject
,
525 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
528 IN ULONG BytesToWrite
,
541 IN PFILE_OBJECT FileObject
,
546 OUT PIO_STATUS_BLOCK IoStatus
557 IN PFILE_OBJECT FileObject
,
570 CcWaitForCurrentLazyWriterActivity (
575 return STATUS_NOT_IMPLEMENTED
;
582 CcZeroData (IN PFILE_OBJECT FileObject
,
583 IN PLARGE_INTEGER StartOffset
,
584 IN PLARGE_INTEGER EndOffset
,
588 LARGE_INTEGER WriteOffset
;
593 IO_STATUS_BLOCK Iosb
;
596 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
597 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
600 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
601 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
603 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
605 /* File is not cached */
607 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
611 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
613 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
617 CurrentLength
= Length
;
619 MmInitializeMdl(Mdl
, (PVOID
)(ULONG_PTR
)WriteOffset
.QuadPart
, CurrentLength
);
620 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
621 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
623 ((PPFN_NUMBER
)(Mdl
+ 1))[i
] = CcZeroPage
;
625 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
626 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
627 if (Status
== STATUS_PENDING
)
629 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
630 Status
= Iosb
.Status
;
632 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
633 if (!NT_SUCCESS(Status
))
637 WriteOffset
.QuadPart
+= CurrentLength
;
638 Length
-= CurrentLength
;
646 PLIST_ENTRY current_entry
;
647 PCACHE_SEGMENT CacheSeg
, current
, previous
;
650 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
653 /* testing, if the requested datas are available */
654 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
655 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
656 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
658 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
659 BcbSegmentListEntry
);
660 if (!CacheSeg
->Valid
)
662 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
663 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
664 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
665 WriteOffset
.u
.LowPart
+ Length
<=
666 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
668 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
669 /* datas not available */
673 current_entry
= current_entry
->Flink
;
675 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
680 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
681 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
683 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
687 CurrentLength
= Length
;
689 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
690 Offset
+ CurrentLength
, &CacheSeg
);
691 if (!NT_SUCCESS(Status
))
697 while (current
!= NULL
)
699 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
701 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
705 /* read the segment */
706 Status
= ReadCacheSegment(current
);
707 if (!NT_SUCCESS(Status
))
709 DPRINT1("ReadCacheSegment failed, status %x\n",
713 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
717 TempLength
= Bcb
->CacheSegmentSize
;
719 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
721 WriteOffset
.QuadPart
+= TempLength
;
722 CurrentLength
-= TempLength
;
723 Length
-= TempLength
;
725 current
= current
->NextInChain
;
729 while (current
!= NULL
)
732 current
= current
->NextInChain
;
733 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);