[NTOSKRNL] Make the CcWaitForCurrentLazyWriterActivity() stub return success instead...
[reactos.git] / 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 Status = STATUS_SUCCESS;
90 _SEH2_TRY
91 {
92 MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess);
93 }
94 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
95 {
96 Status = _SEH2_GetExceptionCode();
97 KeBugCheck(CACHE_MANAGER);
98 } _SEH2_END;
99
100 if (NT_SUCCESS(Status))
101 {
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)
106 {
107 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
108 Status = IoStatus.Status;
109 }
110
111 MmUnlockPages(Mdl);
112 }
113
114 IoFreeMdl(Mdl);
115
116 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
117 {
118 DPRINT1("IoPageRead failed, Status %x\n", Status);
119 return Status;
120 }
121
122 if (Size < VACB_MAPPING_GRANULARITY)
123 {
124 RtlZeroMemory((char*)Vacb->BaseAddress + Size,
125 VACB_MAPPING_GRANULARITY - Size);
126 }
127
128 return STATUS_SUCCESS;
129 }
130
131 NTSTATUS
132 NTAPI
133 CcWriteVirtualAddress (
134 PROS_VACB Vacb)
135 {
136 ULONG Size;
137 PMDL Mdl;
138 NTSTATUS Status;
139 IO_STATUS_BLOCK IoStatus;
140 KEVENT Event;
141
142 Vacb->Dirty = FALSE;
143 Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
144 if (Size > VACB_MAPPING_GRANULARITY)
145 {
146 Size = VACB_MAPPING_GRANULARITY;
147 }
148 //
149 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
150 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
151 //
152 {
153 ULONG i = 0;
154 do
155 {
156 MmGetPfnForProcess(NULL, (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i << PAGE_SHIFT)));
157 } while (++i < (Size >> PAGE_SHIFT));
158 }
159
160 Mdl = IoAllocateMdl(Vacb->BaseAddress, Size, FALSE, FALSE, NULL);
161 if (!Mdl)
162 {
163 return STATUS_INSUFFICIENT_RESOURCES;
164 }
165
166 Status = STATUS_SUCCESS;
167 _SEH2_TRY
168 {
169 MmProbeAndLockPages(Mdl, KernelMode, IoReadAccess);
170 }
171 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
172 {
173 Status = _SEH2_GetExceptionCode();
174 KeBugCheck(CACHE_MANAGER);
175 } _SEH2_END;
176
177 if (NT_SUCCESS(Status))
178 {
179 KeInitializeEvent(&Event, NotificationEvent, FALSE);
180 Status = IoSynchronousPageWrite(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
181 if (Status == STATUS_PENDING)
182 {
183 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
184 Status = IoStatus.Status;
185 }
186
187 MmUnlockPages(Mdl);
188 }
189 IoFreeMdl(Mdl);
190 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
191 {
192 DPRINT1("IoPageWrite failed, Status %x\n", Status);
193 Vacb->Dirty = TRUE;
194 return Status;
195 }
196
197 return STATUS_SUCCESS;
198 }
199
200 NTSTATUS
201 ReadWriteOrZero(
202 _Inout_ PVOID BaseAddress,
203 _Inout_opt_ PVOID Buffer,
204 _In_ ULONG Length,
205 _In_ CC_COPY_OPERATION Operation)
206 {
207 NTSTATUS Status = STATUS_SUCCESS;
208
209 if (Operation == CcOperationZero)
210 {
211 /* Zero */
212 RtlZeroMemory(BaseAddress, Length);
213 }
214 else
215 {
216 _SEH2_TRY
217 {
218 if (Operation == CcOperationWrite)
219 RtlCopyMemory(BaseAddress, Buffer, Length);
220 else
221 RtlCopyMemory(Buffer, BaseAddress, Length);
222 }
223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
224 {
225 Status = _SEH2_GetExceptionCode();
226 }
227 _SEH2_END;
228 }
229 return Status;
230 }
231
232 BOOLEAN
233 CcCopyData (
234 _In_ PFILE_OBJECT FileObject,
235 _In_ LONGLONG FileOffset,
236 _Inout_ PVOID Buffer,
237 _In_ LONGLONG Length,
238 _In_ CC_COPY_OPERATION Operation,
239 _In_ BOOLEAN Wait,
240 _Out_ PIO_STATUS_BLOCK IoStatus)
241 {
242 NTSTATUS Status;
243 LONGLONG CurrentOffset;
244 ULONG BytesCopied;
245 KIRQL OldIrql;
246 PROS_SHARED_CACHE_MAP SharedCacheMap;
247 PLIST_ENTRY ListEntry;
248 PROS_VACB Vacb;
249 ULONG PartialLength;
250 PVOID BaseAddress;
251 BOOLEAN Valid;
252
253 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
254 CurrentOffset = FileOffset;
255 BytesCopied = 0;
256
257 if (!Wait)
258 {
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)
265 {
266 Vacb = CONTAINING_RECORD(ListEntry,
267 ROS_VACB,
268 CacheMapVacbListEntry);
269 ListEntry = ListEntry->Flink;
270 if (!Vacb->Valid &&
271 DoRangesIntersect(Vacb->FileOffset.QuadPart,
272 VACB_MAPPING_GRANULARITY,
273 CurrentOffset, Length))
274 {
275 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
276 /* data not available */
277 return FALSE;
278 }
279 if (Vacb->FileOffset.QuadPart >= CurrentOffset + Length)
280 break;
281 }
282 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
283 }
284
285 PartialLength = CurrentOffset % VACB_MAPPING_GRANULARITY;
286 if (PartialLength != 0)
287 {
288 PartialLength = min(Length, VACB_MAPPING_GRANULARITY - PartialLength);
289 Status = CcRosRequestVacb(SharedCacheMap,
290 ROUND_DOWN(CurrentOffset,
291 VACB_MAPPING_GRANULARITY),
292 &BaseAddress,
293 &Valid,
294 &Vacb);
295 if (!NT_SUCCESS(Status))
296 ExRaiseStatus(Status);
297 if (!Valid)
298 {
299 Status = CcReadVirtualAddress(Vacb);
300 if (!NT_SUCCESS(Status))
301 {
302 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
303 ExRaiseStatus(Status);
304 }
305 }
306 Status = ReadWriteOrZero((PUCHAR)BaseAddress + CurrentOffset % VACB_MAPPING_GRANULARITY,
307 Buffer,
308 PartialLength,
309 Operation);
310
311 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
312
313 if (!NT_SUCCESS(Status))
314 ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
315
316 Length -= PartialLength;
317 CurrentOffset += PartialLength;
318 BytesCopied += PartialLength;
319
320 if (Operation != CcOperationZero)
321 Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
322 }
323
324 while (Length > 0)
325 {
326 ASSERT(CurrentOffset % VACB_MAPPING_GRANULARITY == 0);
327 PartialLength = min(VACB_MAPPING_GRANULARITY, Length);
328 Status = CcRosRequestVacb(SharedCacheMap,
329 CurrentOffset,
330 &BaseAddress,
331 &Valid,
332 &Vacb);
333 if (!NT_SUCCESS(Status))
334 ExRaiseStatus(Status);
335 if (!Valid &&
336 (Operation == CcOperationRead ||
337 PartialLength < VACB_MAPPING_GRANULARITY))
338 {
339 Status = CcReadVirtualAddress(Vacb);
340 if (!NT_SUCCESS(Status))
341 {
342 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
343 ExRaiseStatus(Status);
344 }
345 }
346 Status = ReadWriteOrZero(BaseAddress, Buffer, PartialLength, Operation);
347
348 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
349
350 if (!NT_SUCCESS(Status))
351 ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
352
353 Length -= PartialLength;
354 CurrentOffset += PartialLength;
355 BytesCopied += PartialLength;
356
357 if (Operation != CcOperationZero)
358 Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
359 }
360 IoStatus->Status = STATUS_SUCCESS;
361 IoStatus->Information = BytesCopied;
362 return TRUE;
363 }
364
365 /*
366 * @unimplemented
367 */
368 BOOLEAN
369 NTAPI
370 CcCanIWrite (
371 IN PFILE_OBJECT FileObject,
372 IN ULONG BytesToWrite,
373 IN BOOLEAN Wait,
374 IN BOOLEAN Retrying)
375 {
376 CCTRACE(CC_API_DEBUG, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n",
377 FileObject, BytesToWrite, Wait, Retrying);
378
379 return TRUE;
380 }
381
382 /*
383 * @implemented
384 */
385 BOOLEAN
386 NTAPI
387 CcCopyRead (
388 IN PFILE_OBJECT FileObject,
389 IN PLARGE_INTEGER FileOffset,
390 IN ULONG Length,
391 IN BOOLEAN Wait,
392 OUT PVOID Buffer,
393 OUT PIO_STATUS_BLOCK IoStatus)
394 {
395 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d\n",
396 FileObject, FileOffset->QuadPart, Length, Wait);
397
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,
401 Buffer, IoStatus);
402
403 return CcCopyData(FileObject,
404 FileOffset->QuadPart,
405 Buffer,
406 Length,
407 CcOperationRead,
408 Wait,
409 IoStatus);
410 }
411
412 /*
413 * @implemented
414 */
415 BOOLEAN
416 NTAPI
417 CcCopyWrite (
418 IN PFILE_OBJECT FileObject,
419 IN PLARGE_INTEGER FileOffset,
420 IN ULONG Length,
421 IN BOOLEAN Wait,
422 IN PVOID Buffer)
423 {
424 IO_STATUS_BLOCK IoStatus;
425
426 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d Buffer=%p\n",
427 FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
428
429 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
430 "Length %lu, Wait %u, Buffer 0x%p)\n",
431 FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
432
433 return CcCopyData(FileObject,
434 FileOffset->QuadPart,
435 Buffer,
436 Length,
437 CcOperationWrite,
438 Wait,
439 &IoStatus);
440 }
441
442 /*
443 * @unimplemented
444 */
445 VOID
446 NTAPI
447 CcDeferWrite (
448 IN PFILE_OBJECT FileObject,
449 IN PCC_POST_DEFERRED_WRITE PostRoutine,
450 IN PVOID Context1,
451 IN PVOID Context2,
452 IN ULONG BytesToWrite,
453 IN BOOLEAN Retrying)
454 {
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);
457
458 PostRoutine(Context1, Context2);
459 }
460
461 /*
462 * @unimplemented
463 */
464 VOID
465 NTAPI
466 CcFastCopyRead (
467 IN PFILE_OBJECT FileObject,
468 IN ULONG FileOffset,
469 IN ULONG Length,
470 IN ULONG PageCount,
471 OUT PVOID Buffer,
472 OUT PIO_STATUS_BLOCK IoStatus)
473 {
474 LARGE_INTEGER LargeFileOffset;
475 BOOLEAN Success;
476
477 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%lu Length=%lu PageCount=%lu Buffer=%p\n",
478 FileObject, FileOffset, Length, PageCount, Buffer);
479
480 DBG_UNREFERENCED_PARAMETER(PageCount);
481
482 LargeFileOffset.QuadPart = FileOffset;
483 Success = CcCopyRead(FileObject,
484 &LargeFileOffset,
485 Length,
486 TRUE,
487 Buffer,
488 IoStatus);
489 ASSERT(Success == TRUE);
490 }
491
492 /*
493 * @unimplemented
494 */
495 VOID
496 NTAPI
497 CcFastCopyWrite (
498 IN PFILE_OBJECT FileObject,
499 IN ULONG FileOffset,
500 IN ULONG Length,
501 IN PVOID Buffer)
502 {
503 LARGE_INTEGER LargeFileOffset;
504 BOOLEAN Success;
505
506 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%lu Length=%lu Buffer=%p\n",
507 FileObject, FileOffset, Length, Buffer);
508
509 LargeFileOffset.QuadPart = FileOffset;
510 Success = CcCopyWrite(FileObject,
511 &LargeFileOffset,
512 Length,
513 TRUE,
514 Buffer);
515 ASSERT(Success == TRUE);
516 }
517
518 /*
519 * @unimplemented
520 */
521 NTSTATUS
522 NTAPI
523 CcWaitForCurrentLazyWriterActivity (
524 VOID)
525 {
526 UNIMPLEMENTED;
527 return STATUS_SUCCESS;
528 }
529
530 /*
531 * @implemented
532 */
533 BOOLEAN
534 NTAPI
535 CcZeroData (
536 IN PFILE_OBJECT FileObject,
537 IN PLARGE_INTEGER StartOffset,
538 IN PLARGE_INTEGER EndOffset,
539 IN BOOLEAN Wait)
540 {
541 NTSTATUS Status;
542 LARGE_INTEGER WriteOffset;
543 LONGLONG Length;
544 ULONG CurrentLength;
545 PMDL Mdl;
546 ULONG i;
547 IO_STATUS_BLOCK Iosb;
548 KEVENT Event;
549
550 CCTRACE(CC_API_DEBUG, "FileObject=%p StartOffset=%I64u EndOffset=%I64u Wait=%d\n",
551 FileObject, StartOffset->QuadPart, EndOffset->QuadPart, Wait);
552
553 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
554 "Wait %u)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
555 Wait);
556
557 Length = EndOffset->QuadPart - StartOffset->QuadPart;
558 WriteOffset.QuadPart = StartOffset->QuadPart;
559
560 if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
561 {
562 /* File is not cached */
563
564 Mdl = _alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
565
566 while (Length > 0)
567 {
568 if (Length + WriteOffset.QuadPart % PAGE_SIZE > MAX_ZERO_LENGTH)
569 {
570 CurrentLength = MAX_ZERO_LENGTH - WriteOffset.QuadPart % PAGE_SIZE;
571 }
572 else
573 {
574 CurrentLength = Length;
575 }
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++)
579 {
580 ((PPFN_NUMBER)(Mdl + 1))[i] = CcZeroPage;
581 }
582 KeInitializeEvent(&Event, NotificationEvent, FALSE);
583 Status = IoSynchronousPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
584 if (Status == STATUS_PENDING)
585 {
586 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
587 Status = Iosb.Status;
588 }
589 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
590 {
591 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
592 }
593 if (!NT_SUCCESS(Status))
594 {
595 return FALSE;
596 }
597 WriteOffset.QuadPart += CurrentLength;
598 Length -= CurrentLength;
599 }
600 }
601 else
602 {
603 IO_STATUS_BLOCK IoStatus;
604
605 return CcCopyData(FileObject,
606 WriteOffset.QuadPart,
607 NULL,
608 Length,
609 CcOperationZero,
610 Wait,
611 &IoStatus);
612 }
613
614 return TRUE;
615 }