[NTOSKRNL] Don't let CcWriteVirtualAddress() deal with VACB dirty status
[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: Some people?
8 * Pierre Schweitzer (pierre@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 static PFN_NUMBER CcZeroPage = 0;
20
21 #define MAX_ZERO_LENGTH (256 * 1024)
22
23 typedef enum _CC_COPY_OPERATION
24 {
25 CcOperationRead,
26 CcOperationWrite,
27 CcOperationZero
28 } CC_COPY_OPERATION;
29
30 ULONG CcRosTraceLevel = 0;
31 ULONG CcFastMdlReadWait;
32 ULONG CcFastMdlReadNotPossible;
33 ULONG CcFastReadNotPossible;
34 ULONG CcFastReadWait;
35 ULONG CcFastReadNoWait;
36 ULONG CcFastReadResourceMiss;
37
38 extern KEVENT iLazyWriterNotify;
39
40 /* FUNCTIONS *****************************************************************/
41
42 VOID
43 NTAPI
44 MiZeroPhysicalPage (
45 IN PFN_NUMBER PageFrameIndex
46 );
47
48 VOID
49 NTAPI
50 CcInitCacheZeroPage (
51 VOID)
52 {
53 NTSTATUS Status;
54
55 MI_SET_USAGE(MI_USAGE_CACHE);
56 //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
57 Status = MmRequestPageMemoryConsumer(MC_SYSTEM, TRUE, &CcZeroPage);
58 if (!NT_SUCCESS(Status))
59 {
60 DbgPrint("Can't allocate CcZeroPage.\n");
61 KeBugCheck(CACHE_MANAGER);
62 }
63 MiZeroPhysicalPage(CcZeroPage);
64 }
65
66 NTSTATUS
67 NTAPI
68 CcReadVirtualAddress (
69 PROS_VACB Vacb)
70 {
71 ULONG Size, Pages;
72 PMDL Mdl;
73 NTSTATUS Status;
74 IO_STATUS_BLOCK IoStatus;
75 KEVENT Event;
76
77 Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
78 if (Size > VACB_MAPPING_GRANULARITY)
79 {
80 Size = VACB_MAPPING_GRANULARITY;
81 }
82
83 Pages = BYTES_TO_PAGES(Size);
84 ASSERT(Pages * PAGE_SIZE <= VACB_MAPPING_GRANULARITY);
85
86 Mdl = IoAllocateMdl(Vacb->BaseAddress, Pages * PAGE_SIZE, FALSE, FALSE, NULL);
87 if (!Mdl)
88 {
89 return STATUS_INSUFFICIENT_RESOURCES;
90 }
91
92 Status = STATUS_SUCCESS;
93 _SEH2_TRY
94 {
95 MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess);
96 }
97 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
98 {
99 Status = _SEH2_GetExceptionCode();
100 KeBugCheck(CACHE_MANAGER);
101 } _SEH2_END;
102
103 if (NT_SUCCESS(Status))
104 {
105 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
106 KeInitializeEvent(&Event, NotificationEvent, FALSE);
107 Status = IoPageRead(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
108 if (Status == STATUS_PENDING)
109 {
110 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
111 Status = IoStatus.Status;
112 }
113
114 MmUnlockPages(Mdl);
115 }
116
117 IoFreeMdl(Mdl);
118
119 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
120 {
121 DPRINT1("IoPageRead failed, Status %x\n", Status);
122 return Status;
123 }
124
125 if (Size < VACB_MAPPING_GRANULARITY)
126 {
127 RtlZeroMemory((char*)Vacb->BaseAddress + Size,
128 VACB_MAPPING_GRANULARITY - Size);
129 }
130
131 return STATUS_SUCCESS;
132 }
133
134 NTSTATUS
135 NTAPI
136 CcWriteVirtualAddress (
137 PROS_VACB Vacb)
138 {
139 ULONG Size;
140 PMDL Mdl;
141 NTSTATUS Status;
142 IO_STATUS_BLOCK IoStatus;
143 KEVENT Event;
144
145 Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
146 if (Size > VACB_MAPPING_GRANULARITY)
147 {
148 Size = VACB_MAPPING_GRANULARITY;
149 }
150 //
151 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
152 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
153 //
154 {
155 ULONG i = 0;
156 do
157 {
158 MmGetPfnForProcess(NULL, (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i << PAGE_SHIFT)));
159 } while (++i < (Size >> PAGE_SHIFT));
160 }
161
162 Mdl = IoAllocateMdl(Vacb->BaseAddress, Size, FALSE, FALSE, NULL);
163 if (!Mdl)
164 {
165 return STATUS_INSUFFICIENT_RESOURCES;
166 }
167
168 Status = STATUS_SUCCESS;
169 _SEH2_TRY
170 {
171 MmProbeAndLockPages(Mdl, KernelMode, IoReadAccess);
172 }
173 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
174 {
175 Status = _SEH2_GetExceptionCode();
176 KeBugCheck(CACHE_MANAGER);
177 } _SEH2_END;
178
179 if (NT_SUCCESS(Status))
180 {
181 KeInitializeEvent(&Event, NotificationEvent, FALSE);
182 Status = IoSynchronousPageWrite(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
183 if (Status == STATUS_PENDING)
184 {
185 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
186 Status = IoStatus.Status;
187 }
188
189 MmUnlockPages(Mdl);
190 }
191 IoFreeMdl(Mdl);
192 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
193 {
194 DPRINT1("IoPageWrite failed, Status %x\n", Status);
195 return Status;
196 }
197
198 return STATUS_SUCCESS;
199 }
200
201 NTSTATUS
202 ReadWriteOrZero(
203 _Inout_ PVOID BaseAddress,
204 _Inout_opt_ PVOID Buffer,
205 _In_ ULONG Length,
206 _In_ CC_COPY_OPERATION Operation)
207 {
208 NTSTATUS Status = STATUS_SUCCESS;
209
210 if (Operation == CcOperationZero)
211 {
212 /* Zero */
213 RtlZeroMemory(BaseAddress, Length);
214 }
215 else
216 {
217 _SEH2_TRY
218 {
219 if (Operation == CcOperationWrite)
220 RtlCopyMemory(BaseAddress, Buffer, Length);
221 else
222 RtlCopyMemory(Buffer, BaseAddress, Length);
223 }
224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
225 {
226 Status = _SEH2_GetExceptionCode();
227 }
228 _SEH2_END;
229 }
230 return Status;
231 }
232
233 BOOLEAN
234 CcCopyData (
235 _In_ PFILE_OBJECT FileObject,
236 _In_ LONGLONG FileOffset,
237 _Inout_ PVOID Buffer,
238 _In_ LONGLONG Length,
239 _In_ CC_COPY_OPERATION Operation,
240 _In_ BOOLEAN Wait,
241 _Out_ PIO_STATUS_BLOCK IoStatus)
242 {
243 NTSTATUS Status;
244 LONGLONG CurrentOffset;
245 ULONG BytesCopied;
246 KIRQL OldIrql;
247 PROS_SHARED_CACHE_MAP SharedCacheMap;
248 PLIST_ENTRY ListEntry;
249 PROS_VACB Vacb;
250 ULONG PartialLength;
251 PVOID BaseAddress;
252 BOOLEAN Valid;
253
254 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
255 CurrentOffset = FileOffset;
256 BytesCopied = 0;
257
258 if (!Wait)
259 {
260 /* test if the requested data is available */
261 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql);
262 /* FIXME: this loop doesn't take into account areas that don't have
263 * a VACB in the list yet */
264 ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink;
265 while (ListEntry != &SharedCacheMap->CacheMapVacbListHead)
266 {
267 Vacb = CONTAINING_RECORD(ListEntry,
268 ROS_VACB,
269 CacheMapVacbListEntry);
270 ListEntry = ListEntry->Flink;
271 if (!Vacb->Valid &&
272 DoRangesIntersect(Vacb->FileOffset.QuadPart,
273 VACB_MAPPING_GRANULARITY,
274 CurrentOffset, Length))
275 {
276 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
277 /* data not available */
278 return FALSE;
279 }
280 if (Vacb->FileOffset.QuadPart >= CurrentOffset + Length)
281 break;
282 }
283 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql);
284 }
285
286 PartialLength = CurrentOffset % VACB_MAPPING_GRANULARITY;
287 if (PartialLength != 0)
288 {
289 PartialLength = min(Length, VACB_MAPPING_GRANULARITY - PartialLength);
290 Status = CcRosRequestVacb(SharedCacheMap,
291 ROUND_DOWN(CurrentOffset,
292 VACB_MAPPING_GRANULARITY),
293 &BaseAddress,
294 &Valid,
295 &Vacb);
296 if (!NT_SUCCESS(Status))
297 ExRaiseStatus(Status);
298 if (!Valid)
299 {
300 Status = CcReadVirtualAddress(Vacb);
301 if (!NT_SUCCESS(Status))
302 {
303 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
304 ExRaiseStatus(Status);
305 }
306 }
307 Status = ReadWriteOrZero((PUCHAR)BaseAddress + CurrentOffset % VACB_MAPPING_GRANULARITY,
308 Buffer,
309 PartialLength,
310 Operation);
311
312 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
313
314 if (!NT_SUCCESS(Status))
315 ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
316
317 Length -= PartialLength;
318 CurrentOffset += PartialLength;
319 BytesCopied += PartialLength;
320
321 if (Operation != CcOperationZero)
322 Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
323 }
324
325 while (Length > 0)
326 {
327 ASSERT(CurrentOffset % VACB_MAPPING_GRANULARITY == 0);
328 PartialLength = min(VACB_MAPPING_GRANULARITY, Length);
329 Status = CcRosRequestVacb(SharedCacheMap,
330 CurrentOffset,
331 &BaseAddress,
332 &Valid,
333 &Vacb);
334 if (!NT_SUCCESS(Status))
335 ExRaiseStatus(Status);
336 if (!Valid &&
337 (Operation == CcOperationRead ||
338 PartialLength < VACB_MAPPING_GRANULARITY))
339 {
340 Status = CcReadVirtualAddress(Vacb);
341 if (!NT_SUCCESS(Status))
342 {
343 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
344 ExRaiseStatus(Status);
345 }
346 }
347 Status = ReadWriteOrZero(BaseAddress, Buffer, PartialLength, Operation);
348
349 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, Operation != CcOperationRead, FALSE);
350
351 if (!NT_SUCCESS(Status))
352 ExRaiseStatus(STATUS_INVALID_USER_BUFFER);
353
354 Length -= PartialLength;
355 CurrentOffset += PartialLength;
356 BytesCopied += PartialLength;
357
358 if (Operation != CcOperationZero)
359 Buffer = (PVOID)((ULONG_PTR)Buffer + PartialLength);
360 }
361 IoStatus->Status = STATUS_SUCCESS;
362 IoStatus->Information = BytesCopied;
363 return TRUE;
364 }
365
366 /*
367 * @unimplemented
368 */
369 BOOLEAN
370 NTAPI
371 CcCanIWrite (
372 IN PFILE_OBJECT FileObject,
373 IN ULONG BytesToWrite,
374 IN BOOLEAN Wait,
375 IN BOOLEAN Retrying)
376 {
377 PFSRTL_COMMON_FCB_HEADER Fcb;
378 PROS_SHARED_CACHE_MAP SharedCacheMap;
379
380 CCTRACE(CC_API_DEBUG, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n",
381 FileObject, BytesToWrite, Wait, Retrying);
382
383 /* We cannot write if dirty pages count is above threshold */
384 if (CcTotalDirtyPages > CcDirtyPageThreshold)
385 {
386 return FALSE;
387 }
388
389 /* We cannot write if dirty pages count will bring use above
390 * XXX: Might not be accurate
391 */
392 if (CcTotalDirtyPages + (BytesToWrite / PAGE_SIZE) > CcDirtyPageThreshold)
393 {
394 return FALSE;
395 }
396
397 /* Is there a limit per file object? */
398 Fcb = FileObject->FsContext;
399 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
400 if (!BooleanFlagOn(Fcb->Flags, FSRTL_FLAG_LIMIT_MODIFIED_PAGES) ||
401 SharedCacheMap->DirtyPageThreshold == 0)
402 {
403 /* Nope, so that's fine, allow write operation */
404 return TRUE;
405 }
406
407 /* Is dirty page count above local threshold? */
408 if (SharedCacheMap->DirtyPages > SharedCacheMap->DirtyPageThreshold)
409 {
410 return FALSE;
411 }
412
413 /* We cannot write if dirty pages count will bring use above
414 * XXX: Might not be accurate
415 */
416 if (SharedCacheMap->DirtyPages + (BytesToWrite / PAGE_SIZE) > SharedCacheMap->DirtyPageThreshold)
417 {
418 return FALSE;
419 }
420
421 return TRUE;
422 }
423
424 /*
425 * @implemented
426 */
427 BOOLEAN
428 NTAPI
429 CcCopyRead (
430 IN PFILE_OBJECT FileObject,
431 IN PLARGE_INTEGER FileOffset,
432 IN ULONG Length,
433 IN BOOLEAN Wait,
434 OUT PVOID Buffer,
435 OUT PIO_STATUS_BLOCK IoStatus)
436 {
437 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d\n",
438 FileObject, FileOffset->QuadPart, Length, Wait);
439
440 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
441 "Length %lu, Wait %u, Buffer 0x%p, IoStatus 0x%p)\n",
442 FileObject, FileOffset->QuadPart, Length, Wait,
443 Buffer, IoStatus);
444
445 return CcCopyData(FileObject,
446 FileOffset->QuadPart,
447 Buffer,
448 Length,
449 CcOperationRead,
450 Wait,
451 IoStatus);
452 }
453
454 /*
455 * @implemented
456 */
457 BOOLEAN
458 NTAPI
459 CcCopyWrite (
460 IN PFILE_OBJECT FileObject,
461 IN PLARGE_INTEGER FileOffset,
462 IN ULONG Length,
463 IN BOOLEAN Wait,
464 IN PVOID Buffer)
465 {
466 IO_STATUS_BLOCK IoStatus;
467
468 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%I64d Length=%lu Wait=%d Buffer=%p\n",
469 FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
470
471 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
472 "Length %lu, Wait %u, Buffer 0x%p)\n",
473 FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
474
475 return CcCopyData(FileObject,
476 FileOffset->QuadPart,
477 Buffer,
478 Length,
479 CcOperationWrite,
480 Wait,
481 &IoStatus);
482 }
483
484 /*
485 * @implemented
486 */
487 VOID
488 NTAPI
489 CcDeferWrite (
490 IN PFILE_OBJECT FileObject,
491 IN PCC_POST_DEFERRED_WRITE PostRoutine,
492 IN PVOID Context1,
493 IN PVOID Context2,
494 IN ULONG BytesToWrite,
495 IN BOOLEAN Retrying)
496 {
497 PDEFERRED_WRITE Context;
498
499 CCTRACE(CC_API_DEBUG, "FileObject=%p PostRoutine=%p Context1=%p Context2=%p BytesToWrite=%lu Retrying=%d\n",
500 FileObject, PostRoutine, Context1, Context2, BytesToWrite, Retrying);
501
502 /* Try to allocate a context for queueing the write operation */
503 Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEFERRED_WRITE), 'CcDw');
504 /* If it failed, immediately execute the operation! */
505 if (Context == NULL)
506 {
507 PostRoutine(Context1, Context2);
508 return;
509 }
510
511 /* Otherwise, initialize the context */
512 RtlZeroMemory(Context, sizeof(DEFERRED_WRITE));
513 Context->NodeTypeCode = NODE_TYPE_DEFERRED_WRITE;
514 Context->NodeByteSize = sizeof(DEFERRED_WRITE);
515 Context->FileObject = FileObject;
516 Context->PostRoutine = PostRoutine;
517 Context->Context1 = Context1;
518 Context->Context2 = Context2;
519 Context->BytesToWrite = BytesToWrite;
520
521 /* And queue it */
522 if (Retrying)
523 {
524 /* To the top, if that's a retry */
525 ExInterlockedInsertHeadList(&CcDeferredWrites,
526 &Context->DeferredWriteLinks,
527 &CcDeferredWriteSpinLock);
528 }
529 else
530 {
531 /* To the bottom, if that's a first time */
532 ExInterlockedInsertTailList(&CcDeferredWrites,
533 &Context->DeferredWriteLinks,
534 &CcDeferredWriteSpinLock);
535 }
536 }
537
538 /*
539 * @unimplemented
540 */
541 VOID
542 NTAPI
543 CcFastCopyRead (
544 IN PFILE_OBJECT FileObject,
545 IN ULONG FileOffset,
546 IN ULONG Length,
547 IN ULONG PageCount,
548 OUT PVOID Buffer,
549 OUT PIO_STATUS_BLOCK IoStatus)
550 {
551 LARGE_INTEGER LargeFileOffset;
552 BOOLEAN Success;
553
554 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%lu Length=%lu PageCount=%lu Buffer=%p\n",
555 FileObject, FileOffset, Length, PageCount, Buffer);
556
557 DBG_UNREFERENCED_PARAMETER(PageCount);
558
559 LargeFileOffset.QuadPart = FileOffset;
560 Success = CcCopyRead(FileObject,
561 &LargeFileOffset,
562 Length,
563 TRUE,
564 Buffer,
565 IoStatus);
566 ASSERT(Success == TRUE);
567 }
568
569 /*
570 * @unimplemented
571 */
572 VOID
573 NTAPI
574 CcFastCopyWrite (
575 IN PFILE_OBJECT FileObject,
576 IN ULONG FileOffset,
577 IN ULONG Length,
578 IN PVOID Buffer)
579 {
580 LARGE_INTEGER LargeFileOffset;
581 BOOLEAN Success;
582
583 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%lu Length=%lu Buffer=%p\n",
584 FileObject, FileOffset, Length, Buffer);
585
586 LargeFileOffset.QuadPart = FileOffset;
587 Success = CcCopyWrite(FileObject,
588 &LargeFileOffset,
589 Length,
590 TRUE,
591 Buffer);
592 ASSERT(Success == TRUE);
593 }
594
595 /*
596 * @implemented
597 */
598 NTSTATUS
599 NTAPI
600 CcWaitForCurrentLazyWriterActivity (
601 VOID)
602 {
603 NTSTATUS Status;
604
605 /* Lazy writer is done when its event is set */
606 Status = KeWaitForSingleObject(&iLazyWriterNotify,
607 Executive,
608 KernelMode,
609 FALSE,
610 NULL);
611 if (!NT_SUCCESS(Status))
612 {
613 return Status;
614 }
615
616 return STATUS_SUCCESS;
617 }
618
619 /*
620 * @implemented
621 */
622 BOOLEAN
623 NTAPI
624 CcZeroData (
625 IN PFILE_OBJECT FileObject,
626 IN PLARGE_INTEGER StartOffset,
627 IN PLARGE_INTEGER EndOffset,
628 IN BOOLEAN Wait)
629 {
630 NTSTATUS Status;
631 LARGE_INTEGER WriteOffset;
632 LONGLONG Length;
633 ULONG CurrentLength;
634 PMDL Mdl;
635 ULONG i;
636 IO_STATUS_BLOCK Iosb;
637 KEVENT Event;
638
639 CCTRACE(CC_API_DEBUG, "FileObject=%p StartOffset=%I64u EndOffset=%I64u Wait=%d\n",
640 FileObject, StartOffset->QuadPart, EndOffset->QuadPart, Wait);
641
642 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
643 "Wait %u)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
644 Wait);
645
646 Length = EndOffset->QuadPart - StartOffset->QuadPart;
647 WriteOffset.QuadPart = StartOffset->QuadPart;
648
649 if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
650 {
651 /* File is not cached */
652
653 Mdl = _alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
654
655 while (Length > 0)
656 {
657 if (Length + WriteOffset.QuadPart % PAGE_SIZE > MAX_ZERO_LENGTH)
658 {
659 CurrentLength = MAX_ZERO_LENGTH - WriteOffset.QuadPart % PAGE_SIZE;
660 }
661 else
662 {
663 CurrentLength = Length;
664 }
665 MmInitializeMdl(Mdl, (PVOID)(ULONG_PTR)WriteOffset.QuadPart, CurrentLength);
666 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
667 for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
668 {
669 ((PPFN_NUMBER)(Mdl + 1))[i] = CcZeroPage;
670 }
671 KeInitializeEvent(&Event, NotificationEvent, FALSE);
672 Status = IoSynchronousPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
673 if (Status == STATUS_PENDING)
674 {
675 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
676 Status = Iosb.Status;
677 }
678 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
679 {
680 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
681 }
682 if (!NT_SUCCESS(Status))
683 {
684 return FALSE;
685 }
686 WriteOffset.QuadPart += CurrentLength;
687 Length -= CurrentLength;
688 }
689 }
690 else
691 {
692 IO_STATUS_BLOCK IoStatus;
693
694 return CcCopyData(FileObject,
695 WriteOffset.QuadPart,
696 NULL,
697 Length,
698 CcOperationZero,
699 Wait,
700 &IoStatus);
701 }
702
703 return TRUE;
704 }