[NTOSKRNL]
[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 Mdl = IoAllocateMdl(CacheSeg->BaseAddress, Size, FALSE, FALSE, NULL);
203 MmBuildMdlForNonPagedPool(Mdl);
204 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
205 KeInitializeEvent(&Event, NotificationEvent, FALSE);
206 Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, & Event, &IoStatus);
207 if (Status == STATUS_PENDING)
208 {
209 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
210 Status = IoStatus.Status;
211 }
212
213 IoFreeMdl(Mdl);
214
215 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
216 {
217 DPRINT1("IoPageRead failed, Status %x\n", Status);
218 return Status;
219 }
220 if (CacheSeg->Bcb->CacheSegmentSize > Size)
221 {
222 memset ((char*)CacheSeg->BaseAddress + Size, 0,
223 CacheSeg->Bcb->CacheSegmentSize - Size);
224 }
225 return STATUS_SUCCESS;
226 }
227
228 NTSTATUS
229 NTAPI
230 WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
231 {
232 ULONG Size;
233 PMDL Mdl;
234 NTSTATUS Status;
235 IO_STATUS_BLOCK IoStatus;
236 LARGE_INTEGER SegOffset;
237 KEVENT Event;
238
239 CacheSeg->Dirty = FALSE;
240 SegOffset.QuadPart = CacheSeg->FileOffset;
241 Size = (ULONG)(CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset);
242 if (Size > CacheSeg->Bcb->CacheSegmentSize)
243 {
244 Size = CacheSeg->Bcb->CacheSegmentSize;
245 }
246 //
247 // Nonpaged pool PDEs in ReactOS must actually be synchronized between the
248 // MmGlobalPageDirectory and the real system PDE directory. What a mess...
249 //
250 {
251 int i = 0;
252 do
253 {
254 MmGetPfnForProcess(NULL, (PVOID)((ULONG_PTR)CacheSeg->BaseAddress + (i << PAGE_SHIFT)));
255 } while (++i < (Size >> PAGE_SHIFT));
256 }
257 Mdl = IoAllocateMdl(CacheSeg->BaseAddress, Size, FALSE, FALSE, NULL);
258 MmBuildMdlForNonPagedPool(Mdl);
259 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
260 KeInitializeEvent(&Event, NotificationEvent, FALSE);
261 Status = IoSynchronousPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &Event, &IoStatus);
262 if (Status == STATUS_PENDING)
263 {
264 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
265 Status = IoStatus.Status;
266 }
267 IoFreeMdl(Mdl);
268 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
269 {
270 DPRINT1("IoPageWrite failed, Status %x\n", Status);
271 CacheSeg->Dirty = TRUE;
272 return(Status);
273 }
274 return(STATUS_SUCCESS);
275 }
276
277
278 /*
279 * @unimplemented
280 */
281 BOOLEAN NTAPI
282 CcCanIWrite (
283 IN PFILE_OBJECT FileObject,
284 IN ULONG BytesToWrite,
285 IN BOOLEAN Wait,
286 IN BOOLEAN Retrying)
287 {
288 UNIMPLEMENTED;
289 return FALSE;
290 }
291
292
293 /*
294 * @implemented
295 */
296 BOOLEAN NTAPI
297 CcCopyRead (IN PFILE_OBJECT FileObject,
298 IN PLARGE_INTEGER FileOffset,
299 IN ULONG Length,
300 IN BOOLEAN Wait,
301 OUT PVOID Buffer,
302 OUT PIO_STATUS_BLOCK IoStatus)
303 {
304 ULONG ReadOffset;
305 ULONG TempLength;
306 NTSTATUS Status = STATUS_SUCCESS;
307 PVOID BaseAddress;
308 PCACHE_SEGMENT CacheSeg;
309 BOOLEAN Valid;
310 ULONG ReadLength = 0;
311 PBCB Bcb;
312 KIRQL oldirql;
313 PLIST_ENTRY current_entry;
314 PCACHE_SEGMENT current;
315
316 DPRINT("CcCopyRead(FileObject 0x%p, FileOffset %I64x, "
317 "Length %d, Wait %d, Buffer 0x%p, IoStatus 0x%p)\n",
318 FileObject, FileOffset->QuadPart, Length, Wait,
319 Buffer, IoStatus);
320
321 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
322 ReadOffset = (ULONG)FileOffset->QuadPart;
323
324 DPRINT("AllocationSize %d, FileSize %d\n",
325 (ULONG)Bcb->AllocationSize.QuadPart,
326 (ULONG)Bcb->FileSize.QuadPart);
327
328 /*
329 * Check for the nowait case that all the cache segments that would
330 * cover this read are in memory.
331 */
332 if (!Wait)
333 {
334 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
335 current_entry = Bcb->BcbSegmentListHead.Flink;
336 while (current_entry != &Bcb->BcbSegmentListHead)
337 {
338 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
339 BcbSegmentListEntry);
340 if (!current->Valid && current->FileOffset < ReadOffset + Length
341 && current->FileOffset + Bcb->CacheSegmentSize > ReadOffset)
342 {
343 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
344 IoStatus->Status = STATUS_UNSUCCESSFUL;
345 IoStatus->Information = 0;
346 return FALSE;
347 }
348 current_entry = current_entry->Flink;
349 }
350 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
351 }
352
353 TempLength = ReadOffset % Bcb->CacheSegmentSize;
354 if (TempLength != 0)
355 {
356 TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
357 Status = CcRosRequestCacheSegment(Bcb,
358 ROUND_DOWN(ReadOffset,
359 Bcb->CacheSegmentSize),
360 &BaseAddress, &Valid, &CacheSeg);
361 if (!NT_SUCCESS(Status))
362 {
363 IoStatus->Information = 0;
364 IoStatus->Status = Status;
365 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
366 return FALSE;
367 }
368 if (!Valid)
369 {
370 Status = ReadCacheSegment(CacheSeg);
371 if (!NT_SUCCESS(Status))
372 {
373 IoStatus->Information = 0;
374 IoStatus->Status = Status;
375 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
376 return FALSE;
377 }
378 }
379 memcpy (Buffer, (char*)BaseAddress + ReadOffset % Bcb->CacheSegmentSize,
380 TempLength);
381 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
382 ReadLength += TempLength;
383 Length -= TempLength;
384 ReadOffset += TempLength;
385 Buffer = (PVOID)((char*)Buffer + TempLength);
386 }
387 while (Length > 0)
388 {
389 TempLength = min(max(Bcb->CacheSegmentSize, MAX_RW_LENGTH), Length);
390 Status = ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
391 if (!NT_SUCCESS(Status))
392 {
393 IoStatus->Information = 0;
394 IoStatus->Status = Status;
395 DPRINT1("ReadCacheSegmentChain failed, Status %x\n", Status);
396 return FALSE;
397 }
398
399 ReadLength += TempLength;
400 Length -= TempLength;
401 ReadOffset += TempLength;
402
403 Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
404 }
405 IoStatus->Status = STATUS_SUCCESS;
406 IoStatus->Information = ReadLength;
407 DPRINT("CcCopyRead O.K.\n");
408 return TRUE;
409 }
410
411 /*
412 * @implemented
413 */
414 BOOLEAN NTAPI
415 CcCopyWrite (IN PFILE_OBJECT FileObject,
416 IN PLARGE_INTEGER FileOffset,
417 IN ULONG Length,
418 IN BOOLEAN Wait,
419 IN PVOID Buffer)
420 {
421 NTSTATUS Status;
422 ULONG WriteOffset;
423 KIRQL oldirql;
424 PBCB Bcb;
425 PLIST_ENTRY current_entry;
426 PCACHE_SEGMENT CacheSeg;
427 ULONG TempLength;
428 PVOID BaseAddress;
429 BOOLEAN Valid;
430
431 DPRINT("CcCopyWrite(FileObject 0x%p, FileOffset %I64x, "
432 "Length %d, Wait %d, Buffer 0x%p)\n",
433 FileObject, FileOffset->QuadPart, Length, Wait, Buffer);
434
435 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
436 WriteOffset = (ULONG)FileOffset->QuadPart;
437
438 if (!Wait)
439 {
440 /* testing, if the requested datas are available */
441 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
442 current_entry = Bcb->BcbSegmentListHead.Flink;
443 while (current_entry != &Bcb->BcbSegmentListHead)
444 {
445 CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
446 BcbSegmentListEntry);
447 if (!CacheSeg->Valid)
448 {
449 if ((WriteOffset >= CacheSeg->FileOffset &&
450 WriteOffset < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
451 || (WriteOffset + Length > CacheSeg->FileOffset &&
452 WriteOffset + Length <= CacheSeg->FileOffset +
453 Bcb->CacheSegmentSize))
454 {
455 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
456 /* datas not available */
457 return(FALSE);
458 }
459 }
460 current_entry = current_entry->Flink;
461 }
462 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
463 }
464
465 TempLength = WriteOffset % Bcb->CacheSegmentSize;
466 if (TempLength != 0)
467 {
468 ULONG ROffset;
469 ROffset = ROUND_DOWN(WriteOffset, Bcb->CacheSegmentSize);
470 TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
471 Status = CcRosRequestCacheSegment(Bcb, ROffset,
472 &BaseAddress, &Valid, &CacheSeg);
473 if (!NT_SUCCESS(Status))
474 {
475 return(FALSE);
476 }
477 if (!Valid)
478 {
479 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
480 {
481 return(FALSE);
482 }
483 }
484 memcpy ((char*)BaseAddress + WriteOffset % Bcb->CacheSegmentSize,
485 Buffer, TempLength);
486 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
487
488 Length -= TempLength;
489 WriteOffset += TempLength;
490
491 Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
492 }
493
494 while (Length > 0)
495 {
496 TempLength = min (Bcb->CacheSegmentSize, Length);
497 Status = CcRosRequestCacheSegment(Bcb, WriteOffset,
498 &BaseAddress, &Valid, &CacheSeg);
499 if (!NT_SUCCESS(Status))
500 {
501 return(FALSE);
502 }
503 if (!Valid && TempLength < Bcb->CacheSegmentSize)
504 {
505 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
506 {
507 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
508 return FALSE;
509 }
510 }
511 memcpy (BaseAddress, Buffer, TempLength);
512 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
513 Length -= TempLength;
514 WriteOffset += TempLength;
515
516 Buffer = (PVOID)((ULONG_PTR)Buffer + TempLength);
517 }
518 return(TRUE);
519 }
520
521 /*
522 * @unimplemented
523 */
524 VOID
525 NTAPI
526 CcDeferWrite (
527 IN PFILE_OBJECT FileObject,
528 IN PCC_POST_DEFERRED_WRITE PostRoutine,
529 IN PVOID Context1,
530 IN PVOID Context2,
531 IN ULONG BytesToWrite,
532 IN BOOLEAN Retrying
533 )
534 {
535 UNIMPLEMENTED;
536 }
537
538 /*
539 * @unimplemented
540 */
541 VOID
542 NTAPI
543 CcFastCopyRead (
544 IN PFILE_OBJECT FileObject,
545 IN ULONG FileOffset,
546 IN ULONG Length,
547 IN ULONG PageCount,
548 OUT PVOID Buffer,
549 OUT PIO_STATUS_BLOCK IoStatus
550 )
551 {
552 UNIMPLEMENTED;
553 }
554 /*
555 * @unimplemented
556 */
557 VOID
558 NTAPI
559 CcFastCopyWrite(
560 IN PFILE_OBJECT FileObject,
561 IN ULONG FileOffset,
562 IN ULONG Length,
563 IN PVOID Buffer)
564 {
565 UNIMPLEMENTED;
566 }
567
568 /*
569 * @unimplemented
570 */
571 NTSTATUS
572 NTAPI
573 CcWaitForCurrentLazyWriterActivity (
574 VOID
575 )
576 {
577 UNIMPLEMENTED;
578 return STATUS_NOT_IMPLEMENTED;
579 }
580
581 /*
582 * @implemented
583 */
584 BOOLEAN NTAPI
585 CcZeroData (IN PFILE_OBJECT FileObject,
586 IN PLARGE_INTEGER StartOffset,
587 IN PLARGE_INTEGER EndOffset,
588 IN BOOLEAN Wait)
589 {
590 NTSTATUS Status;
591 LARGE_INTEGER WriteOffset;
592 ULONG Length;
593 ULONG CurrentLength;
594 PMDL Mdl;
595 ULONG i;
596 IO_STATUS_BLOCK Iosb;
597 KEVENT Event;
598
599 DPRINT("CcZeroData(FileObject 0x%p, StartOffset %I64x, EndOffset %I64x, "
600 "Wait %d)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
601 Wait);
602
603 Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
604 WriteOffset.QuadPart = StartOffset->QuadPart;
605
606 if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
607 {
608 /* File is not cached */
609
610 Mdl = _alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
611
612 while (Length > 0)
613 {
614 if (Length + WriteOffset.u.LowPart % PAGE_SIZE > MAX_ZERO_LENGTH)
615 {
616 CurrentLength = MAX_ZERO_LENGTH - WriteOffset.u.LowPart % PAGE_SIZE;
617 }
618 else
619 {
620 CurrentLength = Length;
621 }
622 MmInitializeMdl(Mdl, (PVOID)(ULONG_PTR)WriteOffset.QuadPart, CurrentLength);
623 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
624 for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
625 {
626 ((PPFN_NUMBER)(Mdl + 1))[i] = CcZeroPage;
627 }
628 KeInitializeEvent(&Event, NotificationEvent, FALSE);
629 Status = IoSynchronousPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
630 if (Status == STATUS_PENDING)
631 {
632 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
633 Status = Iosb.Status;
634 }
635 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
636 if (!NT_SUCCESS(Status))
637 {
638 return(FALSE);
639 }
640 WriteOffset.QuadPart += CurrentLength;
641 Length -= CurrentLength;
642 }
643 }
644 else
645 {
646 /* File is cached */
647 KIRQL oldirql;
648 PBCB Bcb;
649 PLIST_ENTRY current_entry;
650 PCACHE_SEGMENT CacheSeg, current, previous;
651 ULONG TempLength;
652
653 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
654 if (Wait)
655 {
656 /* testing, if the requested datas are available */
657 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
658 current_entry = Bcb->BcbSegmentListHead.Flink;
659 while (current_entry != &Bcb->BcbSegmentListHead)
660 {
661 CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
662 BcbSegmentListEntry);
663 if (!CacheSeg->Valid)
664 {
665 if ((WriteOffset.u.LowPart >= CacheSeg->FileOffset &&
666 WriteOffset.u.LowPart < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
667 || (WriteOffset.u.LowPart + Length > CacheSeg->FileOffset &&
668 WriteOffset.u.LowPart + Length <=
669 CacheSeg->FileOffset + Bcb->CacheSegmentSize))
670 {
671 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
672 /* datas not available */
673 return(FALSE);
674 }
675 }
676 current_entry = current_entry->Flink;
677 }
678 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
679 }
680 while (Length > 0)
681 {
682 ULONG Offset;
683 Offset = WriteOffset.u.LowPart % Bcb->CacheSegmentSize;
684 if (Length + Offset > MAX_ZERO_LENGTH)
685 {
686 CurrentLength = MAX_ZERO_LENGTH - Offset;
687 }
688 else
689 {
690 CurrentLength = Length;
691 }
692 Status = CcRosGetCacheSegmentChain (Bcb, WriteOffset.u.LowPart - Offset,
693 Offset + CurrentLength, &CacheSeg);
694 if (!NT_SUCCESS(Status))
695 {
696 return FALSE;
697 }
698 current = CacheSeg;
699
700 while (current != NULL)
701 {
702 Offset = WriteOffset.u.LowPart % Bcb->CacheSegmentSize;
703 if (Offset != 0 ||
704 Offset + CurrentLength < Bcb->CacheSegmentSize)
705 {
706 if (!current->Valid)
707 {
708 /* read the segment */
709 Status = ReadCacheSegment(current);
710 if (!NT_SUCCESS(Status))
711 {
712 DPRINT1("ReadCacheSegment failed, status %x\n",
713 Status);
714 }
715 }
716 TempLength = min (CurrentLength, Bcb->CacheSegmentSize - Offset);
717 }
718 else
719 {
720 TempLength = Bcb->CacheSegmentSize;
721 }
722 memset ((PUCHAR)current->BaseAddress + Offset, 0, TempLength);
723
724 WriteOffset.QuadPart += TempLength;
725 CurrentLength -= TempLength;
726 Length -= TempLength;
727
728 current = current->NextInChain;
729 }
730
731 current = CacheSeg;
732 while (current != NULL)
733 {
734 previous = current;
735 current = current->NextInChain;
736 CcRosReleaseCacheSegment(Bcb, previous, TRUE, TRUE, FALSE);
737 }
738 }
739 }
740 return(TRUE);
741 }