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