1 /* $Id: copy.c,v 1.8 2002/08/08 17:54:13 dwelch Exp $
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
;
64 Status
= CcRosGetCacheSegmentChain(Bcb
, ReadOffset
, Length
, &head
);
65 if (!NT_SUCCESS(Status
))
70 while (current
!= NULL
)
73 * If the current segment is valid then copy it into the
78 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
79 memcpy(Buffer
, current
->BaseAddress
, TempLength
);
81 Length
= Length
- TempLength
;
83 current
= current
->NextInChain
;
84 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
87 * Otherwise read in as much as we can.
91 PCACHE_SEGMENT current2
;
98 * Count the maximum number of bytes we could read starting
99 * from the current segment.
103 while (current2
!= NULL
&& !current2
->Valid
)
105 current2
= current2
->NextInChain
;
106 current_size
+= Bcb
->CacheSegmentSize
;
110 * Create an MDL which contains all their pages.
112 Mdl
= MmCreateMdl(NULL
, NULL
, current_size
);
113 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
116 while (current2
!= NULL
&& !current2
->Valid
)
118 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGESIZE
); i
++)
121 PHYSICAL_ADDRESS page
;
122 address
= current2
->BaseAddress
+ (i
* PAGESIZE
);
123 page
= MmGetPhysicalAddressForProcess(NULL
, address
);
124 ((PULONG
)(Mdl
+ 1))[offset
] = page
.u
.LowPart
;
127 current2
= current2
->NextInChain
;
131 * Read in the information.
133 SegOffset
.QuadPart
= current
->FileOffset
;
134 Status
= IoPageRead(Bcb
->FileObject
,
139 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
141 while (current
!= NULL
)
144 current
= current
->NextInChain
;
145 CcRosReleaseCacheSegment(Bcb
, previous
, FALSE
, FALSE
, FALSE
);
149 while (current
!= NULL
&& !current
->Valid
)
152 current
= current
->NextInChain
;
153 TempLength
= min(Bcb
->CacheSegmentSize
, Length
);
154 memcpy(Buffer
, previous
->BaseAddress
, TempLength
);
155 Buffer
+= TempLength
;
156 Length
= Length
- TempLength
;
157 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);
161 return(STATUS_SUCCESS
);
165 ReadCacheSegment(PCACHE_SEGMENT CacheSeg
)
170 LARGE_INTEGER SegOffset
;
171 IO_STATUS_BLOCK IoStatus
;
173 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
174 Size
= CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
;
175 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
177 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
179 Mdl
= MmCreateMdl(NULL
, CacheSeg
->BaseAddress
, Size
);
180 MmBuildMdlForNonPagedPool(Mdl
);
181 Status
= IoPageRead(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &IoStatus
,
183 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
185 CcRosReleaseCacheSegment(CacheSeg
->Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
186 DPRINT1("IoPageRead failed, Status %x\n", Status
);
189 if (CacheSeg
->Bcb
->CacheSegmentSize
> Size
)
191 memset (CacheSeg
->BaseAddress
+ Size
, 0,
192 CacheSeg
->Bcb
->CacheSegmentSize
- Size
);
194 return STATUS_SUCCESS
;
198 WriteCacheSegment(PCACHE_SEGMENT CacheSeg
)
203 IO_STATUS_BLOCK IoStatus
;
204 LARGE_INTEGER SegOffset
;
206 CacheSeg
->Dirty
= FALSE
;
207 SegOffset
.QuadPart
= CacheSeg
->FileOffset
;
208 Size
= CacheSeg
->Bcb
->AllocationSize
.QuadPart
- CacheSeg
->FileOffset
;
209 if (Size
> CacheSeg
->Bcb
->CacheSegmentSize
)
211 Size
= CacheSeg
->Bcb
->CacheSegmentSize
;
213 Mdl
= MmCreateMdl(NULL
, CacheSeg
->BaseAddress
, Size
);
214 MmBuildMdlForNonPagedPool(Mdl
);
215 Status
= IoPageWrite(CacheSeg
->Bcb
->FileObject
, Mdl
, &SegOffset
, &IoStatus
,
217 if (!NT_SUCCESS(Status
))
219 DPRINT1("IoPageWrite failed, Status %x\n", Status
);
220 CacheSeg
->Dirty
= TRUE
;
223 return(STATUS_SUCCESS
);
227 CcCopyRead (IN PFILE_OBJECT FileObject
,
228 IN PLARGE_INTEGER FileOffset
,
232 OUT PIO_STATUS_BLOCK IoStatus
)
236 NTSTATUS Status
= STATUS_SUCCESS
;
238 PCACHE_SEGMENT CacheSeg
;
240 ULONG ReadLength
= 0;
243 PLIST_ENTRY current_entry
;
244 PCACHE_SEGMENT current
;
246 DPRINT("CcCopyRead(FileObject %x, FileOffset %x, "
247 "Length %d, Wait %d, Buffer %x, IoStatus %x)\n",
248 FileObject
, (ULONG
)FileOffset
->QuadPart
, Length
, Wait
,
251 Bcb
= ((REACTOS_COMMON_FCB_HEADER
*)FileObject
->FsContext
)->Bcb
;
252 ReadOffset
= FileOffset
->QuadPart
;
254 DPRINT("AllocationSize %d, FileSize %d\n",
255 (ULONG
)Bcb
->AllocationSize
.QuadPart
,
256 (ULONG
)Bcb
->FileSize
.QuadPart
);
259 * Check for the nowait case that all the cache segments that would
260 * cover this read are in memory.
264 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
265 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
266 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
268 current
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
269 BcbSegmentListEntry
);
270 if (!current
->Valid
&& current
->FileOffset
< ReadOffset
+ Length
271 && current
->FileOffset
+ Bcb
->CacheSegmentSize
> ReadOffset
)
273 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
274 IoStatus
->Status
= STATUS_UNSUCCESSFUL
;
275 IoStatus
->Information
= 0;
278 current_entry
= current_entry
->Flink
;
280 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
283 TempLength
= ReadOffset
% Bcb
->CacheSegmentSize
;
286 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
287 Status
= CcRosRequestCacheSegment(Bcb
,
288 ROUND_DOWN(ReadOffset
,
289 Bcb
->CacheSegmentSize
),
290 &BaseAddress
, &Valid
, &CacheSeg
);
291 if (!NT_SUCCESS(Status
))
293 IoStatus
->Information
= 0;
294 IoStatus
->Status
= Status
;
295 DPRINT("CcRosRequestCacheSegment faild, Status %x\n", Status
);
300 Status
= ReadCacheSegment(CacheSeg
);
301 if (!NT_SUCCESS(Status
))
303 IoStatus
->Information
= 0;
304 IoStatus
->Status
= Status
;
308 memcpy (Buffer
, BaseAddress
+ ReadOffset
% Bcb
->CacheSegmentSize
,
310 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
311 ReadLength
+= TempLength
;
312 Length
-= TempLength
;
313 ReadOffset
+= TempLength
;
314 Buffer
+= TempLength
;
318 TempLength
= min(max(Bcb
->CacheSegmentSize
, 65536), Length
);
319 ReadCacheSegmentChain(Bcb
, ReadOffset
, TempLength
, Buffer
);
320 ReadLength
+= TempLength
;
321 Length
-= TempLength
;
322 ReadOffset
+= TempLength
;
323 Buffer
+= TempLength
;
325 IoStatus
->Status
= STATUS_SUCCESS
;
326 IoStatus
->Information
= ReadLength
;
327 DPRINT("CcCopyRead O.K.\n");
332 CcCopyWrite (IN PFILE_OBJECT FileObject
,
333 IN PLARGE_INTEGER FileOffset
,
342 PLIST_ENTRY current_entry
;
343 PCACHE_SEGMENT CacheSeg
;
348 DPRINT("CcCopyWrite(FileObject %x, FileOffset %x, "
349 "Length %d, Wait %d, Buffer %x)\n",
350 FileObject
, (ULONG
)FileOffset
->QuadPart
, Length
, Wait
, Buffer
);
352 Bcb
= ((REACTOS_COMMON_FCB_HEADER
*)FileObject
->FsContext
)->Bcb
;
353 WriteOffset
= (ULONG
)FileOffset
->QuadPart
;
357 /* testing, if the requested datas are available */
358 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
359 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
360 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
362 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
363 BcbSegmentListEntry
);
364 if (!CacheSeg
->Valid
)
366 if ((WriteOffset
>= CacheSeg
->FileOffset
&&
367 WriteOffset
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
368 || (WriteOffset
+ Length
> CacheSeg
->FileOffset
&&
369 WriteOffset
+ Length
<= CacheSeg
->FileOffset
+
370 Bcb
->CacheSegmentSize
))
372 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
373 /* datas not available */
377 current_entry
= current_entry
->Flink
;
379 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
382 TempLength
= WriteOffset
% Bcb
->CacheSegmentSize
;
386 ROffset
= ROUND_DOWN(WriteOffset
, Bcb
->CacheSegmentSize
);
387 TempLength
= min (Length
, Bcb
->CacheSegmentSize
- TempLength
);
388 Status
= CcRosRequestCacheSegment(Bcb
, ROffset
,
389 &BaseAddress
, &Valid
, &CacheSeg
);
390 if (!NT_SUCCESS(Status
))
396 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
401 memcpy (BaseAddress
+ WriteOffset
% Bcb
->CacheSegmentSize
,
403 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
405 Length
-= TempLength
;
406 WriteOffset
+= TempLength
;
407 Buffer
+= TempLength
;
412 TempLength
= min (Bcb
->CacheSegmentSize
, Length
);
413 Status
= CcRosRequestCacheSegment(Bcb
, WriteOffset
,
414 &BaseAddress
, &Valid
, &CacheSeg
);
415 if (!NT_SUCCESS(Status
))
419 if (!Valid
&& TempLength
< Bcb
->CacheSegmentSize
)
421 if (!NT_SUCCESS(ReadCacheSegment(CacheSeg
)))
426 memcpy (BaseAddress
, Buffer
, TempLength
);
427 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, TRUE
, FALSE
);
428 Length
-= TempLength
;
429 WriteOffset
+= TempLength
;
430 Buffer
+= TempLength
;
436 CcZeroData (IN PFILE_OBJECT FileObject
,
437 IN PLARGE_INTEGER StartOffset
,
438 IN PLARGE_INTEGER EndOffset
,
442 LARGE_INTEGER WriteOffset
;
446 IO_STATUS_BLOCK Iosb
;
448 DPRINT("CcZeroData(FileObject %x, StartOffset %I64x, EndOffset %I64x, "
449 "Wait %d\n", FileObject
, StartOffset
->QuadPart
, EndOffset
->QuadPart
,
452 Length
= EndOffset
->u
.LowPart
- StartOffset
->u
.LowPart
;
455 * FIXME: NT uses the shared cache map field for cached/non cached detection
457 if (((PREACTOS_COMMON_FCB_HEADER
)FileObject
->FsContext
)->Bcb
== NULL
)
459 /* File is not cached */
460 WriteOffset
.QuadPart
= StartOffset
->QuadPart
;
464 if (Length
+ WriteOffset
.u
.LowPart
% PAGESIZE
> 262144)
466 Mdl
= MmCreateMdl(NULL
, (PVOID
)WriteOffset
.u
.LowPart
,
467 262144 - WriteOffset
.u
.LowPart
% PAGESIZE
);
468 WriteOffset
.QuadPart
+=
469 (262144 - WriteOffset
.u
.LowPart
% PAGESIZE
);
470 Length
-= (262144 - WriteOffset
.u
.LowPart
% PAGESIZE
);
475 MmCreateMdl(NULL
, (PVOID
)WriteOffset
.u
.LowPart
,
476 Length
- WriteOffset
.u
.LowPart
% PAGESIZE
);
477 WriteOffset
.QuadPart
+=
478 (Length
- WriteOffset
.u
.LowPart
% PAGESIZE
);
485 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
| MDL_IO_PAGE_READ
);
486 for (i
= 0; i
< ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
)); i
++)
488 ((PULONG
)(Mdl
+ 1))[i
] = CcZeroPage
.u
.LowPart
;
490 Status
= IoPageWrite(FileObject
, Mdl
, StartOffset
, &Iosb
, TRUE
);
491 if (!NT_SUCCESS(Status
))
502 PLIST_ENTRY current_entry
;
503 PCACHE_SEGMENT CacheSeg
, current
, previous
;
508 PHYSICAL_ADDRESS page
;
510 Start
= StartOffset
->u
.LowPart
;
511 Bcb
= ((REACTOS_COMMON_FCB_HEADER
*)FileObject
->FsContext
)->Bcb
;
514 /* testing, if the requested datas are available */
515 KeAcquireSpinLock(&Bcb
->BcbLock
, &oldirql
);
516 current_entry
= Bcb
->BcbSegmentListHead
.Flink
;
517 while (current_entry
!= &Bcb
->BcbSegmentListHead
)
519 CacheSeg
= CONTAINING_RECORD(current_entry
, CACHE_SEGMENT
,
520 BcbSegmentListEntry
);
521 if (!CacheSeg
->Valid
)
523 if ((Start
>= CacheSeg
->FileOffset
&&
524 Start
< CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
)
525 || (Start
+ Length
> CacheSeg
->FileOffset
&&
527 CacheSeg
->FileOffset
+ Bcb
->CacheSegmentSize
))
529 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
530 /* datas not available */
534 current_entry
= current_entry
->Flink
;
536 KeReleaseSpinLock(&Bcb
->BcbLock
, oldirql
);
541 ULONG RStart
= ROUND_DOWN(Start
, Bcb
->CacheSegmentSize
);
542 WriteOffset
.QuadPart
= ROUND_DOWN(Start
, Bcb
->CacheSegmentSize
);
543 if (Start
% Bcb
->CacheSegmentSize
+ Length
> 262144)
545 Mdl
= MmCreateMdl(NULL
, NULL
, 262144);
550 Status
= CcRosGetCacheSegmentChain (Bcb
, RStart
,
552 if (!NT_SUCCESS(Status
))
561 Mdl
= MmCreateMdl(NULL
, (PVOID
)RStart
,
562 ROUND_UP(Start
% Bcb
->CacheSegmentSize
+
563 Length
, Bcb
->CacheSegmentSize
));
568 RLength
= ROUND_UP(RStart
+ Length
, Bcb
->CacheSegmentSize
);
569 RLength
= min(RLength
, Bcb
->AllocationSize
.u
.LowPart
);
571 Status
= CcRosGetCacheSegmentChain (Bcb
, RStart
, RLength
,
573 if (!NT_SUCCESS(Status
))
579 Mdl
->MdlFlags
|= (MDL_PAGES_LOCKED
|MDL_IO_PAGE_READ
);
582 while (current
!= NULL
)
584 if ((Start
% Bcb
->CacheSegmentSize
) != 0 ||
585 Start
% Bcb
->CacheSegmentSize
+ Length
<
586 Bcb
->CacheSegmentSize
)
591 Status
= ReadCacheSegment(current
);
592 if (!NT_SUCCESS(Status
))
594 DPRINT1("ReadCacheSegment failed, status %x\n",
598 TempLength
= min (Length
, Bcb
->CacheSegmentSize
-
599 Start
% Bcb
->CacheSegmentSize
);
600 memset (current
->BaseAddress
+ Start
% Bcb
->CacheSegmentSize
,
605 TempLength
= Bcb
->CacheSegmentSize
;
606 memset (current
->BaseAddress
, 0, Bcb
->CacheSegmentSize
);
609 Length
-= TempLength
;
611 size
= ((Mdl
->Size
- sizeof(MDL
)) / sizeof(ULONG
));
612 for (i
= 0; i
< (Bcb
->CacheSegmentSize
/ PAGESIZE
) &&
616 Address
= current
->BaseAddress
+ (i
* PAGESIZE
);
618 MmGetPhysicalAddressForProcess(NULL
, Address
);
619 ((PULONG
)(Mdl
+ 1))[count
++] = page
.u
.LowPart
;
621 current
= current
->NextInChain
;
624 /* Write the Segment */
625 Status
= IoPageWrite(FileObject
, Mdl
, &WriteOffset
, &Iosb
, TRUE
);
626 if (!NT_SUCCESS(Status
))
628 DPRINT1("IoPageWrite failed, status %x\n", Status
);
631 while (current
!= NULL
)
634 current
= current
->NextInChain
;
635 CcRosReleaseCacheSegment(Bcb
, previous
, TRUE
, FALSE
, FALSE
);