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