2004-08-15 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / cc / copy.c
1 /* $Id: copy.c,v 1.30 2004/08/15 16:38:59 chorns Exp $
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 (64 * 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
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)
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 MdlPages = (PPFN_TYPE)(Mdl + 1);
135 while (current2 != NULL && !current2->Valid)
136 {
137 PVOID address = current2->BaseAddress;
138 for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++, address += PAGE_SIZE)
139 {
140 *MdlPages++ = MmGetPfnForProcess(NULL, address);
141 }
142 current2 = current2->NextInChain;
143 }
144
145 /*
146 * Read in the information.
147 */
148 SegOffset.QuadPart = current->FileOffset;
149 KeInitializeEvent(&Event, NotificationEvent, FALSE);
150 Status = IoPageRead(Bcb->FileObject,
151 Mdl,
152 &SegOffset,
153 &Event,
154 &Iosb);
155 if (Status == STATUS_PENDING)
156 {
157 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
158 Status = Iosb.Status;
159 }
160 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
161 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
162 {
163 while (current != NULL)
164 {
165 previous = current;
166 current = current->NextInChain;
167 CcRosReleaseCacheSegment(Bcb, previous, FALSE, FALSE, FALSE);
168 }
169 return(Status);
170 }
171 while (current != NULL && !current->Valid)
172 {
173 previous = current;
174 current = current->NextInChain;
175 TempLength = min(Bcb->CacheSegmentSize, Length);
176 memcpy(Buffer, previous->BaseAddress, TempLength);
177 #if defined(__GNUC__)
178 Buffer += TempLength;
179 #else
180 {
181 char* pTemp = Buffer;
182 pTemp += TempLength;
183 Buffer = pTemp;
184 }
185 #endif
186 Length = Length - TempLength;
187 CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
188 }
189 }
190 }
191 return(STATUS_SUCCESS);
192 }
193
194 NTSTATUS
195 ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
196 {
197 ULONG Size;
198 PMDL Mdl;
199 NTSTATUS Status;
200 LARGE_INTEGER SegOffset;
201 IO_STATUS_BLOCK IoStatus;
202 KEVENT Event;
203
204 SegOffset.QuadPart = CacheSeg->FileOffset;
205 Size = (ULONG)(CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset);
206 if (Size > CacheSeg->Bcb->CacheSegmentSize)
207 {
208 Size = CacheSeg->Bcb->CacheSegmentSize;
209 }
210 Mdl = alloca(MmSizeOfMdl(CacheSeg->BaseAddress, Size));
211 MmInitializeMdl(Mdl, CacheSeg->BaseAddress, Size);
212 MmBuildMdlForNonPagedPool(Mdl);
213 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
214 KeInitializeEvent(&Event, NotificationEvent, FALSE);
215 Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, & Event, &IoStatus);
216 if (Status == STATUS_PENDING)
217 {
218 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
219 Status = IoStatus.Status;
220 }
221
222 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
223 {
224 DPRINT1("IoPageRead failed, Status %x\n", Status);
225 return Status;
226 }
227 if (CacheSeg->Bcb->CacheSegmentSize > Size)
228 {
229 memset ((char*)CacheSeg->BaseAddress + Size, 0,
230 CacheSeg->Bcb->CacheSegmentSize - Size);
231 }
232 return STATUS_SUCCESS;
233 }
234
235 NTSTATUS
236 WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
237 {
238 ULONG Size;
239 PMDL Mdl;
240 NTSTATUS Status;
241 IO_STATUS_BLOCK IoStatus;
242 LARGE_INTEGER SegOffset;
243 KEVENT Event;
244
245 CacheSeg->Dirty = FALSE;
246 SegOffset.QuadPart = CacheSeg->FileOffset;
247 Size = (ULONG)(CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset);
248 if (Size > CacheSeg->Bcb->CacheSegmentSize)
249 {
250 Size = CacheSeg->Bcb->CacheSegmentSize;
251 }
252 Mdl = alloca(MmSizeOfMdl(CacheSeg->BaseAddress, Size));
253 MmInitializeMdl(Mdl, CacheSeg->BaseAddress, Size);
254 MmBuildMdlForNonPagedPool(Mdl);
255 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
256 KeInitializeEvent(&Event, NotificationEvent, FALSE);
257 Status = IoPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &Event, &IoStatus);
258 if (Status == STATUS_PENDING)
259 {
260 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
261 Status = IoStatus.Status;
262 }
263 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
264 {
265 DPRINT1("IoPageWrite failed, Status %x\n", Status);
266 CacheSeg->Dirty = TRUE;
267 return(Status);
268 }
269 return(STATUS_SUCCESS);
270 }
271
272
273 /*
274 * @unimplemented
275 */
276 BOOLEAN STDCALL
277 CcCanIWrite (
278 IN PFILE_OBJECT FileObject,
279 IN ULONG BytesToWrite,
280 IN BOOLEAN Wait,
281 IN BOOLEAN Retrying)
282 {
283 UNIMPLEMENTED;
284 return FALSE;
285 }
286
287
288 /*
289 * @implemented
290 */
291 BOOLEAN STDCALL
292 CcCopyRead (IN PFILE_OBJECT FileObject,
293 IN PLARGE_INTEGER FileOffset,
294 IN ULONG Length,
295 IN BOOLEAN Wait,
296 OUT PVOID Buffer,
297 OUT PIO_STATUS_BLOCK IoStatus)
298 {
299 ULONG ReadOffset;
300 ULONG TempLength;
301 NTSTATUS Status = STATUS_SUCCESS;
302 PVOID BaseAddress;
303 PCACHE_SEGMENT CacheSeg;
304 BOOLEAN Valid;
305 ULONG ReadLength = 0;
306 PBCB Bcb;
307 KIRQL oldirql;
308 PLIST_ENTRY current_entry;
309 PCACHE_SEGMENT current;
310
311 DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
312 "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
313 FileObject, (ULONG)FileOffset->QuadPart, Length, Wait,
314 Buffer, IoStatus);
315
316 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
317 ReadOffset = (ULONG)FileOffset->QuadPart;
318
319 DPRINT("AllocationSize %d, FileSize %d\n",
320 (ULONG)Bcb->AllocationSize.QuadPart,
321 (ULONG)Bcb->FileSize.QuadPart);
322
323 /*
324 * Check for the nowait case that all the cache segments that would
325 * cover this read are in memory.
326 */
327 if (!Wait)
328 {
329 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
330 current_entry = Bcb->BcbSegmentListHead.Flink;
331 while (current_entry != &Bcb->BcbSegmentListHead)
332 {
333 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
334 BcbSegmentListEntry);
335 if (!current->Valid && current->FileOffset < ReadOffset + Length
336 && current->FileOffset + Bcb->CacheSegmentSize > ReadOffset)
337 {
338 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
339 IoStatus->Status = STATUS_UNSUCCESSFUL;
340 IoStatus->Information = 0;
341 return FALSE;
342 }
343 current_entry = current_entry->Flink;
344 }
345 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
346 }
347
348 TempLength = ReadOffset % Bcb->CacheSegmentSize;
349 if (TempLength != 0)
350 {
351 TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
352 Status = CcRosRequestCacheSegment(Bcb,
353 ROUND_DOWN(ReadOffset,
354 Bcb->CacheSegmentSize),
355 &BaseAddress, &Valid, &CacheSeg);
356 if (!NT_SUCCESS(Status))
357 {
358 IoStatus->Information = 0;
359 IoStatus->Status = Status;
360 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
361 return FALSE;
362 }
363 if (!Valid)
364 {
365 Status = ReadCacheSegment(CacheSeg);
366 if (!NT_SUCCESS(Status))
367 {
368 IoStatus->Information = 0;
369 IoStatus->Status = Status;
370 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
371 return FALSE;
372 }
373 }
374 memcpy (Buffer, (char*)BaseAddress + ReadOffset % Bcb->CacheSegmentSize,
375 TempLength);
376 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
377 ReadLength += TempLength;
378 Length -= TempLength;
379 ReadOffset += TempLength;
380 Buffer = (PVOID)((char*)Buffer + TempLength);
381 }
382 while (Length > 0)
383 {
384 TempLength = min(max(Bcb->CacheSegmentSize, MAX_RW_LENGTH), Length);
385 ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
386 ReadLength += TempLength;
387 Length -= TempLength;
388 ReadOffset += TempLength;
389 #if defined(__GNUC__)
390 Buffer += TempLength;
391 #else
392 {
393 char* pTemp = Buffer;
394 pTemp += TempLength;
395 Buffer = pTemp;
396 }
397 #endif
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 %x, FileOffset %x, "
426 "Length %d, Wait %d, Buffer %x)\n",
427 FileObject, (ULONG)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 #if defined(__GNUC__)
485 Buffer += TempLength;
486 #else
487 {
488 char* pTemp = Buffer;
489 pTemp += TempLength;
490 Buffer = pTemp;
491 }
492 #endif
493 }
494
495 while (Length > 0)
496 {
497 TempLength = min (Bcb->CacheSegmentSize, Length);
498 Status = CcRosRequestCacheSegment(Bcb, WriteOffset,
499 &BaseAddress, &Valid, &CacheSeg);
500 if (!NT_SUCCESS(Status))
501 {
502 return(FALSE);
503 }
504 if (!Valid && TempLength < Bcb->CacheSegmentSize)
505 {
506 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
507 {
508 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
509 return FALSE;
510 }
511 }
512 memcpy (BaseAddress, Buffer, TempLength);
513 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
514 Length -= TempLength;
515 WriteOffset += TempLength;
516 #if defined(__GNUC__)
517 Buffer += TempLength;
518 #else
519 {
520 char* pTemp = Buffer;
521 pTemp += TempLength;
522 Buffer = pTemp;
523 }
524 #endif
525 }
526 return(TRUE);
527 }
528
529 /*
530 * @unimplemented
531 */
532 VOID
533 STDCALL
534 CcDeferWrite (
535 IN PFILE_OBJECT FileObject,
536 IN PCC_POST_DEFERRED_WRITE PostRoutine,
537 IN PVOID Context1,
538 IN PVOID Context2,
539 IN ULONG BytesToWrite,
540 IN BOOLEAN Retrying
541 )
542 {
543 UNIMPLEMENTED;
544 }
545
546 /*
547 * @unimplemented
548 */
549 BOOLEAN
550 STDCALL
551 CcFastCopyRead (
552 IN PFILE_OBJECT FileObject,
553 IN ULONG FileOffset,
554 IN ULONG Length,
555 IN ULONG PageCount,
556 OUT PVOID Buffer,
557 OUT PIO_STATUS_BLOCK IoStatus
558 )
559 {
560 UNIMPLEMENTED;
561 return FALSE;
562 }
563 /*
564 * @unimplemented
565 */
566 BOOLEAN
567 STDCALL
568 CcFastCopyWrite (
569 IN PFILE_OBJECT FileObject,
570 IN PLARGE_INTEGER FileOffset,
571 IN ULONG Length,
572 IN PVOID Buffer
573 )
574 {
575 UNIMPLEMENTED;
576 return FALSE;
577 }
578
579 /*
580 * @unimplemented
581 */
582 NTSTATUS
583 STDCALL
584 CcWaitForCurrentLazyWriterActivity (
585 VOID
586 )
587 {
588 UNIMPLEMENTED;
589 return STATUS_NOT_IMPLEMENTED;
590 }
591
592 /*
593 * @implemented
594 */
595 BOOLEAN STDCALL
596 CcZeroData (IN PFILE_OBJECT FileObject,
597 IN PLARGE_INTEGER StartOffset,
598 IN PLARGE_INTEGER EndOffset,
599 IN BOOLEAN Wait)
600 {
601 NTSTATUS Status;
602 LARGE_INTEGER WriteOffset;
603 ULONG Length;
604 ULONG CurrentLength;
605 PMDL Mdl;
606 ULONG i;
607 IO_STATUS_BLOCK Iosb;
608 KEVENT Event;
609
610 DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
611 "Wait %d)\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
612 Wait);
613
614 Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
615 WriteOffset.QuadPart = StartOffset->QuadPart;
616
617 if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
618 {
619 /* File is not cached */
620
621 Mdl = alloca(MmSizeOfMdl(NULL, MAX_ZERO_LENGTH));
622
623 while (Length > 0)
624 {
625 if (Length + WriteOffset.u.LowPart % PAGE_SIZE > MAX_ZERO_LENGTH)
626 {
627 CurrentLength = MAX_ZERO_LENGTH - WriteOffset.u.LowPart % PAGE_SIZE;
628 }
629 else
630 {
631 CurrentLength = Length;
632 }
633 MmInitializeMdl(Mdl, (PVOID)WriteOffset.u.LowPart, CurrentLength);
634 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
635 for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
636 {
637 ((PPFN_TYPE)(Mdl + 1))[i] = CcZeroPage;
638 }
639 KeInitializeEvent(&Event, NotificationEvent, FALSE);
640 Status = IoPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
641 if (Status == STATUS_PENDING)
642 {
643 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
644 Status = Iosb.Status;
645 }
646 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
647 if (!NT_SUCCESS(Status))
648 {
649 return(FALSE);
650 }
651 WriteOffset.QuadPart += CurrentLength;
652 Length -= CurrentLength;
653 }
654 }
655 else
656 {
657 /* File is cached */
658 KIRQL oldirql;
659 PBCB Bcb;
660 PLIST_ENTRY current_entry;
661 PCACHE_SEGMENT CacheSeg, current, previous;
662 ULONG TempLength;
663
664 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
665 if (Wait)
666 {
667 /* testing, if the requested datas are available */
668 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
669 current_entry = Bcb->BcbSegmentListHead.Flink;
670 while (current_entry != &Bcb->BcbSegmentListHead)
671 {
672 CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
673 BcbSegmentListEntry);
674 if (!CacheSeg->Valid)
675 {
676 if ((WriteOffset.u.LowPart >= CacheSeg->FileOffset &&
677 WriteOffset.u.LowPart < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
678 || (WriteOffset.u.LowPart + Length > CacheSeg->FileOffset &&
679 WriteOffset.u.LowPart + Length <=
680 CacheSeg->FileOffset + Bcb->CacheSegmentSize))
681 {
682 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
683 /* datas not available */
684 return(FALSE);
685 }
686 }
687 current_entry = current_entry->Flink;
688 }
689 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
690 }
691 while (Length > 0)
692 {
693 ULONG Offset;
694 Offset = WriteOffset.u.LowPart % Bcb->CacheSegmentSize;
695 if (Length + Offset > MAX_ZERO_LENGTH)
696 {
697 CurrentLength = MAX_ZERO_LENGTH - Offset;
698 }
699 else
700 {
701 CurrentLength = Length;
702 }
703 Status = CcRosGetCacheSegmentChain (Bcb, WriteOffset.u.LowPart - Offset,
704 Offset + CurrentLength, &CacheSeg);
705 if (!NT_SUCCESS(Status))
706 {
707 return FALSE;
708 }
709 current = CacheSeg;
710
711 while (current != NULL)
712 {
713 Offset = WriteOffset.u.LowPart % Bcb->CacheSegmentSize;
714 if (Offset != 0 ||
715 Offset + CurrentLength < Bcb->CacheSegmentSize)
716 {
717 if (!current->Valid)
718 {
719 /* read the segment */
720 Status = ReadCacheSegment(current);
721 if (!NT_SUCCESS(Status))
722 {
723 DPRINT1("ReadCacheSegment failed, status %x\n",
724 Status);
725 }
726 }
727 TempLength = min (CurrentLength, Bcb->CacheSegmentSize - Offset);
728 }
729 else
730 {
731 TempLength = Bcb->CacheSegmentSize;
732 }
733 memset ((PUCHAR)current->BaseAddress + Offset, 0, TempLength);
734
735 WriteOffset.QuadPart += TempLength;
736 CurrentLength -= TempLength;
737 Length -= TempLength;
738
739 current = current->NextInChain;
740 }
741
742 current = CacheSeg;
743 while (current != NULL)
744 {
745 previous = current;
746 current = current->NextInChain;
747 CcRosReleaseCacheSegment(Bcb, previous, TRUE, TRUE, FALSE);
748 }
749 }
750 }
751 return(TRUE);
752 }