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