0835f25b603e98fd206dcaa7e16477ccb153140f
[reactos.git] / reactos / ntoskrnl / cc / copy.c
1 /* $Id: copy.c,v 1.14 2003/02/13 22:24:18 hbirr 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 = 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