update for HEAD-2003091401
[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       DPRINT1("IoPageRead failed, Status %x\n", Status);
200       return Status;
201     }
202   if (CacheSeg->Bcb->CacheSegmentSize > Size)
203     {
204       memset (CacheSeg->BaseAddress + Size, 0, 
205               CacheSeg->Bcb->CacheSegmentSize - Size);
206     }
207   return STATUS_SUCCESS;
208 }
209
210 NTSTATUS 
211 WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
212 {
213   ULONG Size;
214   PMDL Mdl;
215   NTSTATUS Status;
216   IO_STATUS_BLOCK IoStatus;
217   LARGE_INTEGER SegOffset;
218   KEVENT Event;
219
220   CacheSeg->Dirty = FALSE;
221   SegOffset.QuadPart = CacheSeg->FileOffset;
222   Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
223   if (Size > CacheSeg->Bcb->CacheSegmentSize)
224     {
225       Size = CacheSeg->Bcb->CacheSegmentSize;
226     }
227   Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
228   MmBuildMdlForNonPagedPool(Mdl);
229   KeInitializeEvent(&Event, NotificationEvent, FALSE);
230   Status = IoPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &Event, &IoStatus);
231   if (Status == STATUS_PENDING)
232   {
233      KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
234      Status = IoStatus.Status;
235   }
236   if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
237     {
238       DPRINT1("IoPageWrite failed, Status %x\n", Status);
239       CacheSeg->Dirty = TRUE;
240       return(Status);
241     }
242   return(STATUS_SUCCESS);
243 }
244
245 /*
246  * @implemented
247  */
248 BOOLEAN STDCALL
249 CcCopyRead (IN PFILE_OBJECT FileObject,
250             IN PLARGE_INTEGER FileOffset,
251             IN ULONG Length,
252             IN BOOLEAN Wait,
253             OUT PVOID Buffer,
254             OUT PIO_STATUS_BLOCK IoStatus)
255 {
256   ULONG ReadOffset;
257   ULONG TempLength;
258   NTSTATUS Status = STATUS_SUCCESS;
259   PVOID BaseAddress;
260   PCACHE_SEGMENT CacheSeg;
261   BOOLEAN Valid;
262   ULONG ReadLength = 0;
263   PBCB Bcb;
264   KIRQL oldirql;
265   PLIST_ENTRY current_entry;
266   PCACHE_SEGMENT current;
267   
268   DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
269          "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
270          FileObject, (ULONG)FileOffset->QuadPart, Length, Wait,
271          Buffer, IoStatus);
272
273   Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
274   ReadOffset = FileOffset->QuadPart;
275   
276   DPRINT("AllocationSize %d, FileSize %d\n",
277          (ULONG)Bcb->AllocationSize.QuadPart,
278          (ULONG)Bcb->FileSize.QuadPart);
279
280   /*
281    * Check for the nowait case that all the cache segments that would
282    * cover this read are in memory.
283    */
284   if (!Wait)
285     {
286       KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
287       current_entry = Bcb->BcbSegmentListHead.Flink;
288       while (current_entry != &Bcb->BcbSegmentListHead)
289         {
290           current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 
291                                       BcbSegmentListEntry);
292           if (!current->Valid && current->FileOffset < ReadOffset + Length
293               && current->FileOffset + Bcb->CacheSegmentSize > ReadOffset)
294             {
295               KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
296               IoStatus->Status = STATUS_UNSUCCESSFUL;
297               IoStatus->Information = 0;
298               return FALSE;
299             }
300           current_entry = current_entry->Flink;
301         }
302       KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
303     }
304
305   TempLength = ReadOffset % Bcb->CacheSegmentSize;
306   if (TempLength != 0)
307     {
308       TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
309       Status = CcRosRequestCacheSegment(Bcb,
310                                         ROUND_DOWN(ReadOffset, 
311                                                    Bcb->CacheSegmentSize),
312                                         &BaseAddress, &Valid, &CacheSeg);
313       if (!NT_SUCCESS(Status))
314         {
315           IoStatus->Information = 0;
316           IoStatus->Status = Status;
317           DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
318           return FALSE;
319         }
320       if (!Valid)
321         {
322           Status = ReadCacheSegment(CacheSeg);
323           if (!NT_SUCCESS(Status))
324             {
325               IoStatus->Information = 0;
326               IoStatus->Status = Status;
327               CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
328               return FALSE;
329             }
330         }
331       memcpy (Buffer, BaseAddress + ReadOffset % Bcb->CacheSegmentSize, 
332               TempLength);
333       CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
334       ReadLength += TempLength;
335       Length -= TempLength;
336       ReadOffset += TempLength;
337       Buffer += TempLength;
338     }  
339   while (Length > 0)
340     {
341       TempLength = min(max(Bcb->CacheSegmentSize, 65536), Length);
342       ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
343       ReadLength += TempLength;
344       Length -= TempLength;
345       ReadOffset += TempLength;
346       Buffer += TempLength;
347     }
348   IoStatus->Status = STATUS_SUCCESS;
349   IoStatus->Information = ReadLength;
350   DPRINT("CcCopyRead O.K.\n");
351   return TRUE;
352 }
353
354 /*
355  * @implemented
356  */
357 BOOLEAN STDCALL
358 CcCopyWrite (IN PFILE_OBJECT FileObject,
359              IN PLARGE_INTEGER FileOffset,
360              IN ULONG Length,
361              IN BOOLEAN Wait,
362              IN PVOID Buffer)
363 {
364    NTSTATUS Status;
365    ULONG WriteOffset;
366    KIRQL oldirql;
367    PBCB Bcb;
368    PLIST_ENTRY current_entry;
369    PCACHE_SEGMENT CacheSeg;
370    ULONG TempLength;
371    PVOID BaseAddress;
372    BOOLEAN Valid;
373
374    DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
375           "Length %d, Wait %d, Buffer %x)\n",
376           FileObject, (ULONG)FileOffset->QuadPart, Length, Wait, Buffer);
377
378    Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
379    WriteOffset = (ULONG)FileOffset->QuadPart;
380
381    if (!Wait)
382      {
383        /* testing, if the requested datas are available */
384        KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
385        current_entry = Bcb->BcbSegmentListHead.Flink;
386        while (current_entry != &Bcb->BcbSegmentListHead)
387          {
388            CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 
389                                         BcbSegmentListEntry);
390            if (!CacheSeg->Valid)
391              {
392                if ((WriteOffset >= CacheSeg->FileOffset && 
393                     WriteOffset < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
394                    || (WriteOffset + Length > CacheSeg->FileOffset && 
395                        WriteOffset + Length <= CacheSeg->FileOffset + 
396                        Bcb->CacheSegmentSize))
397                  {
398                    KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
399                    /* datas not available */
400                    return(FALSE);
401                  }
402              }
403            current_entry = current_entry->Flink;
404          }
405        KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
406      }
407
408    TempLength = WriteOffset % Bcb->CacheSegmentSize;
409    if (TempLength != 0)
410      {
411        ULONG ROffset;
412        ROffset = ROUND_DOWN(WriteOffset, Bcb->CacheSegmentSize);
413        TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
414        Status = CcRosRequestCacheSegment(Bcb, ROffset,
415                                          &BaseAddress, &Valid, &CacheSeg);
416        if (!NT_SUCCESS(Status))
417          {
418            return(FALSE);
419          }
420        if (!Valid)
421          {
422            if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
423              {
424                return(FALSE);
425              }
426          }
427        memcpy (BaseAddress + WriteOffset % Bcb->CacheSegmentSize, 
428                Buffer, TempLength);
429        CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
430        
431        Length -= TempLength;
432        WriteOffset += TempLength;
433        Buffer += TempLength;
434      }
435    
436    while (Length > 0)
437      {
438        TempLength = min (Bcb->CacheSegmentSize, Length);
439        Status = CcRosRequestCacheSegment(Bcb, WriteOffset,
440                                          &BaseAddress, &Valid, &CacheSeg);
441        if (!NT_SUCCESS(Status))
442          {
443            return(FALSE);
444          }
445        if (!Valid && TempLength < Bcb->CacheSegmentSize)
446          {
447            if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
448              {
449                CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
450                return FALSE;
451              }
452          }
453        memcpy (BaseAddress, Buffer, TempLength);
454        CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
455        Length -= TempLength;
456        WriteOffset += TempLength;
457        Buffer += TempLength;
458      }
459    return(TRUE);
460 }
461
462 /*
463  * @implemented
464  */
465 BOOLEAN STDCALL
466 CcZeroData (IN PFILE_OBJECT     FileObject,
467             IN PLARGE_INTEGER   StartOffset,
468             IN PLARGE_INTEGER   EndOffset,
469             IN BOOLEAN          Wait)
470 {
471   NTSTATUS Status;
472   LARGE_INTEGER WriteOffset;
473   ULONG Length;
474   PMDL Mdl;
475   ULONG i;
476   IO_STATUS_BLOCK Iosb;
477   KEVENT Event;
478   
479   DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
480          "Wait %d\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart, 
481          Wait);
482   
483   Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
484
485   if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
486     {
487       /* File is not cached */
488       WriteOffset.QuadPart = StartOffset->QuadPart;
489       
490       while (Length > 0)
491         {
492           if (Length + WriteOffset.u.LowPart % PAGE_SIZE > 262144)
493             {
494               Mdl = MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart, 
495                                 262144 - WriteOffset.u.LowPart % PAGE_SIZE);
496               WriteOffset.QuadPart += 
497                 (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
498               Length -= (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
499             }
500           else
501             {
502               Mdl = 
503                 MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart, 
504                             Length - WriteOffset.u.LowPart % PAGE_SIZE);
505               WriteOffset.QuadPart += 
506                 (Length - WriteOffset.u.LowPart % PAGE_SIZE);
507               Length = 0;
508             }
509           if (Mdl == NULL)
510             {
511               return(FALSE);
512             }
513           Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
514           for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
515             {
516               ((PULONG)(Mdl + 1))[i] = CcZeroPage.u.LowPart;
517             }
518           KeInitializeEvent(&Event, NotificationEvent, FALSE);
519           Status = IoPageWrite(FileObject, Mdl, StartOffset, &Event, &Iosb);
520           if (Status == STATUS_PENDING)
521           {
522              KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
523              Status = Iosb.Status;
524           }
525           if (!NT_SUCCESS(Status))
526             {
527               return(FALSE);
528             }
529         }
530     }
531   else
532     {
533       /* File is cached */
534       KIRQL oldirql;
535       PBCB Bcb;
536       PLIST_ENTRY current_entry;
537       PCACHE_SEGMENT CacheSeg, current, previous;
538       ULONG TempLength;
539       ULONG Start;
540       ULONG count;
541       ULONG size;
542       PHYSICAL_ADDRESS page;
543
544       Start = StartOffset->u.LowPart;
545       Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
546       if (Wait)
547         {
548           /* testing, if the requested datas are available */
549           KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
550           current_entry = Bcb->BcbSegmentListHead.Flink;
551           while (current_entry != &Bcb->BcbSegmentListHead)
552             {
553               CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, 
554                                            BcbSegmentListEntry);
555               if (!CacheSeg->Valid)
556                 {
557                   if ((Start >= CacheSeg->FileOffset && 
558                        Start < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
559                       || (Start + Length > CacheSeg->FileOffset && 
560                           Start + Length <= 
561                           CacheSeg->FileOffset + Bcb->CacheSegmentSize))
562                     {
563                       KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
564                       /* datas not available */
565                       return(FALSE);
566                     }
567                 }
568               current_entry = current_entry->Flink;
569             }
570           KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
571         }
572       
573       while (Length > 0)
574         {
575           ULONG RStart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
576           WriteOffset.QuadPart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
577           if (Start % Bcb->CacheSegmentSize + Length > 262144)
578             {
579               Mdl = MmCreateMdl(NULL, NULL, 262144);
580               if (Mdl == NULL)
581                 {
582                   return FALSE;
583                 }
584               Status = CcRosGetCacheSegmentChain (Bcb, RStart,
585                                                   262144, &CacheSeg);
586               if (!NT_SUCCESS(Status))
587                 {
588                   ExFreePool(Mdl);
589                   return(FALSE);
590                 }
591             }
592           else
593             {
594               ULONG RLength;
595               RLength = Start % Bcb->CacheSegmentSize + Length;
596               RLength = ROUND_UP(RLength, Bcb->CacheSegmentSize);
597               Mdl = MmCreateMdl(NULL, (PVOID)RStart, RLength);
598               if (Mdl == NULL)
599                 {
600                   return(FALSE);
601                 }
602               Status = CcRosGetCacheSegmentChain (Bcb, RStart, RLength,
603                                                   &CacheSeg);
604               if (!NT_SUCCESS(Status))
605                 {
606                   ExFreePool(Mdl);
607                   return(FALSE);
608                 }
609             }
610           Mdl->MdlFlags |= (MDL_PAGES_LOCKED|MDL_IO_PAGE_READ);
611           current = CacheSeg;
612           count = 0;
613           while (current != NULL)
614             {
615               if ((Start % Bcb->CacheSegmentSize) != 0 || 
616                   Start % Bcb->CacheSegmentSize + Length < 
617                   Bcb->CacheSegmentSize)
618                 {
619                   if (!current->Valid)
620                     {
621                       /* Segment lesen */
622                       Status = ReadCacheSegment(current);
623                       if (!NT_SUCCESS(Status))
624                         {
625                           DPRINT1("ReadCacheSegment failed, status %x\n", 
626                                   Status);
627                         }
628                     }
629                   TempLength = min (Length, Bcb->CacheSegmentSize - 
630                                     Start % Bcb->CacheSegmentSize);
631                   memset (current->BaseAddress + Start % Bcb->CacheSegmentSize,
632                           0, TempLength);
633                 }
634               else
635                 {
636                   TempLength = Bcb->CacheSegmentSize;
637                   memset (current->BaseAddress, 0, Bcb->CacheSegmentSize);
638                 }
639               Start += TempLength;
640               Length -= TempLength;
641               
642               size = ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG));
643               for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE) && 
644                      count < size; i++)
645                 {
646                   PVOID Address;
647                   Address = current->BaseAddress + (i * PAGE_SIZE);
648                   page = 
649                     MmGetPhysicalAddressForProcess(NULL, Address);
650                   ((PULONG)(Mdl + 1))[count++] = page.u.LowPart;
651                 }
652               current = current->NextInChain;
653             }
654           
655           /* Write the Segment */
656           KeInitializeEvent(&Event, NotificationEvent, FALSE);
657           Status = IoPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
658           if (Status == STATUS_PENDING)
659           {
660              KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
661              Status = Iosb.Status;
662           }
663           if (!NT_SUCCESS(Status))
664             {
665               DPRINT1("IoPageWrite failed, status %x\n", Status);
666             }
667           current = CacheSeg;
668           while (current != NULL)
669             {
670               previous = current;
671               current = current->NextInChain;
672               CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
673             }
674         }
675     }
676   return(TRUE);
677 }
678