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
8 * PROGRAMMERS: Hartmut Birr
11 /* INCLUDES ******************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *******************************************************************/
19 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
21 static PFN_TYPE CcZeroPage
= 0;
23 #define MAX_ZERO_LENGTH (256 * 1024)
24 #define MAX_RW_LENGTH (256 * 1024)
27 /* void * alloca(size_t size); */
28 #elif defined(_MSC_VER)
29 void* _alloca(size_t size
);
31 #error Unknown compiler for alloca intrinsic stack allocation "function"
34 ULONG EXPORTED CcFastMdlReadWait
;
35 ULONG EXPORTED CcFastReadNotPossible
;
36 ULONG EXPORTED CcFastReadWait
;
37 ULONG CcFastReadNoWait
;
38 ULONG CcFastReadResourceMiss
;
41 /* FUNCTIONS *****************************************************************/
44 CcInitCacheZeroPage(VOID
)
48 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &CcZeroPage
);
49 if (!NT_SUCCESS(Status
))
51 DbgPrint("Can't allocate CcZeroPage.\n");
54 Status
= MiZeroPage(CcZeroPage
);
55 if (!NT_SUCCESS(Status
))
57 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
);
103 Length
= Length
- TempLength
;
105 current
= current
->NextInChain
;
106 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
109 * Otherwise read in as much as we can.
113 PCACHE_SEGMENT current2
;
119 * Count the maximum number of bytes we could read starting
120 * from the current segment.
124 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
126 current2
= current2
->NextInChain
;
127 current_size
+= Bcb
->CacheSegmentSize
;
131 * Create an MDL which contains all their pages.
133 MmInitializeMdl(Mdl
, NULL
, current_size
);
134 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
137 MdlPages
= (PPFN_TYPE
)(Mdl
+ 1);
138 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
140 PVOID address
= current2
->BaseAddress
;
141 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++, address
+= PAGE_SIZE
)
143 *MdlPages
++ = MmGetPfnForProcess(NULL
, address
);
145 current2
= current2
->NextInChain
;
146 current_size
+= Bcb
->CacheSegmentSize
;
150 * Read in the information.
152 SegOffset
.QuadPart
= current
->FileOffset
;
153 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
154 Status
= IoPageRead(Bcb
->FileObject
,
159 if (Status
== STATUS_PENDING
)
161 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
162 Status
= Iosb
.Status
;
164 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
166 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
168 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
170 while (current
!= NULL
)
173 current
= current
->NextInChain
;
174 CcRosReleaseCacheSegment(Bcb
, previous
, FALSE
, FALSE
, FALSE
);
179 while (current
!= NULL
&& !current
->Valid
&& current_size
< MAX_RW_LENGTH
)
182 current
= current
->NextInChain
;
183 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
184 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
185 #if defined(__GNUC__)
186 Buffer
+= TempLength
;
189 char* pTemp
= Buffer
;
194 Length
= Length
- TempLength
;
195 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
196 current_size
+= Bcb
->CacheSegmentSize
;
200 return(STATUS_SUCCESS
);
204 ReadCacheSegment(PCACHE_SEGMENT CacheSeg
)
209 LARGE_INTEGER SegOffset
;
210 IO_STATUS_BLOCK IoStatus
;
213 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
214 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
215 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
217 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
219 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
220 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
221 MmBuildMdlForNonPagedPool(Mdl
);
222 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
223 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
224 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, & Event
, &IoStatus
);
225 if (Status
== STATUS_PENDING
)
227 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
228 Status
= IoStatus
.Status
;
231 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
233 DPRINT1("IoPageRead failed, Status %x\n", Status
);
236 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
238 memset ((char*)CacheSeg
->BaseAddress
+ Size
, 0,
239 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
241 return STATUS_SUCCESS
;
245 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
250 IO_STATUS_BLOCK IoStatus
;
251 LARGE_INTEGER SegOffset
;
254 CacheSeg
->Dirty
= FALSE
;
255 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
256 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
257 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
259 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
261 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
262 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
263 MmBuildMdlForNonPagedPool(Mdl
);
264 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
265 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
266 Status
= IoSynchronousPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
267 if (Status
== STATUS_PENDING
)
269 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
270 Status
= IoStatus
.Status
;
272 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
274 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
275 CacheSeg
->Dirty
= TRUE
;
278 return(STATUS_SUCCESS
);
287 IN PFILE_OBJECT FileObject
,
288 IN ULONG BytesToWrite
,
301 CcCopyRead (IN PFILE_OBJECT FileObject
,
302 IN PLARGE_INTEGER FileOffset
,
306 OUT PIO_STATUS_BLOCK IoStatus
)
310 NTSTATUS Status
= STATUS_SUCCESS
;
312 PCACHE_SEGMENT CacheSeg
;
314 ULONG ReadLength
= 0;
317 PLIST_ENTRY current_entry
;
318 PCACHE_SEGMENT current
;
320 DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
321 "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
322 FileObject
, (ULONG
)FileOffset
->QuadPart
, Length
, Wait
,
325 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
326 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
328 DPRINT("AllocationSize %d, FileSize %d\n",
329 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
330 (ULONG
)Bcb
->FileSize
.QuadPart
);
333 * Check for the nowait case that all the cache segments that would
334 * cover this read are in memory.
338 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
339 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
340 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
342 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
343 BcbSegmentListEntry
);
344 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
345 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
347 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
348 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
349 IoStatus
->Information
= 0;
352 current_entry
= current_entry
->Flink
;
354 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
357 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
360 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
361 Status
= CcRosRequestCacheSegment(Bcb
,
362 ROUND_DOWN(ReadOffset
,
363 Bcb
->CacheSegmentSize
),
364 &BaseAddress
, &Valid
, &CacheSeg
);
365 if (!NT_SUCCESS(Status
))
367 IoStatus
->Information
= 0;
368 IoStatus
->Status
= Status
;
369 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
374 Status
= ReadCacheSegment(CacheSeg
);
375 if (!NT_SUCCESS(Status
))
377 IoStatus
->Information
= 0;
378 IoStatus
->Status
= Status
;
379 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
383 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
385 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
386 ReadLength
+= TempLength
;
387 Length
-= TempLength
;
388 ReadOffset
+= TempLength
;
389 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
393 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
394 ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
395 ReadLength
+= TempLength
;
396 Length
-= TempLength
;
397 ReadOffset
+= TempLength
;
398 #if defined(__GNUC__)
399 Buffer
+= TempLength
;
402 char* pTemp
= Buffer
;
408 IoStatus
->Status
= STATUS_SUCCESS
;
409 IoStatus
->Information
= ReadLength
;
410 DPRINT("CcCopyRead O.K.\n");
418 CcCopyWrite (IN PFILE_OBJECT FileObject
,
419 IN PLARGE_INTEGER FileOffset
,
428 PLIST_ENTRY current_entry
;
429 PCACHE_SEGMENT CacheSeg
;
434 DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
435 "Length %d, Wait %d, Buffer %x)\n",
436 FileObject
, (ULONG
)FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
438 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
439 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
443 /* testing, if the requested datas are available */
444 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
445 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
446 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
448 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
449 BcbSegmentListEntry
);
450 if (!CacheSeg
->Valid
)
452 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
453 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
454 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
455 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
456 Bcb
->CacheSegmentSize
))
458 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
459 /* datas not available */
463 current_entry
= current_entry
->Flink
;
465 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
468 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
472 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
473 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
474 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
475 &BaseAddress
, &Valid
, &CacheSeg
);
476 if (!NT_SUCCESS(Status
))
482 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
487 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
489 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
491 Length
-= TempLength
;
492 WriteOffset
+= TempLength
;
493 #if defined(__GNUC__)
494 Buffer
+= TempLength
;
497 char* pTemp
= Buffer
;
506 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
507 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
508 &BaseAddress
, &Valid
, &CacheSeg
);
509 if (!NT_SUCCESS(Status
))
513 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
515 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
517 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
521 memcpy (BaseAddress
, Buffer
, TempLength
);
522 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
523 Length
-= TempLength
;
524 WriteOffset
+= TempLength
;
525 #if defined(__GNUC__)
526 Buffer
+= TempLength
;
529 char* pTemp
= Buffer
;
544 IN PFILE_OBJECT FileObject
,
545 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
548 IN ULONG BytesToWrite
,
561 IN PFILE_OBJECT FileObject
,
566 OUT PIO_STATUS_BLOCK IoStatus
577 IN PFILE_OBJECT FileObject
,
590 CcWaitForCurrentLazyWriterActivity (
595 return STATUS_NOT_IMPLEMENTED
;
602 CcZeroData (IN PFILE_OBJECT FileObject
,
603 IN PLARGE_INTEGER StartOffset
,
604 IN PLARGE_INTEGER EndOffset
,
608 LARGE_INTEGER WriteOffset
;
613 IO_STATUS_BLOCK Iosb
;
616 DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
617 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
620 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
621 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
623 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
625 /* File is not cached */
627 Mdl
= alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
631 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
633 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
637 CurrentLength
= Length
;
639 MmInitializeMdl(Mdl
, (PVOID
)WriteOffset
.u
.LowPart
, CurrentLength
);
640 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
641 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
643 ((PPFN_TYPE
)(Mdl
+ 1))[i
] = CcZeroPage
;
645 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
646 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
647 if (Status
== STATUS_PENDING
)
649 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
650 Status
= Iosb
.Status
;
652 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
653 if (!NT_SUCCESS(Status
))
657 WriteOffset
.QuadPart
+= CurrentLength
;
658 Length
-= CurrentLength
;
666 PLIST_ENTRY current_entry
;
667 PCACHE_SEGMENT CacheSeg
, current
, previous
;
670 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
673 /* testing, if the requested datas are available */
674 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
675 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
676 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
678 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
679 BcbSegmentListEntry
);
680 if (!CacheSeg
->Valid
)
682 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
683 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
684 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
685 WriteOffset
.u
.LowPart
+ Length
<=
686 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
688 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
689 /* datas not available */
693 current_entry
= current_entry
->Flink
;
695 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
700 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
701 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
703 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
707 CurrentLength
= Length
;
709 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
710 Offset
+ CurrentLength
, &CacheSeg
);
711 if (!NT_SUCCESS(Status
))
717 while (current
!= NULL
)
719 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
721 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
725 /* read the segment */
726 Status
= ReadCacheSegment(current
);
727 if (!NT_SUCCESS(Status
))
729 DPRINT1("ReadCacheSegment failed, status %x\n",
733 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
737 TempLength
= Bcb
->CacheSegmentSize
;
739 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
741 WriteOffset
.QuadPart
+= TempLength
;
742 CurrentLength
-= TempLength
;
743 Length
-= TempLength
;
745 current
= current
->NextInChain
;
749 while (current
!= NULL
)
752 current
= current
->NextInChain
;
753 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);