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)))
30 static PHYSICAL_ADDRESS CcZeroPage = (PHYSICAL_ADDRESS)0LL;
31 #endif /* LIBCAPTIVE */
33 /* FUNCTIONS *****************************************************************/
38 CcInitCacheZeroPage(VOID)
42 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &CcZeroPage);
43 if (!NT_SUCCESS(Status))
45 DbgPrint("Can't allocate CcZeroPage.\n");
48 Status = MiZeroPage(CcZeroPage);
49 if (!NT_SUCCESS(Status))
51 DbgPrint("Can't zero out CcZeroPage.\n");
57 ReadCacheSegmentChain(PBCB Bcb, ULONG ReadOffset, ULONG Length,
61 PCACHE_SEGMENT current;
62 PCACHE_SEGMENT previous;
64 LARGE_INTEGER SegOffset;
69 Status = CcRosGetCacheSegmentChain(Bcb, ReadOffset, Length, &head);
70 if (!NT_SUCCESS(Status))
75 while (current != NULL)
78 * If the current segment is valid then copy it into the
83 TempLength = min(Bcb->CacheSegmentSize, Length);
84 memcpy(Buffer, current->BaseAddress, TempLength);
86 Length = Length - TempLength;
88 current = current->NextInChain;
89 CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
92 * Otherwise read in as much as we can.
96 PCACHE_SEGMENT current2;
103 * Count the maximum number of bytes we could read starting
104 * from the current segment.
108 while (current2 != NULL && !current2->Valid)
110 current2 = current2->NextInChain;
111 current_size += Bcb->CacheSegmentSize;
115 * Create an MDL which contains all their pages.
117 Mdl = MmCreateMdl(NULL, NULL, current_size);
118 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
121 while (current2 != NULL && !current2->Valid)
123 for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE); i++)
126 PHYSICAL_ADDRESS page;
127 address = current2->BaseAddress + (i * PAGE_SIZE);
128 page = MmGetPhysicalAddressForProcess(NULL, address);
129 ((PULONG)(Mdl + 1))[offset] = page.u.LowPart;
132 current2 = current2->NextInChain;
136 * Read in the information.
138 SegOffset.QuadPart = current->FileOffset;
139 KeInitializeEvent(&Event, NotificationEvent, FALSE);
140 Status = IoPageRead(Bcb->FileObject,
145 if (Status == STATUS_PENDING)
147 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
148 Status = Iosb.Status;
150 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
152 while (current != NULL)
155 current = current->NextInChain;
156 CcRosReleaseCacheSegment(Bcb, previous, FALSE, FALSE, FALSE);
160 while (current != NULL && !current->Valid)
163 current = current->NextInChain;
164 TempLength = min(Bcb->CacheSegmentSize, Length);
165 memcpy(Buffer, previous->BaseAddress, TempLength);
166 Buffer += TempLength;
167 Length = Length - TempLength;
168 CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
172 return(STATUS_SUCCESS);
175 #endif /* LIBCAPTIVE */
178 ReadCacheSegment(PCACHE_SEGMENT CacheSeg)
183 LARGE_INTEGER SegOffset;
184 IO_STATUS_BLOCK IoStatus;
187 SegOffset.QuadPart = CacheSeg->FileOffset;
188 Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
189 if (Size > CacheSeg->Bcb->CacheSegmentSize)
191 Size = CacheSeg->Bcb->CacheSegmentSize;
193 Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
194 MmBuildMdlForNonPagedPool(Mdl);
195 KeInitializeEvent(&Event, NotificationEvent, FALSE);
196 Status = IoPageRead(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, & Event, &IoStatus);
197 if (Status == STATUS_PENDING)
199 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
200 Status = IoStatus.Status;
203 if (!NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE)
205 CcRosReleaseCacheSegment(CacheSeg->Bcb, CacheSeg, FALSE, FALSE, FALSE);
206 DPRINT1("IoPageRead failed, Status %x\n", Status);
209 if (CacheSeg->Bcb->CacheSegmentSize > Size)
211 memset (CacheSeg->BaseAddress + Size, 0,
212 CacheSeg->Bcb->CacheSegmentSize - Size);
214 return STATUS_SUCCESS;
220 WriteCacheSegment(PCACHE_SEGMENT CacheSeg)
225 IO_STATUS_BLOCK IoStatus;
226 LARGE_INTEGER SegOffset;
229 CacheSeg->Dirty = FALSE;
230 SegOffset.QuadPart = CacheSeg->FileOffset;
231 Size = CacheSeg->Bcb->AllocationSize.QuadPart - CacheSeg->FileOffset;
232 if (Size > CacheSeg->Bcb->CacheSegmentSize)
234 Size = CacheSeg->Bcb->CacheSegmentSize;
236 Mdl = MmCreateMdl(NULL, CacheSeg->BaseAddress, Size);
237 MmBuildMdlForNonPagedPool(Mdl);
238 KeInitializeEvent(&Event, NotificationEvent, FALSE);
239 Status = IoPageWrite(CacheSeg->Bcb->FileObject, Mdl, &SegOffset, &Event, &IoStatus);
240 if (Status == STATUS_PENDING)
242 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
243 Status = IoStatus.Status;
245 if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
247 DPRINT1("IoPageWrite failed, Status %x\n", Status);
248 CacheSeg->Dirty = TRUE;
251 return(STATUS_SUCCESS);
255 CcCopyRead (IN PFILE_OBJECT FileObject,
256 IN PLARGE_INTEGER FileOffset,
260 OUT PIO_STATUS_BLOCK IoStatus)
264 NTSTATUS Status = STATUS_SUCCESS;
266 PCACHE_SEGMENT CacheSeg;
268 ULONG ReadLength = 0;
271 PLIST_ENTRY current_entry;
272 PCACHE_SEGMENT current;
274 DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
275 "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
276 FileObject, (ULONG)FileOffset->QuadPart, Length, Wait,
279 Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
280 ReadOffset = FileOffset->QuadPart;
282 DPRINT("AllocationSize %d, FileSize %d\n",
283 (ULONG)Bcb->AllocationSize.QuadPart,
284 (ULONG)Bcb->FileSize.QuadPart);
287 * Check for the nowait case that all the cache segments that would
288 * cover this read are in memory.
292 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
293 current_entry = Bcb->BcbSegmentListHead.Flink;
294 while (current_entry != &Bcb->BcbSegmentListHead)
296 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
297 BcbSegmentListEntry);
298 if (!current->Valid && current->FileOffset < ReadOffset + Length
299 && current->FileOffset + Bcb->CacheSegmentSize > ReadOffset)
301 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
302 IoStatus->Status = STATUS_UNSUCCESSFUL;
303 IoStatus->Information = 0;
306 current_entry = current_entry->Flink;
308 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
311 TempLength = ReadOffset % Bcb->CacheSegmentSize;
314 TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
315 Status = CcRosRequestCacheSegment(Bcb,
316 ROUND_DOWN(ReadOffset,
317 Bcb->CacheSegmentSize),
318 &BaseAddress, &Valid, &CacheSeg);
319 if (!NT_SUCCESS(Status))
321 IoStatus->Information = 0;
322 IoStatus->Status = Status;
323 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status);
328 Status = ReadCacheSegment(CacheSeg);
329 if (!NT_SUCCESS(Status))
331 IoStatus->Information = 0;
332 IoStatus->Status = Status;
336 memcpy (Buffer, BaseAddress + ReadOffset % Bcb->CacheSegmentSize,
338 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, FALSE, FALSE);
339 ReadLength += TempLength;
340 Length -= TempLength;
341 ReadOffset += TempLength;
342 Buffer += TempLength;
346 TempLength = min(max(Bcb->CacheSegmentSize, 65536), Length);
347 ReadCacheSegmentChain(Bcb, ReadOffset, TempLength, Buffer);
348 ReadLength += TempLength;
349 Length -= TempLength;
350 ReadOffset += TempLength;
351 Buffer += TempLength;
353 IoStatus->Status = STATUS_SUCCESS;
354 IoStatus->Information = ReadLength;
355 DPRINT("CcCopyRead O.K.\n");
360 CcCopyWrite (IN PFILE_OBJECT FileObject,
361 IN PLARGE_INTEGER FileOffset,
370 PLIST_ENTRY current_entry;
371 PCACHE_SEGMENT CacheSeg;
376 DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
377 "Length %d, Wait %d, Buffer %x)\n",
378 FileObject, (ULONG)FileOffset->QuadPart, Length, Wait, Buffer);
380 Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
381 WriteOffset = (ULONG)FileOffset->QuadPart;
385 /* testing, if the requested datas are available */
386 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
387 current_entry = Bcb->BcbSegmentListHead.Flink;
388 while (current_entry != &Bcb->BcbSegmentListHead)
390 CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
391 BcbSegmentListEntry);
392 if (!CacheSeg->Valid)
394 if ((WriteOffset >= CacheSeg->FileOffset &&
395 WriteOffset < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
396 || (WriteOffset + Length > CacheSeg->FileOffset &&
397 WriteOffset + Length <= CacheSeg->FileOffset +
398 Bcb->CacheSegmentSize))
400 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
401 /* datas not available */
405 current_entry = current_entry->Flink;
407 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
410 TempLength = WriteOffset % Bcb->CacheSegmentSize;
414 ROffset = ROUND_DOWN(WriteOffset, Bcb->CacheSegmentSize);
415 TempLength = min (Length, Bcb->CacheSegmentSize - TempLength);
416 Status = CcRosRequestCacheSegment(Bcb, ROffset,
417 &BaseAddress, &Valid, &CacheSeg);
418 if (!NT_SUCCESS(Status))
424 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
429 memcpy (BaseAddress + WriteOffset % Bcb->CacheSegmentSize,
431 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
433 Length -= TempLength;
434 WriteOffset += TempLength;
435 Buffer += TempLength;
440 TempLength = min (Bcb->CacheSegmentSize, Length);
441 Status = CcRosRequestCacheSegment(Bcb, WriteOffset,
442 &BaseAddress, &Valid, &CacheSeg);
443 if (!NT_SUCCESS(Status))
447 if (!Valid && TempLength < Bcb->CacheSegmentSize)
449 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg)))
454 memcpy (BaseAddress, Buffer, TempLength);
455 CcRosReleaseCacheSegment(Bcb, CacheSeg, TRUE, TRUE, FALSE);
456 Length -= TempLength;
457 WriteOffset += TempLength;
458 Buffer += TempLength;
464 CcZeroData (IN PFILE_OBJECT FileObject,
465 IN PLARGE_INTEGER StartOffset,
466 IN PLARGE_INTEGER EndOffset,
470 LARGE_INTEGER WriteOffset;
474 IO_STATUS_BLOCK Iosb;
477 DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
478 "Wait %d\n", FileObject, StartOffset->QuadPart, EndOffset->QuadPart,
481 Length = EndOffset->u.LowPart - StartOffset->u.LowPart;
483 if (FileObject->SectionObjectPointers->SharedCacheMap == NULL)
485 /* File is not cached */
486 WriteOffset.QuadPart = StartOffset->QuadPart;
490 if (Length + WriteOffset.u.LowPart % PAGE_SIZE > 262144)
492 Mdl = MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart,
493 262144 - WriteOffset.u.LowPart % PAGE_SIZE);
494 WriteOffset.QuadPart +=
495 (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
496 Length -= (262144 - WriteOffset.u.LowPart % PAGE_SIZE);
501 MmCreateMdl(NULL, (PVOID)WriteOffset.u.LowPart,
502 Length - WriteOffset.u.LowPart % PAGE_SIZE);
503 WriteOffset.QuadPart +=
504 (Length - WriteOffset.u.LowPart % PAGE_SIZE);
511 Mdl->MdlFlags |= (MDL_PAGES_LOCKED | MDL_IO_PAGE_READ);
512 for (i = 0; i < ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG)); i++)
514 ((PULONG)(Mdl + 1))[i] = CcZeroPage.u.LowPart;
516 KeInitializeEvent(&Event, NotificationEvent, FALSE);
517 Status = IoPageWrite(FileObject, Mdl, StartOffset, &Event, &Iosb);
518 if (Status == STATUS_PENDING)
520 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
521 Status = Iosb.Status;
523 if (!NT_SUCCESS(Status))
534 PLIST_ENTRY current_entry;
535 PCACHE_SEGMENT CacheSeg, current, previous;
540 PHYSICAL_ADDRESS page;
542 Start = StartOffset->u.LowPart;
543 Bcb = FileObject->SectionObjectPointers->SharedCacheMap;
546 /* testing, if the requested datas are available */
547 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
548 current_entry = Bcb->BcbSegmentListHead.Flink;
549 while (current_entry != &Bcb->BcbSegmentListHead)
551 CacheSeg = CONTAINING_RECORD(current_entry, CACHE_SEGMENT,
552 BcbSegmentListEntry);
553 if (!CacheSeg->Valid)
555 if ((Start >= CacheSeg->FileOffset &&
556 Start < CacheSeg->FileOffset + Bcb->CacheSegmentSize)
557 || (Start + Length > CacheSeg->FileOffset &&
559 CacheSeg->FileOffset + Bcb->CacheSegmentSize))
561 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
562 /* datas not available */
566 current_entry = current_entry->Flink;
568 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
573 ULONG RStart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
574 WriteOffset.QuadPart = ROUND_DOWN(Start, Bcb->CacheSegmentSize);
575 if (Start % Bcb->CacheSegmentSize + Length > 262144)
577 Mdl = MmCreateMdl(NULL, NULL, 262144);
582 Status = CcRosGetCacheSegmentChain (Bcb, RStart,
584 if (!NT_SUCCESS(Status))
593 RLength = Start % Bcb->CacheSegmentSize + Length;
594 RLength = ROUND_UP(RLength, Bcb->CacheSegmentSize);
595 Mdl = MmCreateMdl(NULL, (PVOID)RStart, RLength);
600 Status = CcRosGetCacheSegmentChain (Bcb, RStart, RLength,
602 if (!NT_SUCCESS(Status))
608 Mdl->MdlFlags |= (MDL_PAGES_LOCKED|MDL_IO_PAGE_READ);
611 while (current != NULL)
613 if ((Start % Bcb->CacheSegmentSize) != 0 ||
614 Start % Bcb->CacheSegmentSize + Length <
615 Bcb->CacheSegmentSize)
620 Status = ReadCacheSegment(current);
621 if (!NT_SUCCESS(Status))
623 DPRINT1("ReadCacheSegment failed, status %x\n",
627 TempLength = min (Length, Bcb->CacheSegmentSize -
628 Start % Bcb->CacheSegmentSize);
629 memset (current->BaseAddress + Start % Bcb->CacheSegmentSize,
634 TempLength = Bcb->CacheSegmentSize;
635 memset (current->BaseAddress, 0, Bcb->CacheSegmentSize);
638 Length -= TempLength;
640 size = ((Mdl->Size - sizeof(MDL)) / sizeof(ULONG));
641 for (i = 0; i < (Bcb->CacheSegmentSize / PAGE_SIZE) &&
645 Address = current->BaseAddress + (i * PAGE_SIZE);
647 MmGetPhysicalAddressForProcess(NULL, Address);
648 ((PULONG)(Mdl + 1))[count++] = page.u.LowPart;
650 current = current->NextInChain;
653 /* Write the Segment */
654 KeInitializeEvent(&Event, NotificationEvent, FALSE);
655 Status = IoPageWrite(FileObject, Mdl, &WriteOffset, &Event, &Iosb);
656 if (Status == STATUS_PENDING)
658 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
659 Status = Iosb.Status;
661 if (!NT_SUCCESS(Status))
663 DPRINT1("IoPageWrite failed, status %x\n", Status);
666 while (current != NULL)
669 current = current->NextInChain;
670 CcRosReleaseCacheSegment(Bcb, previous, TRUE, FALSE, FALSE);
677 #endif /* LIBCAPTIVE */