[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / cc / copy.c
1 /*
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
6 *
7 * PROGRAMMERS:
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 static PFN_NUMBER CcZeroPage = 0;
19
20 #define MAX_ZERO_LENGTH (256 * 1024)
21
22 typedef enum _CC_COPY_OPERATION
23 {
24 CcOperationRead,
25 CcOperationWrite,
26 CcOperationZero
27 } CC_COPY_OPERATION;
28
29 ULONG CcRosTraceLevel = 0;
30 ULONG CcFastMdlReadWait;
31 ULONG CcFastMdlReadNotPossible;
32 ULONG CcFastReadNotPossible;
33 ULONG CcFastReadWait;
34 ULONG CcFastReadNoWait;
35 ULONG CcFastReadResourceMiss;
36
37 /* FUNCTIONS *****************************************************************/
38
39 VOID
40 NTAPI
41 MiZeroPhysicalPage (
42 IN PFN_NUMBER PageFrameIndex
43 );
44
45 VOID
46 NTAPI
47 CcInitCacheZeroPage (
48 VOID)
49 {
50 NTSTATUS Status;
51
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))
56 {
57 DbgPrint("Can't allocate CcZeroPage.\n");
58 KeBugCheck(CACHE_MANAGER);
59 }
60 MiZeroPhysicalPage(CcZeroPage);
61 }
62
63 NTSTATUS
64 NTAPI
65 CcReadVirtualAddress (
66 PROS_VACB Vacb)
67 {
68 ULONG Size, Pages;
69 PMDL Mdl;
70 NTSTATUS Status;
71 IO_STATUS_BLOCK IoStatus;
72 KEVENT Event;
73
74 Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
75 if (Size > VACB_MAPPING_GRANULARITY)
76 {
77 Size = VACB_MAPPING_GRANULARITY;
78 }
79
80 Pages = BYTES_TO_PAGES(Size);
81 ASSERT(Pages * PAGE_SIZE <= VACB_MAPPING_GRANULARITY);
82
83 Mdl = IoAllocateMdl(Vacb->BaseAddress, Pages * PAGE_SIZE, FALSE, FALSE, NULL);
84 if (!Mdl)
85 {
86 return STATUS_INSUFFICIENT_RESOURCES;
87 }
88
89 MmBuildMdlForNonPagedPool(Mdl);
90 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
91 KeInitializeEvent(&Event, NotificationEvent, FALSE);
92 Status = IoPageRead(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
93 if (Status == STATUS_PENDING)
94 {
95 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
96 Status = IoStatus.Status;
97 }
98
99 IoFreeMdl(Mdl);
100
101 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
102 {
103 DPRINT1("IoPageRead failed, Status %x\n", Status);
104 return Status;
105 }
106
107 if (Size < VACB_MAPPING_GRANULARITY)
108 {
109 RtlZeroMemory((char*)Vacb->BaseAddress + Size,
110 VACB_MAPPING_GRANULARITY - Size);
111 }
112
113 return STATUS_SUCCESS;
114 }
115
116 NTSTATUS
117 NTAPI
118 CcWriteVirtualAddress (
119 PROS_VACB Vacb)
120 {
121 ULONG Size;
122 PMDL Mdl;
123 NTSTATUS Status;
124 IO_STATUS_BLOCK IoStatus;
125 KEVENT Event;
126
127 Vacb->Dirty = FALSE;
128 Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
129 if (Size > VACB_MAPPING_GRANULARITY)
130 {
131 Size = VACB_MAPPING_GRANULARITY;
132 }
133 //
134 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
135 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
136 //
137 {
138 ULONG i = 0;
139 do
140 {
141 MmGetPfnForProcess(NULL, (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i << PAGE_SHIFT)));
142 } while (++i < (Size >> PAGE_SHIFT));
143 }
144
145 Mdl = IoAllocateMdl(Vacb->BaseAddress, Size, FALSE, FALSE, NULL);
146 if (!Mdl)
147 {
148 return STATUS_INSUFFICIENT_RESOURCES;
149 }
150 MmBuildMdlForNonPagedPool(Mdl);
151 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
152 KeInitializeEvent(&Event, NotificationEvent, FALSE);
153 Status = IoSynchronousPageWrite(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
154 if (Status == STATUS_PENDING)
155 {
156 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
157 Status = IoStatus.Status;
158 }
159 IoFreeMdl(Mdl);
160 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
161 {
162 DPRINT1("IoPageWrite failed, Status %x\n", Status);
163 Vacb->Dirty = TRUE;
164 return Status;
165 }
166
167 return STATUS_SUCCESS;
168 }
169
170 NTSTATUS
171 ReadWriteOrZero(
172 _Inout_ PVOID BaseAddress,
173 _Inout_opt_ PVOID Buffer,
174 _In_ ULONG Length,
175 _In_ CC_COPY_OPERATION Operation)
176 {
177 NTSTATUS Status = STATUS_SUCCESS;
178
179 if (Operation == CcOperationZero)
180 {
181 /* Zero */
182 RtlZeroMemory(BaseAddress, Length);
183 }
184 else
185 {
186 _SEH2_TRY
187 {
188 if (Operation == CcOperationWrite)
189 RtlCopyMemory(BaseAddress, Buffer, Length);
190 else
191 RtlCopyMemory(Buffer, BaseAddress, Length);
192 }
193 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
194 {
195 Status = _SEH2_GetExceptionCode();
196 }
197 _SEH2_END;
198 }
199 return Status;
200 }
201
202 BOOLEAN
203 CcCopyData (
204 _In_ PFILE_OBJECT FileObject,
205 _In_ LONGLONG FileOffset,
206 _Inout_ PVOID Buffer,
207 _In_ LONGLONG Length,
208 _In_ CC_COPY_OPERATION Operation,
209 _In_ BOOLEAN Wait,
210 _Out_ PIO_STATUS_BLOCK IoStatus)
211 {
212 NTSTATUS Status;
213 LONGLONG CurrentOffset;
214 ULONG BytesCopied;
215 KIRQL OldIrql;
216 PROS_SHARED_CACHE_MAP SharedCacheMap;
217 PLIST_ENTRY ListEntry;
218 PROS_VACB Vacb;
219 ULONG PartialLength;
220 PVOID BaseAddress;
221 BOOLEAN Valid;
222
223 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
224 CurrentOffset = FileOffset;
225 BytesCopied = 0;
226
227 if (!Wait)
228 {
229 /* test if the requested data is available */
230 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
231 /* FIXME: this loop doesn't take into account areas that don't have
232 * a VACB in the list yet */
233 ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink;
234 while (ListEntry != &SharedCacheMap->CacheMapVacbListHead)
235 {
236 Vacb = CONTAINING_RECORD(ListEntry,
237 ROS_VACB,
238 CacheMapVacbListEntry);
239 ListEntry = ListEntry->Flink;
240 if (!Vacb->Valid &&
241 DoRangesIntersect(Vacb->FileOffset.QuadPart,
242 VACB_MAPPING_GRANULARITY,
243 CurrentOffset, Length))
244 {
245 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
246 /* data not available */
247 return FALSE;
248 }
249 if (Vacb->FileOffset.QuadPart >= CurrentOffset + Length)
250 break;
251 }
252 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
253 }
254
255 PartialLength = CurrentOffset % VACB_MAPPING_GRANULARITY;
256 if (PartialLength != 0)
257 {
258 PartialLength = min(Length, VACB_MAPPING_GRANULARITY - PartialLength);
259 Status = CcRosRequestVacb(SharedCacheMap,
260 ROUND_DOWN(CurrentOffset,
261 VACB_MAPPING_GRANULARITY),
262 &BaseAddress,
263 &Valid,
264 &Vacb);
265 if (!NT_SUCCESS(Status))
266 ExRaiseStatus(Status);
267 if (!Valid)
268 {
269 Status = CcReadVirtualAddress(Vacb);
270 if (!NT_SUCCESS(Status))
271 {
272 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
273 ExRaiseStatus(Status);
274 }
275 }
276 Status = ReadWriteOrZero((PUCHAR)BaseAddress + CurrentOffset % VACB_MAPPING_GRANULARITY,
277 Buffer,
278 PartialLength,
279 Operation);
280
281 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
282
283 if (!NT_SUCCESS(Status))
284 ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
285
286 Length -= PartialLength;
287 CurrentOffset += PartialLength;
288 BytesCopied += PartialLength;
289
290 if (Operation != CcOperationZero)
291 Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
292 }
293
294 while (Length > 0)
295 {
296 ASSERT(CurrentOffset % VACB_MAPPING_GRANULARITY == 0);
297 PartialLength = min(VACB_MAPPING_GRANULARITY, Length);
298 Status = CcRosRequestVacb(SharedCacheMap,
299 CurrentOffset,
300 &BaseAddress,
301 &Valid,
302 &Vacb);
303 if (!NT_SUCCESS(Status))
304 ExRaiseStatus(Status);
305 if (!Valid &&
306 (Operation == CcOperationRead ||
307 PartialLength < VACB_MAPPING_GRANULARITY))
308 {
309 Status = CcReadVirtualAddress(Vacb);
310 if (!NT_SUCCESS(Status))
311 {
312 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
313 ExRaiseStatus(Status);
314 }
315 }
316 Status = ReadWriteOrZero(BaseAddress, Buffer, PartialLength, Operation);
317
318 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
319
320 if (!NT_SUCCESS(Status))
321 ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
322
323 Length -= PartialLength;
324 CurrentOffset += PartialLength;
325 BytesCopied += PartialLength;
326
327 if (Operation != CcOperationZero)
328 Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
329 }
330 IoStatus->Status = STATUS_SUCCESS;
331 IoStatus->Information = BytesCopied;
332 return TRUE;
333 }
334
335 /*
336 * @unimplemented
337 */
338 BOOLEAN
339 NTAPI
340 CcCanIWrite (
341 IN PFILE_OBJECT FileObject,
342 IN ULONG BytesToWrite,
343 IN BOOLEAN Wait,
344 IN BOOLEAN Retrying)
345 {
346 CCTRACE(CC_API_DEBUG, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n",
347 FileObject, BytesToWrite, Wait, Retrying);
348
349 return TRUE;
350 }
351
352 /*
353 * @implemented
354 */
355 BOOLEAN
356 NTAPI
357 CcCopyRead (
358 IN PFILE_OBJECT FileObject,
359 IN PLARGE_INTEGER FileOffset,
360 IN ULONG Length,
361 IN BOOLEAN Wait,
362 OUT PVOID Buffer,
363 OUT PIO_STATUS_BLOCK IoStatus)
364 {
365 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d\n",
366 FileObject, FileOffset->QuadPart, Length, Wait);
367
368 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
369 "Length %lu, Wait %u, Buffer 0x%p, IoStatus 0x%p)\n",
370 FileObject, FileOffset->QuadPart, Length, Wait,
371 Buffer, IoStatus);
372
373 return CcCopyData(FileObject,
374 FileOffset->QuadPart,
375 Buffer,
376 Length,
377 CcOperationRead,
378 Wait,
379 IoStatus);
380 }
381
382 /*
383 * @implemented
384 */
385 BOOLEAN
386 NTAPI
387 CcCopyWrite (
388 IN PFILE_OBJECT FileObject,
389 IN PLARGE_INTEGER FileOffset,
390 IN ULONG Length,
391 IN BOOLEAN Wait,
392 IN PVOID Buffer)
393 {
394 IO_STATUS_BLOCK IoStatus;
395
396 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d Buffer=%p\n",
397 FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
398
399 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
400 "Length %lu, Wait %u, Buffer 0x%p)\n",
401 FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
402
403 return CcCopyData(FileObject,
404 FileOffset->QuadPart,
405 Buffer,
406 Length,
407 CcOperationWrite,
408 Wait,
409 &IoStatus);
410 }
411
412 /*
413 * @unimplemented
414 */
415 VOID
416 NTAPI
417 CcDeferWrite (
418 IN PFILE_OBJECT FileObject,
419 IN PCC_POST_DEFERRED_WRITE PostRoutine,
420 IN PVOID Context1,
421 IN PVOID Context2,
422 IN ULONG BytesToWrite,
423 IN BOOLEAN Retrying)
424 {
425 CCTRACE(CC_API_DEBUG, "FileObject=%p PostRoutine=%p Context1=%p Context2=%p BytesToWrite=%lu Retrying=%d\n",
426 FileObject, PostRoutine, Context1, Context2, BytesToWrite, Retrying);
427
428 PostRoutine(Context1, Context2);
429 }
430
431 /*
432 * @unimplemented
433 */
434 VOID
435 NTAPI
436 CcFastCopyRead (
437 IN PFILE_OBJECT FileObject,
438 IN ULONG FileOffset,
439 IN ULONG Length,
440 IN ULONG PageCount,
441 OUT PVOID Buffer,
442 OUT PIO_STATUS_BLOCK IoStatus)
443 {
444 LARGE_INTEGER LargeFileOffset;
445 BOOLEAN Success;
446
447 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%lu Length=%lu PageCount=%lu Buffer=%p\n",
448 FileObject, FileOffset, Length, PageCount, Buffer);
449
450 DBG_UNREFERENCED_PARAMETER(PageCount);
451
452 LargeFileOffset.QuadPart = FileOffset;
453 Success = CcCopyRead(FileObject,
454 &LargeFileOffset,
455 Length,
456 TRUE,
457 Buffer,
458 IoStatus);
459 ASSERT(Success == TRUE);
460 }
461
462 /*
463 * @unimplemented
464 */
465 VOID
466 NTAPI
467 CcFastCopyWrite (
468 IN PFILE_OBJECT FileObject,
469 IN ULONG FileOffset,
470 IN ULONG Length,
471 IN PVOID Buffer)
472 {
473 LARGE_INTEGER LargeFileOffset;
474 BOOLEAN Success;
475
476 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%lu Length=%lu Buffer=%p\n",
477 FileObject, FileOffset, Length, Buffer);
478
479 LargeFileOffset.QuadPart = FileOffset;
480 Success = CcCopyWrite(FileObject,
481 &LargeFileOffset,
482 Length,
483 TRUE,
484 Buffer);
485 ASSERT(Success == TRUE);
486 }
487
488 /*
489 * @unimplemented
490 */
491 NTSTATUS
492 NTAPI
493 CcWaitForCurrentLazyWriterActivity (
494 VOID)
495 {
496 UNIMPLEMENTED;
497 return STATUS_NOT_IMPLEMENTED;
498 }
499
500 /*
501 * @implemented
502 */
503 BOOLEAN
504 NTAPI
505 CcZeroData (
506 IN PFILE_OBJECT FileObject,
507 IN PLARGE_INTEGER StartOffset,
508 IN PLARGE_INTEGER EndOffset,
509 IN BOOLEAN Wait)
510 {
511 NTSTATUS Status;
512 LARGE_INTEGER WriteOffset;
513 LONGLONG Length;
514 ULONG CurrentLength;
515 PMDL Mdl;
516 ULONG i;
517 IO_STATUS_BLOCK Iosb;
518 KEVENT Event;
519
520 CCTRACE(CC_API_DEBUG, "FileObject=%p StartOffset=%I64u EndOffset=%I64u Wait=%d\n",
521 FileObject, StartOffset->QuadPart, EndOffset->QuadPart, Wait);
522
523 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
524 "Wait %u)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
525 Wait);
526
527 Length = EndOffset->QuadPart - StartOffset->QuadPart;
528 WriteOffset.QuadPart = StartOffset->QuadPart;
529
530 if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
531 {
532 /* File is not cached */
533
534 Mdl = _alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
535
536 while (Length > 0)
537 {
538 if (Length + WriteOffset.QuadPart % PAGE_SIZE > MAX_ZERO_LENGTH)
539 {
540 CurrentLength = MAX_ZERO_LENGTH - WriteOffset.QuadPart % PAGE_SIZE;
541 }
542 else
543 {
544 CurrentLength = Length;
545 }
546 MmInitializeMdl(Mdl, (PVOID)(ULONG_PTR)WriteOffset.QuadPart, CurrentLength);
547 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
548 for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
549 {
550 ((PPFN_NUMBER)(Mdl + 1))[i] = CcZeroPage;
551 }
552 KeInitializeEvent(&Event, NotificationEvent, FALSE);
553 Status = IoSynchronousPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
554 if (Status == STATUS_PENDING)
555 {
556 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
557 Status = Iosb.Status;
558 }
559 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
560 {
561 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
562 }
563 if (!NT_SUCCESS(Status))
564 {
565 return FALSE;
566 }
567 WriteOffset.QuadPart += CurrentLength;
568 Length -= CurrentLength;
569 }
570 }
571 else
572 {
573 IO_STATUS_BLOCK IoStatus;
574
575 return CcCopyData(FileObject,
576 WriteOffset.QuadPart,
577 NULL,
578 Length,
579 CcOperationZero,
580 Wait,
581 &IoStatus);
582 }
583
584 return TRUE;
585 }