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 /* FUNCTIONS *****************************************************************/
42 IN PFN_NUMBER PageFrameIndex
52 MI_SET_USAGE(MI_USAGE_CACHE
);
53 //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
54 Status
= MmRequestPageMemoryConsumer(MC_SYSTEM
, TRUE
, &CcZeroPage
);
55 if (!NT_SUCCESS(Status
))
57 DbgPrint("Can't allocate CcZeroPage.\n");
58 KeBugCheck(CACHE_MANAGER
);
60 MiZeroPhysicalPage(CcZeroPage
);
65 CcReadVirtualAddress (
71 IO_STATUS_BLOCK IoStatus
;
74 Size
= (ULONG
)(Vacb
->SharedCacheMap
->SectionSize
.QuadPart
- Vacb
->FileOffset
.QuadPart
);
75 if (Size
> VACB_MAPPING_GRANULARITY
)
77 Size
= VACB_MAPPING_GRANULARITY
;
80 Pages
= BYTES_TO_PAGES(Size
);
81 ASSERT(Pages
* PAGE_SIZE
<= VACB_MAPPING_GRANULARITY
);
83 Mdl
= IoAllocateMdl(Vacb
->BaseAddress
, Pages
* PAGE_SIZE
, FALSE
, FALSE
, NULL
);
86 return STATUS_INSUFFICIENT_RESOURCES
;
89 Status
= STATUS_SUCCESS
;
92 MmProbeAndLockPages(Mdl
, KernelMode
, IoWriteAccess
);
94 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
96 Status
= _SEH2_GetExceptionCode();
97 KeBugCheck(CACHE_MANAGER
);
100 if (NT_SUCCESS(Status
))
102 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
103 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
104 Status
= IoPageRead(Vacb
->SharedCacheMap
->FileObject
, Mdl
, &Vacb
->FileOffset
, &Event
, &IoStatus
);
105 if (Status
== STATUS_PENDING
)
107 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
108 Status
= IoStatus
.Status
;
116 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
118 DPRINT1("IoPageRead failed, Status %x\n", Status
);
122 if (Size
< VACB_MAPPING_GRANULARITY
)
124 RtlZeroMemory((char*)Vacb
->BaseAddress
+ Size
,
125 VACB_MAPPING_GRANULARITY
- Size
);
128 return STATUS_SUCCESS
;
133 CcWriteVirtualAddress (
139 IO_STATUS_BLOCK IoStatus
;
143 Size
= (ULONG
)(Vacb
->SharedCacheMap
->SectionSize
.QuadPart
- Vacb
->FileOffset
.QuadPart
);
144 if (Size
> VACB_MAPPING_GRANULARITY
)
146 Size
= VACB_MAPPING_GRANULARITY
;
149 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
150 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
156 MmGetPfnForProcess(NULL
, (PVOID
)((ULONG_PTR
)Vacb
->BaseAddress
+ (i
<< PAGE_SHIFT
)));
157 } while (++i
< (Size
>> PAGE_SHIFT
));
160 Mdl
= IoAllocateMdl(Vacb
->BaseAddress
, Size
, FALSE
, FALSE
, NULL
);
163 return STATUS_INSUFFICIENT_RESOURCES
;
166 Status
= STATUS_SUCCESS
;
169 MmProbeAndLockPages(Mdl
, KernelMode
, IoReadAccess
);
171 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
173 Status
= _SEH2_GetExceptionCode();
174 KeBugCheck(CACHE_MANAGER
);
177 if (NT_SUCCESS(Status
))
179 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
180 Status
= IoSynchronousPageWrite(Vacb
->SharedCacheMap
->FileObject
, Mdl
, &Vacb
->FileOffset
, &Event
, &IoStatus
);
181 if (Status
== STATUS_PENDING
)
183 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
184 Status
= IoStatus
.Status
;
190 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
192 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
197 return STATUS_SUCCESS
;
202 _Inout_ PVOID BaseAddress
,
203 _Inout_opt_ PVOID Buffer
,
205 _In_ CC_COPY_OPERATION Operation
)
207 NTSTATUS Status
= STATUS_SUCCESS
;
209 if (Operation
== CcOperationZero
)
212 RtlZeroMemory(BaseAddress
, Length
);
218 if (Operation
== CcOperationWrite
)
219 RtlCopyMemory(BaseAddress
, Buffer
, Length
);
221 RtlCopyMemory(Buffer
, BaseAddress
, Length
);
223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
225 Status
= _SEH2_GetExceptionCode();
234 _In_ PFILE_OBJECT FileObject
,
235 _In_ LONGLONG FileOffset
,
236 _Inout_ PVOID Buffer
,
237 _In_ LONGLONG Length
,
238 _In_ CC_COPY_OPERATION Operation
,
240 _Out_ PIO_STATUS_BLOCK IoStatus
)
243 LONGLONG CurrentOffset
;
246 PROS_SHARED_CACHE_MAP SharedCacheMap
;
247 PLIST_ENTRY ListEntry
;
253 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
254 CurrentOffset
= FileOffset
;
259 /* test if the requested data is available */
260 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &OldIrql
);
261 /* FIXME: this loop doesn't take into account areas that don't have
262 * a VACB in the list yet */
263 ListEntry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
264 while (ListEntry
!= &SharedCacheMap
->CacheMapVacbListHead
)
266 Vacb
= CONTAINING_RECORD(ListEntry
,
268 CacheMapVacbListEntry
);
269 ListEntry
= ListEntry
->Flink
;
271 DoRangesIntersect(Vacb
->FileOffset
.QuadPart
,
272 VACB_MAPPING_GRANULARITY
,
273 CurrentOffset
, Length
))
275 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, OldIrql
);
276 /* data not available */
279 if (Vacb
->FileOffset
.QuadPart
>= CurrentOffset
+ Length
)
282 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, OldIrql
);
285 PartialLength
= CurrentOffset
% VACB_MAPPING_GRANULARITY
;
286 if (PartialLength
!= 0)
288 PartialLength
= min(Length
, VACB_MAPPING_GRANULARITY
- PartialLength
);
289 Status
= CcRosRequestVacb(SharedCacheMap
,
290 ROUND_DOWN(CurrentOffset
,
291 VACB_MAPPING_GRANULARITY
),
295 if (!NT_SUCCESS(Status
))
296 ExRaiseStatus(Status
);
299 Status
= CcReadVirtualAddress(Vacb
);
300 if (!NT_SUCCESS(Status
))
302 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
303 ExRaiseStatus(Status
);
306 Status
= ReadWriteOrZero((PUCHAR
)BaseAddress
+ CurrentOffset
% VACB_MAPPING_GRANULARITY
,
311 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, Operation
!= CcOperationRead
, FALSE
);
313 if (!NT_SUCCESS(Status
))
314 ExRaiseStatus(STATUS_INVALID_USER_BUFFER
);
316 Length
-= PartialLength
;
317 CurrentOffset
+= PartialLength
;
318 BytesCopied
+= PartialLength
;
320 if (Operation
!= CcOperationZero
)
321 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ PartialLength
);
326 ASSERT(CurrentOffset
% VACB_MAPPING_GRANULARITY
== 0);
327 PartialLength
= min(VACB_MAPPING_GRANULARITY
, Length
);
328 Status
= CcRosRequestVacb(SharedCacheMap
,
333 if (!NT_SUCCESS(Status
))
334 ExRaiseStatus(Status
);
336 (Operation
== CcOperationRead
||
337 PartialLength
< VACB_MAPPING_GRANULARITY
))
339 Status
= CcReadVirtualAddress(Vacb
);
340 if (!NT_SUCCESS(Status
))
342 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
343 ExRaiseStatus(Status
);
346 Status
= ReadWriteOrZero(BaseAddress
, Buffer
, PartialLength
, Operation
);
348 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, Operation
!= CcOperationRead
, FALSE
);
350 if (!NT_SUCCESS(Status
))
351 ExRaiseStatus(STATUS_INVALID_USER_BUFFER
);
353 Length
-= PartialLength
;
354 CurrentOffset
+= PartialLength
;
355 BytesCopied
+= PartialLength
;
357 if (Operation
!= CcOperationZero
)
358 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ PartialLength
);
360 IoStatus
->Status
= STATUS_SUCCESS
;
361 IoStatus
->Information
= BytesCopied
;
371 IN PFILE_OBJECT FileObject
,
372 IN ULONG BytesToWrite
,
376 CCTRACE(CC_API_DEBUG
, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n",
377 FileObject
, BytesToWrite
, Wait
, Retrying
);
388 IN PFILE_OBJECT FileObject
,
389 IN PLARGE_INTEGER FileOffset
,
393 OUT PIO_STATUS_BLOCK IoStatus
)
395 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d\n",
396 FileObject
, FileOffset
->QuadPart
, Length
, Wait
);
398 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
399 "Length %lu, Wait %u, Buffer 0x%p, IoStatus 0x%p)\n",
400 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
403 return CcCopyData(FileObject
,
404 FileOffset
->QuadPart
,
418 IN PFILE_OBJECT FileObject
,
419 IN PLARGE_INTEGER FileOffset
,
424 IO_STATUS_BLOCK IoStatus
;
426 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d Buffer=%p\n",
427 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
429 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
430 "Length %lu, Wait %u, Buffer 0x%p)\n",
431 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
433 return CcCopyData(FileObject
,
434 FileOffset
->QuadPart
,
448 IN PFILE_OBJECT FileObject
,
449 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
452 IN ULONG BytesToWrite
,
455 CCTRACE(CC_API_DEBUG
, "FileObject=%p PostRoutine=%p Context1=%p Context2=%p BytesToWrite=%lu Retrying=%d\n",
456 FileObject
, PostRoutine
, Context1
, Context2
, BytesToWrite
, Retrying
);
458 PostRoutine(Context1
, Context2
);
467 IN PFILE_OBJECT FileObject
,
472 OUT PIO_STATUS_BLOCK IoStatus
)
474 LARGE_INTEGER LargeFileOffset
;
477 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%lu Length=%lu PageCount=%lu Buffer=%p\n",
478 FileObject
, FileOffset
, Length
, PageCount
, Buffer
);
480 DBG_UNREFERENCED_PARAMETER(PageCount
);
482 LargeFileOffset
.QuadPart
= FileOffset
;
483 Success
= CcCopyRead(FileObject
,
489 ASSERT(Success
== TRUE
);
498 IN PFILE_OBJECT FileObject
,
503 LARGE_INTEGER LargeFileOffset
;
506 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%lu Length=%lu Buffer=%p\n",
507 FileObject
, FileOffset
, Length
, Buffer
);
509 LargeFileOffset
.QuadPart
= FileOffset
;
510 Success
= CcCopyWrite(FileObject
,
515 ASSERT(Success
== TRUE
);
523 CcWaitForCurrentLazyWriterActivity (
527 return STATUS_SUCCESS
;
536 IN PFILE_OBJECT FileObject
,
537 IN PLARGE_INTEGER StartOffset
,
538 IN PLARGE_INTEGER EndOffset
,
542 LARGE_INTEGER WriteOffset
;
547 IO_STATUS_BLOCK Iosb
;
550 CCTRACE(CC_API_DEBUG
, "FileObject=%p StartOffset=%I64u EndOffset=%I64u Wait=%d\n",
551 FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
, Wait
);
553 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
554 "Wait %u)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
557 Length
= EndOffset
->QuadPart
- StartOffset
->QuadPart
;
558 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
560 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
562 /* File is not cached */
564 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
568 if (Length
+ WriteOffset
.QuadPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
570 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.QuadPart
% PAGE_SIZE
;
574 CurrentLength
= Length
;
576 MmInitializeMdl(Mdl
, (PVOID
)(ULONG_PTR
)WriteOffset
.QuadPart
, CurrentLength
);
577 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
578 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
580 ((PPFN_NUMBER
)(Mdl
+ 1))[i
] = CcZeroPage
;
582 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
583 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
584 if (Status
== STATUS_PENDING
)
586 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
587 Status
= Iosb
.Status
;
589 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
591 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
593 if (!NT_SUCCESS(Status
))
597 WriteOffset
.QuadPart
+= CurrentLength
;
598 Length
-= CurrentLength
;
603 IO_STATUS_BLOCK IoStatus
;
605 return CcCopyData(FileObject
,
606 WriteOffset
.QuadPart
,