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
7 * PROGRAMMER: Hartmut Birr
12 /* INCLUDES ******************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS *******************************************************************/
20 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
22 static PFN_TYPE CcZeroPage
= 0;
24 #define MAX_ZERO_LENGTH (256 * 1024)
25 #define MAX_RW_LENGTH (256 * 1024)
28 void * alloca(size_t size
);
29 #elif defined(_MSC_VER)
30 void* _alloca(size_t size
);
32 #error Unknown compiler for alloca intrinsic stack allocation "function"
35 ULONG EXPORTED CcFastMdlReadWait
;
36 ULONG EXPORTED CcFastReadNotPossible
;
37 ULONG EXPORTED CcFastReadWait
;
38 ULONG CcFastReadNoWait
;
39 ULONG CcFastReadResourceMiss
;
42 /* FUNCTIONS *****************************************************************/
45 CcInitCacheZeroPage(VOID
)
49 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &CcZeroPage
);
50 if (!NT_SUCCESS(Status
))
52 DbgPrint("Can't allocate CcZeroPage.\n");
55 Status
= MiZeroPage(CcZeroPage
);
56 if (!NT_SUCCESS(Status
))
58 DbgPrint("Can't zero out CcZeroPage.\n");
64 ReadCacheSegmentChain(PBCB Bcb
, ULONG ReadOffset
, ULONG Length
,
68 PCACHE_SEGMENT current
;
69 PCACHE_SEGMENT previous
;
71 LARGE_INTEGER SegOffset
;
77 Mdl
= alloca(MmSizeOfMdl(NULL
, MAX_RW_LENGTH
));
79 Status
= CcRosGetCacheSegmentChain(Bcb
, ReadOffset
, Length
, &head
);
80 if (!NT_SUCCESS(Status
))
85 while (current
!= NULL
)
88 * If the current segment is valid then copy it into the
93 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
94 memcpy(Buffer
, current
->BaseAddress
, TempLength
);
104 Length
= Length
- TempLength
;
106 current
= current
->NextInChain
;
107 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
110 * Otherwise read in as much as we can.
114 PCACHE_SEGMENT current2
;
120 * Count the maximum number of bytes we could read starting
121 * from the current segment.
125 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
127 current2
= current2
->NextInChain
;
128 current_size
+= Bcb
->CacheSegmentSize
;
132 * Create an MDL which contains all their pages.
134 MmInitializeMdl(Mdl
, NULL
, current_size
);
135 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
138 MdlPages
= (PPFN_TYPE
)(Mdl
+ 1);
139 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
141 PVOID address
= current2
->BaseAddress
;
142 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++, address
+= PAGE_SIZE
)
144 *MdlPages
++ = MmGetPfnForProcess(NULL
, address
);
146 current2
= current2
->NextInChain
;
147 current_size
+= Bcb
->CacheSegmentSize
;
151 * Read in the information.
153 SegOffset
.QuadPart
= current
->FileOffset
;
154 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
155 Status
= IoPageRead(Bcb
->FileObject
,
160 if (Status
== STATUS_PENDING
)
162 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
163 Status
= Iosb
.Status
;
165 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
167 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
169 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
171 while (current
!= NULL
)
174 current
= current
->NextInChain
;
175 CcRosReleaseCacheSegment(Bcb
, previous
, FALSE
, FALSE
, FALSE
);
180 while (current
!= NULL
&& !current
->Valid
&& current_size
< MAX_RW_LENGTH
)
183 current
= current
->NextInChain
;
184 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
185 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
186 #if defined(__GNUC__)
187 Buffer
+= TempLength
;
190 char* pTemp
= Buffer
;
195 Length
= Length
- TempLength
;
196 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
197 current_size
+= Bcb
->CacheSegmentSize
;
201 return(STATUS_SUCCESS
);
205 ReadCacheSegment(PCACHE_SEGMENT CacheSeg
)
210 LARGE_INTEGER SegOffset
;
211 IO_STATUS_BLOCK IoStatus
;
214 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
215 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
216 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
218 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
220 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
221 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
222 MmBuildMdlForNonPagedPool(Mdl
);
223 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
224 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
225 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, & Event
, &IoStatus
);
226 if (Status
== STATUS_PENDING
)
228 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
229 Status
= IoStatus
.Status
;
232 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
234 DPRINT1("IoPageRead failed, Status %x\n", Status
);
237 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
239 memset ((char*)CacheSeg
->BaseAddress
+ Size
, 0,
240 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
242 return STATUS_SUCCESS
;
246 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
251 IO_STATUS_BLOCK IoStatus
;
252 LARGE_INTEGER SegOffset
;
255 CacheSeg
->Dirty
= FALSE
;
256 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
257 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
258 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
260 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
262 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
263 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
264 MmBuildMdlForNonPagedPool(Mdl
);
265 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
266 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
267 Status
= IoPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
268 if (Status
== STATUS_PENDING
)
270 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
271 Status
= IoStatus
.Status
;
273 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
275 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
276 CacheSeg
->Dirty
= TRUE
;
279 return(STATUS_SUCCESS
);
288 IN PFILE_OBJECT FileObject
,
289 IN ULONG BytesToWrite
,
302 CcCopyRead (IN PFILE_OBJECT FileObject
,
303 IN PLARGE_INTEGER FileOffset
,
307 OUT PIO_STATUS_BLOCK IoStatus
)
311 NTSTATUS Status
= STATUS_SUCCESS
;
313 PCACHE_SEGMENT CacheSeg
;
315 ULONG ReadLength
= 0;
318 PLIST_ENTRY current_entry
;
319 PCACHE_SEGMENT current
;
321 DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
322 "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
323 FileObject
, (ULONG
)FileOffset
->QuadPart
, Length
, Wait
,
326 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
327 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
329 DPRINT("AllocationSize %d, FileSize %d\n",
330 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
331 (ULONG
)Bcb
->FileSize
.QuadPart
);
334 * Check for the nowait case that all the cache segments that would
335 * cover this read are in memory.
339 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
340 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
341 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
343 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
344 BcbSegmentListEntry
);
345 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
346 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
348 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
349 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
350 IoStatus
->Information
= 0;
353 current_entry
= current_entry
->Flink
;
355 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
358 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
361 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
362 Status
= CcRosRequestCacheSegment(Bcb
,
363 ROUND_DOWN(ReadOffset
,
364 Bcb
->CacheSegmentSize
),
365 &BaseAddress
, &Valid
, &CacheSeg
);
366 if (!NT_SUCCESS(Status
))
368 IoStatus
->Information
= 0;
369 IoStatus
->Status
= Status
;
370 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
375 Status
= ReadCacheSegment(CacheSeg
);
376 if (!NT_SUCCESS(Status
))
378 IoStatus
->Information
= 0;
379 IoStatus
->Status
= Status
;
380 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
384 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
386 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
387 ReadLength
+= TempLength
;
388 Length
-= TempLength
;
389 ReadOffset
+= TempLength
;
390 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
394 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
395 ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
396 ReadLength
+= TempLength
;
397 Length
-= TempLength
;
398 ReadOffset
+= TempLength
;
399 #if defined(__GNUC__)
400 Buffer
+= TempLength
;
403 char* pTemp
= Buffer
;
409 IoStatus
->Status
= STATUS_SUCCESS
;
410 IoStatus
->Information
= ReadLength
;
411 DPRINT("CcCopyRead O.K.\n");
419 CcCopyWrite (IN PFILE_OBJECT FileObject
,
420 IN PLARGE_INTEGER FileOffset
,
429 PLIST_ENTRY current_entry
;
430 PCACHE_SEGMENT CacheSeg
;
435 DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
436 "Length %d, Wait %d, Buffer %x)\n",
437 FileObject
, (ULONG
)FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
439 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
440 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
444 /* testing, if the requested datas are available */
445 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
446 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
447 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
449 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
450 BcbSegmentListEntry
);
451 if (!CacheSeg
->Valid
)
453 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
454 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
455 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
456 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
457 Bcb
->CacheSegmentSize
))
459 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
460 /* datas not available */
464 current_entry
= current_entry
->Flink
;
466 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
469 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
473 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
474 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
475 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
476 &BaseAddress
, &Valid
, &CacheSeg
);
477 if (!NT_SUCCESS(Status
))
483 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
488 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
490 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
492 Length
-= TempLength
;
493 WriteOffset
+= TempLength
;
494 #if defined(__GNUC__)
495 Buffer
+= TempLength
;
498 char* pTemp
= Buffer
;
507 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
508 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
509 &BaseAddress
, &Valid
, &CacheSeg
);
510 if (!NT_SUCCESS(Status
))
514 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
516 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
518 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
522 memcpy (BaseAddress
, Buffer
, TempLength
);
523 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
524 Length
-= TempLength
;
525 WriteOffset
+= TempLength
;
526 #if defined(__GNUC__)
527 Buffer
+= TempLength
;
530 char* pTemp
= Buffer
;
545 IN PFILE_OBJECT FileObject
,
546 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
549 IN ULONG BytesToWrite
,
562 IN PFILE_OBJECT FileObject
,
567 OUT PIO_STATUS_BLOCK IoStatus
578 IN PFILE_OBJECT FileObject
,
591 CcWaitForCurrentLazyWriterActivity (
596 return STATUS_NOT_IMPLEMENTED
;
603 CcZeroData (IN PFILE_OBJECT FileObject
,
604 IN PLARGE_INTEGER StartOffset
,
605 IN PLARGE_INTEGER EndOffset
,
609 LARGE_INTEGER WriteOffset
;
614 IO_STATUS_BLOCK Iosb
;
617 DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
618 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
621 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
622 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
624 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
626 /* File is not cached */
628 Mdl
= alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
632 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
634 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
638 CurrentLength
= Length
;
640 MmInitializeMdl(Mdl
, (PVOID
)WriteOffset
.u
.LowPart
, CurrentLength
);
641 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
642 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
644 ((PPFN_TYPE
)(Mdl
+ 1))[i
] = CcZeroPage
;
646 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
647 Status
= IoPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
648 if (Status
== STATUS_PENDING
)
650 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
651 Status
= Iosb
.Status
;
653 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
654 if (!NT_SUCCESS(Status
))
658 WriteOffset
.QuadPart
+= CurrentLength
;
659 Length
-= CurrentLength
;
667 PLIST_ENTRY current_entry
;
668 PCACHE_SEGMENT CacheSeg
, current
, previous
;
671 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
674 /* testing, if the requested datas are available */
675 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
676 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
677 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
679 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
680 BcbSegmentListEntry
);
681 if (!CacheSeg
->Valid
)
683 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
684 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
685 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
686 WriteOffset
.u
.LowPart
+ Length
<=
687 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
689 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
690 /* datas not available */
694 current_entry
= current_entry
->Flink
;
696 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
701 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
702 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
704 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
708 CurrentLength
= Length
;
710 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
711 Offset
+ CurrentLength
, &CacheSeg
);
712 if (!NT_SUCCESS(Status
))
718 while (current
!= NULL
)
720 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
722 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
726 /* read the segment */
727 Status
= ReadCacheSegment(current
);
728 if (!NT_SUCCESS(Status
))
730 DPRINT1("ReadCacheSegment failed, status %x\n",
734 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
738 TempLength
= Bcb
->CacheSegmentSize
;
740 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
742 WriteOffset
.QuadPart
+= TempLength
;
743 CurrentLength
-= TempLength
;
744 Length
-= TempLength
;
746 current
= current
->NextInChain
;
750 while (current
!= NULL
)
753 current
= current
->NextInChain
;
754 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);