Sync with trunk r63430.
[reactos.git] / ntoskrnl / mm / pagefile.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/pagefile.c
22 * PURPOSE: Paging file functions
23 * PROGRAMMER: David Welch (welch@mcmail.com)
24 * UPDATE HISTORY:
25 * Created 22/05/98
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ntoskrnl.h>
31 #define NDEBUG
32 #include <debug.h>
33
34 #if defined (ALLOC_PRAGMA)
35 #pragma alloc_text(INIT, MmInitPagingFile)
36 #endif
37
38 PVOID
39 NTAPI
40 MiFindExportedRoutineByName(IN PVOID DllBase,
41 IN PANSI_STRING ExportName);
42
43 /* TYPES *********************************************************************/
44
45 typedef struct _PAGINGFILE
46 {
47 LIST_ENTRY PagingFileListEntry;
48 PFILE_OBJECT FileObject;
49 LARGE_INTEGER MaximumSize;
50 LARGE_INTEGER CurrentSize;
51 ULONG FreePages;
52 ULONG UsedPages;
53 PULONG AllocMap;
54 KSPIN_LOCK AllocMapLock;
55 ULONG AllocMapSize;
56 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
57 }
58 PAGINGFILE, *PPAGINGFILE;
59
60 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
61 {
62 struct _RETRIEVEL_DESCRIPTOR_LIST* Next;
63 RETRIEVAL_POINTERS_BUFFER RetrievalPointers;
64 }
65 RETRIEVEL_DESCRIPTOR_LIST, *PRETRIEVEL_DESCRIPTOR_LIST;
66
67 /* GLOBALS *******************************************************************/
68
69 #define PAIRS_PER_RUN (1024)
70
71 #define MAX_PAGING_FILES (32)
72
73 /* List of paging files, both used and free */
74 static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
75
76 /* Lock for examining the list of paging files */
77 static KSPIN_LOCK PagingFileListLock;
78
79 /* Number of paging files */
80 static ULONG MiPagingFileCount;
81 ULONG MmNumberOfPagingFiles;
82
83 /* Number of pages that are available for swapping */
84 PFN_COUNT MiFreeSwapPages;
85
86 /* Number of pages that have been allocated for swapping */
87 PFN_COUNT MiUsedSwapPages;
88
89 BOOLEAN MmZeroPageFile;
90
91 /*
92 * Number of pages that have been reserved for swapping but not yet allocated
93 */
94 static PFN_COUNT MiReservedSwapPages;
95
96 /*
97 * Ratio between reserved and available swap pages, e.g. setting this to five
98 * forces one swap page to be available for every five swap pages that are
99 * reserved. Setting this to zero turns off commit checking altogether.
100 */
101 #define MM_PAGEFILE_COMMIT_RATIO (1)
102
103 /*
104 * Number of pages that can be used for potentially swapable memory without
105 * pagefile space being reserved. The intention is that this allows smss
106 * to start up and create page files while ordinarily having a commit
107 * ratio of one.
108 */
109 #define MM_PAGEFILE_COMMIT_GRACE (256)
110
111 /*
112 * Translate between a swap entry and a file and offset pair.
113 */
114 #define FILE_FROM_ENTRY(i) ((i) & 0x0f)
115 #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
116 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)
117
118 /* Make sure there can be only 16 paging files */
119 C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES);
120
121 static BOOLEAN MmSwapSpaceMessage = FALSE;
122
123 /* FUNCTIONS *****************************************************************/
124
125 VOID
126 NTAPI
127 MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages)
128 {
129 memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE));
130
131 /* FIXME: this flag should be set by the caller perhaps? */
132 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
133 }
134
135
136 BOOLEAN
137 NTAPI
138 MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject)
139 {
140 ULONG i;
141
142 /* Loop through all the paging files */
143 for (i = 0; i < MiPagingFileCount; i++)
144 {
145 /* Check if this is one of them */
146 if (PagingFileList[i]->FileObject == FileObject) return TRUE;
147 }
148
149 /* Nothing found */
150 return FALSE;
151 }
152
153 VOID
154 NTAPI
155 MmShowOutOfSpaceMessagePagingFile(VOID)
156 {
157 if (!MmSwapSpaceMessage)
158 {
159 DPRINT1("MM: Out of swap space.\n");
160 MmSwapSpaceMessage = TRUE;
161 }
162 }
163
164 static LARGE_INTEGER
165 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers, LARGE_INTEGER Offset)
166 {
167 /* Simple binary search */
168 ULONG first, last, mid;
169 first = 0;
170 last = RetrievalPointers->ExtentCount - 1;
171 while (first <= last)
172 {
173 mid = (last - first) / 2 + first;
174 if (Offset.QuadPart < RetrievalPointers->Extents[mid].NextVcn.QuadPart)
175 {
176 if (mid == 0)
177 {
178 Offset.QuadPart += RetrievalPointers->Extents[0].Lcn.QuadPart - RetrievalPointers->StartingVcn.QuadPart;
179 return Offset;
180 }
181 else
182 {
183 if (Offset.QuadPart >= RetrievalPointers->Extents[mid-1].NextVcn.QuadPart)
184 {
185 Offset.QuadPart += RetrievalPointers->Extents[mid].Lcn.QuadPart - RetrievalPointers->Extents[mid-1].NextVcn.QuadPart;
186 return Offset;
187 }
188 last = mid - 1;
189 }
190 }
191 else
192 {
193 if (mid == RetrievalPointers->ExtentCount - 1)
194 {
195 break;
196 }
197 if (Offset.QuadPart < RetrievalPointers->Extents[mid+1].NextVcn.QuadPart)
198 {
199 Offset.QuadPart += RetrievalPointers->Extents[mid+1].Lcn.QuadPart - RetrievalPointers->Extents[mid].NextVcn.QuadPart;
200 return Offset;
201 }
202 first = mid + 1;
203 }
204 }
205 KeBugCheck(MEMORY_MANAGEMENT);
206 #if defined(__GNUC__)
207
208 return (LARGE_INTEGER)0LL;
209 #else
210
211 {
212 const LARGE_INTEGER dummy =
213 {
214 0
215 };
216 return dummy;
217 }
218 #endif
219 }
220
221 NTSTATUS
222 NTAPI
223 MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
224 {
225 ULONG i;
226 ULONG_PTR offset;
227 LARGE_INTEGER file_offset;
228 IO_STATUS_BLOCK Iosb;
229 NTSTATUS Status;
230 KEVENT Event;
231 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
232 PMDL Mdl = (PMDL)MdlBase;
233
234 DPRINT("MmWriteToSwapPage\n");
235
236 if (SwapEntry == 0)
237 {
238 KeBugCheck(MEMORY_MANAGEMENT);
239 return(STATUS_UNSUCCESSFUL);
240 }
241
242 i = FILE_FROM_ENTRY(SwapEntry);
243 offset = OFFSET_FROM_ENTRY(SwapEntry);
244
245 if (PagingFileList[i]->FileObject == NULL ||
246 PagingFileList[i]->FileObject->DeviceObject == NULL)
247 {
248 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
249 KeBugCheck(MEMORY_MANAGEMENT);
250 }
251
252 MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
253 MmBuildMdlFromPages(Mdl, &Page);
254 Mdl->MdlFlags |= MDL_PAGES_LOCKED;
255
256 file_offset.QuadPart = offset * PAGE_SIZE;
257 file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset);
258
259 KeInitializeEvent(&Event, NotificationEvent, FALSE);
260 Status = IoSynchronousPageWrite(PagingFileList[i]->FileObject,
261 Mdl,
262 &file_offset,
263 &Event,
264 &Iosb);
265 if (Status == STATUS_PENDING)
266 {
267 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
268 Status = Iosb.Status;
269 }
270
271 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
272 {
273 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
274 }
275 return(Status);
276 }
277
278 NTSTATUS
279 NTAPI
280 MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
281 {
282 ULONG i;
283 ULONG_PTR offset;
284 LARGE_INTEGER file_offset;
285 IO_STATUS_BLOCK Iosb;
286 NTSTATUS Status;
287 KEVENT Event;
288 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
289 PMDL Mdl = (PMDL)MdlBase;
290
291 DPRINT("MmReadFromSwapPage\n");
292
293 if (SwapEntry == 0)
294 {
295 KeBugCheck(MEMORY_MANAGEMENT);
296 return(STATUS_UNSUCCESSFUL);
297 }
298
299 i = FILE_FROM_ENTRY(SwapEntry);
300 offset = OFFSET_FROM_ENTRY(SwapEntry);
301
302 if (PagingFileList[i]->FileObject == NULL ||
303 PagingFileList[i]->FileObject->DeviceObject == NULL)
304 {
305 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
306 KeBugCheck(MEMORY_MANAGEMENT);
307 }
308
309 MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
310 MmBuildMdlFromPages(Mdl, &Page);
311 Mdl->MdlFlags |= MDL_PAGES_LOCKED;
312
313 file_offset.QuadPart = offset * PAGE_SIZE;
314 file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset);
315
316 KeInitializeEvent(&Event, NotificationEvent, FALSE);
317 Status = IoPageRead(PagingFileList[i]->FileObject,
318 Mdl,
319 &file_offset,
320 &Event,
321 &Iosb);
322 if (Status == STATUS_PENDING)
323 {
324 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
325 Status = Iosb.Status;
326 }
327 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
328 {
329 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
330 }
331 return(Status);
332 }
333
334 VOID
335 INIT_FUNCTION
336 NTAPI
337 MmInitPagingFile(VOID)
338 {
339 ULONG i;
340
341 KeInitializeSpinLock(&PagingFileListLock);
342
343 MiFreeSwapPages = 0;
344 MiUsedSwapPages = 0;
345 MiReservedSwapPages = 0;
346
347 for (i = 0; i < MAX_PAGING_FILES; i++)
348 {
349 PagingFileList[i] = NULL;
350 }
351 MiPagingFileCount = 0;
352 }
353
354 static ULONG
355 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
356 {
357 KIRQL oldIrql;
358 ULONG i, j;
359
360 KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
361
362 for (i = 0; i < PagingFile->AllocMapSize; i++)
363 {
364 for (j = 0; j < 32; j++)
365 {
366 if (!(PagingFile->AllocMap[i] & (1 << j)))
367 {
368 PagingFile->AllocMap[i] |= (1 << j);
369 PagingFile->UsedPages++;
370 PagingFile->FreePages--;
371 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
372 return((i * 32) + j);
373 }
374 }
375 }
376
377 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
378 return(0xFFFFFFFF);
379 }
380
381 VOID
382 NTAPI
383 MmFreeSwapPage(SWAPENTRY Entry)
384 {
385 ULONG i;
386 ULONG_PTR off;
387 KIRQL oldIrql;
388
389 i = FILE_FROM_ENTRY(Entry);
390 off = OFFSET_FROM_ENTRY(Entry);
391
392 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
393 if (PagingFileList[i] == NULL)
394 {
395 KeBugCheck(MEMORY_MANAGEMENT);
396 }
397 KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock);
398
399 PagingFileList[i]->AllocMap[off >> 5] &= (~(1 << (off % 32)));
400
401 PagingFileList[i]->FreePages++;
402 PagingFileList[i]->UsedPages--;
403
404 MiFreeSwapPages++;
405 MiUsedSwapPages--;
406
407 KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock);
408 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
409 }
410
411 SWAPENTRY
412 NTAPI
413 MmAllocSwapPage(VOID)
414 {
415 KIRQL oldIrql;
416 ULONG i;
417 ULONG off;
418 SWAPENTRY entry;
419
420 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
421
422 if (MiFreeSwapPages == 0)
423 {
424 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
425 return(0);
426 }
427
428 for (i = 0; i < MAX_PAGING_FILES; i++)
429 {
430 if (PagingFileList[i] != NULL &&
431 PagingFileList[i]->FreePages >= 1)
432 {
433 off = MiAllocPageFromPagingFile(PagingFileList[i]);
434 if (off == 0xFFFFFFFF)
435 {
436 KeBugCheck(MEMORY_MANAGEMENT);
437 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
438 return(STATUS_UNSUCCESSFUL);
439 }
440 MiUsedSwapPages++;
441 MiFreeSwapPages--;
442 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
443
444 entry = ENTRY_FROM_FILE_OFFSET(i, off);
445 return(entry);
446 }
447 }
448
449 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
450 KeBugCheck(MEMORY_MANAGEMENT);
451 return(0);
452 }
453
454 static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
455 MmAllocRetrievelDescriptorList(ULONG Pairs)
456 {
457 ULONG Size;
458 PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
459
460 Size = sizeof(RETRIEVEL_DESCRIPTOR_LIST) + Pairs * 2 * sizeof(LARGE_INTEGER);
461 RetDescList = ExAllocatePool(NonPagedPool, Size);
462 if (RetDescList)
463 {
464 RtlZeroMemory(RetDescList, Size);
465 }
466
467 return RetDescList;
468 }
469
470 NTSTATUS NTAPI
471 NtCreatePagingFile(IN PUNICODE_STRING FileName,
472 IN PLARGE_INTEGER InitialSize,
473 IN PLARGE_INTEGER MaximumSize,
474 IN ULONG Reserved)
475 {
476 NTSTATUS Status;
477 OBJECT_ATTRIBUTES ObjectAttributes;
478 HANDLE FileHandle;
479 IO_STATUS_BLOCK IoStatus;
480 PFILE_OBJECT FileObject;
481 PPAGINGFILE PagingFile;
482 KIRQL oldIrql;
483 ULONG AllocMapSize;
484 FILE_FS_SIZE_INFORMATION FsSizeInformation;
485 PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
486 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList;
487 ULONG i;
488 ULONG BytesPerAllocationUnit;
489 LARGE_INTEGER Vcn;
490 ULONG ExtentCount;
491 LARGE_INTEGER MaxVcn;
492 ULONG Count;
493 ULONG Size;
494 KPROCESSOR_MODE PreviousMode;
495 UNICODE_STRING CapturedFileName;
496 LARGE_INTEGER SafeInitialSize, SafeMaximumSize;
497
498 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
499 FileName, InitialSize->QuadPart);
500
501 if (MiPagingFileCount >= MAX_PAGING_FILES)
502 {
503 return(STATUS_TOO_MANY_PAGING_FILES);
504 }
505
506 PreviousMode = ExGetPreviousMode();
507
508 if (PreviousMode != KernelMode)
509 {
510 _SEH2_TRY
511 {
512 SafeInitialSize = ProbeForReadLargeInteger(InitialSize);
513 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
514 }
515 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
516 {
517 /* Return the exception code */
518 _SEH2_YIELD(return _SEH2_GetExceptionCode());
519 }
520 _SEH2_END;
521 }
522 else
523 {
524 SafeInitialSize = *InitialSize;
525 SafeMaximumSize = *MaximumSize;
526 }
527
528 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
529 smaller than the maximum */
530 if (0 != SafeInitialSize.u.HighPart)
531 {
532 return STATUS_INVALID_PARAMETER_2;
533 }
534 if (0 != SafeMaximumSize.u.HighPart)
535 {
536 return STATUS_INVALID_PARAMETER_3;
537 }
538 if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart)
539 {
540 return STATUS_INVALID_PARAMETER_MIX;
541 }
542
543 Status = ProbeAndCaptureUnicodeString(&CapturedFileName,
544 PreviousMode,
545 FileName);
546 if (!NT_SUCCESS(Status))
547 {
548 return(Status);
549 }
550
551 InitializeObjectAttributes(&ObjectAttributes,
552 &CapturedFileName,
553 0,
554 NULL,
555 NULL);
556
557 Status = IoCreateFile(&FileHandle,
558 FILE_ALL_ACCESS,
559 &ObjectAttributes,
560 &IoStatus,
561 NULL,
562 0,
563 0,
564 FILE_OPEN_IF,
565 FILE_SYNCHRONOUS_IO_NONALERT,
566 NULL,
567 0,
568 CreateFileTypeNone,
569 NULL,
570 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
571
572 ReleaseCapturedUnicodeString(&CapturedFileName,
573 PreviousMode);
574 if (!NT_SUCCESS(Status))
575 {
576 return(Status);
577 }
578
579 Status = ZwQueryVolumeInformationFile(FileHandle,
580 &IoStatus,
581 &FsSizeInformation,
582 sizeof(FILE_FS_SIZE_INFORMATION),
583 FileFsSizeInformation);
584 if (!NT_SUCCESS(Status))
585 {
586 ZwClose(FileHandle);
587 return Status;
588 }
589
590 BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit *
591 FsSizeInformation.BytesPerSector;
592 /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
593 * a problem if the paging file is fragmented. Suppose the first cluster
594 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
595 * paging file but of another file. We can't write a complete page (4096
596 * bytes) to the physical location of cluster 3042 then. */
597 if (BytesPerAllocationUnit % PAGE_SIZE)
598 {
599 DPRINT1("BytesPerAllocationUnit %lu is not a multiple of PAGE_SIZE %d\n",
600 BytesPerAllocationUnit, PAGE_SIZE);
601 ZwClose(FileHandle);
602 return STATUS_UNSUCCESSFUL;
603 }
604
605 Status = ZwSetInformationFile(FileHandle,
606 &IoStatus,
607 &SafeInitialSize,
608 sizeof(LARGE_INTEGER),
609 FileAllocationInformation);
610 if (!NT_SUCCESS(Status))
611 {
612 ZwClose(FileHandle);
613 return(Status);
614 }
615
616 Status = ObReferenceObjectByHandle(FileHandle,
617 FILE_ALL_ACCESS,
618 IoFileObjectType,
619 PreviousMode,
620 (PVOID*)&FileObject,
621 NULL);
622 if (!NT_SUCCESS(Status))
623 {
624 ZwClose(FileHandle);
625 return(Status);
626 }
627
628 CurrentRetDescList = RetDescList = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
629
630 if (CurrentRetDescList == NULL)
631 {
632 ObDereferenceObject(FileObject);
633 ZwClose(FileHandle);
634 return(STATUS_NO_MEMORY);
635 }
636
637 #if defined(__GNUC__)
638 Vcn.QuadPart = 0LL;
639 #else
640
641 Vcn.QuadPart = 0;
642 #endif
643
644 ExtentCount = 0;
645 MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit;
646 while(1)
647 {
648 Status = ZwFsControlFile(FileHandle,
649 0,
650 NULL,
651 NULL,
652 &IoStatus,
653 FSCTL_GET_RETRIEVAL_POINTERS,
654 &Vcn,
655 sizeof(LARGE_INTEGER),
656 &CurrentRetDescList->RetrievalPointers,
657 sizeof(RETRIEVAL_POINTERS_BUFFER) + PAIRS_PER_RUN * 2 * sizeof(LARGE_INTEGER));
658 if (!NT_SUCCESS(Status))
659 {
660 while (RetDescList)
661 {
662 CurrentRetDescList = RetDescList;
663 RetDescList = RetDescList->Next;
664 ExFreePool(CurrentRetDescList);
665 }
666 ObDereferenceObject(FileObject);
667 ZwClose(FileHandle);
668 return(Status);
669 }
670 ExtentCount += CurrentRetDescList->RetrievalPointers.ExtentCount;
671 if (CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn.QuadPart < MaxVcn.QuadPart)
672 {
673 CurrentRetDescList->Next = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
674 if (CurrentRetDescList->Next == NULL)
675 {
676 while (RetDescList)
677 {
678 CurrentRetDescList = RetDescList;
679 RetDescList = RetDescList->Next;
680 ExFreePool(CurrentRetDescList);
681 }
682 ObDereferenceObject(FileObject);
683 ZwClose(FileHandle);
684 return(STATUS_NO_MEMORY);
685 }
686 Vcn = CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn;
687 CurrentRetDescList = CurrentRetDescList->Next;
688 }
689 else
690 {
691 break;
692 }
693 }
694
695 PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
696 if (PagingFile == NULL)
697 {
698 while (RetDescList)
699 {
700 CurrentRetDescList = RetDescList;
701 RetDescList = RetDescList->Next;
702 ExFreePool(CurrentRetDescList);
703 }
704 ObDereferenceObject(FileObject);
705 ZwClose(FileHandle);
706 return(STATUS_NO_MEMORY);
707 }
708
709 RtlZeroMemory(PagingFile, sizeof(*PagingFile));
710
711 PagingFile->FileObject = FileObject;
712 PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart;
713 PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart;
714 PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE);
715 PagingFile->UsedPages = 0;
716 KeInitializeSpinLock(&PagingFile->AllocMapLock);
717
718 AllocMapSize = (PagingFile->FreePages / 32) + 1;
719 PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
720 AllocMapSize * sizeof(ULONG));
721 PagingFile->AllocMapSize = AllocMapSize;
722
723 if (PagingFile->AllocMap == NULL)
724 {
725 while (RetDescList)
726 {
727 CurrentRetDescList = RetDescList;
728 RetDescList = RetDescList->Next;
729 ExFreePool(CurrentRetDescList);
730 }
731 ExFreePool(PagingFile);
732 ObDereferenceObject(FileObject);
733 ZwClose(FileHandle);
734 return(STATUS_NO_MEMORY);
735 }
736 DPRINT("ExtentCount: %lu\n", ExtentCount);
737 Size = sizeof(RETRIEVAL_POINTERS_BUFFER) + ExtentCount * 2 * sizeof(LARGE_INTEGER);
738 PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size);
739 if (PagingFile->RetrievalPointers == NULL)
740 {
741 while (RetDescList)
742 {
743 CurrentRetDescList = RetDescList;
744 RetDescList = RetDescList->Next;
745 ExFreePool(CurrentRetDescList);
746 }
747 ExFreePool(PagingFile->AllocMap);
748 ExFreePool(PagingFile);
749 ObDereferenceObject(FileObject);
750 ZwClose(FileHandle);
751 return(STATUS_NO_MEMORY);
752 }
753
754 RtlZeroMemory(PagingFile->AllocMap, AllocMapSize * sizeof(ULONG));
755 RtlZeroMemory(PagingFile->RetrievalPointers, Size);
756
757 Count = 0;
758 PagingFile->RetrievalPointers->ExtentCount = ExtentCount;
759 PagingFile->RetrievalPointers->StartingVcn = RetDescList->RetrievalPointers.StartingVcn;
760 CurrentRetDescList = RetDescList;
761 while (CurrentRetDescList)
762 {
763 memcpy(&PagingFile->RetrievalPointers->Extents[Count],
764 CurrentRetDescList->RetrievalPointers.Extents,
765 CurrentRetDescList->RetrievalPointers.ExtentCount * 2 * sizeof(LARGE_INTEGER));
766 Count += CurrentRetDescList->RetrievalPointers.ExtentCount;
767 RetDescList = CurrentRetDescList;
768 CurrentRetDescList = CurrentRetDescList->Next;
769 ExFreePool(RetDescList);
770 }
771
772 if (PagingFile->RetrievalPointers->ExtentCount != ExtentCount ||
773 PagingFile->RetrievalPointers->Extents[ExtentCount - 1].NextVcn.QuadPart != MaxVcn.QuadPart)
774 {
775 ExFreePool(PagingFile->RetrievalPointers);
776 ExFreePool(PagingFile->AllocMap);
777 ExFreePool(PagingFile);
778 ObDereferenceObject(FileObject);
779 ZwClose(FileHandle);
780 return(STATUS_UNSUCCESSFUL);
781 }
782
783 /*
784 * Change the entries from lcn's to volume offset's.
785 */
786 PagingFile->RetrievalPointers->StartingVcn.QuadPart *= BytesPerAllocationUnit;
787 for (i = 0; i < ExtentCount; i++)
788 {
789 PagingFile->RetrievalPointers->Extents[i].Lcn.QuadPart *= BytesPerAllocationUnit;
790 PagingFile->RetrievalPointers->Extents[i].NextVcn.QuadPart *= BytesPerAllocationUnit;
791 }
792
793 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
794 for (i = 0; i < MAX_PAGING_FILES; i++)
795 {
796 if (PagingFileList[i] == NULL)
797 {
798 PagingFileList[i] = PagingFile;
799 break;
800 }
801 }
802 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
803 MiPagingFileCount++;
804 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
805
806 ZwClose(FileHandle);
807
808 MmSwapSpaceMessage = FALSE;
809
810 return(STATUS_SUCCESS);
811 }
812
813 /* EOF */