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
7 * PROGRAMMERS: Some people?
8 * Pierre Schweitzer (pierre@reactos.org)
11 /* INCLUDES ******************************************************************/
17 /* GLOBALS *******************************************************************/
19 static PFN_NUMBER CcZeroPage
= 0;
21 #define MAX_ZERO_LENGTH (256 * 1024)
23 typedef enum _CC_COPY_OPERATION
30 ULONG CcRosTraceLevel
= 0;
31 ULONG CcFastMdlReadWait
;
32 ULONG CcFastMdlReadNotPossible
;
33 ULONG CcFastReadNotPossible
;
35 ULONG CcFastReadNoWait
;
36 ULONG CcFastReadResourceMiss
;
38 /* FUNCTIONS *****************************************************************/
43 IN PFN_NUMBER PageFrameIndex
53 MI_SET_USAGE(MI_USAGE_CACHE
);
54 //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
55 Status
= MmRequestPageMemoryConsumer(MC_SYSTEM
, TRUE
, &CcZeroPage
);
56 if (!NT_SUCCESS(Status
))
58 DbgPrint("Can't allocate CcZeroPage.\n");
59 KeBugCheck(CACHE_MANAGER
);
61 MiZeroPhysicalPage(CcZeroPage
);
66 CcReadVirtualAddress (
72 IO_STATUS_BLOCK IoStatus
;
75 Size
= (ULONG
)(Vacb
->SharedCacheMap
->SectionSize
.QuadPart
- Vacb
->FileOffset
.QuadPart
);
76 if (Size
> VACB_MAPPING_GRANULARITY
)
78 Size
= VACB_MAPPING_GRANULARITY
;
81 Pages
= BYTES_TO_PAGES(Size
);
82 ASSERT(Pages
* PAGE_SIZE
<= VACB_MAPPING_GRANULARITY
);
84 Mdl
= IoAllocateMdl(Vacb
->BaseAddress
, Pages
* PAGE_SIZE
, FALSE
, FALSE
, NULL
);
87 return STATUS_INSUFFICIENT_RESOURCES
;
90 Status
= STATUS_SUCCESS
;
93 MmProbeAndLockPages(Mdl
, KernelMode
, IoWriteAccess
);
95 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
)
97 Status
= _SEH2_GetExceptionCode();
98 KeBugCheck(CACHE_MANAGER
);
101 if (NT_SUCCESS(Status
))
103 Mdl
->MdlFlags
|= MDL_IO_PAGE_READ
;
104 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
105 Status
= IoPageRead(Vacb
->SharedCacheMap
->FileObject
, Mdl
, &Vacb
->FileOffset
, &Event
, &IoStatus
);
106 if (Status
== STATUS_PENDING
)
108 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
109 Status
= IoStatus
.Status
;
117 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
119 DPRINT1("IoPageRead failed, Status %x\n", Status
);
123 if (Size
< VACB_MAPPING_GRANULARITY
)
125 RtlZeroMemory((char*)Vacb
->BaseAddress
+ Size
,
126 VACB_MAPPING_GRANULARITY
- Size
);
129 return STATUS_SUCCESS
;
134 CcWriteVirtualAddress (
140 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
);
196 return STATUS_SUCCESS
;
201 _Inout_ PVOID BaseAddress
,
202 _Inout_opt_ PVOID Buffer
,
204 _In_ CC_COPY_OPERATION Operation
)
206 NTSTATUS Status
= STATUS_SUCCESS
;
208 if (Operation
== CcOperationZero
)
211 RtlZeroMemory(BaseAddress
, Length
);
217 if (Operation
== CcOperationWrite
)
218 RtlCopyMemory(BaseAddress
, Buffer
, Length
);
220 RtlCopyMemory(Buffer
, BaseAddress
, Length
);
222 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
224 Status
= _SEH2_GetExceptionCode();
233 _In_ PFILE_OBJECT FileObject
,
234 _In_ LONGLONG FileOffset
,
235 _Inout_ PVOID Buffer
,
236 _In_ LONGLONG Length
,
237 _In_ CC_COPY_OPERATION Operation
,
239 _Out_ PIO_STATUS_BLOCK IoStatus
)
242 LONGLONG CurrentOffset
;
245 PROS_SHARED_CACHE_MAP SharedCacheMap
;
246 PLIST_ENTRY ListEntry
;
252 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
253 CurrentOffset
= FileOffset
;
258 /* test if the requested data is available */
259 KeAcquireSpinLock(&SharedCacheMap
->CacheMapLock
, &OldIrql
);
260 /* FIXME: this loop doesn't take into account areas that don't have
261 * a VACB in the list yet */
262 ListEntry
= SharedCacheMap
->CacheMapVacbListHead
.Flink
;
263 while (ListEntry
!= &SharedCacheMap
->CacheMapVacbListHead
)
265 Vacb
= CONTAINING_RECORD(ListEntry
,
267 CacheMapVacbListEntry
);
268 ListEntry
= ListEntry
->Flink
;
270 DoRangesIntersect(Vacb
->FileOffset
.QuadPart
,
271 VACB_MAPPING_GRANULARITY
,
272 CurrentOffset
, Length
))
274 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, OldIrql
);
275 /* data not available */
278 if (Vacb
->FileOffset
.QuadPart
>= CurrentOffset
+ Length
)
281 KeReleaseSpinLock(&SharedCacheMap
->CacheMapLock
, OldIrql
);
284 PartialLength
= CurrentOffset
% VACB_MAPPING_GRANULARITY
;
285 if (PartialLength
!= 0)
287 PartialLength
= min(Length
, VACB_MAPPING_GRANULARITY
- PartialLength
);
288 Status
= CcRosRequestVacb(SharedCacheMap
,
289 ROUND_DOWN(CurrentOffset
,
290 VACB_MAPPING_GRANULARITY
),
294 if (!NT_SUCCESS(Status
))
295 ExRaiseStatus(Status
);
298 Status
= CcReadVirtualAddress(Vacb
);
299 if (!NT_SUCCESS(Status
))
301 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
302 ExRaiseStatus(Status
);
305 Status
= ReadWriteOrZero((PUCHAR
)BaseAddress
+ CurrentOffset
% VACB_MAPPING_GRANULARITY
,
310 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, Operation
!= CcOperationRead
, FALSE
);
312 if (!NT_SUCCESS(Status
))
313 ExRaiseStatus(STATUS_INVALID_USER_BUFFER
);
315 Length
-= PartialLength
;
316 CurrentOffset
+= PartialLength
;
317 BytesCopied
+= PartialLength
;
319 if (Operation
!= CcOperationZero
)
320 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ PartialLength
);
325 ASSERT(CurrentOffset
% VACB_MAPPING_GRANULARITY
== 0);
326 PartialLength
= min(VACB_MAPPING_GRANULARITY
, Length
);
327 Status
= CcRosRequestVacb(SharedCacheMap
,
332 if (!NT_SUCCESS(Status
))
333 ExRaiseStatus(Status
);
335 (Operation
== CcOperationRead
||
336 PartialLength
< VACB_MAPPING_GRANULARITY
))
338 Status
= CcReadVirtualAddress(Vacb
);
339 if (!NT_SUCCESS(Status
))
341 CcRosReleaseVacb(SharedCacheMap
, Vacb
, FALSE
, FALSE
, FALSE
);
342 ExRaiseStatus(Status
);
345 Status
= ReadWriteOrZero(BaseAddress
, Buffer
, PartialLength
, Operation
);
347 CcRosReleaseVacb(SharedCacheMap
, Vacb
, TRUE
, Operation
!= CcOperationRead
, FALSE
);
349 if (!NT_SUCCESS(Status
))
350 ExRaiseStatus(STATUS_INVALID_USER_BUFFER
);
352 Length
-= PartialLength
;
353 CurrentOffset
+= PartialLength
;
354 BytesCopied
+= PartialLength
;
356 if (Operation
!= CcOperationZero
)
357 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ PartialLength
);
359 IoStatus
->Status
= STATUS_SUCCESS
;
360 IoStatus
->Information
= BytesCopied
;
370 IN PFILE_OBJECT FileObject
,
371 IN ULONG BytesToWrite
,
375 PFSRTL_COMMON_FCB_HEADER Fcb
;
376 PROS_SHARED_CACHE_MAP SharedCacheMap
;
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 /* Is there a limit per file object? */
396 Fcb
= FileObject
->FsContext
;
397 SharedCacheMap
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
398 if (!BooleanFlagOn(Fcb
->Flags
, FSRTL_FLAG_LIMIT_MODIFIED_PAGES
) ||
399 SharedCacheMap
->DirtyPageThreshold
== 0)
401 /* Nope, so that's fine, allow write operation */
405 /* Is dirty page count above local threshold? */
406 if (SharedCacheMap
->DirtyPages
> SharedCacheMap
->DirtyPageThreshold
)
411 /* We cannot write if dirty pages count will bring use above
412 * XXX: Might not be accurate
414 if (SharedCacheMap
->DirtyPages
+ (BytesToWrite
/ PAGE_SIZE
) > SharedCacheMap
->DirtyPageThreshold
)
428 IN PFILE_OBJECT FileObject
,
429 IN PLARGE_INTEGER FileOffset
,
433 OUT PIO_STATUS_BLOCK IoStatus
)
435 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d\n",
436 FileObject
, FileOffset
->QuadPart
, Length
, Wait
);
438 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
439 "Length %lu, Wait %u, Buffer 0x%p, IoStatus 0x%p)\n",
440 FileObject
, FileOffset
->QuadPart
, Length
, Wait
,
443 return CcCopyData(FileObject
,
444 FileOffset
->QuadPart
,
458 IN PFILE_OBJECT FileObject
,
459 IN PLARGE_INTEGER FileOffset
,
464 IO_STATUS_BLOCK IoStatus
;
466 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d Buffer=%p\n",
467 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
469 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
470 "Length %lu, Wait %u, Buffer 0x%p)\n",
471 FileObject
, FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
473 return CcCopyData(FileObject
,
474 FileOffset
->QuadPart
,
488 IN PFILE_OBJECT FileObject
,
489 IN PCC_POST_DEFERRED_WRITE PostRoutine
,
492 IN ULONG BytesToWrite
,
495 PDEFERRED_WRITE Context
;
497 CCTRACE(CC_API_DEBUG
, "FileObject=%p PostRoutine=%p Context1=%p Context2=%p BytesToWrite=%lu Retrying=%d\n",
498 FileObject
, PostRoutine
, Context1
, Context2
, BytesToWrite
, Retrying
);
500 /* Try to allocate a context for queueing the write operation */
501 Context
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(DEFERRED_WRITE
), 'CcDw');
502 /* If it failed, immediately execute the operation! */
505 PostRoutine(Context1
, Context2
);
509 /* Otherwise, initialize the context */
510 RtlZeroMemory(Context
, sizeof(DEFERRED_WRITE
));
511 Context
->NodeTypeCode
= NODE_TYPE_DEFERRED_WRITE
;
512 Context
->NodeByteSize
= sizeof(DEFERRED_WRITE
);
513 Context
->FileObject
= FileObject
;
514 Context
->PostRoutine
= PostRoutine
;
515 Context
->Context1
= Context1
;
516 Context
->Context2
= Context2
;
517 Context
->BytesToWrite
= BytesToWrite
;
522 /* To the top, if that's a retry */
523 ExInterlockedInsertHeadList(&CcDeferredWrites
,
524 &Context
->DeferredWriteLinks
,
525 &CcDeferredWriteSpinLock
);
529 /* To the bottom, if that's a first time */
530 ExInterlockedInsertTailList(&CcDeferredWrites
,
531 &Context
->DeferredWriteLinks
,
532 &CcDeferredWriteSpinLock
);
535 /* FIXME: lock master */
536 if (!LazyWriter
.ScanActive
)
538 CcScheduleLazyWriteScan(FALSE
);
548 IN PFILE_OBJECT FileObject
,
553 OUT PIO_STATUS_BLOCK IoStatus
)
555 LARGE_INTEGER LargeFileOffset
;
558 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%lu Length=%lu PageCount=%lu Buffer=%p\n",
559 FileObject
, FileOffset
, Length
, PageCount
, Buffer
);
561 DBG_UNREFERENCED_PARAMETER(PageCount
);
563 LargeFileOffset
.QuadPart
= FileOffset
;
564 Success
= CcCopyRead(FileObject
,
570 ASSERT(Success
== TRUE
);
579 IN PFILE_OBJECT FileObject
,
584 LARGE_INTEGER LargeFileOffset
;
587 CCTRACE(CC_API_DEBUG
, "FileObject=%p FileOffset=%lu Length=%lu Buffer=%p\n",
588 FileObject
, FileOffset
, Length
, Buffer
);
590 LargeFileOffset
.QuadPart
= FileOffset
;
591 Success
= CcCopyWrite(FileObject
,
596 ASSERT(Success
== TRUE
);
605 IN PFILE_OBJECT FileObject
,
606 IN PLARGE_INTEGER StartOffset
,
607 IN PLARGE_INTEGER EndOffset
,
611 LARGE_INTEGER WriteOffset
;
616 IO_STATUS_BLOCK Iosb
;
619 CCTRACE(CC_API_DEBUG
, "FileObject=%p StartOffset=%I64u EndOffset=%I64u Wait=%d\n",
620 FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
, Wait
);
622 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
623 "Wait %u)\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
626 Length
= EndOffset
->QuadPart
- StartOffset
->QuadPart
;
627 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
629 if (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
631 /* File is not cached */
633 Mdl
= _alloca(MmSizeOfMdl(NULL
, MAX_ZERO_LENGTH
));
637 if (Length
+ WriteOffset
.QuadPart
% PAGE_SIZE
> MAX_ZERO_LENGTH
)
639 CurrentLength
= MAX_ZERO_LENGTH
- WriteOffset
.QuadPart
% PAGE_SIZE
;
643 CurrentLength
= Length
;
645 MmInitializeMdl(Mdl
, (PVOID
)(ULONG_PTR
)WriteOffset
.QuadPart
, CurrentLength
);
646 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
647 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
649 ((PPFN_NUMBER
)(Mdl
+ 1))[i
] = CcZeroPage
;
651 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
652 Status
= IoSynchronousPageWrite(FileObject
, Mdl
, &WriteOffset
, &Event
, &Iosb
);
653 if (Status
== STATUS_PENDING
)
655 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
656 Status
= Iosb
.Status
;
658 if (Mdl
->MdlFlags
& MDL_MAPPED_TO_SYSTEM_VA
)
660 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
662 if (!NT_SUCCESS(Status
))
666 WriteOffset
.QuadPart
+= CurrentLength
;
667 Length
-= CurrentLength
;
672 IO_STATUS_BLOCK IoStatus
;
674 return CcCopyData(FileObject
,
675 WriteOffset
.QuadPart
,