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)
24 /* void * alloca(size_t size); */
25 #elif defined(_MSC_VER)
26 void* _alloca(size_t size
);
28 #error Unknown compiler for alloca intrinsic stack allocation "function"
31 ULONG CcFastMdlReadWait
;
32 ULONG CcFastMdlReadNotPossible
;
33 ULONG CcFastReadNotPossible
;
35 ULONG CcFastReadNoWait
;
36 ULONG CcFastReadResourceMiss
;
38 /* FUNCTIONS *****************************************************************/
42 CcInitCacheZeroPage(VOID
)
46 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &CcZeroPage
);
47 if (!NT_SUCCESS(Status
))
49 DbgPrint("Can't allocate CcZeroPage.\n");
50 KeBugCheck(CACHE_MANAGER
);
52 Status
= MiZeroPage(CcZeroPage
);
53 if (!NT_SUCCESS(Status
))
55 DbgPrint("Can't zero out CcZeroPage.\n");
56 KeBugCheck(CACHE_MANAGER
);
62 ReadCacheSegmentChain(PBCB Bcb
, ULONG ReadOffset
, ULONG Length
,
66 PCACHE_SEGMENT current
;
67 PCACHE_SEGMENT previous
;
69 LARGE_INTEGER SegOffset
;
75 Mdl
= alloca(MmSizeOfMdl(NULL
, MAX_RW_LENGTH
));
77 Status
= CcRosGetCacheSegmentChain(Bcb
, ReadOffset
, Length
, &head
);
78 if (!NT_SUCCESS(Status
))
83 while (current
!= NULL
)
86 * If the current segment is valid then copy it into the
91 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
92 memcpy(Buffer
, current
->BaseAddress
, TempLength
);
94 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
96 Length
= Length
- TempLength
;
98 current
= current
->NextInChain
;
99 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
102 * Otherwise read in as much as we can.
106 PCACHE_SEGMENT current2
;
112 * Count the maximum number of bytes we could read starting
113 * from the current segment.
117 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
119 current2
= current2
->NextInChain
;
120 current_size
+= Bcb
->CacheSegmentSize
;
124 * Create an MDL which contains all their pages.
126 MmInitializeMdl(Mdl
, NULL
, current_size
);
127 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
130 MdlPages
= (PPFN_TYPE
)(Mdl
+ 1);
131 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
133 PVOID address
= current2
->BaseAddress
;
134 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++, address
= RVA(address
, PAGE_SIZE
))
136 *MdlPages
++ = MmGetPfnForProcess(NULL
, address
);
138 current2
= current2
->NextInChain
;
139 current_size
+= Bcb
->CacheSegmentSize
;
143 * Read in the information.
145 SegOffset
.QuadPart
= current
->FileOffset
;
146 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
147 Status
= IoPageRead(Bcb
->FileObject
,
152 if (Status
== STATUS_PENDING
)
154 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
155 Status
= Iosb
.Status
;
157 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
159 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
161 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
163 while (current
!= NULL
)
166 current
= current
->NextInChain
;
167 CcRosReleaseCacheSegment(Bcb
, previous
, FALSE
, FALSE
, FALSE
);
172 while (current
!= NULL
&& !current
->Valid
&& current_size
< MAX_RW_LENGTH
)
175 current
= current
->NextInChain
;
176 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
177 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
179 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
181 Length
= Length
- TempLength
;
182 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
183 current_size
+= Bcb
->CacheSegmentSize
;
187 return(STATUS_SUCCESS
);
192 ReadCacheSegment(PCACHE_SEGMENT CacheSeg
)
197 LARGE_INTEGER SegOffset
;
198 IO_STATUS_BLOCK IoStatus
;
201 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
202 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
203 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
205 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
207 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
208 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
209 MmBuildMdlForNonPagedPool(Mdl
);
210 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
211 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
212 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, & Event
, &IoStatus
);
213 if (Status
== STATUS_PENDING
)
215 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
216 Status
= IoStatus
.Status
;
219 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
221 DPRINT1("IoPageRead failed, Status %x\n", Status
);
224 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
226 memset ((char*)CacheSeg
->BaseAddress
+ Size
, 0,
227 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
229 return STATUS_SUCCESS
;
234 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
239 IO_STATUS_BLOCK IoStatus
;
240 LARGE_INTEGER SegOffset
;
243 CacheSeg
->Dirty
= FALSE
;
244 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
245 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
246 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
248 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
250 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
251 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
252 MmBuildMdlForNonPagedPool(Mdl
);
253 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
254 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
255 Status
= IoSynchronousPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
256 if (Status
== STATUS_PENDING
)
258 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
259 Status
= IoStatus
.Status
;
261 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
263 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
264 CacheSeg
->Dirty
= TRUE
;
267 return(STATUS_SUCCESS
);
276 IN PFILE_OBJECT FileObject
,
277 IN ULONG BytesToWrite
,
290 CcCopyRead (IN PFILE_OBJECT FileObject
,
291 IN PLARGE_INTEGER FileOffset
,
295 OUT PIO_STATUS_BLOCK IoStatus
)
299 NTSTATUS Status
= STATUS_SUCCESS
;
301 PCACHE_SEGMENT CacheSeg
;
303 ULONG ReadLength
= 0;
306 PLIST_ENTRY current_entry
;
307 PCACHE_SEGMENT current
;
309 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
310 "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n",
311 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
314 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
315 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
317 DPRINT("AllocationSize %d, FileSize %d\n",
318 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
319 (ULONG
)Bcb
->FileSize
.QuadPart
);
322 * Check for the nowait case that all the cache segments that would
323 * cover this read are in memory.
327 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
328 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
329 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
331 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
332 BcbSegmentListEntry
);
333 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
334 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
336 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
337 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
338 IoStatus
->Information
= 0;
341 current_entry
= current_entry
->Flink
;
343 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
346 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
349 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
350 Status
= CcRosRequestCacheSegment(Bcb
,
351 ROUND_DOWN(ReadOffset
,
352 Bcb
->CacheSegmentSize
),
353 &BaseAddress
, &Valid
, &CacheSeg
);
354 if (!NT_SUCCESS(Status
))
356 IoStatus
->Information
= 0;
357 IoStatus
->Status
= Status
;
358 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
363 Status
= ReadCacheSegment(CacheSeg
);
364 if (!NT_SUCCESS(Status
))
366 IoStatus
->Information
= 0;
367 IoStatus
->Status
= Status
;
368 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
372 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
374 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
375 ReadLength
+= TempLength
;
376 Length
-= TempLength
;
377 ReadOffset
+= TempLength
;
378 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
382 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
383 Status
= ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
384 if (!NT_SUCCESS(Status
))
386 IoStatus
->Information
= 0;
387 IoStatus
->Status
= Status
;
388 DPRINT1("ReadCacheSegmentChain failed, Status %x\n", Status
);
392 ReadLength
+= TempLength
;
393 Length
-= TempLength
;
394 ReadOffset
+= TempLength
;
396 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
398 IoStatus
->Status
= STATUS_SUCCESS
;
399 IoStatus
->Information
= ReadLength
;
400 DPRINT("CcCopyRead O.K.\n");
408 CcCopyWrite (IN PFILE_OBJECT FileObject
,
409 IN PLARGE_INTEGER FileOffset
,
418 PLIST_ENTRY current_entry
;
419 PCACHE_SEGMENT CacheSeg
;
424 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
425 "Length %d, Wait %d, Buffer 0x%p)\n",
426 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
428 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
429 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
433 /* testing, if the requested datas are available */
434 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
435 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
436 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
438 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
439 BcbSegmentListEntry
);
440 if (!CacheSeg
->Valid
)
442 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
443 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
444 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
445 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
446 Bcb
->CacheSegmentSize
))
448 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
449 /* datas not available */
453 current_entry
= current_entry
->Flink
;
455 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
458 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
462 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
463 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
464 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
465 &BaseAddress
, &Valid
, &CacheSeg
);
466 if (!NT_SUCCESS(Status
))
472 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
477 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
479 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
481 Length
-= TempLength
;
482 WriteOffset
+= TempLength
;
484 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
489 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
490 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
491 &BaseAddress
, &Valid
, &CacheSeg
);
492 if (!NT_SUCCESS(Status
))
496 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
498 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
500 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
504 memcpy (BaseAddress
, Buffer
, TempLength
);
505 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
506 Length
-= TempLength
;
507 WriteOffset
+= TempLength
;
509 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ TempLength
);
520 IN PFILE_OBJECT FileObject
,
521 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
524 IN ULONG BytesToWrite
,
537 IN PFILE_OBJECT FileObject
,
542 OUT PIO_STATUS_BLOCK IoStatus
553 IN PFILE_OBJECT FileObject
,
566 CcWaitForCurrentLazyWriterActivity (
571 return STATUS_NOT_IMPLEMENTED
;
578 CcZeroData (IN PFILE_OBJECT FileObject
,
579 IN PLARGE_INTEGER StartOffset
,
580 IN PLARGE_INTEGER EndOffset
,
584 LARGE_INTEGER WriteOffset
;
589 IO_STATUS_BLOCK Iosb
;
592 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
593 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
596 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
597 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
599 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
601 /* File is not cached */
603 Mdl
= alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
607 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
609 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
613 CurrentLength
= Length
;
615 MmInitializeMdl(Mdl
, (PVOID
)WriteOffset
.u
.LowPart
, CurrentLength
);
616 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
617 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
619 ((PPFN_TYPE
)(Mdl
+ 1))[i
] = CcZeroPage
;
621 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
622 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
623 if (Status
== STATUS_PENDING
)
625 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
626 Status
= Iosb
.Status
;
628 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
629 if (!NT_SUCCESS(Status
))
633 WriteOffset
.QuadPart
+= CurrentLength
;
634 Length
-= CurrentLength
;
642 PLIST_ENTRY current_entry
;
643 PCACHE_SEGMENT CacheSeg
, current
, previous
;
646 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
649 /* testing, if the requested datas are available */
650 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
651 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
652 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
654 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
655 BcbSegmentListEntry
);
656 if (!CacheSeg
->Valid
)
658 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
659 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
660 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
661 WriteOffset
.u
.LowPart
+ Length
<=
662 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
664 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
665 /* datas not available */
669 current_entry
= current_entry
->Flink
;
671 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
676 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
677 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
679 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
683 CurrentLength
= Length
;
685 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
686 Offset
+ CurrentLength
, &CacheSeg
);
687 if (!NT_SUCCESS(Status
))
693 while (current
!= NULL
)
695 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
697 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
701 /* read the segment */
702 Status
= ReadCacheSegment(current
);
703 if (!NT_SUCCESS(Status
))
705 DPRINT1("ReadCacheSegment failed, status %x\n",
709 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
713 TempLength
= Bcb
->CacheSegmentSize
;
715 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
717 WriteOffset
.QuadPart
+= TempLength
;
718 CurrentLength
-= TempLength
;
719 Length
-= TempLength
;
721 current
= current
->NextInChain
;
725 while (current
!= NULL
)
728 current
= current
->NextInChain
;
729 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);