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 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 EXPORTED CcFastMdlReadWait
;
33 ULONG EXPORTED CcFastReadNotPossible
;
34 ULONG EXPORTED CcFastReadWait
;
35 ULONG CcFastReadNoWait
;
36 ULONG CcFastReadResourceMiss
;
39 /* FUNCTIONS *****************************************************************/
42 CcInitCacheZeroPage(VOID
)
46 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &CcZeroPage
);
47 if (!NT_SUCCESS(Status
))
49 DbgPrint("Can't allocate CcZeroPage.\n");
52 Status
= MiZeroPage(CcZeroPage
);
53 if (!NT_SUCCESS(Status
))
55 DbgPrint("Can't zero out CcZeroPage.\n");
61 ReadCacheSegmentChain(PBCB Bcb
, ULONG ReadOffset
, ULONG Length
,
65 PCACHE_SEGMENT current
;
66 PCACHE_SEGMENT previous
;
68 LARGE_INTEGER SegOffset
;
74 Mdl
= alloca(MmSizeOfMdl(NULL
, MAX_RW_LENGTH
));
76 Status
= CcRosGetCacheSegmentChain(Bcb
, ReadOffset
, Length
, &head
);
77 if (!NT_SUCCESS(Status
))
82 while (current
!= NULL
)
85 * If the current segment is valid then copy it into the
90 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
91 memcpy(Buffer
, current
->BaseAddress
, TempLength
);
101 Length
= Length
- TempLength
;
103 current
= current
->NextInChain
;
104 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
107 * Otherwise read in as much as we can.
111 PCACHE_SEGMENT current2
;
117 * Count the maximum number of bytes we could read starting
118 * from the current segment.
122 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
124 current2
= current2
->NextInChain
;
125 current_size
+= Bcb
->CacheSegmentSize
;
129 * Create an MDL which contains all their pages.
131 MmInitializeMdl(Mdl
, NULL
, current_size
);
132 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
135 MdlPages
= (PPFN_TYPE
)(Mdl
+ 1);
136 while (current2
!= NULL
&& !current2
->Valid
&& current_size
< MAX_RW_LENGTH
)
138 PVOID address
= current2
->BaseAddress
;
139 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++, address
= RVA(address
, PAGE_SIZE
))
141 *MdlPages
++ = MmGetPfnForProcess(NULL
, address
);
143 current2
= current2
->NextInChain
;
144 current_size
+= Bcb
->CacheSegmentSize
;
148 * Read in the information.
150 SegOffset
.QuadPart
= current
->FileOffset
;
151 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
152 Status
= IoPageRead(Bcb
->FileObject
,
157 if (Status
== STATUS_PENDING
)
159 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
160 Status
= Iosb
.Status
;
162 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
164 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
166 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
168 while (current
!= NULL
)
171 current
= current
->NextInChain
;
172 CcRosReleaseCacheSegment(Bcb
, previous
, FALSE
, FALSE
, FALSE
);
177 while (current
!= NULL
&& !current
->Valid
&& current_size
< MAX_RW_LENGTH
)
180 current
= current
->NextInChain
;
181 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
182 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
183 #if defined(__GNUC__)
184 Buffer
+= TempLength
;
187 char* pTemp
= Buffer
;
192 Length
= Length
- TempLength
;
193 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
194 current_size
+= Bcb
->CacheSegmentSize
;
198 return(STATUS_SUCCESS
);
202 ReadCacheSegment(PCACHE_SEGMENT CacheSeg
)
207 LARGE_INTEGER SegOffset
;
208 IO_STATUS_BLOCK IoStatus
;
211 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
212 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
213 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
215 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
217 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
218 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
219 MmBuildMdlForNonPagedPool(Mdl
);
220 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
221 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
222 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, & Event
, &IoStatus
);
223 if (Status
== STATUS_PENDING
)
225 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
226 Status
= IoStatus
.Status
;
229 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
231 DPRINT1("IoPageRead failed, Status %x\n", Status
);
234 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
236 memset ((char*)CacheSeg
->BaseAddress
+ Size
, 0,
237 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
239 return STATUS_SUCCESS
;
243 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
248 IO_STATUS_BLOCK IoStatus
;
249 LARGE_INTEGER SegOffset
;
252 CacheSeg
->Dirty
= FALSE
;
253 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
254 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
255 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
257 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
259 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
260 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
261 MmBuildMdlForNonPagedPool(Mdl
);
262 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
263 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
264 Status
= IoSynchronousPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
265 if (Status
== STATUS_PENDING
)
267 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
268 Status
= IoStatus
.Status
;
270 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
272 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
273 CacheSeg
->Dirty
= TRUE
;
276 return(STATUS_SUCCESS
);
285 IN PFILE_OBJECT FileObject
,
286 IN ULONG BytesToWrite
,
299 CcCopyRead (IN PFILE_OBJECT FileObject
,
300 IN PLARGE_INTEGER FileOffset
,
304 OUT PIO_STATUS_BLOCK IoStatus
)
308 NTSTATUS Status
= STATUS_SUCCESS
;
310 PCACHE_SEGMENT CacheSeg
;
312 ULONG ReadLength
= 0;
315 PLIST_ENTRY current_entry
;
316 PCACHE_SEGMENT current
;
318 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
319 "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n",
320 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
323 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
324 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
326 DPRINT("AllocationSize %d, FileSize %d\n",
327 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
328 (ULONG
)Bcb
->FileSize
.QuadPart
);
331 * Check for the nowait case that all the cache segments that would
332 * cover this read are in memory.
336 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
337 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
338 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
340 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
341 BcbSegmentListEntry
);
342 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
343 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
345 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
346 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
347 IoStatus
->Information
= 0;
350 current_entry
= current_entry
->Flink
;
352 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
355 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
358 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
359 Status
= CcRosRequestCacheSegment(Bcb
,
360 ROUND_DOWN(ReadOffset
,
361 Bcb
->CacheSegmentSize
),
362 &BaseAddress
, &Valid
, &CacheSeg
);
363 if (!NT_SUCCESS(Status
))
365 IoStatus
->Information
= 0;
366 IoStatus
->Status
= Status
;
367 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
372 Status
= ReadCacheSegment(CacheSeg
);
373 if (!NT_SUCCESS(Status
))
375 IoStatus
->Information
= 0;
376 IoStatus
->Status
= Status
;
377 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
381 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
383 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
384 ReadLength
+= TempLength
;
385 Length
-= TempLength
;
386 ReadOffset
+= TempLength
;
387 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
391 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
392 ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
393 ReadLength
+= TempLength
;
394 Length
-= TempLength
;
395 ReadOffset
+= TempLength
;
396 #if defined(__GNUC__)
397 Buffer
+= TempLength
;
400 char* pTemp
= Buffer
;
406 IoStatus
->Status
= STATUS_SUCCESS
;
407 IoStatus
->Information
= ReadLength
;
408 DPRINT("CcCopyRead O.K.\n");
416 CcCopyWrite (IN PFILE_OBJECT FileObject
,
417 IN PLARGE_INTEGER FileOffset
,
426 PLIST_ENTRY current_entry
;
427 PCACHE_SEGMENT CacheSeg
;
432 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
433 "Length %d, Wait %d, Buffer 0x%p)\n",
434 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
436 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
437 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
441 /* testing, if the requested datas are available */
442 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
443 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
444 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
446 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
447 BcbSegmentListEntry
);
448 if (!CacheSeg
->Valid
)
450 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
451 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
452 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
453 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
454 Bcb
->CacheSegmentSize
))
456 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
457 /* datas not available */
461 current_entry
= current_entry
->Flink
;
463 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
466 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
470 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
471 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
472 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
473 &BaseAddress
, &Valid
, &CacheSeg
);
474 if (!NT_SUCCESS(Status
))
480 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
485 memcpy ((char*)BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
487 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
489 Length
-= TempLength
;
490 WriteOffset
+= TempLength
;
491 #if defined(__GNUC__)
492 Buffer
+= TempLength
;
495 char* pTemp
= Buffer
;
504 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
505 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
506 &BaseAddress
, &Valid
, &CacheSeg
);
507 if (!NT_SUCCESS(Status
))
511 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
513 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
515 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
519 memcpy (BaseAddress
, Buffer
, TempLength
);
520 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
521 Length
-= TempLength
;
522 WriteOffset
+= TempLength
;
523 #if defined(__GNUC__)
524 Buffer
+= TempLength
;
527 char* pTemp
= Buffer
;
542 IN PFILE_OBJECT FileObject
,
543 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
546 IN ULONG BytesToWrite
,
559 IN PFILE_OBJECT FileObject
,
564 OUT PIO_STATUS_BLOCK IoStatus
575 IN PFILE_OBJECT FileObject
,
588 CcWaitForCurrentLazyWriterActivity (
593 return STATUS_NOT_IMPLEMENTED
;
600 CcZeroData (IN PFILE_OBJECT FileObject
,
601 IN PLARGE_INTEGER StartOffset
,
602 IN PLARGE_INTEGER EndOffset
,
606 LARGE_INTEGER WriteOffset
;
611 IO_STATUS_BLOCK Iosb
;
614 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
615 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
618 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
619 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
621 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
623 /* File is not cached */
625 Mdl
= alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
629 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
631 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
635 CurrentLength
= Length
;
637 MmInitializeMdl(Mdl
, (PVOID
)WriteOffset
.u
.LowPart
, CurrentLength
);
638 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
639 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
641 ((PPFN_TYPE
)(Mdl
+ 1))[i
] = CcZeroPage
;
643 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
644 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
645 if (Status
== STATUS_PENDING
)
647 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
648 Status
= Iosb
.Status
;
650 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
651 if (!NT_SUCCESS(Status
))
655 WriteOffset
.QuadPart
+= CurrentLength
;
656 Length
-= CurrentLength
;
664 PLIST_ENTRY current_entry
;
665 PCACHE_SEGMENT CacheSeg
, current
, previous
;
668 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
671 /* testing, if the requested datas are available */
672 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
673 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
674 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
676 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
677 BcbSegmentListEntry
);
678 if (!CacheSeg
->Valid
)
680 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
681 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
682 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
683 WriteOffset
.u
.LowPart
+ Length
<=
684 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
686 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
687 /* datas not available */
691 current_entry
= current_entry
->Flink
;
693 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
698 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
699 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
701 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
705 CurrentLength
= Length
;
707 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
708 Offset
+ CurrentLength
, &CacheSeg
);
709 if (!NT_SUCCESS(Status
))
715 while (current
!= NULL
)
717 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
719 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
723 /* read the segment */
724 Status
= ReadCacheSegment(current
);
725 if (!NT_SUCCESS(Status
))
727 DPRINT1("ReadCacheSegment failed, status %x\n",
731 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
735 TempLength
= Bcb
->CacheSegmentSize
;
737 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
739 WriteOffset
.QuadPart
+= TempLength
;
740 CurrentLength
-= TempLength
;
741 Length
-= TempLength
;
743 current
= current
->NextInChain
;
747 while (current
!= NULL
)
750 current
= current
->NextInChain
;
751 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);