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_TYPE 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 *****************************************************************/
34 CcInitCacheZeroPage(VOID
)
38 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &CcZeroPage
);
39 if (!NT_SUCCESS(Status
))
41 DbgPrint("Can't allocate CcZeroPage.\n");
42 KeBugCheck(CACHE_MANAGER
);
44 Status
= MiZeroPage(CcZeroPage
);
45 if (!NT_SUCCESS(Status
))
47 DbgPrint("Can't zero out CcZeroPage.\n");
48 KeBugCheck(CACHE_MANAGER
);
54 ReadCacheSegmentChain(PBCB Bcb
, ULONG ReadOffset
, ULONG Length
,
58 PCACHE_SEGMENT current
;
59 PCACHE_SEGMENT previous
;
61 LARGE_INTEGER SegOffset
;
67 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_RW_LENGTH
));
69 Status
= CcRosGetCacheSegmentChain(Bcb
, ReadOffset
, Length
, &head
);
70 if (!NT_SUCCESS(Status
))
75 while (current
!= NULL
)
78 * If the current segment is valid then copy it into the
83 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
84 memcpy(Buffer
, current
->BaseAddress
, TempLength
);
86 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
88 Length
= Length
- TempLength
;
90 current
= current
->NextInChain
;
91 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
94 * Otherwise read in as much as we can.
98 PCACHE_SEGMENT current2
;
104 * Count the maximum number of bytes we could read starting
105 * from the current segment.
109 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
111 current2
= current2
->NextInChain
;
112 current_size
+= Bcb
->CacheSegmentSize
;
116 * Create an MDL which contains all their pages.
118 MmInitializeMdl(Mdl
, NULL
, current_size
);
119 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
122 MdlPages
= (PPFN_TYPE
)(Mdl
+ 1);
123 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
125 PVOID address
= current2
->BaseAddress
;
126 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++, address
= RVA(address
, PAGE_SIZE
))
128 *MdlPages
++ = MmGetPfnForProcess(NULL
, address
);
130 current2
= current2
->NextInChain
;
131 current_size
+= Bcb
->CacheSegmentSize
;
135 * Read in the information.
137 SegOffset
.QuadPart
= current
->FileOffset
;
138 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
139 Status
= IoPageRead(Bcb
->FileObject
,
144 if (Status
== STATUS_PENDING
)
146 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
147 Status
= Iosb
.Status
;
149 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
151 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
153 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
155 while (current
!= NULL
)
158 current
= current
->NextInChain
;
159 CcRosReleaseCacheSegment(Bcb
, previous
, FALSE
, FALSE
, FALSE
);
164 while (current
!= NULL
&& !current
->Valid
&& current_size
< MAX_RW_LENGTH
)
167 current
= current
->NextInChain
;
168 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
169 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
171 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
173 Length
= Length
- TempLength
;
174 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
175 current_size
+= Bcb
->CacheSegmentSize
;
179 return(STATUS_SUCCESS
);
184 ReadCacheSegment(PCACHE_SEGMENT CacheSeg
)
189 LARGE_INTEGER SegOffset
;
190 IO_STATUS_BLOCK IoStatus
;
193 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
194 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
195 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
197 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
199 Mdl
= _alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
200 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
201 MmBuildMdlForNonPagedPool(Mdl
);
202 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
203 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
204 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, & Event
, &IoStatus
);
205 if (Status
== STATUS_PENDING
)
207 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
208 Status
= IoStatus
.Status
;
211 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
213 DPRINT1("IoPageRead failed, Status %x\n", Status
);
216 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
218 memset ((char*)CacheSeg
->BaseAddress
+ Size
, 0,
219 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
221 return STATUS_SUCCESS
;
226 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
231 IO_STATUS_BLOCK IoStatus
;
232 LARGE_INTEGER SegOffset
;
235 CacheSeg
->Dirty
= FALSE
;
236 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
237 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
238 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
240 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
243 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
244 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
250 MmGetPfnForProcess(NULL
, (PVOID
)((ULONG_PTR
)CacheSeg
->BaseAddress
+ (i
<< PAGE_SHIFT
)));
251 } while (++i
< (Size
>> PAGE_SHIFT
));
253 Mdl
= _alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
254 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
255 MmBuildMdlForNonPagedPool(Mdl
);
256 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
257 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
258 Status
= IoSynchronousPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
259 if (Status
== STATUS_PENDING
)
261 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
262 Status
= IoStatus
.Status
;
264 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
266 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
267 CacheSeg
->Dirty
= TRUE
;
270 return(STATUS_SUCCESS
);
279 IN PFILE_OBJECT FileObject
,
280 IN ULONG BytesToWrite
,
293 CcCopyRead (IN PFILE_OBJECT FileObject
,
294 IN PLARGE_INTEGER FileOffset
,
298 OUT PIO_STATUS_BLOCK IoStatus
)
302 NTSTATUS Status
= STATUS_SUCCESS
;
304 PCACHE_SEGMENT CacheSeg
;
306 ULONG ReadLength
= 0;
309 PLIST_ENTRY current_entry
;
310 PCACHE_SEGMENT current
;
312 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
313 "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n",
314 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
317 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
318 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
320 DPRINT("AllocationSize %d, FileSize %d\n",
321 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
322 (ULONG
)Bcb
->FileSize
.QuadPart
);
325 * Check for the nowait case that all the cache segments that would
326 * cover this read are in memory.
330 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
331 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
332 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
334 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
335 BcbSegmentListEntry
);
336 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
337 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
339 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
340 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
341 IoStatus
->Information
= 0;
344 current_entry
= current_entry
->Flink
;
346 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
349 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
352 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
353 Status
= CcRosRequestCacheSegment(Bcb
,
354 ROUND_DOWN(ReadOffset
,
355 Bcb
->CacheSegmentSize
),
356 &BaseAddress
, &Valid
, &CacheSeg
);
357 if (!NT_SUCCESS(Status
))
359 IoStatus
->Information
= 0;
360 IoStatus
->Status
= Status
;
361 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
366 Status
= ReadCacheSegment(CacheSeg
);
367 if (!NT_SUCCESS(Status
))
369 IoStatus
->Information
= 0;
370 IoStatus
->Status
= Status
;
371 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
375 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
377 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
378 ReadLength
+= TempLength
;
379 Length
-= TempLength
;
380 ReadOffset
+= TempLength
;
381 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
385 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
386 Status
= ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
387 if (!NT_SUCCESS(Status
))
389 IoStatus
->Information
= 0;
390 IoStatus
->Status
= Status
;
391 DPRINT1("ReadCacheSegmentChain failed, Status %x\n", Status
);
395 ReadLength
+= TempLength
;
396 Length
-= TempLength
;
397 ReadOffset
+= TempLength
;
399 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
401 IoStatus
->Status
= STATUS_SUCCESS
;
402 IoStatus
->Information
= ReadLength
;
403 DPRINT("CcCopyRead O.K.\n");
411 CcCopyWrite (IN PFILE_OBJECT FileObject
,
412 IN PLARGE_INTEGER FileOffset
,
421 PLIST_ENTRY current_entry
;
422 PCACHE_SEGMENT CacheSeg
;
427 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
428 "Length %d, Wait %d, Buffer 0x%p)\n",
429 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
431 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
432 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
436 /* testing, if the requested datas are available */
437 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
438 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
439 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
441 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
442 BcbSegmentListEntry
);
443 if (!CacheSeg
->Valid
)
445 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
446 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
447 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
448 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
449 Bcb
->CacheSegmentSize
))
451 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
452 /* datas not available */
456 current_entry
= current_entry
->Flink
;
458 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
461 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
465 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
466 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
467 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
468 &BaseAddress
, &Valid
, &CacheSeg
);
469 if (!NT_SUCCESS(Status
))
475 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
480 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
482 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
484 Length
-= TempLength
;
485 WriteOffset
+= TempLength
;
487 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
492 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
493 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
494 &BaseAddress
, &Valid
, &CacheSeg
);
495 if (!NT_SUCCESS(Status
))
499 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
501 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
503 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
507 memcpy (BaseAddress
, Buffer
, TempLength
);
508 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
509 Length
-= TempLength
;
510 WriteOffset
+= TempLength
;
512 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
523 IN PFILE_OBJECT FileObject
,
524 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
527 IN ULONG BytesToWrite
,
540 IN PFILE_OBJECT FileObject
,
545 OUT PIO_STATUS_BLOCK IoStatus
556 IN PFILE_OBJECT FileObject
,
569 CcWaitForCurrentLazyWriterActivity (
574 return STATUS_NOT_IMPLEMENTED
;
581 CcZeroData (IN PFILE_OBJECT FileObject
,
582 IN PLARGE_INTEGER StartOffset
,
583 IN PLARGE_INTEGER EndOffset
,
587 LARGE_INTEGER WriteOffset
;
592 IO_STATUS_BLOCK Iosb
;
595 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
596 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
599 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
600 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
602 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
604 /* File is not cached */
606 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
610 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
612 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
616 CurrentLength
= Length
;
618 MmInitializeMdl(Mdl
, (PVOID
)(ULONG_PTR
)WriteOffset
.QuadPart
, CurrentLength
);
619 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
620 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
622 ((PPFN_TYPE
)(Mdl
+ 1))[i
] = CcZeroPage
;
624 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
625 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
626 if (Status
== STATUS_PENDING
)
628 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
629 Status
= Iosb
.Status
;
631 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
632 if (!NT_SUCCESS(Status
))
636 WriteOffset
.QuadPart
+= CurrentLength
;
637 Length
-= CurrentLength
;
645 PLIST_ENTRY current_entry
;
646 PCACHE_SEGMENT CacheSeg
, current
, previous
;
649 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
652 /* testing, if the requested datas are available */
653 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
654 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
655 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
657 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
658 BcbSegmentListEntry
);
659 if (!CacheSeg
->Valid
)
661 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
662 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
663 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
664 WriteOffset
.u
.LowPart
+ Length
<=
665 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
667 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
668 /* datas not available */
672 current_entry
= current_entry
->Flink
;
674 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
679 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
680 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
682 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
686 CurrentLength
= Length
;
688 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
689 Offset
+ CurrentLength
, &CacheSeg
);
690 if (!NT_SUCCESS(Status
))
696 while (current
!= NULL
)
698 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
700 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
704 /* read the segment */
705 Status
= ReadCacheSegment(current
);
706 if (!NT_SUCCESS(Status
))
708 DPRINT1("ReadCacheSegment failed, status %x\n",
712 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
716 TempLength
= Bcb
->CacheSegmentSize
;
718 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
720 WriteOffset
.QuadPart
+= TempLength
;
721 CurrentLength
-= TempLength
;
722 Length
-= TempLength
;
724 current
= current
->NextInChain
;
728 while (current
!= NULL
)
731 current
= current
->NextInChain
;
732 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);