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