1 /* $Id: copy.c,v 1.30 2004/08/15 16:38:59 chorns Exp $
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 (64 * 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
;
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
)
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
);
134 MdlPages
= (PPFN_TYPE
)(Mdl
+ 1);
135 while (current2
!= NULL
&& !current2
->Valid
)
137 PVOID address
= current2
->BaseAddress
;
138 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGE_SIZE
); i
++, address
+= PAGE_SIZE
)
140 *MdlPages
++ = MmGetPfnForProcess(NULL
, address
);
142 current2
= current2
->NextInChain
;
146 * Read in the information.
148 SegOffset
.QuadPart
= current
->FileOffset
;
149 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
150 Status
= IoPageRead(Bcb
->FileObject
,
155 if (Status
== STATUS_PENDING
)
157 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
158 Status
= Iosb
.Status
;
160 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
);
171 while (current
!= NULL
&& !current
->Valid
)
174 current
= current
->NextInChain
;
175 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
176 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
177 #if defined(__GNUC__)
178 Buffer
+= TempLength
;
181 char* pTemp
= Buffer
;
186 Length
= Length
- TempLength
;
187 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
191 return(STATUS_SUCCESS
);
195 ReadCacheSegment(PCACHE_SEGMENT CacheSeg
)
200 LARGE_INTEGER SegOffset
;
201 IO_STATUS_BLOCK IoStatus
;
204 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
205 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
206 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
208 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
210 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
211 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
212 MmBuildMdlForNonPagedPool(Mdl
);
213 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
214 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
215 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, & Event
, &IoStatus
);
216 if (Status
== STATUS_PENDING
)
218 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
219 Status
= IoStatus
.Status
;
222 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
224 DPRINT1("IoPageRead failed, Status %x\n", Status
);
227 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
229 memset ((char*)CacheSeg
->BaseAddress
+ Size
, 0,
230 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
232 return STATUS_SUCCESS
;
236 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
241 IO_STATUS_BLOCK IoStatus
;
242 LARGE_INTEGER SegOffset
;
245 CacheSeg
->Dirty
= FALSE
;
246 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
247 Size
= (ULONG
)(CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
);
248 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
250 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
252 Mdl
= alloca(MmSizeOfMdl(CacheSeg
->BaseAddress
, Size
));
253 MmInitializeMdl(Mdl
, CacheSeg
->BaseAddress
, Size
);
254 MmBuildMdlForNonPagedPool(Mdl
);
255 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
256 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
257 Status
= IoPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &Event
, &IoStatus
);
258 if (Status
== STATUS_PENDING
)
260 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
261 Status
= IoStatus
.Status
;
263 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
265 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
266 CacheSeg
->Dirty
= TRUE
;
269 return(STATUS_SUCCESS
);
278 IN PFILE_OBJECT FileObject
,
279 IN ULONG BytesToWrite
,
292 CcCopyRead (IN PFILE_OBJECT FileObject
,
293 IN PLARGE_INTEGER FileOffset
,
297 OUT PIO_STATUS_BLOCK IoStatus
)
301 NTSTATUS Status
= STATUS_SUCCESS
;
303 PCACHE_SEGMENT CacheSeg
;
305 ULONG ReadLength
= 0;
308 PLIST_ENTRY current_entry
;
309 PCACHE_SEGMENT current
;
311 DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
312 "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
313 FileObject
, (ULONG
)FileOffset
->QuadPart
, Length
, Wait
,
316 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
317 ReadOffset
= (ULONG
)FileOffset
->QuadPart
;
319 DPRINT("AllocationSize %d, FileSize %d\n",
320 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
321 (ULONG
)Bcb
->FileSize
.QuadPart
);
324 * Check for the nowait case that all the cache segments that would
325 * cover this read are in memory.
329 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
330 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
331 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
333 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
334 BcbSegmentListEntry
);
335 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
336 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
338 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
339 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
340 IoStatus
->Information
= 0;
343 current_entry
= current_entry
->Flink
;
345 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
348 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
351 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
352 Status
= CcRosRequestCacheSegment(Bcb
,
353 ROUND_DOWN(ReadOffset
,
354 Bcb
->CacheSegmentSize
),
355 &BaseAddress
, &Valid
, &CacheSeg
);
356 if (!NT_SUCCESS(Status
))
358 IoStatus
->Information
= 0;
359 IoStatus
->Status
= Status
;
360 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
365 Status
= ReadCacheSegment(CacheSeg
);
366 if (!NT_SUCCESS(Status
))
368 IoStatus
->Information
= 0;
369 IoStatus
->Status
= Status
;
370 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
374 memcpy (Buffer
, (char*)BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
376 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
377 ReadLength
+= TempLength
;
378 Length
-= TempLength
;
379 ReadOffset
+= TempLength
;
380 Buffer
= (PVOID
)((char*)Buffer
+ TempLength
);
384 TempLength
= min(max(Bcb
->CacheSegmentSize
, MAX_RW_LENGTH
), Length
);
385 ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
386 ReadLength
+= TempLength
;
387 Length
-= TempLength
;
388 ReadOffset
+= TempLength
;
389 #if defined(__GNUC__)
390 Buffer
+= TempLength
;
393 char* pTemp
= Buffer
;
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 %x, FileOffset %x, "
426 "Length %d, Wait %d, Buffer %x)\n",
427 FileObject
, (ULONG
)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
;
484 #if defined(__GNUC__)
485 Buffer
+= TempLength
;
488 char* pTemp
= Buffer
;
497 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
498 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
499 &BaseAddress
, &Valid
, &CacheSeg
);
500 if (!NT_SUCCESS(Status
))
504 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
506 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
508 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
512 memcpy (BaseAddress
, Buffer
, TempLength
);
513 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
514 Length
-= TempLength
;
515 WriteOffset
+= TempLength
;
516 #if defined(__GNUC__)
517 Buffer
+= TempLength
;
520 char* pTemp
= Buffer
;
535 IN PFILE_OBJECT FileObject
,
536 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
539 IN ULONG BytesToWrite
,
552 IN PFILE_OBJECT FileObject
,
557 OUT PIO_STATUS_BLOCK IoStatus
569 IN PFILE_OBJECT FileObject
,
570 IN PLARGE_INTEGER FileOffset
,
584 CcWaitForCurrentLazyWriterActivity (
589 return STATUS_NOT_IMPLEMENTED
;
596 CcZeroData (IN PFILE_OBJECT FileObject
,
597 IN PLARGE_INTEGER StartOffset
,
598 IN PLARGE_INTEGER EndOffset
,
602 LARGE_INTEGER WriteOffset
;
607 IO_STATUS_BLOCK Iosb
;
610 DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
611 "Wait %d)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
614 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
615 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
617 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
619 /* File is not cached */
621 Mdl
= alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
625 if (Length
+ WriteOffset
.u
.LowPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
627 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.u
.LowPart
% PAGE_SIZE
;
631 CurrentLength
= Length
;
633 MmInitializeMdl(Mdl
, (PVOID
)WriteOffset
.u
.LowPart
, CurrentLength
);
634 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
635 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
637 ((PPFN_TYPE
)(Mdl
+ 1))[i
] = CcZeroPage
;
639 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
640 Status
= IoPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
641 if (Status
== STATUS_PENDING
)
643 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
644 Status
= Iosb
.Status
;
646 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
647 if (!NT_SUCCESS(Status
))
651 WriteOffset
.QuadPart
+= CurrentLength
;
652 Length
-= CurrentLength
;
660 PLIST_ENTRY current_entry
;
661 PCACHE_SEGMENT CacheSeg
, current
, previous
;
664 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
667 /* testing, if the requested datas are available */
668 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
669 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
670 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
672 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
673 BcbSegmentListEntry
);
674 if (!CacheSeg
->Valid
)
676 if ((WriteOffset
.u
.LowPart
>= CacheSeg
->FileOffset
&&
677 WriteOffset
.u
.LowPart
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
678 || (WriteOffset
.u
.LowPart
+ Length
> CacheSeg
->FileOffset
&&
679 WriteOffset
.u
.LowPart
+ Length
<=
680 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
682 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
683 /* datas not available */
687 current_entry
= current_entry
->Flink
;
689 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
694 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
695 if (Length
+ Offset
> MAX_ZERO_LENGTH
)
697 CurrentLength
= MAX_ZERO_LENGTH
- Offset
;
701 CurrentLength
= Length
;
703 Status
= CcRosGetCacheSegmentChain (Bcb
, WriteOffset
.u
.LowPart
- Offset
,
704 Offset
+ CurrentLength
, &CacheSeg
);
705 if (!NT_SUCCESS(Status
))
711 while (current
!= NULL
)
713 Offset
= WriteOffset
.u
.LowPart
% Bcb
->CacheSegmentSize
;
715 Offset
+ CurrentLength
< Bcb
->CacheSegmentSize
)
719 /* read the segment */
720 Status
= ReadCacheSegment(current
);
721 if (!NT_SUCCESS(Status
))
723 DPRINT1("ReadCacheSegment failed, status %x\n",
727 TempLength
= min (CurrentLength
, Bcb
->CacheSegmentSize
- Offset
);
731 TempLength
= Bcb
->CacheSegmentSize
;
733 memset ((PUCHAR
)current
->BaseAddress
+ Offset
, 0, TempLength
);
735 WriteOffset
.QuadPart
+= TempLength
;
736 CurrentLength
-= TempLength
;
737 Length
-= TempLength
;
739 current
= current
->NextInChain
;
743 while (current
!= NULL
)
746 current
= current
->NextInChain
;
747 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, TRUE
, FALSE
);