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