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_NUMBER CcZeroPage
= 0;
20 #define MAX_ZERO_LENGTH (256 * 1024)
22 typedef enum _CC_COPY_OPERATION
29 ULONG CcRosTraceLevel
= 0;
30 ULONG CcFastMdlReadWait
;
31 ULONG CcFastMdlReadNotPossible
;
32 ULONG CcFastReadNotPossible
;
34 ULONG CcFastReadNoWait
;
35 ULONG CcFastReadResourceMiss
;
37 extern KEVENT iLazyWriterNotify
;
39 /* FUNCTIONS *****************************************************************/
44 IN PFN_NUMBER PageFrameIndex
54 MI_SET_USAGE(MI_USAGE_CACHE
);
55 //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
56 Status
= MmRequestPageMemoryConsumer(MC_SYSTEM
, TRUE
, &CcZeroPage
);
57 if (!NT_SUCCESS(Status
))
59 DbgPrint("Can't allocate CcZeroPage.\n");
60 KeBugCheck(CACHE_MANAGER
);
62 MiZeroPhysicalPage(CcZeroPage
);
67 CcReadVirtualAddress (
73 IO_STATUS_BLOCK IoStatus
;
76 Size
= (ULONG
)(Vacb
->SharedCacheMap
->SectionSize
.QuadPart
- Vacb
->FileOffset
.QuadPart
);
77 if (Size
> VACB_MAPPING_GRANULARITY
)
79 Size
= VACB_MAPPING_GRANULARITY
;
82 Pages
= BYTES_TO_PAGES(Size
);
83 ASSERT(Pages
* PAGE_SIZE
<= VACB_MAPPING_GRANULARITY
);
85 Mdl
= IoAllocateMdl(Vacb
->BaseAddress
, Pages
* PAGE_SIZE
, FALSE
, FALSE
, NULL
);
88 return STATUS_INSUFFICIENT_RESOURCES
;
91 Status
= STATUS_SUCCESS
;
94 MmProbeAndLockPages(Mdl
, KernelMode
, IoWriteAccess
);
96 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
98 Status
= _SEH2_GetExceptionCode();
99 KeBugCheck(CACHE_MANAGER
);
102 if (NT_SUCCESS(Status
))
104 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
105 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
106 Status
= IoPageRead(Vacb
->SharedCacheMap
->FileObject
, Mdl
, &Vacb
->FileOffset
, &Event
, &IoStatus
);
107 if (Status
== STATUS_PENDING
)
109 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
110 Status
= IoStatus
.Status
;
118 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
120 DPRINT1("IoPageRead failed, Status %x\n", Status
);
124 if (Size
< VACB_MAPPING_GRANULARITY
)
126 RtlZeroMemory((char*)Vacb
->BaseAddress
+ Size
,
127 VACB_MAPPING_GRANULARITY
- Size
);
130 return STATUS_SUCCESS
;
135 CcWriteVirtualAddress (
141 IO_STATUS_BLOCK IoStatus
;
145 Size
= (ULONG
)(Vacb
->SharedCacheMap
->SectionSize
.QuadPart
- Vacb
->FileOffset
.QuadPart
);
146 if (Size
> VACB_MAPPING_GRANULARITY
)
148 Size
= VACB_MAPPING_GRANULARITY
;
151 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
152 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
158 MmGetPfnForProcess(NULL
, (PVOID
)((ULONG_PTR
)Vacb
->BaseAddress
+ (i
<< PAGE_SHIFT
)));
159 } while (++i
< (Size
>> PAGE_SHIFT
));
162 Mdl
= IoAllocateMdl(Vacb
->BaseAddress
, Size
, FALSE
, FALSE
, NULL
);
165 return STATUS_INSUFFICIENT_RESOURCES
;
168 Status
= STATUS_SUCCESS
;
171 MmProbeAndLockPages(Mdl
, KernelMode
, IoReadAccess
);
173 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
175 Status
= _SEH2_GetExceptionCode();
176 KeBugCheck(CACHE_MANAGER
);
179 if (NT_SUCCESS(Status
))
181 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
182 Status
= IoSynchronousPageWrite(Vacb
->SharedCacheMap
->FileObject
, Mdl
, &Vacb
->FileOffset
, &Event
, &IoStatus
);
183 if (Status
== STATUS_PENDING
)
185 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
186 Status
= IoStatus
.Status
;
192 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
194 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
199 return STATUS_SUCCESS
;
204 _Inout_ PVOID BaseAddress
,
205 _Inout_opt_ PVOID Buffer
,
207 _In_ CC_COPY_OPERATION Operation
)
209 NTSTATUS Status
= STATUS_SUCCESS
;
211 if (Operation
== CcOperationZero
)
214 RtlZeroMemory(BaseAddress
, Length
);
220 if (Operation
== CcOperationWrite
)
221 RtlCopyMemory(BaseAddress
, Buffer
, Length
);
223 RtlCopyMemory(Buffer
, BaseAddress
, Length
);
225 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
227 Status
= _SEH2_GetExceptionCode();
236 _In_ PFILE_OBJECT FileObject
,
237 _In_ LONGLONG FileOffset
,
238 _Inout_ PVOID Buffer
,
239 _In_ LONGLONG Length
,
240 _In_ CC_COPY_OPERATION Operation
,
242 _Out_ PIO_STATUS_BLOCK IoStatus
)
245 LONGLONG CurrentOffset
;
248 PROS_SHARED_CACHE_MAP SharedCacheMap
;
249 PLIST_ENTRY ListEntry
;
255 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
256 CurrentOffset
= FileOffset
;
261 /* test if the requested data is available */
262 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &OldIrql
);
263 /* FIXME: this loop doesn't take into account areas that don't have
264 * a VACB in the list yet */
265 ListEntry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
266 while (ListEntry
!= &SharedCacheMap
->CacheMapVacbListHead
)
268 Vacb
= CONTAINING_RECORD(ListEntry
,
270 CacheMapVacbListEntry
);
271 ListEntry
= ListEntry
->Flink
;
273 DoRangesIntersect(Vacb
->FileOffset
.QuadPart
,
274 VACB_MAPPING_GRANULARITY
,
275 CurrentOffset
, Length
))
277 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, OldIrql
);
278 /* data not available */
281 if (Vacb
->FileOffset
.QuadPart
>= CurrentOffset
+ Length
)
284 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, OldIrql
);
287 PartialLength
= CurrentOffset
% VACB_MAPPING_GRANULARITY
;
288 if (PartialLength
!= 0)
290 PartialLength
= min(Length
, VACB_MAPPING_GRANULARITY
- PartialLength
);
291 Status
= CcRosRequestVacb(SharedCacheMap
,
292 ROUND_DOWN(CurrentOffset
,
293 VACB_MAPPING_GRANULARITY
),
297 if (!NT_SUCCESS(Status
))
298 ExRaiseStatus(Status
);
301 Status
= CcReadVirtualAddress(Vacb
);
302 if (!NT_SUCCESS(Status
))
304 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
305 ExRaiseStatus(Status
);
308 Status
= ReadWriteOrZero((PUCHAR
)BaseAddress
+ CurrentOffset
% VACB_MAPPING_GRANULARITY
,
313 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, Operation
!= CcOperationRead
, FALSE
);
315 if (!NT_SUCCESS(Status
))
316 ExRaiseStatus(STATUS_INVALID_USER_BUFFER
);
318 Length
-= PartialLength
;
319 CurrentOffset
+= PartialLength
;
320 BytesCopied
+= PartialLength
;
322 if (Operation
!= CcOperationZero
)
323 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ PartialLength
);
328 ASSERT(CurrentOffset
% VACB_MAPPING_GRANULARITY
== 0);
329 PartialLength
= min(VACB_MAPPING_GRANULARITY
, Length
);
330 Status
= CcRosRequestVacb(SharedCacheMap
,
335 if (!NT_SUCCESS(Status
))
336 ExRaiseStatus(Status
);
338 (Operation
== CcOperationRead
||
339 PartialLength
< VACB_MAPPING_GRANULARITY
))
341 Status
= CcReadVirtualAddress(Vacb
);
342 if (!NT_SUCCESS(Status
))
344 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
345 ExRaiseStatus(Status
);
348 Status
= ReadWriteOrZero(BaseAddress
, Buffer
, PartialLength
, Operation
);
350 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, Operation
!= CcOperationRead
, FALSE
);
352 if (!NT_SUCCESS(Status
))
353 ExRaiseStatus(STATUS_INVALID_USER_BUFFER
);
355 Length
-= PartialLength
;
356 CurrentOffset
+= PartialLength
;
357 BytesCopied
+= PartialLength
;
359 if (Operation
!= CcOperationZero
)
360 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ PartialLength
);
362 IoStatus
->Status
= STATUS_SUCCESS
;
363 IoStatus
->Information
= BytesCopied
;
373 IN PFILE_OBJECT FileObject
,
374 IN ULONG BytesToWrite
,
378 CCTRACE(CC_API_DEBUG
, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n",
379 FileObject
, BytesToWrite
, Wait
, Retrying
);
381 /* We cannot write if dirty pages count is above threshold */
382 if (CcTotalDirtyPages
> CcDirtyPageThreshold
)
387 /* We cannot write if dirty pages count will bring use above
388 * XXX: Might not be accurate
390 if (CcTotalDirtyPages
+ (BytesToWrite
/ PAGE_SIZE
) > CcDirtyPageThreshold
)
395 /* FIXME: Handle per-file threshold */
406 IN PFILE_OBJECT FileObject
,
407 IN PLARGE_INTEGER FileOffset
,
411 OUT PIO_STATUS_BLOCK IoStatus
)
413 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d\n",
414 FileObject
, FileOffset
->QuadPart
, Length
, Wait
);
416 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
417 "Length %lu, Wait %u, Buffer 0x%p, IoStatus 0x%p)\n",
418 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
421 return CcCopyData(FileObject
,
422 FileOffset
->QuadPart
,
436 IN PFILE_OBJECT FileObject
,
437 IN PLARGE_INTEGER FileOffset
,
442 IO_STATUS_BLOCK IoStatus
;
444 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d Buffer=%p\n",
445 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
447 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
448 "Length %lu, Wait %u, Buffer 0x%p)\n",
449 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
451 return CcCopyData(FileObject
,
452 FileOffset
->QuadPart
,
466 IN PFILE_OBJECT FileObject
,
467 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
470 IN ULONG BytesToWrite
,
473 PROS_DEFERRED_WRITE_CONTEXT Context
;
475 CCTRACE(CC_API_DEBUG
, "FileObject=%p PostRoutine=%p Context1=%p Context2=%p BytesToWrite=%lu Retrying=%d\n",
476 FileObject
, PostRoutine
, Context1
, Context2
, BytesToWrite
, Retrying
);
478 /* Try to allocate a context for queueing the write operation */
479 Context
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(ROS_DEFERRED_WRITE_CONTEXT
), 'CcDw');
480 /* If it failed, immediately execute the operation! */
483 PostRoutine(Context1
, Context2
);
487 /* Otherwise, initialize the context */
488 Context
->FileObject
= FileObject
;
489 Context
->PostRoutine
= PostRoutine
;
490 Context
->Context1
= Context1
;
491 Context
->Context2
= Context2
;
492 Context
->BytesToWrite
= BytesToWrite
;
493 Context
->Retrying
= Retrying
;
498 /* To the top, if that's a retry */
499 ExInterlockedInsertHeadList(&CcDeferredWrites
,
500 &Context
->CcDeferredWritesEntry
,
501 &CcDeferredWriteSpinLock
);
505 /* To the bottom, if that's a first time */
506 ExInterlockedInsertTailList(&CcDeferredWrites
,
507 &Context
->CcDeferredWritesEntry
,
508 &CcDeferredWriteSpinLock
);
518 IN PFILE_OBJECT FileObject
,
523 OUT PIO_STATUS_BLOCK IoStatus
)
525 LARGE_INTEGER LargeFileOffset
;
528 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%lu Length=%lu PageCount=%lu Buffer=%p\n",
529 FileObject
, FileOffset
, Length
, PageCount
, Buffer
);
531 DBG_UNREFERENCED_PARAMETER(PageCount
);
533 LargeFileOffset
.QuadPart
= FileOffset
;
534 Success
= CcCopyRead(FileObject
,
540 ASSERT(Success
== TRUE
);
549 IN PFILE_OBJECT FileObject
,
554 LARGE_INTEGER LargeFileOffset
;
557 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%lu Length=%lu Buffer=%p\n",
558 FileObject
, FileOffset
, Length
, Buffer
);
560 LargeFileOffset
.QuadPart
= FileOffset
;
561 Success
= CcCopyWrite(FileObject
,
566 ASSERT(Success
== TRUE
);
574 CcWaitForCurrentLazyWriterActivity (
579 /* Lazy writer is done when its event is set */
580 Status
= KeWaitForSingleObject(&iLazyWriterNotify
,
585 if (!NT_SUCCESS(Status
))
590 return STATUS_SUCCESS
;
599 IN PFILE_OBJECT FileObject
,
600 IN PLARGE_INTEGER StartOffset
,
601 IN PLARGE_INTEGER EndOffset
,
605 LARGE_INTEGER WriteOffset
;
610 IO_STATUS_BLOCK Iosb
;
613 CCTRACE(CC_API_DEBUG
, "FileObject=%p StartOffset=%I64u EndOffset=%I64u Wait=%d\n",
614 FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
, Wait
);
616 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
617 "Wait %u)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
620 Length
= EndOffset
->QuadPart
- StartOffset
->QuadPart
;
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
.QuadPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
633 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.QuadPart
% PAGE_SIZE
;
637 CurrentLength
= Length
;
639 MmInitializeMdl(Mdl
, (PVOID
)(ULONG_PTR
)WriteOffset
.QuadPart
, 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_NUMBER
)(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 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
654 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
656 if (!NT_SUCCESS(Status
))
660 WriteOffset
.QuadPart
+= CurrentLength
;
661 Length
-= CurrentLength
;
666 IO_STATUS_BLOCK IoStatus
;
668 return CcCopyData(FileObject
,
669 WriteOffset
.QuadPart
,