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