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