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 MI_SET_USAGE(MI_USAGE_CACHE
);
45 //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
46 Status
= MmRequestPageMemoryConsumer(MC_SYSTEM
, TRUE
, &CcZeroPage
);
47 if (!NT_SUCCESS(Status
))
49 DbgPrint("Can't allocate CcZeroPage.\n");
50 KeBugCheck(CACHE_MANAGER
);
52 MiZeroPhysicalPage(CcZeroPage
);
57 ReadCacheSegmentChain(PBCB Bcb
, ULONG ReadOffset
, ULONG Length
,
61 PCACHE_SEGMENT current
;
62 PCACHE_SEGMENT previous
;
64 LARGE_INTEGER SegOffset
;
70 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_RW_LENGTH
));
72 Status
= CcRosGetCacheSegmentChain(Bcb
, ReadOffset
, Length
, &head
);
73 if (!NT_SUCCESS(Status
))
78 while (current
!= NULL
)
81 * If the current segment is valid then copy it into the
86 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
87 memcpy(Buffer
, current
->BaseAddress
, TempLength
);
89 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
91 Length
= Length
- TempLength
;
93 current
= current
->NextInChain
;
94 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
97 * Otherwise read in as much as we can.
101 PCACHE_SEGMENT current2
;
104 PPFN_NUMBER MdlPages
;
107 * Count the maximum number of bytes we could read starting
108 * from the current segment.
112 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
114 current2
= current2
->NextInChain
;
115 current_size
+= Bcb
->CacheSegmentSize
;
119 * Create an MDL which contains all their pages.
121 MmInitializeMdl(Mdl
, NULL
, current_size
);
122 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
125 MdlPages
= (PPFN_NUMBER
)(Mdl
+ 1);
126 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
128 PVOID address
= current2
->BaseAddress
;
129 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++, address
= RVA(address
, PAGE_SIZE
))
131 *MdlPages
++ = MmGetPfnForProcess(NULL
, address
);
133 current2
= current2
->NextInChain
;
134 current_size
+= Bcb
->CacheSegmentSize
;
138 * Read in the information.
140 SegOffset
.QuadPart
= current
->FileOffset
;
141 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
142 Status
= IoPageRead(Bcb
->FileObject
,
147 if (Status
== STATUS_PENDING
)
149 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
150 Status
= Iosb
.Status
;
152 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
154 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
156 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
158 while (current
!= NULL
)
161 current
= current
->NextInChain
;
162 CcRosReleaseCacheSegment(Bcb
, previous
, FALSE
, FALSE
, FALSE
);
167 while (current
!= NULL
&& !current
->Valid
&& current_size
< MAX_RW_LENGTH
)
170 current
= current
->NextInChain
;
171 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
172 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
174 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
176 Length
= Length
- TempLength
;
177 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
178 current_size
+= Bcb
->CacheSegmentSize
;
182 return(STATUS_SUCCESS
);
187 ReadCacheSegment(PCACHE_SEGMENT CacheSeg
)
192 LARGE_INTEGER SegOffset
;
193 IO_STATUS_BLOCK IoStatus
;
196 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
197 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
198 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
200 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
202 Mdl
= IoAllocateMdl(CacheSeg
->BaseAddress
, Size
, FALSE
, FALSE
, NULL
);
203 MmBuildMdlForNonPagedPool(Mdl
);
204 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
205 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
206 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, & Event
, &IoStatus
);
207 if (Status
== STATUS_PENDING
)
209 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
210 Status
= IoStatus
.Status
;
215 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
217 DPRINT1("IoPageRead failed, Status %x\n", Status
);
220 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
222 memset ((char*)CacheSeg
->BaseAddress
+ Size
, 0,
223 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
225 return STATUS_SUCCESS
;
230 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
235 IO_STATUS_BLOCK IoStatus
;
236 LARGE_INTEGER SegOffset
;
239 CacheSeg
->Dirty
= FALSE
;
240 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
241 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
242 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
244 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
247 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
248 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
254 MmGetPfnForProcess(NULL
, (PVOID
)((ULONG_PTR
)CacheSeg
->BaseAddress
+ (i
<< PAGE_SHIFT
)));
255 } while (++i
< (Size
>> PAGE_SHIFT
));
257 Mdl
= IoAllocateMdl(CacheSeg
->BaseAddress
, Size
, FALSE
, FALSE
, NULL
);
258 MmBuildMdlForNonPagedPool(Mdl
);
259 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
260 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
261 Status
= IoSynchronousPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
262 if (Status
== STATUS_PENDING
)
264 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
265 Status
= IoStatus
.Status
;
268 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
270 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
271 CacheSeg
->Dirty
= TRUE
;
274 return(STATUS_SUCCESS
);
283 IN PFILE_OBJECT FileObject
,
284 IN ULONG BytesToWrite
,
297 CcCopyRead (IN PFILE_OBJECT FileObject
,
298 IN PLARGE_INTEGER FileOffset
,
302 OUT PIO_STATUS_BLOCK IoStatus
)
306 NTSTATUS Status
= STATUS_SUCCESS
;
308 PCACHE_SEGMENT CacheSeg
;
310 ULONG ReadLength
= 0;
313 PLIST_ENTRY current_entry
;
314 PCACHE_SEGMENT current
;
316 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
317 "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n",
318 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
321 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
322 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
324 DPRINT("AllocationSize %d, FileSize %d\n",
325 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
326 (ULONG
)Bcb
->FileSize
.QuadPart
);
329 * Check for the nowait case that all the cache segments that would
330 * cover this read are in memory.
334 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
335 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
336 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
338 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
339 BcbSegmentListEntry
);
340 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
341 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
343 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
344 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
345 IoStatus
->Information
= 0;
348 current_entry
= current_entry
->Flink
;
350 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
353 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
356 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
357 Status
= CcRosRequestCacheSegment(Bcb
,
358 ROUND_DOWN(ReadOffset
,
359 Bcb
->CacheSegmentSize
),
360 &BaseAddress
, &Valid
, &CacheSeg
);
361 if (!NT_SUCCESS(Status
))
363 IoStatus
->Information
= 0;
364 IoStatus
->Status
= Status
;
365 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
370 Status
= ReadCacheSegment(CacheSeg
);
371 if (!NT_SUCCESS(Status
))
373 IoStatus
->Information
= 0;
374 IoStatus
->Status
= Status
;
375 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
379 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
381 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
382 ReadLength
+= TempLength
;
383 Length
-= TempLength
;
384 ReadOffset
+= TempLength
;
385 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
389 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
390 Status
= ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
391 if (!NT_SUCCESS(Status
))
393 IoStatus
->Information
= 0;
394 IoStatus
->Status
= Status
;
395 DPRINT1("ReadCacheSegmentChain failed, Status %x\n", Status
);
399 ReadLength
+= TempLength
;
400 Length
-= TempLength
;
401 ReadOffset
+= TempLength
;
403 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
405 IoStatus
->Status
= STATUS_SUCCESS
;
406 IoStatus
->Information
= ReadLength
;
407 DPRINT("CcCopyRead O.K.\n");
415 CcCopyWrite (IN PFILE_OBJECT FileObject
,
416 IN PLARGE_INTEGER FileOffset
,
425 PLIST_ENTRY current_entry
;
426 PCACHE_SEGMENT CacheSeg
;
431 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
432 "Length %d, Wait %d, Buffer 0x%p)\n",
433 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
435 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
436 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
440 /* testing, if the requested datas are available */
441 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
442 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
443 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
445 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
446 BcbSegmentListEntry
);
447 if (!CacheSeg
->Valid
)
449 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
450 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
451 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
452 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
453 Bcb
->CacheSegmentSize
))
455 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
456 /* datas not available */
460 current_entry
= current_entry
->Flink
;
462 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
465 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
469 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
470 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
471 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
472 &BaseAddress
, &Valid
, &CacheSeg
);
473 if (!NT_SUCCESS(Status
))
479 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
484 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
486 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
488 Length
-= TempLength
;
489 WriteOffset
+= TempLength
;
491 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
496 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
497 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
498 &BaseAddress
, &Valid
, &CacheSeg
);
499 if (!NT_SUCCESS(Status
))
503 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
505 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
507 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
511 memcpy (BaseAddress
, Buffer
, TempLength
);
512 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
513 Length
-= TempLength
;
514 WriteOffset
+= TempLength
;
516 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
527 IN PFILE_OBJECT FileObject
,
528 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
531 IN ULONG BytesToWrite
,
544 IN PFILE_OBJECT FileObject
,
549 OUT PIO_STATUS_BLOCK IoStatus
560 IN PFILE_OBJECT FileObject
,
573 CcWaitForCurrentLazyWriterActivity (
578 return STATUS_NOT_IMPLEMENTED
;
585 CcZeroData (IN PFILE_OBJECT FileObject
,
586 IN PLARGE_INTEGER StartOffset
,
587 IN PLARGE_INTEGER EndOffset
,
591 LARGE_INTEGER WriteOffset
;
596 IO_STATUS_BLOCK Iosb
;
599 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
600 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
603 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
604 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
606 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
608 /* File is not cached */
610 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
614 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
616 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
620 CurrentLength
= Length
;
622 MmInitializeMdl(Mdl
, (PVOID
)(ULONG_PTR
)WriteOffset
.QuadPart
, CurrentLength
);
623 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
624 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
626 ((PPFN_NUMBER
)(Mdl
+ 1))[i
] = CcZeroPage
;
628 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
629 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
630 if (Status
== STATUS_PENDING
)
632 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
633 Status
= Iosb
.Status
;
635 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
636 if (!NT_SUCCESS(Status
))
640 WriteOffset
.QuadPart
+= CurrentLength
;
641 Length
-= CurrentLength
;
649 PLIST_ENTRY current_entry
;
650 PCACHE_SEGMENT CacheSeg
, current
, previous
;
653 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
656 /* testing, if the requested datas are available */
657 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
658 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
659 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
661 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
662 BcbSegmentListEntry
);
663 if (!CacheSeg
->Valid
)
665 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
666 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
667 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
668 WriteOffset
.u
.LowPart
+ Length
<=
669 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
671 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
672 /* datas not available */
676 current_entry
= current_entry
->Flink
;
678 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
683 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
684 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
686 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
690 CurrentLength
= Length
;
692 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
693 Offset
+ CurrentLength
, &CacheSeg
);
694 if (!NT_SUCCESS(Status
))
700 while (current
!= NULL
)
702 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
704 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
708 /* read the segment */
709 Status
= ReadCacheSegment(current
);
710 if (!NT_SUCCESS(Status
))
712 DPRINT1("ReadCacheSegment failed, status %x\n",
716 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
720 TempLength
= Bcb
->CacheSegmentSize
;
722 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
724 WriteOffset
.QuadPart
+= TempLength
;
725 CurrentLength
-= TempLength
;
726 Length
-= TempLength
;
728 current
= current
->NextInChain
;
732 while (current
!= NULL
)
735 current
= current
->NextInChain
;
736 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);