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
12 /* INCLUDES ******************************************************************/
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>
23 #include <internal/debug.h>
25 /* GLOBALS *******************************************************************/
27 #define ROUND_DOWN(N, S) ((N) - ((N) % (S)))
29 static PHYSICAL_ADDRESS CcZeroPage = (PHYSICAL_ADDRESS)0LL;
31 /* FUNCTIONS *****************************************************************/
34 CcInitCacheZeroPage(VOID)
38 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &CcZeroPage);
39 if (!NT_SUCCESS(Status))
41 DbgPrint("Can't allocate CcZeroPage.\n");
44 Status = MiZeroPage(CcZeroPage);
45 if (!NT_SUCCESS(Status))
47 DbgPrint("Can't zero out CcZeroPage.\n");
53 ReadCacheSegmentChain(PBCB Bcb, ULONG ReadOffset, ULONG Length,
57 PCACHE_SEGMENT current;
58 PCACHE_SEGMENT previous;
60 LARGE_INTEGER SegOffset;
65 Status = CcRosGetCacheSegmentChain(Bcb, ReadOffset, Length, &head);
66 if (!NT_SUCCESS(Status))
71 while (current != NULL)
74 * If the current segment is valid then copy it into the
79 TempLength = min(Bcb->CacheSegmentSize, Length);
80 memcpy(Buffer, current->BaseAddress, TempLength);
82 Length = Length - TempLength;
84 current = current->NextInChain;
85 CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
88 * Otherwise read in as much as we can.
92 PCACHE_SEGMENT current2;
99 * Count the maximum number of bytes we could read starting
100 * from the current segment.
104 while (current2 != NULL && !current2->Valid)
106 current2 = current2->NextInChain;
107 current_size += Bcb->CacheSegmentSize;
111 * Create an MDL which contains all their pages.
113 Mdl = MmCreateMdl(NULL, NULL, current_size);
114 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
117 while (current2 != NULL && !current2->Valid)
119 for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++)
122 PHYSICAL_ADDRESS page;
123 address = current2->BaseAddress + (i * PAGE_SIZE);
124 page = MmGetPhysicalAddressForProcess(NULL, address);
125 ((PULONG)(Mdl + 1))[offset] = page.u.LowPart;
128 current2 = current2->NextInChain;
132 * Read in the information.
134 SegOffset.QuadPart = current->FileOffset;
135 KeInitializeEvent(&Event, NotificationEvent, FALSE);
136 Status = IoPageRead(Bcb->FileObject,
141 if (Status == STATUS_PENDING)
143 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
144 Status = Iosb.Status;
146 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
148 while (current != NULL)
151 current = current->NextInChain;
152 CcRosReleaseCacheSegment(Bcb, previous, FALSE, FALSE, FALSE);
156 while (current != NULL && !current->Valid)
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);
168 return(STATUS_SUCCESS);
172 ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
177 LARGE_INTEGER SegOffset;
178 IO_STATUS_BLOCK IoStatus;
181 SegOffset.QuadPart = CacheSeg->FileOffset;
182 Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
183 if (Size > CacheSeg->Bcb->CacheSegmentSize)
185 Size = CacheSeg->Bcb->CacheSegmentSize;
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)
193 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
194 Status = IoStatus.Status;
197 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
199 DPRINT1("IoPageRead failed, Status %x\n", Status);
202 if (CacheSeg->Bcb->CacheSegmentSize > Size)
204 memset (CacheSeg->BaseAddress + Size, 0,
205 CacheSeg->Bcb->CacheSegmentSize - Size);
207 return STATUS_SUCCESS;
211 WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
216 IO_STATUS_BLOCK IoStatus;
217 LARGE_INTEGER SegOffset;
220 CacheSeg->Dirty = FALSE;
221 SegOffset.QuadPart = CacheSeg->FileOffset;
222 Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
223 if (Size > CacheSeg->Bcb->CacheSegmentSize)
225 Size = CacheSeg->Bcb->CacheSegmentSize;
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)
233 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
234 Status = IoStatus.Status;
236 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
238 DPRINT1("IoPageWrite failed, Status %x\n", Status);
239 CacheSeg->Dirty = TRUE;
242 return(STATUS_SUCCESS);
249 CcCopyRead (IN PFILE_OBJECT FileObject,
250 IN PLARGE_INTEGER FileOffset,
254 OUT PIO_STATUS_BLOCK IoStatus)
258 NTSTATUS Status = STATUS_SUCCESS;
260 PCACHE_SEGMENT CacheSeg;
262 ULONG ReadLength = 0;
265 PLIST_ENTRY current_entry;
266 PCACHE_SEGMENT current;
268 DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
269 "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
270 FileObject, (ULONG)FileOffset->QuadPart, Length, Wait,
273 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
274 ReadOffset = FileOffset->QuadPart;
276 DPRINT("AllocationSize %d, FileSize %d\n",
277 (ULONG)Bcb->AllocationSize.QuadPart,
278 (ULONG)Bcb->FileSize.QuadPart);
281 * Check for the nowait case that all the cache segments that would
282 * cover this read are in memory.
286 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
287 current_entry = Bcb->BcbSegmentListHead.Flink;
288 while (current_entry != &Bcb->BcbSegmentListHead)
290 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
291 BcbSegmentListEntry);
292 if (!current->Valid && current->FileOffset < ReadOffset + Length
293 && current->FileOffset + Bcb->CacheSegmentSize > ReadOffset)
295 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
296 IoStatus->Status = STATUS_UNSUCCESSFUL;
297 IoStatus->Information = 0;
300 current_entry = current_entry->Flink;
302 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
305 TempLength = ReadOffset % Bcb->CacheSegmentSize;
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))
315 IoStatus->Information = 0;
316 IoStatus->Status = Status;
317 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
322 Status = ReadCacheSegment(CacheSeg);
323 if (!NT_SUCCESS(Status))
325 IoStatus->Information = 0;
326 IoStatus->Status = Status;
327 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
331 memcpy (Buffer, BaseAddress + ReadOffset % Bcb->CacheSegmentSize,
333 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
334 ReadLength += TempLength;
335 Length -= TempLength;
336 ReadOffset += TempLength;
337 Buffer += TempLength;
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;
348 IoStatus->Status = STATUS_SUCCESS;
349 IoStatus->Information = ReadLength;
350 DPRINT("CcCopyRead O.K.\n");
358 CcCopyWrite (IN PFILE_OBJECT FileObject,
359 IN PLARGE_INTEGER FileOffset,
368 PLIST_ENTRY current_entry;
369 PCACHE_SEGMENT CacheSeg;
374 DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
375 "Length %d, Wait %d, Buffer %x)\n",
376 FileObject, (ULONG)FileOffset->QuadPart, Length, Wait, Buffer);
378 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
379 WriteOffset = (ULONG)FileOffset->QuadPart;
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)
388 CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
389 BcbSegmentListEntry);
390 if (!CacheSeg->Valid)
392 if ((WriteOffset >= CacheSeg->FileOffset &&
393 WriteOffset < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
394 || (WriteOffset + Length > CacheSeg->FileOffset &&
395 WriteOffset + Length <= CacheSeg->FileOffset +
396 Bcb->CacheSegmentSize))
398 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
399 /* datas not available */
403 current_entry = current_entry->Flink;
405 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
408 TempLength = WriteOffset % Bcb->CacheSegmentSize;
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))
422 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
427 memcpy (BaseAddress + WriteOffset % Bcb->CacheSegmentSize,
429 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
431 Length -= TempLength;
432 WriteOffset += TempLength;
433 Buffer += TempLength;
438 TempLength = min (Bcb->CacheSegmentSize, Length);
439 Status = CcRosRequestCacheSegment(Bcb, WriteOffset,
440 &BaseAddress, &Valid, &CacheSeg);
441 if (!NT_SUCCESS(Status))
445 if (!Valid && TempLength < Bcb->CacheSegmentSize)
447 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
449 CcRosReleaseCacheSegment(Bcb, CacheSeg, FALSE, FALSE, FALSE);
453 memcpy (BaseAddress, Buffer, TempLength);
454 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
455 Length -= TempLength;
456 WriteOffset += TempLength;
457 Buffer += TempLength;
466 CcZeroData (IN PFILE_OBJECT FileObject,
467 IN PLARGE_INTEGER StartOffset,
468 IN PLARGE_INTEGER EndOffset,
472 LARGE_INTEGER WriteOffset;
476 IO_STATUS_BLOCK Iosb;
479 DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
480 "Wait %d\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
483 Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
485 if (FileObject->SectionObjectPointer->SharedCacheMap == NULL)
487 /* File is not cached */
488 WriteOffset.QuadPart = StartOffset->QuadPart;
492 if (Length + WriteOffset.u.LowPart % PAGE_SIZE > 262144)
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);
503 MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart,
504 Length - WriteOffset.u.LowPart % PAGE_SIZE);
505 WriteOffset.QuadPart +=
506 (Length - WriteOffset.u.LowPart % PAGE_SIZE);
513 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
514 for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
516 ((PULONG)(Mdl + 1))[i] = CcZeroPage.u.LowPart;
518 KeInitializeEvent(&Event, NotificationEvent, FALSE);
519 Status = IoPageWrite(FileObject, Mdl, StartOffset, &Event, &Iosb);
520 if (Status == STATUS_PENDING)
522 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
523 Status = Iosb.Status;
525 if (!NT_SUCCESS(Status))
536 PLIST_ENTRY current_entry;
537 PCACHE_SEGMENT CacheSeg, current, previous;
542 PHYSICAL_ADDRESS page;
544 Start = StartOffset->u.LowPart;
545 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
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)
553 CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
554 BcbSegmentListEntry);
555 if (!CacheSeg->Valid)
557 if ((Start >= CacheSeg->FileOffset &&
558 Start < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
559 || (Start + Length > CacheSeg->FileOffset &&
561 CacheSeg->FileOffset + Bcb->CacheSegmentSize))
563 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
564 /* datas not available */
568 current_entry = current_entry->Flink;
570 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
575 ULONG RStart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
576 WriteOffset.QuadPart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
577 if (Start % Bcb->CacheSegmentSize + Length > 262144)
579 Mdl = MmCreateMdl(NULL, NULL, 262144);
584 Status = CcRosGetCacheSegmentChain (Bcb, RStart,
586 if (!NT_SUCCESS(Status))
595 RLength = Start % Bcb->CacheSegmentSize + Length;
596 RLength = ROUND_UP(RLength, Bcb->CacheSegmentSize);
597 Mdl = MmCreateMdl(NULL, (PVOID)RStart, RLength);
602 Status = CcRosGetCacheSegmentChain (Bcb, RStart, RLength,
604 if (!NT_SUCCESS(Status))
610 Mdl->MdlFlags |= (MDL_PAGES_LOCKED|MDL_IO_PAGE_READ);
613 while (current != NULL)
615 if ((Start % Bcb->CacheSegmentSize) != 0 ||
616 Start % Bcb->CacheSegmentSize + Length <
617 Bcb->CacheSegmentSize)
622 Status = ReadCacheSegment(current);
623 if (!NT_SUCCESS(Status))
625 DPRINT1("ReadCacheSegment failed, status %x\n",
629 TempLength = min (Length, Bcb->CacheSegmentSize -
630 Start % Bcb->CacheSegmentSize);
631 memset (current->BaseAddress + Start % Bcb->CacheSegmentSize,
636 TempLength = Bcb->CacheSegmentSize;
637 memset (current->BaseAddress, 0, Bcb->CacheSegmentSize);
640 Length -= TempLength;
642 size = ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG));
643 for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE) &&
647 Address = current->BaseAddress + (i * PAGE_SIZE);
649 MmGetPhysicalAddressForProcess(NULL, Address);
650 ((PULONG)(Mdl + 1))[count++] = page.u.LowPart;
652 current = current->NextInChain;
655 /* Write the Segment */
656 KeInitializeEvent(&Event, NotificationEvent, FALSE);
657 Status = IoPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
658 if (Status == STATUS_PENDING)
660 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
661 Status = Iosb.Status;
663 if (!NT_SUCCESS(Status))
665 DPRINT1("IoPageWrite failed, status %x\n", Status);
668 while (current != NULL)
671 current = current->NextInChain;
672 CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);