2002-10-01 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / ntoskrnl / cc / copy.c
1 /* $Id: copy.c,v 1.13 2002/10/01 19:27:20 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 <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))
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 = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb;
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 = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb;
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 /*
476 * FIXME: NT uses the shared cache map field for cached/non cached detection
477 */
478 if (FileObject->SectionObjectPointers->SharedCacheMap == NULL)
479 {
480 /* File is not cached */
481 WriteOffset.QuadPart = StartOffset->QuadPart;
482
483 while (Length > 0)
484 {
485 if (Length + WriteOffset.u.LowPart % PAGE_SIZE > 262144)
486 {
487 Mdl = MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart,
488 262144 - WriteOffset.u.LowPart % PAGE_SIZE);
489 WriteOffset.QuadPart +=
490 (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
491 Length -= (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
492 }
493 else
494 {
495 Mdl =
496 MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart,
497 Length - WriteOffset.u.LowPart % PAGE_SIZE);
498 WriteOffset.QuadPart +=
499 (Length - WriteOffset.u.LowPart % PAGE_SIZE);
500 Length = 0;
501 }
502 if (Mdl == NULL)
503 {
504 return(FALSE);
505 }
506 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
507 for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
508 {
509 ((PULONG)(Mdl + 1))[i] = CcZeroPage.u.LowPart;
510 }
511 KeInitializeEvent(&Event, NotificationEvent, FALSE);
512 Status = IoPageWrite(FileObject, Mdl, StartOffset, &Event, &Iosb);
513 if (Status == STATUS_PENDING)
514 {
515 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
516 Status = Iosb.Status;
517 }
518 if (!NT_SUCCESS(Status))
519 {
520 return(FALSE);
521 }
522 }
523 }
524 else
525 {
526 /* File is cached */
527 KIRQL oldirql;
528 PBCB Bcb;
529 PLIST_ENTRY current_entry;
530 PCACHE_SEGMENT CacheSeg, current, previous;
531 ULONG TempLength;
532 ULONG Start;
533 ULONG count;
534 ULONG size;
535 PHYSICAL_ADDRESS page;
536
537 Start = StartOffset->u.LowPart;
538 Bcb = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb;
539 if (Wait)
540 {
541 /* testing, if the requested datas are available */
542 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
543 current_entry = Bcb->BcbSegmentListHead.Flink;
544 while (current_entry != &Bcb->BcbSegmentListHead)
545 {
546 CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
547 BcbSegmentListEntry);
548 if (!CacheSeg->Valid)
549 {
550 if ((Start >= CacheSeg->FileOffset &&
551 Start < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
552 || (Start + Length > CacheSeg->FileOffset &&
553 Start + Length <=
554 CacheSeg->FileOffset + Bcb->CacheSegmentSize))
555 {
556 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
557 /* datas not available */
558 return(FALSE);
559 }
560 }
561 current_entry = current_entry->Flink;
562 }
563 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
564 }
565
566 while (Length > 0)
567 {
568 ULONG RStart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
569 WriteOffset.QuadPart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
570 if (Start % Bcb->CacheSegmentSize + Length > 262144)
571 {
572 Mdl = MmCreateMdl(NULL, NULL, 262144);
573 if (Mdl == NULL)
574 {
575 return FALSE;
576 }
577 Status = CcRosGetCacheSegmentChain (Bcb, RStart,
578 262144, &CacheSeg);
579 if (!NT_SUCCESS(Status))
580 {
581 ExFreePool(Mdl);
582 return(FALSE);
583 }
584 }
585 else
586 {
587 ULONG RLength;
588 RLength = Start % Bcb->CacheSegmentSize + Length;
589 RLength = ROUND_UP(RLength, Bcb->CacheSegmentSize);
590 Mdl = MmCreateMdl(NULL, (PVOID)RStart, RLength);
591 if (Mdl == NULL)
592 {
593 return(FALSE);
594 }
595 Status = CcRosGetCacheSegmentChain (Bcb, RStart, RLength,
596 &CacheSeg);
597 if (!NT_SUCCESS(Status))
598 {
599 ExFreePool(Mdl);
600 return(FALSE);
601 }
602 }
603 Mdl->MdlFlags |= (MDL_PAGES_LOCKED|MDL_IO_PAGE_READ);
604 current = CacheSeg;
605 count = 0;
606 while (current != NULL)
607 {
608 if ((Start % Bcb->CacheSegmentSize) != 0 ||
609 Start % Bcb->CacheSegmentSize + Length <
610 Bcb->CacheSegmentSize)
611 {
612 if (!current->Valid)
613 {
614 /* Segment lesen */
615 Status = ReadCacheSegment(current);
616 if (!NT_SUCCESS(Status))
617 {
618 DPRINT1("ReadCacheSegment failed, status %x\n",
619 Status);
620 }
621 }
622 TempLength = min (Length, Bcb->CacheSegmentSize -
623 Start % Bcb->CacheSegmentSize);
624 memset (current->BaseAddress + Start % Bcb->CacheSegmentSize,
625 0, TempLength);
626 }
627 else
628 {
629 TempLength = Bcb->CacheSegmentSize;
630 memset (current->BaseAddress, 0, Bcb->CacheSegmentSize);
631 }
632 Start += TempLength;
633 Length -= TempLength;
634
635 size = ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG));
636 for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE) &&
637 count < size; i++)
638 {
639 PVOID Address;
640 Address = current->BaseAddress + (i * PAGE_SIZE);
641 page =
642 MmGetPhysicalAddressForProcess(NULL, Address);
643 ((PULONG)(Mdl + 1))[count++] = page.u.LowPart;
644 }
645 current = current->NextInChain;
646 }
647
648 /* Write the Segment */
649 KeInitializeEvent(&Event, NotificationEvent, FALSE);
650 Status = IoPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
651 if (Status == STATUS_PENDING)
652 {
653 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
654 Status = Iosb.Status;
655 }
656 if (!NT_SUCCESS(Status))
657 {
658 DPRINT1("IoPageWrite failed, status %x\n", Status);
659 }
660 current = CacheSeg;
661 while (current != NULL)
662 {
663 previous = current;
664 current = current->NextInChain;
665 CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
666 }
667 }
668 }
669 return(TRUE);
670 }
671