update for HEAD-2003050101
[reactos.git] / 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 <ddk/ntddk.h>
15 #include <ddk/ntifs.h>
16 #include <internal/mm.h>
17 #include <internal/cc.h>
18 #include <internal/pool.h>
19 #include <internal/io.h>
20 #include <ntos/minmax.h>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 /* GLOBALS *******************************************************************/
26
27 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
28
29 static PHYSICAL_ADDRESS CcZeroPage = (PHYSICAL_ADDRESS)0LL;
30
31 /* FUNCTIONS *****************************************************************/
32
33 VOID 
34 CcInitCacheZeroPage(VOID)
35 {
36    NTSTATUS Status;
37
38    Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &CcZeroPage);
39    if (!NT_SUCCESS(Status))
40    {
41        DbgPrint("Can't allocate CcZeroPage.\n");
42        KeBugCheck(0);
43    }
44    Status = MiZeroPage(CcZeroPage);
45    if (!NT_SUCCESS(Status))
46    {
47        DbgPrint("Can't zero out CcZeroPage.\n");
48        KeBugCheck(0);
49    }
50 }
51
52 NTSTATUS
53 ReadCacheSegmentChain(PBCB Bcb, ULONG ReadOffset, ULONG Length,
54                       PVOID Buffer)
55 {
56   PCACHE_SEGMENT head;
57   PCACHE_SEGMENT current;
58   PCACHE_SEGMENT previous;
59   IO_STATUS_BLOCK Iosb;
60   LARGE_INTEGER SegOffset;
61   NTSTATUS Status;
62   ULONG TempLength;
63   KEVENT Event;
64
65   Status = CcRosGetCacheSegmentChain(Bcb, ReadOffset, Length, &head);
66   if (!NT_SUCCESS(Status))
67     {
68       return(Status);
69     }
70   current = head;
71   while (current != NULL)
72     {
73       /*
74        * If the current segment is valid then copy it into the
75        * user buffer.
76        */
77       if (current->Valid)
78         {
79           TempLength = min(Bcb->CacheSegmentSize, Length);
80           memcpy(Buffer, current->BaseAddress, TempLength);
81           Buffer += TempLength;
82           Length = Length - TempLength; 
83           previous = current;
84           current = current->NextInChain;
85           CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
86         }
87       /*
88        * Otherwise read in as much as we can.
89        */
90       else
91         {
92           PCACHE_SEGMENT current2;
93           ULONG current_size;
94           PMDL Mdl;
95           ULONG i;
96           ULONG offset;
97
98           /*
99            * Count the maximum number of bytes we could read starting
100            * from the current segment.
101            */
102           current2 = current;
103           current_size = 0;
104           while (current2 != NULL && !current2->Valid)
105             {
106               current2 = current2->NextInChain;
107               current_size += Bcb->CacheSegmentSize;
108             }
109           
110           /*
111            * Create an MDL which contains all their pages.
112            */
113           Mdl = MmCreateMdl(NULL, NULL, current_size);
114           Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
115           current2 = current;
116           offset = 0;
117           while (current2 != NULL && !current2->Valid)
118             {
119               for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++)
120                 {
121                   PVOID address;
122                   PHYSICAL_ADDRESS page;
123                   address = current2->BaseAddress + (i * PAGE_SIZE);
124                   page = MmGetPhysicalAddressForProcess(NULL, address);
125                   ((PULONG)(Mdl + 1))[offset] = page.u.LowPart;
126                   offset++;
127                 }
128               current2 = current2->NextInChain;
129             }
130
131           /*
132            * Read in the information.
133            */
134           SegOffset.QuadPart = current->FileOffset;
135           KeInitializeEvent(&Event, NotificationEvent, FALSE);
136           Status = IoPageRead(Bcb->FileObject,
137                               Mdl,
138                               &SegOffset,
139                               &Event,
140                               &Iosb);
141           if (Status == STATUS_PENDING)
142           {
143              KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
144              Status = Iosb.Status;
145           }
146           if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
147             {
148               while (current != NULL)
149                 {
150                   previous = current;
151                   current = current->NextInChain;
152                   CcRosReleaseCacheSegment(Bcb, previous, FALSE, FALSE, FALSE);
153                 }
154               return(Status);
155             }
156           while (current != NULL && !current->Valid)
157             {
158               previous = current;
159               current = current->NextInChain;
160               TempLength = min(Bcb->CacheSegmentSize, Length);
161               memcpy(Buffer, previous->BaseAddress, TempLength);
162               Buffer += TempLength;
163               Length = Length - TempLength; 
164               CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
165             }
166         }
167     }
168   return(STATUS_SUCCESS);
169 }
170
171 NTSTATUS 
172 ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
173 {
174   ULONG Size;
175   PMDL Mdl;
176   NTSTATUS Status;
177   LARGE_INTEGER SegOffset;
178   IO_STATUS_BLOCK IoStatus;
179   KEVENT Event;
180
181   SegOffset.QuadPart = CacheSeg->FileOffset;
182   Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
183   if (Size > CacheSeg->Bcb->CacheSegmentSize)
184     {
185       Size = CacheSeg->Bcb->CacheSegmentSize;
186     }
187   Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
188   MmBuildMdlForNonPagedPool(Mdl);
189   KeInitializeEvent(&Event, NotificationEvent, FALSE);
190   Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, & Event, &IoStatus); 
191   if (Status == STATUS_PENDING)
192   {
193      KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
194      Status = IoStatus.Status;
195   }
196
197   if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
198     {
199       CcRosReleaseCacheSegment(CacheSeg->Bcb, CacheSeg, FALSE, FALSE, FALSE);
200       DPRINT1("IoPageRead failed, Status %x\n", Status);
201       return Status;
202     }
203   if (CacheSeg->Bcb->CacheSegmentSize > Size)
204     {
205       memset (CacheSeg->BaseAddress + Size, 0, 
206               CacheSeg->Bcb->CacheSegmentSize - Size);
207     }
208   return STATUS_SUCCESS;
209 }
210
211 NTSTATUS 
212 WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
213 {
214   ULONG Size;
215   PMDL Mdl;
216   NTSTATUS Status;
217   IO_STATUS_BLOCK IoStatus;
218   LARGE_INTEGER SegOffset;
219   KEVENT Event;
220
221   CacheSeg->Dirty = FALSE;
222   SegOffset.QuadPart = CacheSeg->FileOffset;
223   Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
224   if (Size > CacheSeg->Bcb->CacheSegmentSize)
225     {
226       Size = CacheSeg->Bcb->CacheSegmentSize;
227     }
228   Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
229   MmBuildMdlForNonPagedPool(Mdl);
230   KeInitializeEvent(&Event, NotificationEvent, FALSE);
231   Status = IoPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &Event, &IoStatus);
232   if (Status == STATUS_PENDING)
233   {
234      KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
235      Status = IoStatus.Status;
236   }
237   if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
238     {
239       DPRINT1("IoPageWrite failed, Status %x\n", Status);
240       CacheSeg->Dirty = TRUE;
241       return(Status);
242     }
243   return(STATUS_SUCCESS);
244 }
245
246 BOOLEAN STDCALL
247 CcCopyRead (IN PFILE_OBJECT FileObject,
248             IN PLARGE_INTEGER FileOffset,
249             IN ULONG Length,
250             IN BOOLEAN Wait,
251             OUT PVOID Buffer,
252             OUT PIO_STATUS_BLOCK IoStatus)
253 {
254   ULONG ReadOffset;
255   ULONG TempLength;
256   NTSTATUS Status = STATUS_SUCCESS;
257   PVOID BaseAddress;
258   PCACHE_SEGMENT CacheSeg;
259   BOOLEAN Valid;
260   ULONG ReadLength = 0;
261   PBCB Bcb;
262   KIRQL oldirql;
263   PLIST_ENTRY current_entry;
264   PCACHE_SEGMENT current;
265   
266   DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
267          "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
268          FileObject, (ULONG)FileOffset->QuadPart, Length, Wait,
269          Buffer, IoStatus);
270
271   Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
272   ReadOffset = FileOffset->QuadPart;
273   
274   DPRINT("AllocationSize %d, FileSize %d\n",
275          (ULONG)Bcb->AllocationSize.QuadPart,
276          (ULONG)Bcb->FileSize.QuadPart);
277
278   /*
279    * Check for the nowait case that all the cache segments that would
280    * cover this read are in memory.
281    */
282   if (!Wait)
283     {
284       KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
285       current_entry = Bcb->BcbSegmentListHead.Flink;
286       while (current_entry != &Bcb->BcbSegmentListHead)
287         {
288           current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 
289                                       BcbSegmentListEntry);
290           if (!current->Valid && current->FileOffset < ReadOffset + Length
291               && current->FileOffset + Bcb->CacheSegmentSize > ReadOffset)
292             {
293               KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
294               IoStatus->Status = STATUS_UNSUCCESSFUL;
295               IoStatus->Information = 0;
296               return FALSE;
297             }
298           current_entry = current_entry->Flink;
299         }
300       KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
301     }
302
303   TempLength = ReadOffset % Bcb->CacheSegmentSize;
304   if (TempLength != 0)
305     {
306       TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
307       Status = CcRosRequestCacheSegment(Bcb,
308                                         ROUND_DOWN(ReadOffset, 
309                                                    Bcb->CacheSegmentSize),
310                                         &BaseAddress, &Valid, &CacheSeg);
311       if (!NT_SUCCESS(Status))
312         {
313           IoStatus->Information = 0;
314           IoStatus->Status = Status;
315           DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
316           return FALSE;
317         }
318       if (!Valid)
319         {
320           Status = ReadCacheSegment(CacheSeg);
321           if (!NT_SUCCESS(Status))
322             {
323               IoStatus->Information = 0;
324               IoStatus->Status = Status;
325               return FALSE;
326             }
327         }
328       memcpy (Buffer, BaseAddress + ReadOffset % Bcb->CacheSegmentSize, 
329               TempLength);
330       CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
331       ReadLength += TempLength;
332       Length -= TempLength;
333       ReadOffset += TempLength;
334       Buffer += TempLength;
335     }  
336   while (Length > 0)
337     {
338       TempLength = min(max(Bcb->CacheSegmentSize, 65536), Length);
339       ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
340       ReadLength += TempLength;
341       Length -= TempLength;
342       ReadOffset += TempLength;
343       Buffer += TempLength;
344     }
345   IoStatus->Status = STATUS_SUCCESS;
346   IoStatus->Information = ReadLength;
347   DPRINT("CcCopyRead O.K.\n");
348   return TRUE;
349 }
350
351 BOOLEAN STDCALL
352 CcCopyWrite (IN PFILE_OBJECT FileObject,
353              IN PLARGE_INTEGER FileOffset,
354              IN ULONG Length,
355              IN BOOLEAN Wait,
356              IN PVOID Buffer)
357 {
358    NTSTATUS Status;
359    ULONG WriteOffset;
360    KIRQL oldirql;
361    PBCB Bcb;
362    PLIST_ENTRY current_entry;
363    PCACHE_SEGMENT CacheSeg;
364    ULONG TempLength;
365    PVOID BaseAddress;
366    BOOLEAN Valid;
367
368    DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
369           "Length %d, Wait %d, Buffer %x)\n",
370           FileObject, (ULONG)FileOffset->QuadPart, Length, Wait, Buffer);
371
372    Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
373    WriteOffset = (ULONG)FileOffset->QuadPart;
374
375    if (!Wait)
376      {
377        /* testing, if the requested datas are available */
378        KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
379        current_entry = Bcb->BcbSegmentListHead.Flink;
380        while (current_entry != &Bcb->BcbSegmentListHead)
381          {
382            CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 
383                                         BcbSegmentListEntry);
384            if (!CacheSeg->Valid)
385              {
386                if ((WriteOffset >= CacheSeg->FileOffset && 
387                     WriteOffset < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
388                    || (WriteOffset + Length > CacheSeg->FileOffset && 
389                        WriteOffset + Length <= CacheSeg->FileOffset + 
390                        Bcb->CacheSegmentSize))
391                  {
392                    KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
393                    /* datas not available */
394                    return(FALSE);
395                  }
396              }
397            current_entry = current_entry->Flink;
398          }
399        KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
400      }
401
402    TempLength = WriteOffset % Bcb->CacheSegmentSize;
403    if (TempLength != 0)
404      {
405        ULONG ROffset;
406        ROffset = ROUND_DOWN(WriteOffset, Bcb->CacheSegmentSize);
407        TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
408        Status = CcRosRequestCacheSegment(Bcb, ROffset,
409                                          &BaseAddress, &Valid, &CacheSeg);
410        if (!NT_SUCCESS(Status))
411          {
412            return(FALSE);
413          }
414        if (!Valid)
415          {
416            if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
417              {
418                return(FALSE);
419              }
420          }
421        memcpy (BaseAddress + WriteOffset % Bcb->CacheSegmentSize, 
422                Buffer, TempLength);
423        CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
424        
425        Length -= TempLength;
426        WriteOffset += TempLength;
427        Buffer += TempLength;
428      }
429    
430    while (Length > 0)
431      {
432        TempLength = min (Bcb->CacheSegmentSize, Length);
433        Status = CcRosRequestCacheSegment(Bcb, WriteOffset,
434                                          &BaseAddress, &Valid, &CacheSeg);
435        if (!NT_SUCCESS(Status))
436          {
437            return(FALSE);
438          }
439        if (!Valid && TempLength < Bcb->CacheSegmentSize)
440          {
441            if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
442              {
443                return FALSE;
444              }
445          }
446        memcpy (BaseAddress, Buffer, TempLength);
447        CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
448        Length -= TempLength;
449        WriteOffset += TempLength;
450        Buffer += TempLength;
451      }
452    return(TRUE);
453 }
454
455 BOOLEAN STDCALL
456 CcZeroData (IN PFILE_OBJECT     FileObject,
457             IN PLARGE_INTEGER   StartOffset,
458             IN PLARGE_INTEGER   EndOffset,
459             IN BOOLEAN          Wait)
460 {
461   NTSTATUS Status;
462   LARGE_INTEGER WriteOffset;
463   ULONG Length;
464   PMDL Mdl;
465   ULONG i;
466   IO_STATUS_BLOCK Iosb;
467   KEVENT Event;
468   
469   DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
470          "Wait %d\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart, 
471          Wait);
472   
473   Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
474
475   if (FileObject->SectionObjectPointers->SharedCacheMap == NULL)
476     {
477       /* File is not cached */
478       WriteOffset.QuadPart = StartOffset->QuadPart;
479       
480       while (Length > 0)
481         {
482           if (Length + WriteOffset.u.LowPart % PAGE_SIZE > 262144)
483             {
484               Mdl = MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart, 
485                                 262144 - WriteOffset.u.LowPart % PAGE_SIZE);
486               WriteOffset.QuadPart += 
487                 (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
488               Length -= (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
489             }
490           else
491             {
492               Mdl = 
493                 MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart, 
494                             Length - WriteOffset.u.LowPart % PAGE_SIZE);
495               WriteOffset.QuadPart += 
496                 (Length - WriteOffset.u.LowPart % PAGE_SIZE);
497               Length = 0;
498             }
499           if (Mdl == NULL)
500             {
501               return(FALSE);
502             }
503           Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
504           for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
505             {
506               ((PULONG)(Mdl + 1))[i] = CcZeroPage.u.LowPart;
507             }
508           KeInitializeEvent(&Event, NotificationEvent, FALSE);
509           Status = IoPageWrite(FileObject, Mdl, StartOffset, &Event, &Iosb);
510           if (Status == STATUS_PENDING)
511           {
512              KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
513              Status = Iosb.Status;
514           }
515           if (!NT_SUCCESS(Status))
516             {
517               return(FALSE);
518             }
519         }
520     }
521   else
522     {
523       /* File is cached */
524       KIRQL oldirql;
525       PBCB Bcb;
526       PLIST_ENTRY current_entry;
527       PCACHE_SEGMENT CacheSeg, current, previous;
528       ULONG TempLength;
529       ULONG Start;
530       ULONG count;
531       ULONG size;
532       PHYSICAL_ADDRESS page;
533
534       Start = StartOffset->u.LowPart;
535       Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
536       if (Wait)
537         {
538           /* testing, if the requested datas are available */
539           KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
540           current_entry = Bcb->BcbSegmentListHead.Flink;
541           while (current_entry != &Bcb->BcbSegmentListHead)
542             {
543               CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 
544                                            BcbSegmentListEntry);
545               if (!CacheSeg->Valid)
546                 {
547                   if ((Start >= CacheSeg->FileOffset && 
548                        Start < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
549                       || (Start + Length > CacheSeg->FileOffset && 
550                           Start + Length <= 
551                           CacheSeg->FileOffset + Bcb->CacheSegmentSize))
552                     {
553                       KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
554                       /* datas not available */
555                       return(FALSE);
556                     }
557                 }
558               current_entry = current_entry->Flink;
559             }
560           KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
561         }
562       
563       while (Length > 0)
564         {
565           ULONG RStart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
566           WriteOffset.QuadPart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
567           if (Start % Bcb->CacheSegmentSize + Length > 262144)
568             {
569               Mdl = MmCreateMdl(NULL, NULL, 262144);
570               if (Mdl == NULL)
571                 {
572                   return FALSE;
573                 }
574               Status = CcRosGetCacheSegmentChain (Bcb, RStart,
575                                                   262144, &CacheSeg);
576               if (!NT_SUCCESS(Status))
577                 {
578                   ExFreePool(Mdl);
579                   return(FALSE);
580                 }
581             }
582           else
583             {
584               ULONG RLength;
585               RLength = Start % Bcb->CacheSegmentSize + Length;
586               RLength = ROUND_UP(RLength, Bcb->CacheSegmentSize);
587               Mdl = MmCreateMdl(NULL, (PVOID)RStart, RLength);
588               if (Mdl == NULL)
589                 {
590                   return(FALSE);
591                 }
592               Status = CcRosGetCacheSegmentChain (Bcb, RStart, RLength,
593                                                   &CacheSeg);
594               if (!NT_SUCCESS(Status))
595                 {
596                   ExFreePool(Mdl);
597                   return(FALSE);
598                 }
599             }
600           Mdl->MdlFlags |= (MDL_PAGES_LOCKED|MDL_IO_PAGE_READ);
601           current = CacheSeg;
602           count = 0;
603           while (current != NULL)
604             {
605               if ((Start % Bcb->CacheSegmentSize) != 0 || 
606                   Start % Bcb->CacheSegmentSize + Length < 
607                   Bcb->CacheSegmentSize)
608                 {
609                   if (!current->Valid)
610                     {
611                       /* Segment lesen */
612                       Status = ReadCacheSegment(current);
613                       if (!NT_SUCCESS(Status))
614                         {
615                           DPRINT1("ReadCacheSegment failed, status %x\n", 
616                                   Status);
617                         }
618                     }
619                   TempLength = min (Length, Bcb->CacheSegmentSize - 
620                                     Start % Bcb->CacheSegmentSize);
621                   memset (current->BaseAddress + Start % Bcb->CacheSegmentSize,
622                           0, TempLength);
623                 }
624               else
625                 {
626                   TempLength = Bcb->CacheSegmentSize;
627                   memset (current->BaseAddress, 0, Bcb->CacheSegmentSize);
628                 }
629               Start += TempLength;
630               Length -= TempLength;
631               
632               size = ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG));
633               for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE) && 
634                      count < size; i++)
635                 {
636                   PVOID Address;
637                   Address = current->BaseAddress + (i * PAGE_SIZE);
638                   page = 
639                     MmGetPhysicalAddressForProcess(NULL, Address);
640                   ((PULONG)(Mdl + 1))[count++] = page.u.LowPart;
641                 }
642               current = current->NextInChain;
643             }
644           
645           /* Write the Segment */
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           if (!NT_SUCCESS(Status))
654             {
655               DPRINT1("IoPageWrite failed, status %x\n", Status);
656             }
657           current = CacheSeg;
658           while (current != NULL)
659             {
660               previous = current;
661               current = current->NextInChain;
662               CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
663             }
664         }
665     }
666   return(TRUE);
667 }
668