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
= _alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
203 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
204 MmBuildMdlForNonPagedPool(Mdl
);
205 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
206 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
207 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, & Event
, &IoStatus
);
208 if (Status
== STATUS_PENDING
)
210 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
211 Status
= IoStatus
.Status
;
214 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
216 DPRINT1("IoPageRead failed, Status %x\n", Status
);
219 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
221 memset ((char*)CacheSeg
->BaseAddress
+ Size
, 0,
222 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
224 return STATUS_SUCCESS
;
229 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
234 IO_STATUS_BLOCK IoStatus
;
235 LARGE_INTEGER SegOffset
;
238 CacheSeg
->Dirty
= FALSE
;
239 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
240 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
241 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
243 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
246 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
247 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
253 MmGetPfnForProcess(NULL
, (PVOID
)((ULONG_PTR
)CacheSeg
->BaseAddress
+ (i
<< PAGE_SHIFT
)));
254 } while (++i
< (Size
>> PAGE_SHIFT
));
256 Mdl
= _alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
257 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
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
;
267 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
269 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
270 CacheSeg
->Dirty
= TRUE
;
273 return(STATUS_SUCCESS
);
282 IN PFILE_OBJECT FileObject
,
283 IN ULONG BytesToWrite
,
296 CcCopyRead (IN PFILE_OBJECT FileObject
,
297 IN PLARGE_INTEGER FileOffset
,
301 OUT PIO_STATUS_BLOCK IoStatus
)
305 NTSTATUS Status
= STATUS_SUCCESS
;
307 PCACHE_SEGMENT CacheSeg
;
309 ULONG ReadLength
= 0;
312 PLIST_ENTRY current_entry
;
313 PCACHE_SEGMENT current
;
315 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
316 "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n",
317 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
320 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
321 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
323 DPRINT("AllocationSize %d, FileSize %d\n",
324 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
325 (ULONG
)Bcb
->FileSize
.QuadPart
);
328 * Check for the nowait case that all the cache segments that would
329 * cover this read are in memory.
333 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
334 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
335 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
337 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
338 BcbSegmentListEntry
);
339 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
340 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
342 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
343 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
344 IoStatus
->Information
= 0;
347 current_entry
= current_entry
->Flink
;
349 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
352 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
355 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
356 Status
= CcRosRequestCacheSegment(Bcb
,
357 ROUND_DOWN(ReadOffset
,
358 Bcb
->CacheSegmentSize
),
359 &BaseAddress
, &Valid
, &CacheSeg
);
360 if (!NT_SUCCESS(Status
))
362 IoStatus
->Information
= 0;
363 IoStatus
->Status
= Status
;
364 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
369 Status
= ReadCacheSegment(CacheSeg
);
370 if (!NT_SUCCESS(Status
))
372 IoStatus
->Information
= 0;
373 IoStatus
->Status
= Status
;
374 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
378 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
380 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
381 ReadLength
+= TempLength
;
382 Length
-= TempLength
;
383 ReadOffset
+= TempLength
;
384 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
388 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
389 Status
= ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
390 if (!NT_SUCCESS(Status
))
392 IoStatus
->Information
= 0;
393 IoStatus
->Status
= Status
;
394 DPRINT1("ReadCacheSegmentChain failed, Status %x\n", Status
);
398 ReadLength
+= TempLength
;
399 Length
-= TempLength
;
400 ReadOffset
+= TempLength
;
402 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
404 IoStatus
->Status
= STATUS_SUCCESS
;
405 IoStatus
->Information
= ReadLength
;
406 DPRINT("CcCopyRead O.K.\n");
414 CcCopyWrite (IN PFILE_OBJECT FileObject
,
415 IN PLARGE_INTEGER FileOffset
,
424 PLIST_ENTRY current_entry
;
425 PCACHE_SEGMENT CacheSeg
;
430 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
431 "Length %d, Wait %d, Buffer 0x%p)\n",
432 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
434 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
435 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
439 /* testing, if the requested datas are available */
440 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
441 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
442 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
444 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
445 BcbSegmentListEntry
);
446 if (!CacheSeg
->Valid
)
448 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
449 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
450 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
451 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
452 Bcb
->CacheSegmentSize
))
454 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
455 /* datas not available */
459 current_entry
= current_entry
->Flink
;
461 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
464 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
468 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
469 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
470 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
471 &BaseAddress
, &Valid
, &CacheSeg
);
472 if (!NT_SUCCESS(Status
))
478 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
483 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
485 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
487 Length
-= TempLength
;
488 WriteOffset
+= TempLength
;
490 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
495 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
496 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
497 &BaseAddress
, &Valid
, &CacheSeg
);
498 if (!NT_SUCCESS(Status
))
502 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
504 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
506 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
510 memcpy (BaseAddress
, Buffer
, TempLength
);
511 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
512 Length
-= TempLength
;
513 WriteOffset
+= TempLength
;
515 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
526 IN PFILE_OBJECT FileObject
,
527 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
530 IN ULONG BytesToWrite
,
543 IN PFILE_OBJECT FileObject
,
548 OUT PIO_STATUS_BLOCK IoStatus
559 IN PFILE_OBJECT FileObject
,
572 CcWaitForCurrentLazyWriterActivity (
577 return STATUS_NOT_IMPLEMENTED
;
584 CcZeroData (IN PFILE_OBJECT FileObject
,
585 IN PLARGE_INTEGER StartOffset
,
586 IN PLARGE_INTEGER EndOffset
,
590 LARGE_INTEGER WriteOffset
;
595 IO_STATUS_BLOCK Iosb
;
598 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
599 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
602 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
603 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
605 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
607 /* File is not cached */
609 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
613 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
615 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
619 CurrentLength
= Length
;
621 MmInitializeMdl(Mdl
, (PVOID
)(ULONG_PTR
)WriteOffset
.QuadPart
, CurrentLength
);
622 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
623 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
625 ((PPFN_NUMBER
)(Mdl
+ 1))[i
] = CcZeroPage
;
627 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
628 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
629 if (Status
== STATUS_PENDING
)
631 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
632 Status
= Iosb
.Status
;
634 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
635 if (!NT_SUCCESS(Status
))
639 WriteOffset
.QuadPart
+= CurrentLength
;
640 Length
-= CurrentLength
;
648 PLIST_ENTRY current_entry
;
649 PCACHE_SEGMENT CacheSeg
, current
, previous
;
652 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
655 /* testing, if the requested datas are available */
656 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
657 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
658 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
660 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
661 BcbSegmentListEntry
);
662 if (!CacheSeg
->Valid
)
664 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
665 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
666 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
667 WriteOffset
.u
.LowPart
+ Length
<=
668 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
670 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
671 /* datas not available */
675 current_entry
= current_entry
->Flink
;
677 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
682 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
683 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
685 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
689 CurrentLength
= Length
;
691 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
692 Offset
+ CurrentLength
, &CacheSeg
);
693 if (!NT_SUCCESS(Status
))
699 while (current
!= NULL
)
701 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
703 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
707 /* read the segment */
708 Status
= ReadCacheSegment(current
);
709 if (!NT_SUCCESS(Status
))
711 DPRINT1("ReadCacheSegment failed, status %x\n",
715 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
719 TempLength
= Bcb
->CacheSegmentSize
;
721 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
723 WriteOffset
.QuadPart
+= TempLength
;
724 CurrentLength
-= TempLength
;
725 Length
-= TempLength
;
727 current
= current
->NextInChain
;
731 while (current
!= NULL
)
734 current
= current
->NextInChain
;
735 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);