Sync with trunk r63743.
[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 #define MAX_RW_LENGTH (256 * 1024)
22 C_ASSERT(MAX_RW_LENGTH <= VACB_MAPPING_GRANULARITY);
23
24 ULONG CcFastMdlReadWait;
25 ULONG CcFastMdlReadNotPossible;
26 ULONG CcFastReadNotPossible;
27 ULONG CcFastReadWait;
28 ULONG CcFastReadNoWait;
29 ULONG CcFastReadResourceMiss;
30
31 /* FUNCTIONS *****************************************************************/
32
33 VOID
34 NTAPI
35 MiZeroPhysicalPage (
36 IN PFN_NUMBER PageFrameIndex
37 );
38
39 VOID
40 NTAPI
41 CcInitCacheZeroPage (
42 VOID)
43 {
44 NTSTATUS Status;
45
46 MI_SET_USAGE(MI_USAGE_CACHE);
47 //MI_SET_PROCESS2(PsGetCurrentProcess()->ImageFileName);
48 Status = MmRequestPageMemoryConsumer(MC_SYSTEM, TRUE, &CcZeroPage);
49 if (!NT_SUCCESS(Status))
50 {
51 DbgPrint("Can't allocate CcZeroPage.\n");
52 KeBugCheck(CACHE_MANAGER);
53 }
54 MiZeroPhysicalPage(CcZeroPage);
55 }
56
57 NTSTATUS
58 NTAPI
59 ReadVacbChain (
60 PROS_SHARED_CACHE_MAP SharedCacheMap,
61 ULONG ReadOffset,
62 ULONG Length,
63 PVOID Buffer)
64 {
65 PROS_VACB head;
66 PROS_VACB current;
67 PROS_VACB previous;
68 IO_STATUS_BLOCK Iosb;
69 NTSTATUS Status;
70 ULONG TempLength;
71 KEVENT Event;
72 PMDL Mdl;
73
74 Mdl = _alloca(MmSizeOfMdl(NULL, MAX_RW_LENGTH));
75
76 Status = CcRosGetVacbChain(SharedCacheMap, ReadOffset, Length, &head);
77 if (!NT_SUCCESS(Status))
78 {
79 return Status;
80 }
81 current = head;
82 while (current != NULL)
83 {
84 /*
85 * If the current VACB is valid then copy it into the user buffer.
86 */
87 if (current->Valid)
88 {
89 TempLength = min(VACB_MAPPING_GRANULARITY, Length);
90 RtlCopyMemory(Buffer, current->BaseAddress, TempLength);
91
92 Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
93
94 Length = Length - TempLength;
95 previous = current;
96 current = current->NextInChain;
97 CcRosReleaseVacb(SharedCacheMap, previous, TRUE, FALSE, FALSE);
98 }
99 /*
100 * Otherwise read in as much as we can.
101 */
102 else
103 {
104 PROS_VACB current2;
105 ULONG current_size;
106 ULONG i;
107 PPFN_NUMBER MdlPages;
108
109 /*
110 * Count the maximum number of bytes we could read starting
111 * from the current VACB.
112 */
113 current2 = current;
114 current_size = 0;
115 while ((current2 != NULL) && !current2->Valid && (current_size < MAX_RW_LENGTH))
116 {
117 current2 = current2->NextInChain;
118 current_size += VACB_MAPPING_GRANULARITY;
119 }
120
121 /*
122 * Create an MDL which contains all their pages.
123 */
124 MmInitializeMdl(Mdl, NULL, current_size);
125 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
126 current2 = current;
127 current_size = 0;
128 MdlPages = (PPFN_NUMBER)(Mdl + 1);
129 while ((current2 != NULL) && !current2->Valid && (current_size < MAX_RW_LENGTH))
130 {
131 PVOID address = current2->BaseAddress;
132 for (i = 0; i < VACB_MAPPING_GRANULARITY / PAGE_SIZE; i++, address = RVA(address, PAGE_SIZE))
133 {
134 *MdlPages++ = MmGetPfnForProcess(NULL, address);
135 }
136 current2 = current2->NextInChain;
137 current_size += VACB_MAPPING_GRANULARITY;
138 }
139
140 /*
141 * Read in the information.
142 */
143 KeInitializeEvent(&Event, NotificationEvent, FALSE);
144 Status = IoPageRead(SharedCacheMap->FileObject,
145 Mdl,
146 &current->FileOffset,
147 &Event,
148 &Iosb);
149 if (Status == STATUS_PENDING)
150 {
151 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
152 Status = Iosb.Status;
153 }
154 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
155 {
156 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
157 }
158 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
159 {
160 while (current != NULL)
161 {
162 previous = current;
163 current = current->NextInChain;
164 CcRosReleaseVacb(SharedCacheMap, previous, FALSE, FALSE, FALSE);
165 }
166 return Status;
167 }
168 current_size = 0;
169 while (current != NULL && !current->Valid && current_size < MAX_RW_LENGTH)
170 {
171 previous = current;
172 current = current->NextInChain;
173 TempLength = min(VACB_MAPPING_GRANULARITY, Length);
174 RtlCopyMemory(Buffer, previous->BaseAddress, TempLength);
175
176 Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
177
178 Length = Length - TempLength;
179 CcRosReleaseVacb(SharedCacheMap, previous, TRUE, FALSE, FALSE);
180 current_size += VACB_MAPPING_GRANULARITY;
181 }
182 }
183 }
184 return STATUS_SUCCESS;
185 }
186
187 NTSTATUS
188 NTAPI
189 CcReadVirtualAddress (
190 PROS_VACB Vacb)
191 {
192 ULONG Size;
193 PMDL Mdl;
194 NTSTATUS Status;
195 IO_STATUS_BLOCK IoStatus;
196 KEVENT Event;
197
198 Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
199 if (Size > VACB_MAPPING_GRANULARITY)
200 {
201 Size = VACB_MAPPING_GRANULARITY;
202 }
203
204 Mdl = IoAllocateMdl(Vacb->BaseAddress, Size, FALSE, FALSE, NULL);
205 if (!Mdl)
206 {
207 return STATUS_INSUFFICIENT_RESOURCES;
208 }
209
210 MmBuildMdlForNonPagedPool(Mdl);
211 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
212 KeInitializeEvent(&Event, NotificationEvent, FALSE);
213 Status = IoPageRead(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
214 if (Status == STATUS_PENDING)
215 {
216 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
217 Status = IoStatus.Status;
218 }
219
220 IoFreeMdl(Mdl);
221
222 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
223 {
224 DPRINT1("IoPageRead failed, Status %x\n", Status);
225 return Status;
226 }
227
228 if (Size < VACB_MAPPING_GRANULARITY)
229 {
230 RtlZeroMemory((char*)Vacb->BaseAddress + Size,
231 VACB_MAPPING_GRANULARITY - Size);
232 }
233
234 return STATUS_SUCCESS;
235 }
236
237 NTSTATUS
238 NTAPI
239 CcWriteVirtualAddress (
240 PROS_VACB Vacb)
241 {
242 ULONG Size;
243 PMDL Mdl;
244 NTSTATUS Status;
245 IO_STATUS_BLOCK IoStatus;
246 KEVENT Event;
247
248 Vacb->Dirty = FALSE;
249 Size = (ULONG)(Vacb->SharedCacheMap->SectionSize.QuadPart - Vacb->FileOffset.QuadPart);
250 if (Size > VACB_MAPPING_GRANULARITY)
251 {
252 Size = VACB_MAPPING_GRANULARITY;
253 }
254 //
255 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
256 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
257 //
258 {
259 ULONG i = 0;
260 do
261 {
262 MmGetPfnForProcess(NULL, (PVOID)((ULONG_PTR)Vacb->BaseAddress + (i << PAGE_SHIFT)));
263 } while (++i < (Size >> PAGE_SHIFT));
264 }
265
266 Mdl = IoAllocateMdl(Vacb->BaseAddress, Size, FALSE, FALSE, NULL);
267 if (!Mdl)
268 {
269 return STATUS_INSUFFICIENT_RESOURCES;
270 }
271 MmBuildMdlForNonPagedPool(Mdl);
272 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
273 KeInitializeEvent(&Event, NotificationEvent, FALSE);
274 Status = IoSynchronousPageWrite(Vacb->SharedCacheMap->FileObject, Mdl, &Vacb->FileOffset, &Event, &IoStatus);
275 if (Status == STATUS_PENDING)
276 {
277 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
278 Status = IoStatus.Status;
279 }
280 IoFreeMdl(Mdl);
281 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
282 {
283 DPRINT1("IoPageWrite failed, Status %x\n", Status);
284 Vacb->Dirty = TRUE;
285 return Status;
286 }
287
288 return STATUS_SUCCESS;
289 }
290
291
292 /*
293 * @unimplemented
294 */
295 BOOLEAN
296 NTAPI
297 CcCanIWrite (
298 IN PFILE_OBJECT FileObject,
299 IN ULONG BytesToWrite,
300 IN BOOLEAN Wait,
301 IN BOOLEAN Retrying)
302 {
303 UNIMPLEMENTED;
304 return FALSE;
305 }
306
307
308 /*
309 * @implemented
310 */
311 BOOLEAN
312 NTAPI
313 CcCopyRead (
314 IN PFILE_OBJECT FileObject,
315 IN PLARGE_INTEGER FileOffset,
316 IN ULONG Length,
317 IN BOOLEAN Wait,
318 OUT PVOID Buffer,
319 OUT PIO_STATUS_BLOCK IoStatus)
320 {
321 ULONG ReadOffset;
322 ULONG TempLength;
323 NTSTATUS Status = STATUS_SUCCESS;
324 PVOID BaseAddress;
325 PROS_VACB Vacb;
326 BOOLEAN Valid;
327 ULONG ReadLength = 0;
328 PROS_SHARED_CACHE_MAP SharedCacheMap;
329 KIRQL oldirql;
330 PLIST_ENTRY current_entry;
331 PROS_VACB current;
332
333 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
334 "Length %lu, Wait %u, Buffer 0x%p, IoStatus 0x%p)\n",
335 FileObject, FileOffset->QuadPart, Length, Wait,
336 Buffer, IoStatus);
337
338 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
339 ReadOffset = (ULONG)FileOffset->QuadPart;
340
341 DPRINT("SectionSize %I64d, FileSize %I64d\n",
342 SharedCacheMap->SectionSize.QuadPart,
343 SharedCacheMap->FileSize.QuadPart);
344
345 /*
346 * Check for the nowait case that all the cache VACBs that would
347 * cover this read are in memory.
348 */
349 if (!Wait)
350 {
351 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
352 /* FIXME: this loop doesn't take into account areas that don't have
353 * a VACB in the list yet */
354 current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
355 while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
356 {
357 current = CONTAINING_RECORD(current_entry,
358 ROS_VACB,
359 CacheMapVacbListEntry);
360 if (!current->Valid &&
361 DoRangesIntersect(current->FileOffset.QuadPart,
362 VACB_MAPPING_GRANULARITY,
363 ReadOffset, Length))
364 {
365 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
366 IoStatus->Status = STATUS_UNSUCCESSFUL;
367 IoStatus->Information = 0;
368 return FALSE;
369 }
370 if (current->FileOffset.QuadPart >= ReadOffset + Length)
371 break;
372 current_entry = current_entry->Flink;
373 }
374 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
375 }
376
377 TempLength = ReadOffset % VACB_MAPPING_GRANULARITY;
378 if (TempLength != 0)
379 {
380 TempLength = min(Length, VACB_MAPPING_GRANULARITY - TempLength);
381 Status = CcRosRequestVacb(SharedCacheMap,
382 ROUND_DOWN(ReadOffset,
383 VACB_MAPPING_GRANULARITY),
384 &BaseAddress, &Valid, &Vacb);
385 if (!NT_SUCCESS(Status))
386 {
387 IoStatus->Information = 0;
388 IoStatus->Status = Status;
389 DPRINT("CcRosRequestVacb failed, Status %x\n", Status);
390 return FALSE;
391 }
392 if (!Valid)
393 {
394 Status = CcReadVirtualAddress(Vacb);
395 if (!NT_SUCCESS(Status))
396 {
397 IoStatus->Information = 0;
398 IoStatus->Status = Status;
399 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
400 return FALSE;
401 }
402 }
403 RtlCopyMemory(Buffer,
404 (char*)BaseAddress + ReadOffset % VACB_MAPPING_GRANULARITY,
405 TempLength);
406 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE);
407 ReadLength += TempLength;
408 Length -= TempLength;
409 ReadOffset += TempLength;
410 Buffer = (PVOID)((char*)Buffer + TempLength);
411 }
412
413 while (Length > 0)
414 {
415 TempLength = min(VACB_MAPPING_GRANULARITY, Length);
416 Status = ReadVacbChain(SharedCacheMap, ReadOffset, TempLength, Buffer);
417 if (!NT_SUCCESS(Status))
418 {
419 IoStatus->Information = 0;
420 IoStatus->Status = Status;
421 DPRINT("ReadVacbChain failed, Status %x\n", Status);
422 return FALSE;
423 }
424
425 ReadLength += TempLength;
426 Length -= TempLength;
427 ReadOffset += TempLength;
428
429 Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
430 }
431
432 IoStatus->Status = STATUS_SUCCESS;
433 IoStatus->Information = ReadLength;
434 DPRINT("CcCopyRead O.K.\n");
435 return TRUE;
436 }
437
438 /*
439 * @implemented
440 */
441 BOOLEAN
442 NTAPI
443 CcCopyWrite (
444 IN PFILE_OBJECT FileObject,
445 IN PLARGE_INTEGER FileOffset,
446 IN ULONG Length,
447 IN BOOLEAN Wait,
448 IN PVOID Buffer)
449 {
450 NTSTATUS Status;
451 ULONG WriteOffset;
452 KIRQL oldirql;
453 PROS_SHARED_CACHE_MAP SharedCacheMap;
454 PLIST_ENTRY current_entry;
455 PROS_VACB Vacb;
456 ULONG TempLength;
457 PVOID BaseAddress;
458 BOOLEAN Valid;
459
460 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
461 "Length %lu, Wait %u, Buffer 0x%p)\n",
462 FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
463
464 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
465 WriteOffset = (ULONG)FileOffset->QuadPart;
466
467 if (!Wait)
468 {
469 /* testing, if the requested datas are available */
470 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
471 /* FIXME: this loop doesn't take into account areas that don't have
472 * a VACB in the list yet */
473 current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
474 while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
475 {
476 Vacb = CONTAINING_RECORD(current_entry,
477 ROS_VACB,
478 CacheMapVacbListEntry);
479 if (!Vacb->Valid &&
480 DoRangesIntersect(Vacb->FileOffset.QuadPart,
481 VACB_MAPPING_GRANULARITY,
482 WriteOffset, Length))
483 {
484 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
485 /* datas not available */
486 return FALSE;
487 }
488 if (Vacb->FileOffset.QuadPart >= WriteOffset + Length)
489 break;
490 current_entry = current_entry->Flink;
491 }
492 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
493 }
494
495 TempLength = WriteOffset % VACB_MAPPING_GRANULARITY;
496 if (TempLength != 0)
497 {
498 ULONG ROffset;
499 ROffset = ROUND_DOWN(WriteOffset, VACB_MAPPING_GRANULARITY);
500 TempLength = min(Length, VACB_MAPPING_GRANULARITY - TempLength);
501 Status = CcRosRequestVacb(SharedCacheMap, ROffset,
502 &BaseAddress, &Valid, &Vacb);
503 if (!NT_SUCCESS(Status))
504 {
505 return FALSE;
506 }
507 if (!Valid)
508 {
509 if (!NT_SUCCESS(CcReadVirtualAddress(Vacb)))
510 {
511 return FALSE;
512 }
513 }
514 RtlCopyMemory((char*)BaseAddress + WriteOffset % VACB_MAPPING_GRANULARITY,
515 Buffer,
516 TempLength);
517 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, TRUE, FALSE);
518
519 Length -= TempLength;
520 WriteOffset += TempLength;
521
522 Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
523 }
524
525 while (Length > 0)
526 {
527 TempLength = min(VACB_MAPPING_GRANULARITY, Length);
528 Status = CcRosRequestVacb(SharedCacheMap,
529 WriteOffset,
530 &BaseAddress,
531 &Valid,
532 &Vacb);
533 if (!NT_SUCCESS(Status))
534 {
535 return FALSE;
536 }
537 if (!Valid && TempLength < VACB_MAPPING_GRANULARITY)
538 {
539 if (!NT_SUCCESS(CcReadVirtualAddress(Vacb)))
540 {
541 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE);
542 return FALSE;
543 }
544 }
545 RtlCopyMemory(BaseAddress, Buffer, TempLength);
546 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, TRUE, FALSE);
547 Length -= TempLength;
548 WriteOffset += TempLength;
549
550 Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
551 }
552 return TRUE;
553 }
554
555 /*
556 * @unimplemented
557 */
558 VOID
559 NTAPI
560 CcDeferWrite (
561 IN PFILE_OBJECT FileObject,
562 IN PCC_POST_DEFERRED_WRITE PostRoutine,
563 IN PVOID Context1,
564 IN PVOID Context2,
565 IN ULONG BytesToWrite,
566 IN BOOLEAN Retrying)
567 {
568 UNIMPLEMENTED;
569 }
570
571 /*
572 * @unimplemented
573 */
574 VOID
575 NTAPI
576 CcFastCopyRead (
577 IN PFILE_OBJECT FileObject,
578 IN ULONG FileOffset,
579 IN ULONG Length,
580 IN ULONG PageCount,
581 OUT PVOID Buffer,
582 OUT PIO_STATUS_BLOCK IoStatus)
583 {
584 UNIMPLEMENTED;
585 }
586 /*
587 * @unimplemented
588 */
589 VOID
590 NTAPI
591 CcFastCopyWrite (
592 IN PFILE_OBJECT FileObject,
593 IN ULONG FileOffset,
594 IN ULONG Length,
595 IN PVOID Buffer)
596 {
597 UNIMPLEMENTED;
598 }
599
600 /*
601 * @unimplemented
602 */
603 NTSTATUS
604 NTAPI
605 CcWaitForCurrentLazyWriterActivity (
606 VOID)
607 {
608 UNIMPLEMENTED;
609 return STATUS_NOT_IMPLEMENTED;
610 }
611
612 /*
613 * @implemented
614 */
615 BOOLEAN
616 NTAPI
617 CcZeroData (
618 IN PFILE_OBJECT FileObject,
619 IN PLARGE_INTEGER StartOffset,
620 IN PLARGE_INTEGER EndOffset,
621 IN BOOLEAN Wait)
622 {
623 NTSTATUS Status;
624 LARGE_INTEGER WriteOffset;
625 ULONG Length;
626 ULONG CurrentLength;
627 PMDL Mdl;
628 ULONG i;
629 IO_STATUS_BLOCK Iosb;
630 KEVENT Event;
631
632 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
633 "Wait %u)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
634 Wait);
635
636 Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
637 WriteOffset.QuadPart = StartOffset->QuadPart;
638
639 if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
640 {
641 /* File is not cached */
642
643 Mdl = _alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
644
645 while (Length > 0)
646 {
647 if (Length + WriteOffset.u.LowPart % PAGE_SIZE > MAX_ZERO_LENGTH)
648 {
649 CurrentLength = MAX_ZERO_LENGTH - WriteOffset.u.LowPart % PAGE_SIZE;
650 }
651 else
652 {
653 CurrentLength = Length;
654 }
655 MmInitializeMdl(Mdl, (PVOID)(ULONG_PTR)WriteOffset.QuadPart, CurrentLength);
656 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
657 for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
658 {
659 ((PPFN_NUMBER)(Mdl + 1))[i] = CcZeroPage;
660 }
661 KeInitializeEvent(&Event, NotificationEvent, FALSE);
662 Status = IoSynchronousPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
663 if (Status == STATUS_PENDING)
664 {
665 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
666 Status = Iosb.Status;
667 }
668 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
669 {
670 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
671 }
672 if (!NT_SUCCESS(Status))
673 {
674 return FALSE;
675 }
676 WriteOffset.QuadPart += CurrentLength;
677 Length -= CurrentLength;
678 }
679 }
680 else
681 {
682 /* File is cached */
683 KIRQL oldirql;
684 PROS_SHARED_CACHE_MAP SharedCacheMap;
685 PLIST_ENTRY current_entry;
686 PROS_VACB Vacb, current, previous;
687 ULONG TempLength;
688
689 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
690 if (!Wait)
691 {
692 /* testing, if the requested datas are available */
693 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql);
694 /* FIXME: this loop doesn't take into account areas that don't have
695 * a VACB in the list yet */
696 current_entry = SharedCacheMap->CacheMapVacbListHead.Flink;
697 while (current_entry != &SharedCacheMap->CacheMapVacbListHead)
698 {
699 Vacb = CONTAINING_RECORD(current_entry,
700 ROS_VACB,
701 CacheMapVacbListEntry);
702 if (!Vacb->Valid &&
703 DoRangesIntersect(Vacb->FileOffset.QuadPart,
704 VACB_MAPPING_GRANULARITY,
705 WriteOffset.u.LowPart, Length))
706 {
707 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
708 /* datas not available */
709 return FALSE;
710 }
711 if (Vacb->FileOffset.QuadPart >= WriteOffset.u.LowPart + Length)
712 break;
713 current_entry = current_entry->Flink;
714 }
715 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql);
716 }
717
718 while (Length > 0)
719 {
720 ULONG Offset;
721 Offset = WriteOffset.u.LowPart % VACB_MAPPING_GRANULARITY;
722 if (Length + Offset > MAX_ZERO_LENGTH)
723 {
724 CurrentLength = MAX_ZERO_LENGTH - Offset;
725 }
726 else
727 {
728 CurrentLength = Length;
729 }
730 Status = CcRosGetVacbChain(SharedCacheMap, WriteOffset.u.LowPart - Offset,
731 Offset + CurrentLength, &Vacb);
732 if (!NT_SUCCESS(Status))
733 {
734 return FALSE;
735 }
736 current = Vacb;
737
738 while (current != NULL)
739 {
740 Offset = WriteOffset.u.LowPart % VACB_MAPPING_GRANULARITY;
741 if ((Offset != 0) ||
742 (Offset + CurrentLength < VACB_MAPPING_GRANULARITY))
743 {
744 if (!current->Valid)
745 {
746 /* read the block */
747 Status = CcReadVirtualAddress(current);
748 if (!NT_SUCCESS(Status))
749 {
750 DPRINT1("CcReadVirtualAddress failed, status %x\n",
751 Status);
752 }
753 }
754 TempLength = min(CurrentLength, VACB_MAPPING_GRANULARITY - Offset);
755 }
756 else
757 {
758 TempLength = VACB_MAPPING_GRANULARITY;
759 }
760 RtlZeroMemory((PUCHAR)current->BaseAddress + Offset,
761 TempLength);
762
763 WriteOffset.QuadPart += TempLength;
764 CurrentLength -= TempLength;
765 Length -= TempLength;
766
767 current = current->NextInChain;
768 }
769
770 current = Vacb;
771 while (current != NULL)
772 {
773 previous = current;
774 current = current->NextInChain;
775 CcRosReleaseVacb(SharedCacheMap, previous, TRUE, TRUE, FALSE);
776 }
777 }
778 }
779
780 return TRUE;
781 }