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
;
203 Mdl
= IoAllocateMdl(CacheSeg
->BaseAddress
, Size
, FALSE
, FALSE
, NULL
);
206 return STATUS_INSUFFICIENT_RESOURCES
;
208 MmBuildMdlForNonPagedPool(Mdl
);
209 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
210 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
211 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
212 if (Status
== STATUS_PENDING
)
214 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
215 Status
= IoStatus
.Status
;
220 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
222 DPRINT1("IoPageRead failed, Status %x\n", Status
);
226 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
228 RtlZeroMemory((char*)CacheSeg
->BaseAddress
+ Size
,
229 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
232 return STATUS_SUCCESS
;
237 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
242 IO_STATUS_BLOCK IoStatus
;
243 LARGE_INTEGER SegOffset
;
246 CacheSeg
->Dirty
= FALSE
;
247 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
248 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
249 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
251 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
254 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
255 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
261 MmGetPfnForProcess(NULL
, (PVOID
)((ULONG_PTR
)CacheSeg
->BaseAddress
+ (i
<< PAGE_SHIFT
)));
262 } while (++i
< (Size
>> PAGE_SHIFT
));
265 Mdl
= IoAllocateMdl(CacheSeg
->BaseAddress
, Size
, FALSE
, FALSE
, NULL
);
268 return STATUS_INSUFFICIENT_RESOURCES
;
270 MmBuildMdlForNonPagedPool(Mdl
);
271 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
272 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
273 Status
= IoSynchronousPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
274 if (Status
== STATUS_PENDING
)
276 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
277 Status
= IoStatus
.Status
;
280 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
282 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
283 CacheSeg
->Dirty
= TRUE
;
287 return STATUS_SUCCESS
;
296 IN PFILE_OBJECT FileObject
,
297 IN ULONG BytesToWrite
,
310 CcCopyRead (IN PFILE_OBJECT FileObject
,
311 IN PLARGE_INTEGER FileOffset
,
315 OUT PIO_STATUS_BLOCK IoStatus
)
319 NTSTATUS Status
= STATUS_SUCCESS
;
321 PCACHE_SEGMENT CacheSeg
;
323 ULONG ReadLength
= 0;
326 PLIST_ENTRY current_entry
;
327 PCACHE_SEGMENT current
;
329 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
330 "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n",
331 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
334 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
335 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
337 DPRINT("AllocationSize %d, FileSize %d\n",
338 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
339 (ULONG
)Bcb
->FileSize
.QuadPart
);
342 * Check for the nowait case that all the cache segments that would
343 * cover this read are in memory.
347 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
348 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
349 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
351 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
352 BcbSegmentListEntry
);
353 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
354 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
356 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
357 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
358 IoStatus
->Information
= 0;
361 current_entry
= current_entry
->Flink
;
363 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
366 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
369 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
370 Status
= CcRosRequestCacheSegment(Bcb
,
371 ROUND_DOWN(ReadOffset
,
372 Bcb
->CacheSegmentSize
),
373 &BaseAddress
, &Valid
, &CacheSeg
);
374 if (!NT_SUCCESS(Status
))
376 IoStatus
->Information
= 0;
377 IoStatus
->Status
= Status
;
378 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
383 Status
= ReadCacheSegment(CacheSeg
);
384 if (!NT_SUCCESS(Status
))
386 IoStatus
->Information
= 0;
387 IoStatus
->Status
= Status
;
388 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
392 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
394 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
395 ReadLength
+= TempLength
;
396 Length
-= TempLength
;
397 ReadOffset
+= TempLength
;
398 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
402 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
403 Status
= ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
404 if (!NT_SUCCESS(Status
))
406 IoStatus
->Information
= 0;
407 IoStatus
->Status
= Status
;
408 DPRINT1("ReadCacheSegmentChain failed, Status %x\n", Status
);
412 ReadLength
+= TempLength
;
413 Length
-= TempLength
;
414 ReadOffset
+= TempLength
;
416 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
418 IoStatus
->Status
= STATUS_SUCCESS
;
419 IoStatus
->Information
= ReadLength
;
420 DPRINT("CcCopyRead O.K.\n");
428 CcCopyWrite (IN PFILE_OBJECT FileObject
,
429 IN PLARGE_INTEGER FileOffset
,
438 PLIST_ENTRY current_entry
;
439 PCACHE_SEGMENT CacheSeg
;
444 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
445 "Length %d, Wait %d, Buffer 0x%p)\n",
446 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
448 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
449 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
453 /* testing, if the requested datas are available */
454 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
455 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
456 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
458 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
459 BcbSegmentListEntry
);
460 if (!CacheSeg
->Valid
)
462 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
463 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
464 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
465 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
466 Bcb
->CacheSegmentSize
))
468 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
469 /* datas not available */
473 current_entry
= current_entry
->Flink
;
475 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
478 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
482 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
483 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
484 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
485 &BaseAddress
, &Valid
, &CacheSeg
);
486 if (!NT_SUCCESS(Status
))
492 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
497 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
499 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
501 Length
-= TempLength
;
502 WriteOffset
+= TempLength
;
504 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
509 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
510 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
511 &BaseAddress
, &Valid
, &CacheSeg
);
512 if (!NT_SUCCESS(Status
))
516 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
518 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
520 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
524 memcpy (BaseAddress
, Buffer
, TempLength
);
525 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
526 Length
-= TempLength
;
527 WriteOffset
+= TempLength
;
529 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
540 IN PFILE_OBJECT FileObject
,
541 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
544 IN ULONG BytesToWrite
,
557 IN PFILE_OBJECT FileObject
,
562 OUT PIO_STATUS_BLOCK IoStatus
573 IN PFILE_OBJECT FileObject
,
586 CcWaitForCurrentLazyWriterActivity (
591 return STATUS_NOT_IMPLEMENTED
;
598 CcZeroData (IN PFILE_OBJECT FileObject
,
599 IN PLARGE_INTEGER StartOffset
,
600 IN PLARGE_INTEGER EndOffset
,
604 LARGE_INTEGER WriteOffset
;
609 IO_STATUS_BLOCK Iosb
;
612 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
613 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
616 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
617 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
619 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
621 /* File is not cached */
623 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
627 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
629 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
633 CurrentLength
= Length
;
635 MmInitializeMdl(Mdl
, (PVOID
)(ULONG_PTR
)WriteOffset
.QuadPart
, CurrentLength
);
636 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
637 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
639 ((PPFN_NUMBER
)(Mdl
+ 1))[i
] = CcZeroPage
;
641 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
642 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
643 if (Status
== STATUS_PENDING
)
645 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
646 Status
= Iosb
.Status
;
648 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
649 if (!NT_SUCCESS(Status
))
653 WriteOffset
.QuadPart
+= CurrentLength
;
654 Length
-= CurrentLength
;
662 PLIST_ENTRY current_entry
;
663 PCACHE_SEGMENT CacheSeg
, current
, previous
;
666 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
669 /* testing, if the requested datas are available */
670 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
671 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
672 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
674 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
675 BcbSegmentListEntry
);
676 if (!CacheSeg
->Valid
)
678 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
679 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
680 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
681 WriteOffset
.u
.LowPart
+ Length
<=
682 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
684 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
685 /* datas not available */
689 current_entry
= current_entry
->Flink
;
691 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
696 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
697 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
699 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
703 CurrentLength
= Length
;
705 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
706 Offset
+ CurrentLength
, &CacheSeg
);
707 if (!NT_SUCCESS(Status
))
713 while (current
!= NULL
)
715 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
717 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
721 /* read the segment */
722 Status
= ReadCacheSegment(current
);
723 if (!NT_SUCCESS(Status
))
725 DPRINT1("ReadCacheSegment failed, status %x\n",
729 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
733 TempLength
= Bcb
->CacheSegmentSize
;
735 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
737 WriteOffset
.QuadPart
+= TempLength
;
738 CurrentLength
-= TempLength
;
739 Length
-= TempLength
;
741 current
= current
->NextInChain
;
745 while (current
!= NULL
)
748 current
= current
->NextInChain
;
749 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);