3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/cc/copy.c
6 * PURPOSE: Implements cache managers copy interface
11 /* INCLUDES ******************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *******************************************************************/
19 static PFN_TYPE CcZeroPage
= 0;
21 #define MAX_ZERO_LENGTH (256 * 1024)
22 #define MAX_RW_LENGTH (256 * 1024)
25 /* void * alloca(size_t size); */
26 #elif defined(_MSC_VER)
27 void* _alloca(size_t size
);
29 #error Unknown compiler for alloca intrinsic stack allocation "function"
32 ULONG CcFastMdlReadWait
;
33 ULONG CcFastMdlReadNotPossible
;
34 ULONG CcFastReadNotPossible
;
36 ULONG CcFastReadNoWait
;
37 ULONG CcFastReadResourceMiss
;
39 /* FUNCTIONS *****************************************************************/
43 CcInitCacheZeroPage(VOID
)
47 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &CcZeroPage
);
48 if (!NT_SUCCESS(Status
))
50 DbgPrint("Can't allocate CcZeroPage.\n");
53 Status
= MiZeroPage(CcZeroPage
);
54 if (!NT_SUCCESS(Status
))
56 DbgPrint("Can't zero out CcZeroPage.\n");
63 ReadCacheSegmentChain(PBCB Bcb
, ULONG ReadOffset
, ULONG Length
,
67 PCACHE_SEGMENT current
;
68 PCACHE_SEGMENT previous
;
70 LARGE_INTEGER SegOffset
;
76 Mdl
= alloca(MmSizeOfMdl(NULL
, MAX_RW_LENGTH
));
78 Status
= CcRosGetCacheSegmentChain(Bcb
, ReadOffset
, Length
, &head
);
79 if (!NT_SUCCESS(Status
))
84 while (current
!= NULL
)
87 * If the current segment is valid then copy it into the
92 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
93 memcpy(Buffer
, current
->BaseAddress
, TempLength
);
95 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
97 Length
= Length
- TempLength
;
99 current
= current
->NextInChain
;
100 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
103 * Otherwise read in as much as we can.
107 PCACHE_SEGMENT current2
;
113 * Count the maximum number of bytes we could read starting
114 * from the current segment.
118 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
120 current2
= current2
->NextInChain
;
121 current_size
+= Bcb
->CacheSegmentSize
;
125 * Create an MDL which contains all their pages.
127 MmInitializeMdl(Mdl
, NULL
, current_size
);
128 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
131 MdlPages
= (PPFN_TYPE
)(Mdl
+ 1);
132 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
134 PVOID address
= current2
->BaseAddress
;
135 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++, address
= RVA(address
, PAGE_SIZE
))
137 *MdlPages
++ = MmGetPfnForProcess(NULL
, address
);
139 current2
= current2
->NextInChain
;
140 current_size
+= Bcb
->CacheSegmentSize
;
144 * Read in the information.
146 SegOffset
.QuadPart
= current
->FileOffset
;
147 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
148 Status
= IoPageRead(Bcb
->FileObject
,
153 if (Status
== STATUS_PENDING
)
155 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
156 Status
= Iosb
.Status
;
158 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
160 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
162 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
164 while (current
!= NULL
)
167 current
= current
->NextInChain
;
168 CcRosReleaseCacheSegment(Bcb
, previous
, FALSE
, FALSE
, FALSE
);
173 while (current
!= NULL
&& !current
->Valid
&& current_size
< MAX_RW_LENGTH
)
176 current
= current
->NextInChain
;
177 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
178 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
180 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
182 Length
= Length
- TempLength
;
183 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
184 current_size
+= Bcb
->CacheSegmentSize
;
188 return(STATUS_SUCCESS
);
193 ReadCacheSegment(PCACHE_SEGMENT CacheSeg
)
198 LARGE_INTEGER SegOffset
;
199 IO_STATUS_BLOCK IoStatus
;
202 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
203 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
204 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
206 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
208 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
209 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
210 MmBuildMdlForNonPagedPool(Mdl
);
211 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
212 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
213 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, & Event
, &IoStatus
);
214 if (Status
== STATUS_PENDING
)
216 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
217 Status
= IoStatus
.Status
;
220 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
222 DPRINT1("IoPageRead failed, Status %x\n", Status
);
225 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
227 memset ((char*)CacheSeg
->BaseAddress
+ Size
, 0,
228 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
230 return STATUS_SUCCESS
;
235 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
240 IO_STATUS_BLOCK IoStatus
;
241 LARGE_INTEGER SegOffset
;
244 CacheSeg
->Dirty
= FALSE
;
245 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
246 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
247 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
249 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
251 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
252 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
253 MmBuildMdlForNonPagedPool(Mdl
);
254 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
255 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
256 Status
= IoSynchronousPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
257 if (Status
== STATUS_PENDING
)
259 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
260 Status
= IoStatus
.Status
;
262 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
264 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
265 CacheSeg
->Dirty
= TRUE
;
268 return(STATUS_SUCCESS
);
277 IN PFILE_OBJECT FileObject
,
278 IN ULONG BytesToWrite
,
291 CcCopyRead (IN PFILE_OBJECT FileObject
,
292 IN PLARGE_INTEGER FileOffset
,
296 OUT PIO_STATUS_BLOCK IoStatus
)
300 NTSTATUS Status
= STATUS_SUCCESS
;
302 PCACHE_SEGMENT CacheSeg
;
304 ULONG ReadLength
= 0;
307 PLIST_ENTRY current_entry
;
308 PCACHE_SEGMENT current
;
310 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
311 "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n",
312 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
315 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
316 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
318 DPRINT("AllocationSize %d, FileSize %d\n",
319 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
320 (ULONG
)Bcb
->FileSize
.QuadPart
);
323 * Check for the nowait case that all the cache segments that would
324 * cover this read are in memory.
328 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
329 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
330 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
332 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
333 BcbSegmentListEntry
);
334 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
335 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
337 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
338 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
339 IoStatus
->Information
= 0;
342 current_entry
= current_entry
->Flink
;
344 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
347 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
350 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
351 Status
= CcRosRequestCacheSegment(Bcb
,
352 ROUND_DOWN(ReadOffset
,
353 Bcb
->CacheSegmentSize
),
354 &BaseAddress
, &Valid
, &CacheSeg
);
355 if (!NT_SUCCESS(Status
))
357 IoStatus
->Information
= 0;
358 IoStatus
->Status
= Status
;
359 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
364 Status
= ReadCacheSegment(CacheSeg
);
365 if (!NT_SUCCESS(Status
))
367 IoStatus
->Information
= 0;
368 IoStatus
->Status
= Status
;
369 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
373 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
375 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
376 ReadLength
+= TempLength
;
377 Length
-= TempLength
;
378 ReadOffset
+= TempLength
;
379 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
383 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
384 Status
= ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
385 if (!NT_SUCCESS(Status
))
387 IoStatus
->Information
= 0;
388 IoStatus
->Status
= Status
;
389 DPRINT1("ReadCacheSegmentChain failed, Status %x\n", Status
);
393 ReadLength
+= TempLength
;
394 Length
-= TempLength
;
395 ReadOffset
+= TempLength
;
397 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
399 IoStatus
->Status
= STATUS_SUCCESS
;
400 IoStatus
->Information
= ReadLength
;
401 DPRINT("CcCopyRead O.K.\n");
409 CcCopyWrite (IN PFILE_OBJECT FileObject
,
410 IN PLARGE_INTEGER FileOffset
,
419 PLIST_ENTRY current_entry
;
420 PCACHE_SEGMENT CacheSeg
;
425 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
426 "Length %d, Wait %d, Buffer 0x%p)\n",
427 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
429 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
430 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
434 /* testing, if the requested datas are available */
435 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
436 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
437 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
439 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
440 BcbSegmentListEntry
);
441 if (!CacheSeg
->Valid
)
443 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
444 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
445 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
446 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
447 Bcb
->CacheSegmentSize
))
449 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
450 /* datas not available */
454 current_entry
= current_entry
->Flink
;
456 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
459 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
463 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
464 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
465 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
466 &BaseAddress
, &Valid
, &CacheSeg
);
467 if (!NT_SUCCESS(Status
))
473 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
478 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
480 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
482 Length
-= TempLength
;
483 WriteOffset
+= TempLength
;
485 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
490 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
491 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
492 &BaseAddress
, &Valid
, &CacheSeg
);
493 if (!NT_SUCCESS(Status
))
497 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
499 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
501 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
505 memcpy (BaseAddress
, Buffer
, TempLength
);
506 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
507 Length
-= TempLength
;
508 WriteOffset
+= TempLength
;
510 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
521 IN PFILE_OBJECT FileObject
,
522 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
525 IN ULONG BytesToWrite
,
538 IN PFILE_OBJECT FileObject
,
543 OUT PIO_STATUS_BLOCK IoStatus
554 IN PFILE_OBJECT FileObject
,
567 CcWaitForCurrentLazyWriterActivity (
572 return STATUS_NOT_IMPLEMENTED
;
579 CcZeroData (IN PFILE_OBJECT FileObject
,
580 IN PLARGE_INTEGER StartOffset
,
581 IN PLARGE_INTEGER EndOffset
,
585 LARGE_INTEGER WriteOffset
;
590 IO_STATUS_BLOCK Iosb
;
593 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
594 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
597 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
598 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
600 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
602 /* File is not cached */
604 Mdl
= alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
608 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
610 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
614 CurrentLength
= Length
;
616 MmInitializeMdl(Mdl
, (PVOID
)WriteOffset
.u
.LowPart
, CurrentLength
);
617 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
618 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
620 ((PPFN_TYPE
)(Mdl
+ 1))[i
] = CcZeroPage
;
622 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
623 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
624 if (Status
== STATUS_PENDING
)
626 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
627 Status
= Iosb
.Status
;
629 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
630 if (!NT_SUCCESS(Status
))
634 WriteOffset
.QuadPart
+= CurrentLength
;
635 Length
-= CurrentLength
;
643 PLIST_ENTRY current_entry
;
644 PCACHE_SEGMENT CacheSeg
, current
, previous
;
647 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
650 /* testing, if the requested datas are available */
651 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
652 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
653 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
655 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
656 BcbSegmentListEntry
);
657 if (!CacheSeg
->Valid
)
659 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
660 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
661 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
662 WriteOffset
.u
.LowPart
+ Length
<=
663 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
665 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
666 /* datas not available */
670 current_entry
= current_entry
->Flink
;
672 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
677 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
678 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
680 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
684 CurrentLength
= Length
;
686 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
687 Offset
+ CurrentLength
, &CacheSeg
);
688 if (!NT_SUCCESS(Status
))
694 while (current
!= NULL
)
696 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
698 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
702 /* read the segment */
703 Status
= ReadCacheSegment(current
);
704 if (!NT_SUCCESS(Status
))
706 DPRINT1("ReadCacheSegment failed, status %x\n",
710 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
714 TempLength
= Bcb
->CacheSegmentSize
;
716 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
718 WriteOffset
.QuadPart
+= TempLength
;
719 CurrentLength
-= TempLength
;
720 Length
-= TempLength
;
722 current
= current
->NextInChain
;
726 while (current
!= NULL
)
729 current
= current
->NextInChain
;
730 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);