ab59de0eb2bcb530340a3352142d074a89eecbfa
[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 * PROGRAMMER: Hartmut Birr
8 * UPDATE HISTORY:
9 * Created 05.10.2001
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *******************************************************************/
19
20 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
21
22 static PFN_TYPE CcZeroPage = 0;
23
24 #define MAX_ZERO_LENGTH (256 * 1024)
25 #define MAX_RW_LENGTH (256 * 1024)
26
27 #if defined(__GNUC__)
28 /* void * alloca(size_t size); */
29 #elif defined(_MSC_VER)
30 void* _alloca(size_t size);
31 #else
32 #error Unknown compiler for alloca intrinsic stack allocation "function"
33 #endif
34
35 ULONG EXPORTED CcFastMdlReadWait;
36 ULONG EXPORTED CcFastReadNotPossible;
37 ULONG EXPORTED CcFastReadWait;
38 ULONG CcFastReadNoWait;
39 ULONG CcFastReadResourceMiss;
40
41
42 /* FUNCTIONS *****************************************************************/
43
44 VOID
45 CcInitCacheZeroPage(VOID)
46 {
47 NTSTATUS Status;
48
49 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &CcZeroPage);
50 if (!NT_SUCCESS(Status))
51 {
52 DbgPrint("Can't allocate CcZeroPage.\n");
53 KEBUGCHECKCC;
54 }
55 Status = MiZeroPage(CcZeroPage);
56 if (!NT_SUCCESS(Status))
57 {
58 DbgPrint("Can't zero out CcZeroPage.\n");
59 KEBUGCHECKCC;
60 }
61 }
62
63 NTSTATUS
64 ReadCacheSegmentChain(PBCB Bcb, ULONG ReadOffset, ULONG Length,
65 PVOID Buffer)
66 {
67 PCACHE_SEGMENT head;
68 PCACHE_SEGMENT current;
69 PCACHE_SEGMENT previous;
70 IO_STATUS_BLOCK Iosb;
71 LARGE_INTEGER SegOffset;
72 NTSTATUS Status;
73 ULONG TempLength;
74 KEVENT Event;
75 PMDL Mdl;
76
77 Mdl = alloca(MmSizeOfMdl(NULL, MAX_RW_LENGTH));
78
79 Status = CcRosGetCacheSegmentChain(Bcb, ReadOffset, Length, &head);
80 if (!NT_SUCCESS(Status))
81 {
82 return(Status);
83 }
84 current = head;
85 while (current != NULL)
86 {
87 /*
88 * If the current segment is valid then copy it into the
89 * user buffer.
90 */
91 if (current->Valid)
92 {
93 TempLength = min(Bcb->CacheSegmentSize, Length);
94 memcpy(Buffer, current->BaseAddress, TempLength);
95 #if defined(__GNUC__)
96 Buffer += TempLength;
97 #else
98 {
99 char* pTemp = Buffer;
100 pTemp += TempLength;
101 Buffer = pTemp;
102 }
103 #endif
104 Length = Length - TempLength;
105 previous = current;
106 current = current->NextInChain;
107 CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
108 }
109 /*
110 * Otherwise read in as much as we can.
111 */
112 else
113 {
114 PCACHE_SEGMENT current2;
115 ULONG current_size;
116 ULONG i;
117 PPFN_TYPE MdlPages;
118
119 /*
120 * Count the maximum number of bytes we could read starting
121 * from the current segment.
122 */
123 current2 = current;
124 current_size = 0;
125 while (current2 != NULL && !current2->Valid && current_size < MAX_RW_LENGTH)
126 {
127 current2 = current2->NextInChain;
128 current_size += Bcb->CacheSegmentSize;
129 }
130
131 /*
132 * Create an MDL which contains all their pages.
133 */
134 MmInitializeMdl(Mdl, NULL, current_size);
135 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
136 current2 = current;
137 current_size = 0;
138 MdlPages = (PPFN_TYPE)(Mdl + 1);
139 while (current2 != NULL && !current2->Valid && current_size < MAX_RW_LENGTH)
140 {
141 PVOID address = current2->BaseAddress;
142 for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++, address += PAGE_SIZE)
143 {
144 *MdlPages++ = MmGetPfnForProcess(NULL, address);
145 }
146 current2 = current2->NextInChain;
147 current_size += Bcb->CacheSegmentSize;
148 }
149
150 /*
151 * Read in the information.
152 */
153 SegOffset.QuadPart = current->FileOffset;
154 KeInitializeEvent(&Event, NotificationEvent, FALSE);
155 Status = IoPageRead(Bcb->FileObject,
156 Mdl,
157 &SegOffset,
158 &Event,
159 &Iosb);
160 if (Status == STATUS_PENDING)
161 {
162 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
163 Status = Iosb.Status;
164 }
165 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
166 {
167 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
168 }
169 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
170 {
171 while (current != NULL)
172 {
173 previous = current;
174 current = current->NextInChain;
175 CcRosReleaseCacheSegment(Bcb, previous, FALSE, FALSE, FALSE);
176 }
177 return(Status);
178 }
179 current_size = 0;
180 while (current != NULL && !current->Valid && current_size < MAX_RW_LENGTH)
181 {
182 previous = current;
183 current = current->NextInChain;
184 TempLength = min(Bcb->CacheSegmentSize, Length);
185 memcpy(Buffer, previous->BaseAddress, TempLength);
186 #if defined(__GNUC__)
187 Buffer += TempLength;
188 #else
189 {
190 char* pTemp = Buffer;
191 pTemp += TempLength;
192 Buffer = pTemp;
193 }
194 #endif
195 Length = Length - TempLength;
196 CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
197 current_size += Bcb->CacheSegmentSize;
198 }
199 }
200 }
201 return(STATUS_SUCCESS);
202 }
203
204 NTSTATUS
205 ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
206 {
207 ULONG Size;
208 PMDL Mdl;
209 NTSTATUS Status;
210 LARGE_INTEGER SegOffset;
211 IO_STATUS_BLOCK IoStatus;
212 KEVENT Event;
213
214 SegOffset.QuadPart = CacheSeg->FileOffset;
215 Size = (ULONG)(CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset);
216 if (Size > CacheSeg->Bcb->CacheSegmentSize)
217 {
218 Size = CacheSeg->Bcb->CacheSegmentSize;
219 }
220 Mdl = alloca(MmSizeOfMdl(CacheSeg->BaseAddress, Size));
221 MmInitializeMdl(Mdl, CacheSeg->BaseAddress, Size);
222 MmBuildMdlForNonPagedPool(Mdl);
223 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
224 KeInitializeEvent(&Event, NotificationEvent, FALSE);
225 Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, & Event, &IoStatus);
226 if (Status == STATUS_PENDING)
227 {
228 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
229 Status = IoStatus.Status;
230 }
231
232 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
233 {
234 DPRINT1("IoPageRead failed, Status %x\n", Status);
235 return Status;
236 }
237 if (CacheSeg->Bcb->CacheSegmentSize > Size)
238 {
239 memset ((char*)CacheSeg->BaseAddress + Size, 0,
240 CacheSeg->Bcb->CacheSegmentSize - Size);
241 }
242 return STATUS_SUCCESS;
243 }
244
245 NTSTATUS
246 WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
247 {
248 ULONG Size;
249 PMDL Mdl;
250 NTSTATUS Status;
251 IO_STATUS_BLOCK IoStatus;
252 LARGE_INTEGER SegOffset;
253 KEVENT Event;
254
255 CacheSeg->Dirty = FALSE;
256 SegOffset.QuadPart = CacheSeg->FileOffset;
257 Size = (ULONG)(CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset);
258 if (Size > CacheSeg->Bcb->CacheSegmentSize)
259 {
260 Size = CacheSeg->Bcb->CacheSegmentSize;
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 = IoPageWrite(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 STDCALL
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 STDCALL
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 %x, FileOffset %x, "
322 "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
323 FileObject, (ULONG)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 ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
396 ReadLength += TempLength;
397 Length -= TempLength;
398 ReadOffset += TempLength;
399 #if defined(__GNUC__)
400 Buffer += TempLength;
401 #else
402 {
403 char* pTemp = Buffer;
404 pTemp += TempLength;
405 Buffer = pTemp;
406 }
407 #endif
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 STDCALL
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 %x, FileOffset %x, "
436 "Length %d, Wait %d, Buffer %x)\n",
437 FileObject, (ULONG)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 #if defined(__GNUC__)
495 Buffer += TempLength;
496 #else
497 {
498 char* pTemp = Buffer;
499 pTemp += TempLength;
500 Buffer = pTemp;
501 }
502 #endif
503 }
504
505 while (Length > 0)
506 {
507 TempLength = min (Bcb->CacheSegmentSize, Length);
508 Status = CcRosRequestCacheSegment(Bcb, WriteOffset,
509 &BaseAddress, &Valid, &CacheSeg);
510 if (!NT_SUCCESS(Status))
511 {
512 return(FALSE);
513 }
514 if (!Valid && TempLength < Bcb->CacheSegmentSize)
515 {
516 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
517 {
518 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
519 return FALSE;
520 }
521 }
522 memcpy (BaseAddress, Buffer, TempLength);
523 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
524 Length -= TempLength;
525 WriteOffset += TempLength;
526 #if defined(__GNUC__)
527 Buffer += TempLength;
528 #else
529 {
530 char* pTemp = Buffer;
531 pTemp += TempLength;
532 Buffer = pTemp;
533 }
534 #endif
535 }
536 return(TRUE);
537 }
538
539 /*
540 * @unimplemented
541 */
542 VOID
543 STDCALL
544 CcDeferWrite (
545 IN PFILE_OBJECT FileObject,
546 IN PCC_POST_DEFERRED_WRITE PostRoutine,
547 IN PVOID Context1,
548 IN PVOID Context2,
549 IN ULONG BytesToWrite,
550 IN BOOLEAN Retrying
551 )
552 {
553 UNIMPLEMENTED;
554 }
555
556 /*
557 * @unimplemented
558 */
559 VOID
560 STDCALL
561 CcFastCopyRead (
562 IN PFILE_OBJECT FileObject,
563 IN ULONG FileOffset,
564 IN ULONG Length,
565 IN ULONG PageCount,
566 OUT PVOID Buffer,
567 OUT PIO_STATUS_BLOCK IoStatus
568 )
569 {
570 UNIMPLEMENTED;
571 }
572 /*
573 * @unimplemented
574 */
575 VOID
576 STDCALL
577 CcFastCopyWrite(
578 IN PFILE_OBJECT FileObject,
579 IN ULONG FileOffset,
580 IN ULONG Length,
581 IN PVOID Buffer)
582 {
583 UNIMPLEMENTED;
584 }
585
586 /*
587 * @unimplemented
588 */
589 NTSTATUS
590 STDCALL
591 CcWaitForCurrentLazyWriterActivity (
592 VOID
593 )
594 {
595 UNIMPLEMENTED;
596 return STATUS_NOT_IMPLEMENTED;
597 }
598
599 /*
600 * @implemented
601 */
602 BOOLEAN STDCALL
603 CcZeroData (IN PFILE_OBJECT FileObject,
604 IN PLARGE_INTEGER StartOffset,
605 IN PLARGE_INTEGER EndOffset,
606 IN BOOLEAN Wait)
607 {
608 NTSTATUS Status;
609 LARGE_INTEGER WriteOffset;
610 ULONG Length;
611 ULONG CurrentLength;
612 PMDL Mdl;
613 ULONG i;
614 IO_STATUS_BLOCK Iosb;
615 KEVENT Event;
616
617 DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
618 "Wait %d)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
619 Wait);
620
621 Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
622 WriteOffset.QuadPart = StartOffset->QuadPart;
623
624 if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
625 {
626 /* File is not cached */
627
628 Mdl = alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
629
630 while (Length > 0)
631 {
632 if (Length + WriteOffset.u.LowPart % PAGE_SIZE > MAX_ZERO_LENGTH)
633 {
634 CurrentLength = MAX_ZERO_LENGTH - WriteOffset.u.LowPart % PAGE_SIZE;
635 }
636 else
637 {
638 CurrentLength = Length;
639 }
640 MmInitializeMdl(Mdl, (PVOID)WriteOffset.u.LowPart, CurrentLength);
641 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
642 for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
643 {
644 ((PPFN_TYPE)(Mdl + 1))[i] = CcZeroPage;
645 }
646 KeInitializeEvent(&Event, NotificationEvent, FALSE);
647 Status = IoPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
648 if (Status == STATUS_PENDING)
649 {
650 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
651 Status = Iosb.Status;
652 }
653 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
654 if (!NT_SUCCESS(Status))
655 {
656 return(FALSE);
657 }
658 WriteOffset.QuadPart += CurrentLength;
659 Length -= CurrentLength;
660 }
661 }
662 else
663 {
664 /* File is cached */
665 KIRQL oldirql;
666 PBCB Bcb;
667 PLIST_ENTRY current_entry;
668 PCACHE_SEGMENT CacheSeg, current, previous;
669 ULONG TempLength;
670
671 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
672 if (Wait)
673 {
674 /* testing, if the requested datas are available */
675 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
676 current_entry = Bcb->BcbSegmentListHead.Flink;
677 while (current_entry != &Bcb->BcbSegmentListHead)
678 {
679 CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
680 BcbSegmentListEntry);
681 if (!CacheSeg->Valid)
682 {
683 if ((WriteOffset.u.LowPart >= CacheSeg->FileOffset &&
684 WriteOffset.u.LowPart < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
685 || (WriteOffset.u.LowPart + Length > CacheSeg->FileOffset &&
686 WriteOffset.u.LowPart + Length <=
687 CacheSeg->FileOffset + Bcb->CacheSegmentSize))
688 {
689 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
690 /* datas not available */
691 return(FALSE);
692 }
693 }
694 current_entry = current_entry->Flink;
695 }
696 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
697 }
698 while (Length > 0)
699 {
700 ULONG Offset;
701 Offset = WriteOffset.u.LowPart % Bcb->CacheSegmentSize;
702 if (Length + Offset > MAX_ZERO_LENGTH)
703 {
704 CurrentLength = MAX_ZERO_LENGTH - Offset;
705 }
706 else
707 {
708 CurrentLength = Length;
709 }
710 Status = CcRosGetCacheSegmentChain (Bcb, WriteOffset.u.LowPart - Offset,
711 Offset + CurrentLength, &CacheSeg);
712 if (!NT_SUCCESS(Status))
713 {
714 return FALSE;
715 }
716 current = CacheSeg;
717
718 while (current != NULL)
719 {
720 Offset = WriteOffset.u.LowPart % Bcb->CacheSegmentSize;
721 if (Offset != 0 ||
722 Offset + CurrentLength < Bcb->CacheSegmentSize)
723 {
724 if (!current->Valid)
725 {
726 /* read the segment */
727 Status = ReadCacheSegment(current);
728 if (!NT_SUCCESS(Status))
729 {
730 DPRINT1("ReadCacheSegment failed, status %x\n",
731 Status);
732 }
733 }
734 TempLength = min (CurrentLength, Bcb->CacheSegmentSize - Offset);
735 }
736 else
737 {
738 TempLength = Bcb->CacheSegmentSize;
739 }
740 memset ((PUCHAR)current->BaseAddress + Offset, 0, TempLength);
741
742 WriteOffset.QuadPart += TempLength;
743 CurrentLength -= TempLength;
744 Length -= TempLength;
745
746 current = current->NextInChain;
747 }
748
749 current = CacheSeg;
750 while (current != NULL)
751 {
752 previous = current;
753 current = current->NextInChain;
754 CcRosReleaseCacheSegment(Bcb, previous, TRUE, TRUE, FALSE);
755 }
756 }
757 }
758 return(TRUE);
759 }